From deae80857125f0a5d49ea846a08c78e2e2ec1da9 Mon Sep 17 00:00:00 2001 From: cailean Date: Wed, 23 Apr 2025 22:39:37 +0100 Subject: [PATCH] patch for cpp 17 & of 12 --- .github/FUNDING.yml | 10 +- .github/workflows/linux.yml | 114 +- .github/workflows/osx.yml | 120 +- .github/workflows/windows.yml | 134 +- .gitignore | 242 +- LICENSE.md | 18 +- README.md | 496 +- addon_config.mk | 152 +- example_basic/Makefile | 26 +- example_basic/README.md | 14 +- example_basic/addons.make | 8 +- example_basic/addons.make.norpi | 6 +- example_basic/bin/data/ofxpimapper.xml | 239 +- example_basic/src/main.cpp | 14 +- example_basic/src/ofApp.cpp | 76 +- example_basic/src/ofApp.h | 50 +- example_camera/.gitignore | 10 +- example_camera/Makefile | 26 +- example_camera/README.md | 18 +- example_camera/addons.make | 10 +- example_camera/addons.make.norpi | 6 +- example_camera/bin/data/defaultSurfaces.xml | 72 +- example_camera/bin/data/ofxpimapper.xml | 140 +- example_camera/src/CameraSource.cpp | 124 +- example_camera/src/CameraSource.h | 66 +- example_camera/src/main.cpp | 48 +- example_camera/src/ofApp.cpp | 72 +- example_camera/src/ofApp.h | 60 +- example_fbo-sources/.gitignore | 10 +- example_fbo-sources/Makefile | 26 +- example_fbo-sources/README.md | 56 +- example_fbo-sources/addons.make | 8 +- example_fbo-sources/addons.make.norpi | 6 +- .../bin/data/magslideshow_settings.xml | 30 +- example_fbo-sources/bin/data/ofxpimapper.xml | 252 +- .../src/BrickSource/BrickSource.cpp | 104 +- .../src/BrickSource/BrickSource.h | 30 +- .../src/CircleSource/CircleSource.cpp | 86 +- .../src/CircleSource/CircleSource.h | 28 +- .../src/QuadSource/QuadSource.cpp | 124 +- .../src/QuadSource/QuadSource.h | 28 +- .../src/ScanLineSource/ScanlineSource.cpp | 96 +- .../src/ScanLineSource/ScanlineSource.h | 28 +- .../src/SlideShowSource/magSlide.cpp | 402 +- .../src/SlideShowSource/magSlide.h | 526 +- .../SlideShowSource/magSlideShowSource.cpp | 1058 ++-- .../src/SlideShowSource/magSlideShowSource.h | 334 +- .../SlideShowSource/magSlideTransition.cpp | 120 +- .../src/SlideShowSource/magSlideTransition.h | 258 +- .../magSlideTransitionFactory.cpp | 152 +- .../magSlideTransitionFactory.h | 82 +- .../src/SyphonSource/SyphonSource.cpp | 174 +- .../src/SyphonSource/SyphonSource.h | 42 +- example_fbo-sources/src/main.cpp | 14 +- example_fbo-sources/src/ofApp.cpp | 114 +- example_fbo-sources/src/ofApp.h | 74 +- example_pocketvj/.gitignore | 12 +- example_pocketvj/Makefile | 26 +- example_pocketvj/addons.make | 8 +- example_pocketvj/addons.make.norpi | 6 +- example_pocketvj/bin/data/ofxpimapper.xml | 72 +- example_pocketvj/src/main.cpp | 18 +- example_pocketvj/src/ofApp.cpp | 248 +- example_pocketvj/src/ofApp.h | 42 +- example_remote-client/Makefile | 26 +- example_remote-client/README.md | 44 +- example_remote-client/addons.make | 12 +- example_remote-client/addons.make.norpi | 10 +- example_remote-client/bin/data/config.json | 8 +- .../bin/data/ofxpimapper.xml | 72 +- example_remote-client/src/TCPClient.cpp | 98 +- example_remote-client/src/TCPClient.h | 44 +- example_remote-client/src/main.cpp | 14 +- example_remote-client/src/ofApp.cpp | 218 +- example_remote-client/src/ofApp.h | 50 +- example_remote-server/Makefile | 26 +- example_remote-server/README.md | 50 +- example_remote-server/addons.make | 12 +- example_remote-server/addons.make.norpi | 10 +- .../bin/data/ofxpimapper.xml | 72 +- example_remote-server/src/TCPServer.cpp | 190 +- example_remote-server/src/TCPServer.h | 46 +- example_remote-server/src/main.cpp | 14 +- example_remote-server/src/ofApp.cpp | 168 +- example_remote-server/src/ofApp.h | 46 +- example_simpler/.gitignore | 10 +- example_simpler/Makefile | 26 +- example_simpler/addons.make | 8 +- example_simpler/addons.make.norpi | 6 +- example_simpler/bin/data/ofxpimapper.xml | 162 +- example_simpler/src/CustomSource.cpp | 82 +- example_simpler/src/CustomSource.h | 26 +- example_simpler/src/Settings.cpp | 42 +- example_simpler/src/Settings.h | 36 +- example_simpler/src/main.cpp | 44 +- example_simpler/src/ofApp.cpp | 110 +- example_simpler/src/ofApp.h | 56 +- patches/msys2/makefileCommon/config.addons.mk | 532 +- patches/msys2/patch.sh | 16 +- patches/msys2/sound/ofOpenALSoundPlayer.cpp | 2152 ++++---- patches/msys2/sound/ofOpenALSoundPlayer.h | 314 +- patches/ofAppEGLWindow.cpp | 4530 ++++++++--------- patches/ofAppEGLWindow.h | 620 +-- src/Application/Application.cpp | 1336 ++--- src/Application/Application.h | 376 +- src/Application/Modes/ApplicationBaseMode.cpp | 24 +- src/Application/Modes/ApplicationBaseMode.h | 76 +- src/Application/Modes/PresentationMode.cpp | 56 +- src/Application/Modes/PresentationMode.h | 58 +- .../Modes/ProjectionMappingMode.cpp | 618 +-- src/Application/Modes/ProjectionMappingMode.h | 108 +- src/Application/Modes/SourceSelectionMode.cpp | 74 +- src/Application/Modes/SourceSelectionMode.h | 54 +- src/Application/Modes/TextureMappingMode.cpp | 638 +-- src/Application/Modes/TextureMappingMode.h | 142 +- src/Application/SettingsLoader.cpp | 1134 ++--- src/Application/SettingsLoader.h | 86 +- src/Commands/AddGridColCmd.cpp | 54 +- src/Commands/AddGridColCmd.h | 62 +- src/Commands/AddGridRowCmd.cpp | 54 +- src/Commands/AddGridRowCmd.h | 62 +- src/Commands/AddSurfaceCmd.cpp | 54 +- src/Commands/AddSurfaceCmd.h | 60 +- src/Commands/BaseCmd.h | 98 +- src/Commands/ClearSurfacesCmd.cpp | 54 +- src/Commands/ClearSurfacesCmd.h | 66 +- src/Commands/CmdManager.cpp | 54 +- src/Commands/CmdManager.h | 44 +- src/Commands/DeselectSurfaceCmd.cpp | 52 +- src/Commands/DeselectSurfaceCmd.h | 56 +- src/Commands/DeselectTexCoordCmd.cpp | 70 +- src/Commands/DeselectTexCoordCmd.h | 54 +- src/Commands/DuplicateSurfaceCmd.cpp | 54 +- src/Commands/DuplicateSurfaceCmd.h | 62 +- src/Commands/FullscreenSurfaceCmd.cpp | 50 +- src/Commands/FullscreenSurfaceCmd.h | 58 +- src/Commands/MvAllTexCoordsCmd.cpp | 54 +- src/Commands/MvAllTexCoordsCmd.h | 62 +- src/Commands/MvLayerDnCmd.cpp | 92 +- src/Commands/MvLayerDnCmd.h | 56 +- src/Commands/MvLayerUpCmd.cpp | 92 +- src/Commands/MvLayerUpCmd.h | 54 +- src/Commands/MvSelectionCmd.cpp | 46 +- src/Commands/MvSelectionCmd.h | 50 +- src/Commands/MvSurfaceVertCmd.cpp | 46 +- src/Commands/MvSurfaceVertCmd.h | 64 +- src/Commands/MvTexCoordCmd.cpp | 62 +- src/Commands/MvTexCoordCmd.h | 62 +- src/Commands/RmGridColCmd.cpp | 78 +- src/Commands/RmGridColCmd.h | 64 +- src/Commands/RmGridRowCmd.cpp | 78 +- src/Commands/RmGridRowCmd.h | 64 +- src/Commands/RmSurfaceCmd.cpp | 64 +- src/Commands/RmSurfaceCmd.h | 64 +- src/Commands/SaveTexCoordPosCmd.cpp | 44 +- src/Commands/SaveTexCoordPosCmd.h | 60 +- src/Commands/ScaleSurfaceFromToCmd.cpp | 48 +- src/Commands/ScaleSurfaceFromToCmd.h | 52 +- src/Commands/SelNextSurfaceCmd.cpp | 52 +- src/Commands/SelNextSurfaceCmd.h | 62 +- src/Commands/SelNextTexCoordCmd.cpp | 48 +- src/Commands/SelNextTexCoordCmd.h | 52 +- src/Commands/SelNextVertexCmd.cpp | 42 +- src/Commands/SelNextVertexCmd.h | 50 +- src/Commands/SelPrevSurfaceCmd.cpp | 50 +- src/Commands/SelPrevSurfaceCmd.h | 62 +- src/Commands/SelPrevTexCoordCmd.cpp | 48 +- src/Commands/SelPrevTexCoordCmd.h | 52 +- src/Commands/SelPrevVertexCmd.cpp | 42 +- src/Commands/SelPrevVertexCmd.h | 50 +- src/Commands/SelSurfaceCmd.cpp | 50 +- src/Commands/SelSurfaceCmd.h | 64 +- src/Commands/SelTexCoordCmd.cpp | 48 +- src/Commands/SelTexCoordCmd.h | 54 +- src/Commands/SelVertexCmd.cpp | 46 +- src/Commands/SelVertexCmd.h | 54 +- src/Commands/SetApplicationModeCmd.cpp | 122 +- src/Commands/SetApplicationModeCmd.h | 66 +- src/Commands/SetNextSourceCmd.cpp | 212 +- src/Commands/SetNextSourceCmd.h | 74 +- src/Commands/SetPresetCmd.cpp | 54 +- src/Commands/SetPresetCmd.h | 66 +- src/Commands/SetSourceCmd.cpp | 114 +- src/Commands/SetSourceCmd.h | 78 +- src/Commands/SetTexMapDrawModeCmd.cpp | 48 +- src/Commands/SetTexMapDrawModeCmd.h | 62 +- src/Commands/SetVideoSourceCmd.cpp | 102 +- src/Commands/SetVideoSourceCmd.h | 78 +- src/Commands/StartDragSurfaceCmd.cpp | 48 +- src/Commands/StartDragSurfaceCmd.h | 50 +- src/Commands/ToggleAnimatedSourceCmd.cpp | 44 +- src/Commands/ToggleAnimatedSourceCmd.h | 58 +- src/Commands/TogglePerspectiveCmd.cpp | 48 +- src/Commands/TogglePerspectiveCmd.h | 54 +- src/Commands/TranslateCanvasCmd.cpp | 48 +- src/Commands/TranslateCanvasCmd.h | 58 +- src/Gui/Gui.cpp | 236 +- src/Gui/Gui.h | 202 +- src/Gui/Widgets/GuiBaseWidget.h | 58 +- src/Gui/Widgets/LayerPanelWidget.cpp | 106 +- src/Gui/Widgets/LayerPanelWidget.h | 60 +- src/Gui/Widgets/ProjectionEditorWidget.cpp | 494 +- src/Gui/Widgets/ProjectionEditorWidget.h | 102 +- src/Gui/Widgets/ScaleWidget.cpp | 382 +- src/Gui/Widgets/ScaleWidget.h | 98 +- src/Gui/Widgets/SourcesEditorWidget.cpp | 688 +-- src/Gui/Widgets/SourcesEditorWidget.h | 156 +- src/Gui/Widgets/SurfaceHighlightWidget.cpp | 142 +- src/Gui/Widgets/SurfaceHighlightWidget.h | 62 +- src/Gui/Widgets/TextureEditorWidget.cpp | 816 +-- src/Gui/Widgets/TextureEditorWidget.h | 122 +- src/Gui/Widgets/TextureHighlightWidget.cpp | 112 +- src/Gui/Widgets/TextureHighlightWidget.h | 66 +- src/Info/Info.cpp | 120 +- src/Info/Info.h | 42 +- src/MediaServer/DirectoryWatcher.cpp | 168 +- src/MediaServer/DirectoryWatcher.h | 82 +- src/MediaServer/MediaServer.cpp | 886 ++-- src/MediaServer/MediaServer.h | 256 +- src/Mode.h | 26 +- src/Sources/BaseSource.cpp | 152 +- src/Sources/BaseSource.h | 98 +- src/Sources/FboSource.cpp | 208 +- src/Sources/FboSource.h | 104 +- src/Sources/ImageSource.cpp | 82 +- src/Sources/ImageSource.h | 42 +- src/Sources/OMXPlayerCache.cpp | 90 +- src/Sources/OMXPlayerCache.h | 56 +- src/Sources/SourceType.h | 26 +- src/Sources/SourceTypeHelper.h | 102 +- src/Sources/VideoSource.cpp | 268 +- src/Sources/VideoSource.h | 103 +- src/Surfaces/BaseSurface.cpp | 338 +- src/Surfaces/BaseSurface.h | 132 +- src/Surfaces/CircleSurface.cpp | 608 +-- src/Surfaces/CircleSurface.h | 132 +- src/Surfaces/GridWarpSurface.cpp | 510 +- src/Surfaces/GridWarpSurface.h | 100 +- src/Surfaces/HexagonSurface.cpp | 486 +- src/Surfaces/HexagonSurface.h | 88 +- src/Surfaces/QuadSurface.cpp | 680 +-- src/Surfaces/QuadSurface.h | 108 +- src/Surfaces/SurfaceFactory.cpp | 188 +- src/Surfaces/SurfaceFactory.h | 66 +- src/Surfaces/SurfaceManager.cpp | 1076 ++-- src/Surfaces/SurfaceManager.h | 192 +- src/Surfaces/SurfaceStack.cpp | 172 +- src/Surfaces/SurfaceStack.h | 78 +- src/Surfaces/SurfaceType.h | 30 +- src/Surfaces/TriangleSurface.cpp | 406 +- src/Surfaces/TriangleSurface.h | 84 +- src/Types/Vec2.cpp | 223 +- src/Types/Vec2.h | 88 +- src/Types/Vec3.cpp | 270 +- src/Types/Vec3.h | 102 +- src/UserInterface/BaseJoint.cpp | 150 +- src/UserInterface/BaseJoint.h | 102 +- src/UserInterface/CircleJoint.cpp | 142 +- src/UserInterface/CircleJoint.h | 52 +- src/UserInterface/EditorType.h | 24 +- src/UserInterface/GuiMode.h | 24 +- src/UserInterface/RadioList.cpp | 400 +- src/UserInterface/RadioList.h | 110 +- src/Utils/HomographyHelper.cpp | 240 +- src/Utils/HomographyHelper.h | 52 +- src/ofxPiMapper.cpp | 596 +-- src/ofxPiMapper.h | 208 +- 267 files changed, 20945 insertions(+), 20856 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index f8e49c4..33a2a5c 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,5 +1,5 @@ -# These are supported funding model platforms - -github: [kr15h] -patreon: kriwkrow -custom: ['https://paypal.me/kriwkrow'] +# These are supported funding model platforms + +github: [kr15h] +patreon: kriwkrow +custom: ['https://paypal.me/kriwkrow'] diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5913a7b..dd28607 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,57 +1,57 @@ -name: linux -on: - push: - branches: - - master -jobs: - compile: - runs-on: ubuntu-latest - env: - OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_linux64gcc6_release.tar.gz - steps: - - name: Fetch ofxPiMapper - uses: actions/checkout@v2 - with: - fetch-depth: 1 - - name: Download openFrameworks and add ofxPiMapper to addons - run: | - mkdir .ofxPiMapper - mv ./* .ofxPiMapper/ - wget ${OF_URL} --tries=10 --quiet - echo "Unarchive openFrameworks" - OF_ARCHIVE_NAME=$(basename -- "$OF_URL") - tar -xf ${OF_ARCHIVE_NAME} - rm ${OF_ARCHIVE_NAME} - OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .tar.gz) - mv ${OF_EXTRACT_NAME} openFrameworks - mv .ofxPiMapper openFrameworks/addons/ofxPiMapper - - name: Install openFrameworks Dependencies - working-directory: ./openFrameworks/scripts/linux/ubuntu - run: sudo ./install_dependencies.sh -y - - name: Compile openFrameworks - working-directory: ./openFrameworks/scripts/linux - run: ./compileOF.sh - - name: Compile example_basic - working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic - run: mv addons.make.norpi addons.make && make - - name: Compile example_camera - working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera - run: mv addons.make.norpi addons.make && make - - name: Compile example_fbo-sources - working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources - run: mv addons.make.norpi addons.make && make - - name: Compile example_pocketvj - working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj - run: mv addons.make.norpi addons.make && make - - name: Install ofxJSON dependency - working-directory: ./openFrameworks/addons/ - run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 - - name: Compile example_remote-client - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client - run: mv addons.make.norpi addons.make && make - - name: Compile example_remote-server - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server - run: mv addons.make.norpi addons.make && make - - name: Compile example_simpler - working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler - run: mv addons.make.norpi addons.make && make +name: linux +on: + push: + branches: + - master +jobs: + compile: + runs-on: ubuntu-latest + env: + OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_linux64gcc6_release.tar.gz + steps: + - name: Fetch ofxPiMapper + uses: actions/checkout@v2 + with: + fetch-depth: 1 + - name: Download openFrameworks and add ofxPiMapper to addons + run: | + mkdir .ofxPiMapper + mv ./* .ofxPiMapper/ + wget ${OF_URL} --tries=10 --quiet + echo "Unarchive openFrameworks" + OF_ARCHIVE_NAME=$(basename -- "$OF_URL") + tar -xf ${OF_ARCHIVE_NAME} + rm ${OF_ARCHIVE_NAME} + OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .tar.gz) + mv ${OF_EXTRACT_NAME} openFrameworks + mv .ofxPiMapper openFrameworks/addons/ofxPiMapper + - name: Install openFrameworks Dependencies + working-directory: ./openFrameworks/scripts/linux/ubuntu + run: sudo ./install_dependencies.sh -y + - name: Compile openFrameworks + working-directory: ./openFrameworks/scripts/linux + run: ./compileOF.sh + - name: Compile example_basic + working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic + run: mv addons.make.norpi addons.make && make + - name: Compile example_camera + working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera + run: mv addons.make.norpi addons.make && make + - name: Compile example_fbo-sources + working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources + run: mv addons.make.norpi addons.make && make + - name: Compile example_pocketvj + working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj + run: mv addons.make.norpi addons.make && make + - name: Install ofxJSON dependency + working-directory: ./openFrameworks/addons/ + run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 + - name: Compile example_remote-client + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client + run: mv addons.make.norpi addons.make && make + - name: Compile example_remote-server + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server + run: mv addons.make.norpi addons.make && make + - name: Compile example_simpler + working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler + run: mv addons.make.norpi addons.make && make diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 026ba48..b1bb690 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -1,60 +1,60 @@ -name: osx -on: - push: - branches: - - master -jobs: - compile: - runs-on: macos-latest - env: - OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_osx_release.zip - steps: - - name: Fetch ofxPiMapper - uses: actions/checkout@v2 - with: - fetch-depth: 1 - - name: Download openFrameworks and add ofxPiMapper to addons - run: | - mkdir .ofxPiMapper - mv ./* .ofxPiMapper/ - wget ${OF_URL} --tries=10 --quiet - echo "Unarchive openFrameworks" - OF_ARCHIVE_NAME=$(basename -- "$OF_URL") - unzip ${OF_ARCHIVE_NAME} - rm ${OF_ARCHIVE_NAME} - OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .zip) - mv ${OF_EXTRACT_NAME} openFrameworks - mv .ofxPiMapper openFrameworks/addons/ofxPiMapper - - name: Install Dependencies - run: | - set -ev - brew update - brew install gdb - brew install coreutils - - name: Compile openFrameworks - working-directory: ./openFrameworks/scripts/templates/osx - run: make - - name: Compile example_basic - working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic - run: mv addons.make.norpi addons.make && make - - name: Compile example_camera - working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera - run: mv addons.make.norpi addons.make && make - - name: Compile example_fbo-sources - working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources - run: mv addons.make.norpi addons.make && make - - name: Compile example_pocketvj - working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj - run: mv addons.make.norpi addons.make && make - - name: Install ofxJSON dependency - working-directory: ./openFrameworks/addons/ - run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 - - name: Compile example_remote-client - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client - run: mv addons.make.norpi addons.make && make - - name: Compile example_remote-server - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server - run: mv addons.make.norpi addons.make && make - - name: Compile example_simpler - working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler - run: mv addons.make.norpi addons.make && make +name: osx +on: + push: + branches: + - master +jobs: + compile: + runs-on: macos-latest + env: + OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_osx_release.zip + steps: + - name: Fetch ofxPiMapper + uses: actions/checkout@v2 + with: + fetch-depth: 1 + - name: Download openFrameworks and add ofxPiMapper to addons + run: | + mkdir .ofxPiMapper + mv ./* .ofxPiMapper/ + wget ${OF_URL} --tries=10 --quiet + echo "Unarchive openFrameworks" + OF_ARCHIVE_NAME=$(basename -- "$OF_URL") + unzip ${OF_ARCHIVE_NAME} + rm ${OF_ARCHIVE_NAME} + OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .zip) + mv ${OF_EXTRACT_NAME} openFrameworks + mv .ofxPiMapper openFrameworks/addons/ofxPiMapper + - name: Install Dependencies + run: | + set -ev + brew update + brew install gdb + brew install coreutils + - name: Compile openFrameworks + working-directory: ./openFrameworks/scripts/templates/osx + run: make + - name: Compile example_basic + working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic + run: mv addons.make.norpi addons.make && make + - name: Compile example_camera + working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera + run: mv addons.make.norpi addons.make && make + - name: Compile example_fbo-sources + working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources + run: mv addons.make.norpi addons.make && make + - name: Compile example_pocketvj + working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj + run: mv addons.make.norpi addons.make && make + - name: Install ofxJSON dependency + working-directory: ./openFrameworks/addons/ + run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 + - name: Compile example_remote-client + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client + run: mv addons.make.norpi addons.make && make + - name: Compile example_remote-server + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server + run: mv addons.make.norpi addons.make && make + - name: Compile example_simpler + working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler + run: mv addons.make.norpi addons.make && make diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 93cc5ec..88dff75 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,67 +1,67 @@ -name: windows -on: - push: - branches: - - master -jobs: - compile: - runs-on: windows-latest - env: - OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_msys2_mingw64_release.zip - defaults: - run: - shell: msys2 {0} - steps: - - uses: msys2/setup-msys2@v2 - with: - update: true - install: unzip git - msystem: MINGW64 - - uses: actions/checkout@v2 - with: - fetch-depth: 1 - - name: Download openFrameworks and add ofxPiMapper to addons - run: | - mkdir .ofxPiMapper - mv ./* .ofxPiMapper/ - wget ${OF_URL} --tries=10 --quiet - echo "Unarchive openFrameworks" - OF_ARCHIVE_NAME=$(basename -- "$OF_URL") - unzip ${OF_ARCHIVE_NAME} - rm ${OF_ARCHIVE_NAME} - OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .zip) - mv ${OF_EXTRACT_NAME} openFrameworks - mv .ofxPiMapper openFrameworks/addons/ofxPiMapper - - name: Install openFrameworks Dependencies - working-directory: ./openFrameworks/scripts/msys2 - run: ./install_dependencies.sh --noconfirm - - name: Apply patches - working-directory: ./openFrameworks/addons/ofxPiMapper/patches/msys2 - run: ./patch.sh - - name: Compile openFrameworks - working-directory: ./openFrameworks/scripts/msys2 - run: ./compileOF.sh - - name: Compile example_basic - working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic - run: mv addons.make.norpi addons.make && make - - name: Compile example_camera - working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera - run: mv addons.make.norpi addons.make && make - - name: Compile example_fbo-sources - working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources - run: mv addons.make.norpi addons.make && make - - name: Compile example_pocketvj - working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj - run: mv addons.make.norpi addons.make && make - - name: Install ofxJSON dependency - working-directory: ./openFrameworks/addons/ - run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 - - name: Compile example_remote-client - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client - run: mv addons.make.norpi addons.make && make - - name: Compile example_remote-server - working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server - run: mv addons.make.norpi addons.make && make - - name: Compile example_simpler - working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler - run: mv addons.make.norpi addons.make && make +name: windows +on: + push: + branches: + - master +jobs: + compile: + runs-on: windows-latest + env: + OF_URL: https://github.com/openframeworks/openFrameworks/releases/download/0.11.2/of_v0.11.2_msys2_mingw64_release.zip + defaults: + run: + shell: msys2 {0} + steps: + - uses: msys2/setup-msys2@v2 + with: + update: true + install: unzip git + msystem: MINGW64 + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + - name: Download openFrameworks and add ofxPiMapper to addons + run: | + mkdir .ofxPiMapper + mv ./* .ofxPiMapper/ + wget ${OF_URL} --tries=10 --quiet + echo "Unarchive openFrameworks" + OF_ARCHIVE_NAME=$(basename -- "$OF_URL") + unzip ${OF_ARCHIVE_NAME} + rm ${OF_ARCHIVE_NAME} + OF_EXTRACT_NAME=$(basename ${OF_ARCHIVE_NAME} .zip) + mv ${OF_EXTRACT_NAME} openFrameworks + mv .ofxPiMapper openFrameworks/addons/ofxPiMapper + - name: Install openFrameworks Dependencies + working-directory: ./openFrameworks/scripts/msys2 + run: ./install_dependencies.sh --noconfirm + - name: Apply patches + working-directory: ./openFrameworks/addons/ofxPiMapper/patches/msys2 + run: ./patch.sh + - name: Compile openFrameworks + working-directory: ./openFrameworks/scripts/msys2 + run: ./compileOF.sh + - name: Compile example_basic + working-directory: ./openFrameworks/addons/ofxPiMapper/example_basic + run: mv addons.make.norpi addons.make && make + - name: Compile example_camera + working-directory: ./openFrameworks/addons/ofxPiMapper/example_camera + run: mv addons.make.norpi addons.make && make + - name: Compile example_fbo-sources + working-directory: ./openFrameworks/addons/ofxPiMapper/example_fbo-sources + run: mv addons.make.norpi addons.make && make + - name: Compile example_pocketvj + working-directory: ./openFrameworks/addons/ofxPiMapper/example_pocketvj + run: mv addons.make.norpi addons.make && make + - name: Install ofxJSON dependency + working-directory: ./openFrameworks/addons/ + run: git clone https://github.com/jeffcrouse/ofxJSON.git --depth 1 + - name: Compile example_remote-client + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-client + run: mv addons.make.norpi addons.make && make + - name: Compile example_remote-server + working-directory: ./openFrameworks/addons/ofxPiMapper/example_remote-server + run: mv addons.make.norpi addons.make && make + - name: Compile example_simpler + working-directory: ./openFrameworks/addons/ofxPiMapper/example_simpler + run: mv addons.make.norpi addons.make && make diff --git a/.gitignore b/.gitignore index 8cd07bf..b6ae21c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,121 +1,121 @@ -######################### -# general patterns -######################### - -docs/html -docs/tagfile.xml - -*/bin/* -!*/bin/data/ - -# for bin folder in root -/bin/* -!/bin/data/ - -[Bb]uild/ -[Oo]bj/ -*.o -[Dd]ebug*/ -[Rr]elease*/ -*.mode* -*.app/ -*.pyc -.svn/ - -######################### -# IDE -######################### - -# XCode -*.pbxuser -*.perspective -*.perspectivev3 -*.mode1v3 -*.mode2v3 -#XCode 4 -xcuserdata -*.xcworkspace - -# Code::Blocks -*.depend -*.layout -*.cbTemp - -# Visual Studio -*.sdf -*.opensdf -*.suo -*.pdb -*.ilk -*.aps -ipch/ - -# Eclipse -.metadata -local.properties -.externalToolBuilders - -# Codelite -*.session -*.tags -*.workspace.* - -######################### -# operating system -######################### - -# Linux -*~ -# KDE -.directory -.AppleDouble - -# OSX -.DS_Store -*.swp -*~.nib -# Thumbnails -._* - -# Windows -# Windows image file caches -Thumbs.db -# Folder config file -Desktop.ini - -#Android -.csettings - -######################### -# packages -######################### - -# it's better to unpack these files and commit the raw source -# git has its own built in compression methods -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip - -# Logs and databases -*.log -*.sql -*.sqlite - -example/cmake-build-debug/ - -example/\.idea/ - -example/cmake-build-release/ - -example/example\.xcodeproj/xcshareddata/xcschemes/ - -.idea/ - -cmake-build-debug/ - -CMakeLists\.txt +######################### +# general patterns +######################### + +docs/html +docs/tagfile.xml + +*/bin/* +!*/bin/data/ + +# for bin folder in root +/bin/* +!/bin/data/ + +[Bb]uild/ +[Oo]bj/ +*.o +[Dd]ebug*/ +[Rr]elease*/ +*.mode* +*.app/ +*.pyc +.svn/ + +######################### +# IDE +######################### + +# XCode +*.pbxuser +*.perspective +*.perspectivev3 +*.mode1v3 +*.mode2v3 +#XCode 4 +xcuserdata +*.xcworkspace + +# Code::Blocks +*.depend +*.layout +*.cbTemp + +# Visual Studio +*.sdf +*.opensdf +*.suo +*.pdb +*.ilk +*.aps +ipch/ + +# Eclipse +.metadata +local.properties +.externalToolBuilders + +# Codelite +*.session +*.tags +*.workspace.* + +######################### +# operating system +######################### + +# Linux +*~ +# KDE +.directory +.AppleDouble + +# OSX +.DS_Store +*.swp +*~.nib +# Thumbnails +._* + +# Windows +# Windows image file caches +Thumbs.db +# Folder config file +Desktop.ini + +#Android +.csettings + +######################### +# packages +######################### + +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases +*.log +*.sql +*.sqlite + +example/cmake-build-debug/ + +example/\.idea/ + +example/cmake-build-release/ + +example/example\.xcodeproj/xcshareddata/xcschemes/ + +.idea/ + +cmake-build-debug/ + +CMakeLists\.txt diff --git a/LICENSE.md b/LICENSE.md index 57dd202..882064b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,9 +1,9 @@ -ofxPiMapper is distributed under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license). This gives everyone the freedoms to use ofxPiMapper in any context: commercial or non-commercial, public or private, open or closed source. - -**Copyright (c) 2014–2021, Krisjanis Rijnieks and contributors** - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +ofxPiMapper is distributed under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license). This gives everyone the freedoms to use ofxPiMapper in any context: commercial or non-commercial, public or private, open or closed source. + +**Copyright (c) 2014–2021, Krisjanis Rijnieks and contributors** + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 57f9d34..25b2e81 100644 --- a/README.md +++ b/README.md @@ -1,248 +1,248 @@ -# ofxPiMapper - -[![Ubuntu Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/linux/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Alinux) -[![Windows Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/windows/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Awindows) -[![OSX Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/osx/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Aosx) - -Projection mapping addon for openFrameworks that runs on the Raspberry Pi. It has been tested against openFrameworks version (0.11.0). - -The project started as master's thesis project by [Krisjanis Rijnieks](https://rijnieks.com) at the [Aalto Media Lab](https://www.aalto.fi/en/aalto-media-lab). Currently being developed during free time. Please [donate](https://ofxpimapper.com/) to create more free time. - -Note on build status: GitHub Actions ubuntu-latest, windows-latest and osx-latest images with 64bit environments are used. To be reviewed. - -## Disk Image - -For those not using openFrameworks, there is a precompiled disk image available via [ofxPiMapper website](https://ofxpimapper.com). It works with Raspberry Pi up until version 3B+ (with the older BCM2837 chip). Given the recent growing interest in the project, some effort is being put into figuring out how to make the disk image to work on Pi 4 and Pi 5 (and Pi 3B+ with the more recent BCM2837B0 chip). Please [donate](https://ofxpimapper.com/) to increase the frequency and duration of these efforts. - -> **Warning!** It does not work on the latest generation of Raspberry Pi 3B+ with the BCM2837B0 chip. Make sure the Pi has the older BCM2837 chip when purchasing. - -## Introduction - -This repository contains the addon for [openFrameworks](https://openframeworks.cc). It is expected to be used as an extension for your custom openFrameworks project where you create a custom [FBO source](example_fbo-sources) that is being animated by an advanced process rather than a plain video. - -If you are planning to use videos and images only, consider using the precompiled Raspberry Pi image available from the [ofxPiMapper website](https://ofxpimapper.com). It is based on a recent Raspberry Pi OS disk image and contains compiled installation of openFrameworks along with all the scripts and services that make Pi Mapper start automatically. - -## Installation - -Clone or download the repository to your openFrameworks addons folder. Make sure that default openFrameworks examples compile and run before trying ofxPiMapper examples. There are a few things that you should do depending on if you are compiling on the Raspberry Pi or not. - -- Raspberry Pi - Please install the [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) addon before compiling. -- Windows MSYS2 - Go to `patches/msys2` directory and run `./patch.sh` -- Other platforms - Please rename the `addons.make.rpi` file to `addons.make`. - -To test, use Terminal to change the directory to `example_basic`, compile and run. - -``` -cd path/to/openFrameworks/addons/ofxPiMapper/example_basic -make -cd bin -./example_basic -``` - -If you plan to use `example_remote-server` and `example_remote-client`, make sure that you have added [ofxJSON](https://github.com/jeffcrouse/ofxJSON) dependency to your `openFrameworks/addons` folder prior compilation. - -## Usage - -Currently a keyboard and a mouse has to be used in order to do the mapping with ofxPiMapper. - - -### Modes - -PiMapper has 4 modes: - -1. Presentation mode -2. Texture mapping mode -3. Surface editing mode -4. Source assignment mode - -You can access these modes by pressing 1, 2, 3 or 4 respectively. - - -#### Presentation mode - -This mode is activated once the application starts up. It does not show anything else except the final projection mapping as it was saved previously. - - -#### Texture mapping mode - -In this mode you can adjust the texture coordinates of the surface you have selected in the surface editing mode. - - -#### Surface editing mode - -Here you can select, move and distort the surfaces you have created. - - -#### Source assignment mode - -After you select a surface in surface editing mode, activate this mode to be able to choose a source for the surface. Afterwards you might want to go to the texture mapping mode to adjust texture coordinates. - - -### Other shortcuts - -These other shortcuts that you can use while using the example app. - -Key | Function -:--- | :--- -1 | Presentation mode -2 | Texture editing mode -3 | Projection mapping mode, use this to select a surface first -4 | Source selection mode -i | Show info -t | Add triangle surface -q | Add quad surface -g | Add grid warp surface -c | Add circle surface -d | Duplicate selected surface -\+ | Scale surface up -\- | Scale surface down -p | Toggle perspective warping (quad surfaces only) -F | Expand selected surface to fill the screen (quad surfaces only) -] | Add columns to grid surface (grid warp surfaces only) -[ | Remove columns from grid surface (grid warp surfaces only) -} | Add rows to grid surface (grid warp surfaces only) -{ | Remove rows from grid surface (grid warp surfaces only) -. | Select next surface (projection mapping mode only) -, | Select previous surface (projection mapping mode only) -\> | Select next vertex -\< | Select previous vertex -0 | Move selected surface one layer up -9 | Move selected surface one layer down -s | Save composition -l | Hide/show layer panel -z | Undo -rbt | Reboot (Raspberry Pi only) -sdn | Shutdown (Raspberry Pi only) -new | Clear composition (remove all surfaces) -ext | Exit application and return to command line -BACKSPACE ('\' via SSH) | Delete surface. -SPACE | Toggle pause for video sources (texture and projection mapping modes) -TAB | Select next source (no need to use the source selection interface) -Arrow keys | Move selection. If no surface is selected in the projection mapping mode, all surfaces are moved. -\/ | Toggle 1px/10px steps for keyboard moves on Raspberry Pi - -## Notes on Video Encoding - -Easiest way to achieve success is to use [HandBrake](https://handbrake.fr/) with the following settings. This will produce a `.mkv` file with 16bit FLAC audio with 22.05KHz sampling rate. - -``` -Preset: Fast 720p30 -Summary / Format: MKV File -Video / Framerate: Same as source -Video / Profile: Baseline -Audio / Codec: FLAC 16-bit -Audio / Samplerate: 22.05 -``` - -If you are familiar with [ffmpeg](http://ffmpeg.org/), use the following. It will produce a `.mov` file. PCM audio codec with 22KHz sampling rate is used. - -``` -ffmpeg -i input-video.mp4 -s 1280x720 -aspect 16:9 \ - -c:v libx264 -profile:v baseline \ - -c:a pcm_s16le -ar 22000 -ac 2 \ - output-video.mov -``` - -These two settings have shown the best results so far. Audio problems and video playback at the beginning of longer video files was the main issue in most cases. Please open an issue if you have better suggestions. - -## Extended Functionality - -Examples represent extended functionality of ofxPiMapper. Enter each example separately to find out more. - -- [Basic Example](example_basic). -- [FBO Sources Example](example_fbo-sources). -- [Camera Example](example_camera). -- [Remote Control Server](example_remote-server) example. -- [Remote Control Client](example_remote-client) example. -- Readme's for the rest are cooking... - -## Problems with Audio - -If you are having problems with audio playback, here are two steps for you. Before you do these, make sure audio of your video file works. - - -### Step 1 - -Open example openFrameworks application `ofApp.cpp` file in a text editor. - -``` -cd /home/pi/openFrameworks/addons/ofxPiMapper/example -nano src/ofApp.cpp -``` - -Make sure that the following line looks as follows. - -``` -ofx::piMapper::VideoSource::enableAudio = true; -``` - -Save the file (CTRL + X, Y and ENTER). Recompile and run the example. - -``` -make && make run -``` - -### Step 2 - -If the sound still does not work, try to use `raspi-config`. - -``` -sudo raspi-config -``` - -Select "7 Advanced Options" and "A9 Audio" then "0 Auto". You can use one of the force options if you want to be 100% sure. - -Open alsamixer. - -``` -alsamixer -``` - -Set the volume to a value between 90 to 100 by using the arrow keys. ESC to exit the mixer. - -Launch ofxPiMapper example, select a surface and set a video source with audio. Should work. - - -## Development - -Keeping it simple. Developing ofxPiMapper master branch against the latest stable release version of openFrameworks. - - -## Licence - -ofxPiMapper is distributed under the [MIT License](https://en.wikipedia.org/wiki/MIT_License). See the [LICENSE](LICENSE.md) file for further details. Just add my name somewhere along your project [Krisjanis Rijnieks](https://rijnieks.com) whenever possible. - - -## Supporters - -You can become a supporter by donating BitCoins, via PayPal or becoming a Patreon. Please check https://ofxpimapper.com for details. List of supporters below. - -- [Marc-André Gasser](https://www.magdesign.ch/) -- Manuel Meißner - - -## Dependencies - -Before moving on, make sure that you have all the dependencies installed. - - - ofxGui (available in oF by default) - - ofxXmlSettings (available in oF by default) - - [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) (needed only on Raspberry Pi) - -To install dependencies, `cd` into `openFrameworks/addons` directory and execute the following: - -```bash -git clone https://github.com/jvcleave/ofxOMXPlayer.git -``` - -The `ofxOMXPlayer` addon recommends you to use its releases. Currently the latest release is `0.9.0-compatible`. To checkout the code of the relase, go to the `ofxOMXPlayer` addon directory and checkout the relase. - -``` -cd openFrameworks/addons/ofxOMXPlayer -git checkout 0.9.0-compatible -``` - -You can check the latest releases on the [ofxOMXPlayer GitHub repository](https://github.com/jvcleave/ofxOMXPlayer/releases). +# ofxPiMapper + +[![Ubuntu Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/linux/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Alinux) +[![Windows Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/windows/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Awindows) +[![OSX Workflow Badge](https://github.com/kr15h/ofxPiMapper/workflows/osx/badge.svg)](https://github.com/kr15h/ofxPiMapper/actions?query=workflow%3Aosx) + +Projection mapping addon for openFrameworks that runs on the Raspberry Pi. It has been tested against openFrameworks version (0.11.0). + +The project started as master's thesis project by [Krisjanis Rijnieks](https://rijnieks.com) at the [Aalto Media Lab](https://www.aalto.fi/en/aalto-media-lab). Currently being developed during free time. Please [donate](https://ofxpimapper.com/) to create more free time. + +Note on build status: GitHub Actions ubuntu-latest, windows-latest and osx-latest images with 64bit environments are used. To be reviewed. + +## Disk Image + +For those not using openFrameworks, there is a precompiled disk image available via [ofxPiMapper website](https://ofxpimapper.com). It works with Raspberry Pi up until version 3B+ (with the older BCM2837 chip). Given the recent growing interest in the project, some effort is being put into figuring out how to make the disk image to work on Pi 4 and Pi 5 (and Pi 3B+ with the more recent BCM2837B0 chip). Please [donate](https://ofxpimapper.com/) to increase the frequency and duration of these efforts. + +> **Warning!** It does not work on the latest generation of Raspberry Pi 3B+ with the BCM2837B0 chip. Make sure the Pi has the older BCM2837 chip when purchasing. + +## Introduction + +This repository contains the addon for [openFrameworks](https://openframeworks.cc). It is expected to be used as an extension for your custom openFrameworks project where you create a custom [FBO source](example_fbo-sources) that is being animated by an advanced process rather than a plain video. + +If you are planning to use videos and images only, consider using the precompiled Raspberry Pi image available from the [ofxPiMapper website](https://ofxpimapper.com). It is based on a recent Raspberry Pi OS disk image and contains compiled installation of openFrameworks along with all the scripts and services that make Pi Mapper start automatically. + +## Installation + +Clone or download the repository to your openFrameworks addons folder. Make sure that default openFrameworks examples compile and run before trying ofxPiMapper examples. There are a few things that you should do depending on if you are compiling on the Raspberry Pi or not. + +- Raspberry Pi + Please install the [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) addon before compiling. +- Windows MSYS2 + Go to `patches/msys2` directory and run `./patch.sh` +- Other platforms + Please rename the `addons.make.rpi` file to `addons.make`. + +To test, use Terminal to change the directory to `example_basic`, compile and run. + +``` +cd path/to/openFrameworks/addons/ofxPiMapper/example_basic +make +cd bin +./example_basic +``` + +If you plan to use `example_remote-server` and `example_remote-client`, make sure that you have added [ofxJSON](https://github.com/jeffcrouse/ofxJSON) dependency to your `openFrameworks/addons` folder prior compilation. + +## Usage + +Currently a keyboard and a mouse has to be used in order to do the mapping with ofxPiMapper. + + +### Modes + +PiMapper has 4 modes: + +1. Presentation mode +2. Texture mapping mode +3. Surface editing mode +4. Source assignment mode + +You can access these modes by pressing 1, 2, 3 or 4 respectively. + + +#### Presentation mode + +This mode is activated once the application starts up. It does not show anything else except the final projection mapping as it was saved previously. + + +#### Texture mapping mode + +In this mode you can adjust the texture coordinates of the surface you have selected in the surface editing mode. + + +#### Surface editing mode + +Here you can select, move and distort the surfaces you have created. + + +#### Source assignment mode + +After you select a surface in surface editing mode, activate this mode to be able to choose a source for the surface. Afterwards you might want to go to the texture mapping mode to adjust texture coordinates. + + +### Other shortcuts + +These other shortcuts that you can use while using the example app. + +Key | Function +:--- | :--- +1 | Presentation mode +2 | Texture editing mode +3 | Projection mapping mode, use this to select a surface first +4 | Source selection mode +i | Show info +t | Add triangle surface +q | Add quad surface +g | Add grid warp surface +c | Add circle surface +d | Duplicate selected surface +\+ | Scale surface up +\- | Scale surface down +p | Toggle perspective warping (quad surfaces only) +F | Expand selected surface to fill the screen (quad surfaces only) +] | Add columns to grid surface (grid warp surfaces only) +[ | Remove columns from grid surface (grid warp surfaces only) +} | Add rows to grid surface (grid warp surfaces only) +{ | Remove rows from grid surface (grid warp surfaces only) +. | Select next surface (projection mapping mode only) +, | Select previous surface (projection mapping mode only) +\> | Select next vertex +\< | Select previous vertex +0 | Move selected surface one layer up +9 | Move selected surface one layer down +s | Save composition +l | Hide/show layer panel +z | Undo +rbt | Reboot (Raspberry Pi only) +sdn | Shutdown (Raspberry Pi only) +new | Clear composition (remove all surfaces) +ext | Exit application and return to command line +BACKSPACE ('\' via SSH) | Delete surface. +SPACE | Toggle pause for video sources (texture and projection mapping modes) +TAB | Select next source (no need to use the source selection interface) +Arrow keys | Move selection. If no surface is selected in the projection mapping mode, all surfaces are moved. +\/ | Toggle 1px/10px steps for keyboard moves on Raspberry Pi + +## Notes on Video Encoding + +Easiest way to achieve success is to use [HandBrake](https://handbrake.fr/) with the following settings. This will produce a `.mkv` file with 16bit FLAC audio with 22.05KHz sampling rate. + +``` +Preset: Fast 720p30 +Summary / Format: MKV File +Video / Framerate: Same as source +Video / Profile: Baseline +Audio / Codec: FLAC 16-bit +Audio / Samplerate: 22.05 +``` + +If you are familiar with [ffmpeg](http://ffmpeg.org/), use the following. It will produce a `.mov` file. PCM audio codec with 22KHz sampling rate is used. + +``` +ffmpeg -i input-video.mp4 -s 1280x720 -aspect 16:9 \ + -c:v libx264 -profile:v baseline \ + -c:a pcm_s16le -ar 22000 -ac 2 \ + output-video.mov +``` + +These two settings have shown the best results so far. Audio problems and video playback at the beginning of longer video files was the main issue in most cases. Please open an issue if you have better suggestions. + +## Extended Functionality + +Examples represent extended functionality of ofxPiMapper. Enter each example separately to find out more. + +- [Basic Example](example_basic). +- [FBO Sources Example](example_fbo-sources). +- [Camera Example](example_camera). +- [Remote Control Server](example_remote-server) example. +- [Remote Control Client](example_remote-client) example. +- Readme's for the rest are cooking... + +## Problems with Audio + +If you are having problems with audio playback, here are two steps for you. Before you do these, make sure audio of your video file works. + + +### Step 1 + +Open example openFrameworks application `ofApp.cpp` file in a text editor. + +``` +cd /home/pi/openFrameworks/addons/ofxPiMapper/example +nano src/ofApp.cpp +``` + +Make sure that the following line looks as follows. + +``` +ofx::piMapper::VideoSource::enableAudio = true; +``` + +Save the file (CTRL + X, Y and ENTER). Recompile and run the example. + +``` +make && make run +``` + +### Step 2 + +If the sound still does not work, try to use `raspi-config`. + +``` +sudo raspi-config +``` + +Select "7 Advanced Options" and "A9 Audio" then "0 Auto". You can use one of the force options if you want to be 100% sure. + +Open alsamixer. + +``` +alsamixer +``` + +Set the volume to a value between 90 to 100 by using the arrow keys. ESC to exit the mixer. + +Launch ofxPiMapper example, select a surface and set a video source with audio. Should work. + + +## Development + +Keeping it simple. Developing ofxPiMapper master branch against the latest stable release version of openFrameworks. + + +## Licence + +ofxPiMapper is distributed under the [MIT License](https://en.wikipedia.org/wiki/MIT_License). See the [LICENSE](LICENSE.md) file for further details. Just add my name somewhere along your project [Krisjanis Rijnieks](https://rijnieks.com) whenever possible. + + +## Supporters + +You can become a supporter by donating BitCoins, via PayPal or becoming a Patreon. Please check https://ofxpimapper.com for details. List of supporters below. + +- [Marc-André Gasser](https://www.magdesign.ch/) +- Manuel Meißner + + +## Dependencies + +Before moving on, make sure that you have all the dependencies installed. + + - ofxGui (available in oF by default) + - ofxXmlSettings (available in oF by default) + - [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) (needed only on Raspberry Pi) + +To install dependencies, `cd` into `openFrameworks/addons` directory and execute the following: + +```bash +git clone https://github.com/jvcleave/ofxOMXPlayer.git +``` + +The `ofxOMXPlayer` addon recommends you to use its releases. Currently the latest release is `0.9.0-compatible`. To checkout the code of the relase, go to the `ofxOMXPlayer` addon directory and checkout the relase. + +``` +cd openFrameworks/addons/ofxOMXPlayer +git checkout 0.9.0-compatible +``` + +You can check the latest releases on the [ofxOMXPlayer GitHub repository](https://github.com/jvcleave/ofxOMXPlayer/releases). diff --git a/addon_config.mk b/addon_config.mk index a7be1ec..0fb168b 100644 --- a/addon_config.mk +++ b/addon_config.mk @@ -1,76 +1,76 @@ -# All variables and this file are optional, if they are not present the PG and the -# makefiles will try to parse the correct values from the file system. -# -# Variables that specify exclusions can use % as a wildcard to specify that anything in -# that position will match. A partial path can also be specified to, for example, exclude -# a whole folder from the parsed paths from the file system -# -# Variables can be specified using = or += -# = will clear the contents of that variable both specified from the file or the ones parsed -# from the file system -# += will add the values to the previous ones in the file or the ones parsed from the file -# system -# -# The PG can be used to detect errors in this file, just create a new project with this addon -# and the PG will write to the console the kind of error and in which line it is - -meta: -ADDON_NAME = ofxPiMapper -ADDON_DESCRIPTION = Projection mapping addon for openFrameworks -ADDON_AUTHOR = @kr15h -ADDON_TAGS = "addon" "rpi" "mapping" -ADDON_URL = http://github.com/kr15h/ofxPiMapper - -common: -# dependencies with other addons, a list of them separated by spaces -# or use += in several lines -ADDON_DEPENDENCIES = ofxXmlSettings ofxGui - -# include search paths, this will be usually parsed from the file system -# but if the addon or addon libraries need special search paths they can be -# specified here separated by spaces or one per line using += -# ADDON_INCLUDES = - -# any special flag that should be passed to the compiler when using this -# addon -# ADDON_CFLAGS = - -# any special flag that should be passed to the linker when using this -# addon, also used for system libraries with -lname -# ADDON_LDFLAGS = - -# linux only, any library that should be included in the project using -# pkg-config -# ADDON_PKG_CONFIG_LIBRARIES = - -# osx/iOS only, any framework that should be included in the project -# ADDON_FRAMEWORKS = - -# source files, these will be usually parsed from the file system looking -# in the src folders in libs and the root of the addon. if your addon needs -# to include files in different places or a different set of files per platform -# they can be specified here -# ADDON_SOURCES = - -# some addons need resources to be copied to the bin/data folder of the project -# specify here any files that need to be copied, you can use wildcards like * and ? -# ADDON_DATA = - -# when parsing the file system looking for libraries exclude this for all or -# a specific platform -# ADDON_LIBS_EXCLUDE = - -linux64: -# binary libraries, these will be usually parsed from the file system but some -# libraries need to passed to the linker in a specific order -ADDON_LIBS = -linux: -ADDON_LIBS = -win_cb: -ADDON_LIBS = -linuxarmv6l: -ADDON_LIBS = -linuxarmv7l: -ADDON_LIBS = -android/armeabi: -ADDON_LIBS = +# All variables and this file are optional, if they are not present the PG and the +# makefiles will try to parse the correct values from the file system. +# +# Variables that specify exclusions can use % as a wildcard to specify that anything in +# that position will match. A partial path can also be specified to, for example, exclude +# a whole folder from the parsed paths from the file system +# +# Variables can be specified using = or += +# = will clear the contents of that variable both specified from the file or the ones parsed +# from the file system +# += will add the values to the previous ones in the file or the ones parsed from the file +# system +# +# The PG can be used to detect errors in this file, just create a new project with this addon +# and the PG will write to the console the kind of error and in which line it is + +meta: +ADDON_NAME = ofxPiMapper +ADDON_DESCRIPTION = Projection mapping addon for openFrameworks +ADDON_AUTHOR = @kr15h +ADDON_TAGS = "addon" "rpi" "mapping" +ADDON_URL = http://github.com/kr15h/ofxPiMapper + +common: +# dependencies with other addons, a list of them separated by spaces +# or use += in several lines +ADDON_DEPENDENCIES = ofxXmlSettings ofxGui + +# include search paths, this will be usually parsed from the file system +# but if the addon or addon libraries need special search paths they can be +# specified here separated by spaces or one per line using += +# ADDON_INCLUDES = + +# any special flag that should be passed to the compiler when using this +# addon +# ADDON_CFLAGS = + +# any special flag that should be passed to the linker when using this +# addon, also used for system libraries with -lname +# ADDON_LDFLAGS = + +# linux only, any library that should be included in the project using +# pkg-config +# ADDON_PKG_CONFIG_LIBRARIES = + +# osx/iOS only, any framework that should be included in the project +# ADDON_FRAMEWORKS = + +# source files, these will be usually parsed from the file system looking +# in the src folders in libs and the root of the addon. if your addon needs +# to include files in different places or a different set of files per platform +# they can be specified here +# ADDON_SOURCES = + +# some addons need resources to be copied to the bin/data folder of the project +# specify here any files that need to be copied, you can use wildcards like * and ? +# ADDON_DATA = + +# when parsing the file system looking for libraries exclude this for all or +# a specific platform +# ADDON_LIBS_EXCLUDE = + +linux64: +# binary libraries, these will be usually parsed from the file system but some +# libraries need to passed to the linker in a specific order +ADDON_LIBS = +linux: +ADDON_LIBS = +win_cb: +ADDON_LIBS = +linuxarmv6l: +ADDON_LIBS = +linuxarmv7l: +ADDON_LIBS = +android/armeabi: +ADDON_LIBS = diff --git a/example_basic/Makefile b/example_basic/Makefile index 8d8e4c0..c83af71 100644 --- a/example_basic/Makefile +++ b/example_basic/Makefile @@ -1,13 +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 +# 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/example_basic/README.md b/example_basic/README.md index f58ab84..9bff592 100644 --- a/example_basic/README.md +++ b/example_basic/README.md @@ -1,7 +1,7 @@ -# Basic Example - -This is a very basic example. It shows how to use ofxPiMapper addon with it's integrated functionality. You can map images and videos with this. ofxPiMapper takes care of loading and saving your composition. - -For now you have to put your sources under `bin/data/sources`. There are two directories: `images` and `videos`. As you may expect, put images in the `images` folder and videos in the `videos` one. - -The addon is made so that you have to pass the keyboard and mouse events to it. It is because in this way you can gain more control over how it behaves. If you do not pass the keyboard and mouse events, ofxPiMapper reads the configuration file from `data/ofxpimapper.xml` and continues working from there. It just starts up, loads the configuration and displays the composition until the application quits. +# Basic Example + +This is a very basic example. It shows how to use ofxPiMapper addon with it's integrated functionality. You can map images and videos with this. ofxPiMapper takes care of loading and saving your composition. + +For now you have to put your sources under `bin/data/sources`. There are two directories: `images` and `videos`. As you may expect, put images in the `images` folder and videos in the `videos` one. + +The addon is made so that you have to pass the keyboard and mouse events to it. It is because in this way you can gain more control over how it behaves. If you do not pass the keyboard and mouse events, ofxPiMapper reads the configuration file from `data/ofxpimapper.xml` and continues working from there. It just starts up, loads the configuration and displays the composition until the application quits. diff --git a/example_basic/addons.make b/example_basic/addons.make index 963941c..596425d 100644 --- a/example_basic/addons.make +++ b/example_basic/addons.make @@ -1,4 +1,4 @@ -ofxGui -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_basic/addons.make.norpi b/example_basic/addons.make.norpi index e72d2dd..69d8f94 100644 --- a/example_basic/addons.make.norpi +++ b/example_basic/addons.make.norpi @@ -1,3 +1,3 @@ -ofxGui -ofxPiMapper -ofxXmlSettings +ofxGui +ofxPiMapper +ofxXmlSettings diff --git a/example_basic/bin/data/ofxpimapper.xml b/example_basic/bin/data/ofxpimapper.xml index 1e79640..fe78244 100644 --- a/example_basic/bin/data/ofxpimapper.xml +++ b/example_basic/bin/data/ofxpimapper.xml @@ -1,36 +1,203 @@ - - - - - 512.000000000 - 50.000000000 - - - 974.000000000 - 718.000000000 - - - 50.000000000 - 718.000000000 - - - - - 0.500000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - video - gene-nsynthesis-loop-a.mp4 - - - + + + + + 452.000000000 + 221.000000000 + + + 1017.744750977 + 744.464965820 + + + 6.254730225 + 744.464965820 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + video + gene-nsynthesis-loop-c.mp4 + 1 + + + + + + 512.000000000 + 50.000000000 + + + 974.000000000 + 718.000000000 + + + 50.000000000 + 718.000000000 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + video + gene-nsynthesis-loop-a.mp4 + 1 + + + + + + -8.000000000 + 6.000000000 + + + 434.000000000 + 250.000000000 + + + 920.000000000 + 101.000000000 + + + -4.000000000 + 397.000000000 + + + 508.000000000 + 385.000000000 + + + 920.000000000 + 385.000000000 + + + 2.254730225 + 745.464965820 + + + 508.000000000 + 669.000000000 + + + 920.000000000 + 669.000000000 + + + + + 0.000000000 + 0.000000000 + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 0.000000000 + + + 0.000000000 + 0.500000000 + + + 0.500000000 + 0.500000000 + + + 1.000000000 + 0.500000000 + + + 0.000000000 + 1.000000000 + + + 0.500000000 + 1.000000000 + + + 1.000000000 + 1.000000000 + + + + none + none + + + 2 + 2 + + + + + + 267.996795654 + 22.747558594 + + + 267.996795654 + 147.252563477 + + + 434.003723145 + 147.252563477 + + + 434.003723145 + 22.747558594 + + + + + 0.000000000 + 0.000000000 + + + 1.000000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + none + none + + + 1 + + + diff --git a/example_basic/src/main.cpp b/example_basic/src/main.cpp index 1f97405..2da2b3b 100644 --- a/example_basic/src/main.cpp +++ b/example_basic/src/main.cpp @@ -1,7 +1,7 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1024,768,OF_WINDOW); - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" + +int main(){ + ofSetupOpenGL(1024,768,OF_WINDOW); + ofRunApp(new ofApp()); +} diff --git a/example_basic/src/ofApp.cpp b/example_basic/src/ofApp.cpp index c8b58d6..32b56db 100644 --- a/example_basic/src/ofApp.cpp +++ b/example_basic/src/ofApp.cpp @@ -1,38 +1,38 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - mapper.setup(); - - #ifdef TARGET_RASPBERRY_PI - ofSetFullscreen(true); - #endif -} - -void ofApp::update(){ - mapper.update(); -} - -void ofApp::draw(){ - mapper.draw(); -} - -void ofApp::keyPressed(int key){ - mapper.keyPressed(key); -} - -void ofApp::keyReleased(int key){ - mapper.keyReleased(key); -} - -void ofApp::mouseDragged(int x, int y, int button){ - mapper.mouseDragged(x, y, button); -} - -void ofApp::mousePressed(int x, int y, int button){ - mapper.mousePressed(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - mapper.mouseReleased(x, y, button); -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + mapper.setup(); + + #ifdef TARGET_RASPBERRY_PI + ofSetFullscreen(true); + #endif +} + +void ofApp::update(){ + mapper.update(); +} + +void ofApp::draw(){ + mapper.draw(); +} + +void ofApp::keyPressed(int key){ + mapper.keyPressed(key); +} + +void ofApp::keyReleased(int key){ + mapper.keyReleased(key); +} + +void ofApp::mouseDragged(int x, int y, int button){ + mapper.mouseDragged(x, y, button); +} + +void ofApp::mousePressed(int x, int y, int button){ + mapper.mousePressed(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + mapper.mouseReleased(x, y, button); +} diff --git a/example_basic/src/ofApp.h b/example_basic/src/ofApp.h index c74bb4f..2bc449f 100644 --- a/example_basic/src/ofApp.h +++ b/example_basic/src/ofApp.h @@ -1,25 +1,25 @@ -#pragma once - -#include "ofMain.h" -#include "ofxPiMapper.h" - -class ofApp : public ofBaseApp{ -public: - void setup(); - void update(); - void draw(); - - // We need to forward key and mouse events to ofxPiMapper. - // By not doing it we have the opportunity to use ofxPiMapper - // witout the interface. - - void keyPressed(int key); - void keyReleased(int key); - - void mouseDragged(int x, int y, int button); - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - - // This is our mapper object. - ofxPiMapper mapper; -}; +#pragma once + +#include "ofMain.h" +#include "ofxPiMapper.h" + +class ofApp : public ofBaseApp{ +public: + void setup(); + void update(); + void draw(); + + // We need to forward key and mouse events to ofxPiMapper. + // By not doing it we have the opportunity to use ofxPiMapper + // witout the interface. + + void keyPressed(int key); + void keyReleased(int key); + + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + + // This is our mapper object. + ofxPiMapper mapper; +}; diff --git a/example_camera/.gitignore b/example_camera/.gitignore index e4d4b5d..ad71cfd 100644 --- a/example_camera/.gitignore +++ b/example_camera/.gitignore @@ -1,5 +1,5 @@ -obj -*.xcworkspace -*.xcuserdatad -*~ -config.make +obj +*.xcworkspace +*.xcuserdatad +*~ +config.make diff --git a/example_camera/Makefile b/example_camera/Makefile index 8d8e4c0..c83af71 100644 --- a/example_camera/Makefile +++ b/example_camera/Makefile @@ -1,13 +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 +# 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/example_camera/README.md b/example_camera/README.md index 09d037b..48148c4 100644 --- a/example_camera/README.md +++ b/example_camera/README.md @@ -1,9 +1,9 @@ -# Camera Example - -This example demonstrates the possibility to use camera input as a texture source. Make sure you clone the [ofxRPiCameraVideoGrabber](https://github.com/jvcleave/ofxRPiCameraVideoGrabber) addon into your `openFrameworks/addons` folder before compiling on Raspberry Pi. - -``` -cd openFrameworks/addons -git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber.git -``` - +# Camera Example + +This example demonstrates the possibility to use camera input as a texture source. Make sure you clone the [ofxRPiCameraVideoGrabber](https://github.com/jvcleave/ofxRPiCameraVideoGrabber) addon into your `openFrameworks/addons` folder before compiling on Raspberry Pi. + +``` +cd openFrameworks/addons +git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber.git +``` + diff --git a/example_camera/addons.make b/example_camera/addons.make index 0bda1a1..bad4b22 100644 --- a/example_camera/addons.make +++ b/example_camera/addons.make @@ -1,5 +1,5 @@ -ofxGui -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer -ofxRPiCameraVideoGrabber +ofxGui +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer +ofxRPiCameraVideoGrabber diff --git a/example_camera/addons.make.norpi b/example_camera/addons.make.norpi index e72d2dd..69d8f94 100644 --- a/example_camera/addons.make.norpi +++ b/example_camera/addons.make.norpi @@ -1,3 +1,3 @@ -ofxGui -ofxPiMapper -ofxXmlSettings +ofxGui +ofxPiMapper +ofxXmlSettings diff --git a/example_camera/bin/data/defaultSurfaces.xml b/example_camera/bin/data/defaultSurfaces.xml index fc48ade..d4237fc 100755 --- a/example_camera/bin/data/defaultSurfaces.xml +++ b/example_camera/bin/data/defaultSurfaces.xml @@ -1,36 +1,36 @@ - - - - - 415.000000000 - 51.000000000 - - - 581.000000000 - 388.000000000 - - - 183.000000000 - 357.000000000 - - - - - 0.556249976 - 0.108333334 - - - 0.862500012 - 0.941666663 - - - 0.118749999 - 0.862500012 - - - - fbo - Camera Source - - - + + + + + 415.000000000 + 51.000000000 + + + 581.000000000 + 388.000000000 + + + 183.000000000 + 357.000000000 + + + + + 0.556249976 + 0.108333334 + + + 0.862500012 + 0.941666663 + + + 0.118749999 + 0.862500012 + + + + fbo + Camera Source + + + diff --git a/example_camera/bin/data/ofxpimapper.xml b/example_camera/bin/data/ofxpimapper.xml index 11d445a..e1f90ab 100644 --- a/example_camera/bin/data/ofxpimapper.xml +++ b/example_camera/bin/data/ofxpimapper.xml @@ -1,70 +1,70 @@ - - - - - 437.000000000 - 82.000000000 - - - 991.000000000 - 75.000000000 - - - 750.000000000 - 485.000000000 - - - - - 0.351562500 - 0.072222225 - - - 0.857812524 - 0.125000000 - - - 0.549218774 - 0.695833325 - - - - fbo - Camera Source - - - - - - 437.000000000 - 82.000000000 - - - 750.000000000 - 485.000000000 - - - 112.000000000 - 476.000000000 - - - - - 0.341406256 - 0.073611110 - - - 0.557031274 - 0.690277755 - - - 0.064843751 - 0.558333337 - - - - fbo - Camera Source - - - + + + + + 437.000000000 + 82.000000000 + + + 991.000000000 + 75.000000000 + + + 750.000000000 + 485.000000000 + + + + + 0.351562500 + 0.072222225 + + + 0.857812524 + 0.125000000 + + + 0.549218774 + 0.695833325 + + + + fbo + Camera Source + + + + + + 437.000000000 + 82.000000000 + + + 750.000000000 + 485.000000000 + + + 112.000000000 + 476.000000000 + + + + + 0.341406256 + 0.073611110 + + + 0.557031274 + 0.690277755 + + + 0.064843751 + 0.558333337 + + + + fbo + Camera Source + + + diff --git a/example_camera/src/CameraSource.cpp b/example_camera/src/CameraSource.cpp index 2513475..a5d6021 100644 --- a/example_camera/src/CameraSource.cpp +++ b/example_camera/src/CameraSource.cpp @@ -1,62 +1,62 @@ -#include "CameraSource.h" - -CameraSource::CameraSource(){ - name = "Camera Source"; - - _cameraWidth = 1280; - _cameraHeight = 720; - - #ifdef TARGET_RASPBERRY_PI - _omxCameraSettings.width = _cameraWidth; - _omxCameraSettings.height = _cameraHeight; - _omxCameraSettings.framerate = 30; - _omxCameraSettings.enableTexture = true; - _omxCameraSettings.doRecording = false; - - _videoGrabber.setup(_omxCameraSettings); - #else - std::vector devices = _videoGrabber.listDevices(); - _cameraFound = false; - - for(int i = 0; i < devices.size(); i++){ - if(devices[i].bAvailable){ - ofLogNotice() << devices[i].id << ": " << devices[i].deviceName; - _cameraFound = true; - break; - } - } - - if(_cameraFound){ - _videoGrabber.setDeviceID(0); - _videoGrabber.setup(_cameraWidth, _cameraHeight); - } - #endif - - allocate(_cameraWidth, _cameraHeight); -} - -void CameraSource::update(){ - #ifndef TARGET_RASPBERRY_PI - if(_videoGrabber.isInitialized()){ - _videoGrabber.update(); - } - #endif -} - -void CameraSource::draw(){ - ofClear(0); - ofSetHexColor(0xffffff); - #ifdef TARGET_RASPBERRY_PI - ofDisableNormalizedTexCoords(); - _videoGrabber.draw(0, 0); - ofEnableNormalizedTexCoords(); - #else - if(_videoGrabber.isInitialized()){ - ofDisableNormalizedTexCoords(); - _videoGrabber.draw(0, 0); - ofEnableNormalizedTexCoords(); - }else{ - ofDrawBitmapString("no camera", _cameraWidth / 2.0f - 40.0f, _cameraHeight / 2.0f + 10.0f); - } - #endif -} +#include "CameraSource.h" + +CameraSource::CameraSource(){ + name = "Camera Source"; + + _cameraWidth = 1280; + _cameraHeight = 720; + + #ifdef TARGET_RASPBERRY_PI + _omxCameraSettings.width = _cameraWidth; + _omxCameraSettings.height = _cameraHeight; + _omxCameraSettings.framerate = 30; + _omxCameraSettings.enableTexture = true; + _omxCameraSettings.doRecording = false; + + _videoGrabber.setup(_omxCameraSettings); + #else + std::vector devices = _videoGrabber.listDevices(); + _cameraFound = false; + + for(int i = 0; i < devices.size(); i++){ + if(devices[i].bAvailable){ + ofLogNotice() << devices[i].id << ": " << devices[i].deviceName; + _cameraFound = true; + break; + } + } + + if(_cameraFound){ + _videoGrabber.setDeviceID(0); + _videoGrabber.setup(_cameraWidth, _cameraHeight); + } + #endif + + allocate(_cameraWidth, _cameraHeight); +} + +void CameraSource::update(){ + #ifndef TARGET_RASPBERRY_PI + if(_videoGrabber.isInitialized()){ + _videoGrabber.update(); + } + #endif +} + +void CameraSource::draw(){ + ofClear(0); + ofSetHexColor(0xffffff); + #ifdef TARGET_RASPBERRY_PI + ofDisableNormalizedTexCoords(); + _videoGrabber.draw(0, 0); + ofEnableNormalizedTexCoords(); + #else + if(_videoGrabber.isInitialized()){ + ofDisableNormalizedTexCoords(); + _videoGrabber.draw(0, 0); + ofEnableNormalizedTexCoords(); + }else{ + ofDrawBitmapString("no camera", _cameraWidth / 2.0f - 40.0f, _cameraHeight / 2.0f + 10.0f); + } + #endif +} diff --git a/example_camera/src/CameraSource.h b/example_camera/src/CameraSource.h index 5a6ecb2..61aadc2 100644 --- a/example_camera/src/CameraSource.h +++ b/example_camera/src/CameraSource.h @@ -1,34 +1,34 @@ -/* - * CameraSource - * Camera source for ofxPiMapper - * Created by Krisjanis Rijnieks on 25/01/2016 - */ - -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -#ifdef TARGET_RASPBERRY_PI - #include "ofxRPiCameraVideoGrabber.h" -#endif - -class CameraSource : public ofx::piMapper::FboSource { - public: - CameraSource(); - - void update(); - void draw(); - - private: - - #ifdef TARGET_RASPBERRY_PI - OMXCameraSettings _omxCameraSettings; - ofxRPiCameraVideoGrabber _videoGrabber; - #else - ofVideoGrabber _videoGrabber; - #endif - int _cameraWidth; - int _cameraHeight; - bool _cameraFound; +/* + * CameraSource + * Camera source for ofxPiMapper + * Created by Krisjanis Rijnieks on 25/01/2016 + */ + +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +#ifdef TARGET_RASPBERRY_PI + #include "ofxRPiCameraVideoGrabber.h" +#endif + +class CameraSource : public ofx::piMapper::FboSource { + public: + CameraSource(); + + void update(); + void draw(); + + private: + + #ifdef TARGET_RASPBERRY_PI + OMXCameraSettings _omxCameraSettings; + ofxRPiCameraVideoGrabber _videoGrabber; + #else + ofVideoGrabber _videoGrabber; + #endif + int _cameraWidth; + int _cameraHeight; + bool _cameraFound; }; \ No newline at end of file diff --git a/example_camera/src/main.cpp b/example_camera/src/main.cpp index 602382f..a518e54 100644 --- a/example_camera/src/main.cpp +++ b/example_camera/src/main.cpp @@ -1,24 +1,24 @@ -#include "ofMain.h" -#include "ofApp.h" -#include -#include - -int main(int argc, char * argv[]){ - bool fullscreen = false; - - std::vector arguments = std::vector(argv, argv + argc); - for(int i = 0; i < arguments.size(); ++i){ - if(arguments.at(i) == "-f"){ - fullscreen = true; - break; - } - } - - if(fullscreen){ - ofSetupOpenGL(800, 450, OF_FULLSCREEN); - }else{ - ofSetupOpenGL(800, 450, OF_WINDOW); - } - - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" +#include +#include + +int main(int argc, char * argv[]){ + bool fullscreen = false; + + std::vector arguments = std::vector(argv, argv + argc); + for(int i = 0; i < arguments.size(); ++i){ + if(arguments.at(i) == "-f"){ + fullscreen = true; + break; + } + } + + if(fullscreen){ + ofSetupOpenGL(800, 450, OF_FULLSCREEN); + }else{ + ofSetupOpenGL(800, 450, OF_WINDOW); + } + + ofRunApp(new ofApp()); +} diff --git a/example_camera/src/ofApp.cpp b/example_camera/src/ofApp.cpp index 9751f39..8ea1615 100644 --- a/example_camera/src/ofApp.cpp +++ b/example_camera/src/ofApp.cpp @@ -1,36 +1,36 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - cameraSource = new CameraSource(); - piMapper.registerFboSource(*cameraSource); - piMapper.setup(); -} - -void ofApp::update(){ - piMapper.update(); -} - -void ofApp::draw(){ - piMapper.draw(); -} - -void ofApp::keyPressed(int key){ - piMapper.keyPressed(key); -} - -void ofApp::keyReleased(int key){ - piMapper.keyReleased(key); -} - -void ofApp::mousePressed(int x, int y, int button){ - piMapper.mousePressed(x, y, button); -} - -void ofApp::mouseDragged(int x, int y, int button){ - piMapper.mouseDragged(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - piMapper.mouseReleased(x, y, button); -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + cameraSource = new CameraSource(); + piMapper.registerFboSource(*cameraSource); + piMapper.setup(); +} + +void ofApp::update(){ + piMapper.update(); +} + +void ofApp::draw(){ + piMapper.draw(); +} + +void ofApp::keyPressed(int key){ + piMapper.keyPressed(key); +} + +void ofApp::keyReleased(int key){ + piMapper.keyReleased(key); +} + +void ofApp::mousePressed(int x, int y, int button){ + piMapper.mousePressed(x, y, button); +} + +void ofApp::mouseDragged(int x, int y, int button){ + piMapper.mouseDragged(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + piMapper.mouseReleased(x, y, button); +} diff --git a/example_camera/src/ofApp.h b/example_camera/src/ofApp.h index a76db1a..8719b9c 100644 --- a/example_camera/src/ofApp.h +++ b/example_camera/src/ofApp.h @@ -1,31 +1,31 @@ -/* - * CameraSource example - * Can be used with the Raspberry Pi camera module or the Auvidea HDMI bridge. - * B101 HDMI to CSI-2 Bridge (15 pin FPC). - * Available at http://www.auvidea.eu/index.php/theme-styles/2014-12-30-22-32-06/b101 - * Created by Krisjanis Rijnieks on 25/01/2016 - * Last modified on 10/02/2016 - */ - -#pragma once - -#include "ofMain.h" -#include "ofxPiMapper.h" -#include "CameraSource.h" - -class ofApp : public ofBaseApp { - public: - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseDragged(int x, int y, int button); - void mouseReleased(int x, int y, int button); - - ofxPiMapper piMapper; - CameraSource * cameraSource; +/* + * CameraSource example + * Can be used with the Raspberry Pi camera module or the Auvidea HDMI bridge. + * B101 HDMI to CSI-2 Bridge (15 pin FPC). + * Available at http://www.auvidea.eu/index.php/theme-styles/2014-12-30-22-32-06/b101 + * Created by Krisjanis Rijnieks on 25/01/2016 + * Last modified on 10/02/2016 + */ + +#pragma once + +#include "ofMain.h" +#include "ofxPiMapper.h" +#include "CameraSource.h" + +class ofApp : public ofBaseApp { + public: + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseDragged(int x, int y, int button); + void mouseReleased(int x, int y, int button); + + ofxPiMapper piMapper; + CameraSource * cameraSource; }; \ No newline at end of file diff --git a/example_fbo-sources/.gitignore b/example_fbo-sources/.gitignore index e4d4b5d..ad71cfd 100644 --- a/example_fbo-sources/.gitignore +++ b/example_fbo-sources/.gitignore @@ -1,5 +1,5 @@ -obj -*.xcworkspace -*.xcuserdatad -*~ -config.make +obj +*.xcworkspace +*.xcuserdatad +*~ +config.make diff --git a/example_fbo-sources/Makefile b/example_fbo-sources/Makefile index 8d8e4c0..c83af71 100644 --- a/example_fbo-sources/Makefile +++ b/example_fbo-sources/Makefile @@ -1,13 +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 +# 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/example_fbo-sources/README.md b/example_fbo-sources/README.md index 454e3ad..9fc787e 100644 --- a/example_fbo-sources/README.md +++ b/example_fbo-sources/README.md @@ -1,28 +1,28 @@ -# FBO Sources Example - -This example shows how to use custom (FBO) source functionality with ofxPiMapper. Below you can see a list of custom sources and feel free to add your own via pull requests! - -- ScanlineSource -- SlideShowSource - -To build your own source, one should start by extending the `FboSource` class. When the source is ready, it should be instantiated in the `ofApp` class and passed via `mapper.registerFboSource(...source)` function before the `mapper.setup()` call. This will make the source name to appear under **FBO Sources** category in the source selection mode. - -Look at the source code of the custom sources to understand how to build one, but essentially it is extending the `FboSource` class of `ofxPiMapper` and overriding the `setup()`, `update()` and `draw()` functions. - -In the `setup()` function you should set a name for your custom source. - -``` -name = "Name Your Source"; -``` - -Then you should set the dimensions of your source by using the `allocate()` function. - -``` -allocate(500, 500); -``` - -In the `draw()` of your custom `FboSource` you should decide whether you want the previous frame to be cleared from the gfx buffer or not. If you want to draw a fresh frame, use the `ofClear()` function. - -``` -ofClear(0); // Clear with black -``` +# FBO Sources Example + +This example shows how to use custom (FBO) source functionality with ofxPiMapper. Below you can see a list of custom sources and feel free to add your own via pull requests! + +- ScanlineSource +- SlideShowSource + +To build your own source, one should start by extending the `FboSource` class. When the source is ready, it should be instantiated in the `ofApp` class and passed via `mapper.registerFboSource(...source)` function before the `mapper.setup()` call. This will make the source name to appear under **FBO Sources** category in the source selection mode. + +Look at the source code of the custom sources to understand how to build one, but essentially it is extending the `FboSource` class of `ofxPiMapper` and overriding the `setup()`, `update()` and `draw()` functions. + +In the `setup()` function you should set a name for your custom source. + +``` +name = "Name Your Source"; +``` + +Then you should set the dimensions of your source by using the `allocate()` function. + +``` +allocate(500, 500); +``` + +In the `draw()` of your custom `FboSource` you should decide whether you want the previous frame to be cleared from the gfx buffer or not. If you want to draw a fresh frame, use the `ofClear()` function. + +``` +ofClear(0); // Clear with black +``` diff --git a/example_fbo-sources/addons.make b/example_fbo-sources/addons.make index 963941c..596425d 100644 --- a/example_fbo-sources/addons.make +++ b/example_fbo-sources/addons.make @@ -1,4 +1,4 @@ -ofxGui -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_fbo-sources/addons.make.norpi b/example_fbo-sources/addons.make.norpi index e72d2dd..69d8f94 100644 --- a/example_fbo-sources/addons.make.norpi +++ b/example_fbo-sources/addons.make.norpi @@ -1,3 +1,3 @@ -ofxGui -ofxPiMapper -ofxXmlSettings +ofxGui +ofxPiMapper +ofxXmlSettings diff --git a/example_fbo-sources/bin/data/magslideshow_settings.xml b/example_fbo-sources/bin/data/magslideshow_settings.xml index 3e12c23..8a48c5d 100644 --- a/example_fbo-sources/bin/data/magslideshow_settings.xml +++ b/example_fbo-sources/bin/data/magslideshow_settings.xml @@ -1,15 +1,15 @@ - - 800 - 600 - 2 - - NORMAL - 0 - - - Dissolve - 3 - - - FitProportionally - + + 800 + 600 + 2 + + NORMAL + 0 + + + Dissolve + 3 + + + FitProportionally + diff --git a/example_fbo-sources/bin/data/ofxpimapper.xml b/example_fbo-sources/bin/data/ofxpimapper.xml index bd79dc9..6b6fa37 100644 --- a/example_fbo-sources/bin/data/ofxpimapper.xml +++ b/example_fbo-sources/bin/data/ofxpimapper.xml @@ -1,126 +1,126 @@ - - - - - 337.195068359 - 362.146270752 - - - 337.195068359 - 595.853759766 - - - 648.804992676 - 595.853759766 - - - 648.804992676 - 362.146270752 - - - - - 0.000000000 - 0.000000000 - - - 1.000000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - image4.jpg - - - 1 - - - - - - 522.590332031 - 188.924621582 - - - 835.409606934 - 188.924621582 - - - 835.409606934 - 415.075378418 - - - 522.590332031 - 415.075378418 - - - - - 0.000000000 - 0.000000000 - - - 1.000000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - image1.jpg - - - 1 - - - - - - 325.000000000 - 196.999847412 - - - 479.922424316 - 421.000091553 - - - 170.077636719 - 421.000091553 - - - - - 0.500000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - image2.jpg - - - + + + + + 337.195068359 + 362.146270752 + + + 337.195068359 + 595.853759766 + + + 648.804992676 + 595.853759766 + + + 648.804992676 + 362.146270752 + + + + + 0.000000000 + 0.000000000 + + + 1.000000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + image4.jpg + + + 1 + + + + + + 522.590332031 + 188.924621582 + + + 835.409606934 + 188.924621582 + + + 835.409606934 + 415.075378418 + + + 522.590332031 + 415.075378418 + + + + + 0.000000000 + 0.000000000 + + + 1.000000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + image1.jpg + + + 1 + + + + + + 325.000000000 + 196.999847412 + + + 479.922424316 + 421.000091553 + + + 170.077636719 + 421.000091553 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + image2.jpg + + + diff --git a/example_fbo-sources/src/BrickSource/BrickSource.cpp b/example_fbo-sources/src/BrickSource/BrickSource.cpp index df1e9c7..4a8931f 100644 --- a/example_fbo-sources/src/BrickSource/BrickSource.cpp +++ b/example_fbo-sources/src/BrickSource/BrickSource.cpp @@ -1,52 +1,52 @@ -#include "BrickSource.h" - -void BrickSource::setup(){ - // Give our source a decent name - name = "Brick Source"; - - // Allocate our FBO source, decide how big it should be - allocate(500, 500); - ofSetFrameRate(60); - - // Genereate rects to be rendered into the FBO - int numX = 21; - int numY = 21; // change this to add more or less rects - int motar = 4; - int brickLength = 20; - int brickWidth = 20; - int counter = 0; - for(int k = 0; k < numY;k++){ - for(int i = 0; i < numX; i++){ - - bricks.push_back(ofRectangle(i*(brickLength + motar), - k*(brickWidth + motar), - brickLength, - brickWidth)); - brickColor.push_back(ofRandom(0, 220)); - } - } -} - -// Don't do any drawing here -void BrickSource::update(){ - if (ofGetFrameNum()%30 == 0) { - for(int i = 0; i < bricks.size(); i++){ - brickColor[i] = ofRandom(0, 220); - } - } // Move quads -} - -// No need to take care of fbo.begin() and fbo.end() here. -// All within draw() is being rendered into fbo; -void BrickSource::draw(){ - // Fill FBO with our quads - ofClear(0); - //ofBackground(0); - ofFill(); - - for(int i = 0; i < bricks.size(); i++){ - //ofSetLineWidth(ofRandom(5)); - ofSetColor(brickColor[i]); - ofDrawRectangle(bricks[i]); - } -} +#include "BrickSource.h" + +void BrickSource::setup(){ + // Give our source a decent name + name = "Brick Source"; + + // Allocate our FBO source, decide how big it should be + allocate(500, 500); + ofSetFrameRate(60); + + // Genereate rects to be rendered into the FBO + int numX = 21; + int numY = 21; // change this to add more or less rects + int motar = 4; + int brickLength = 20; + int brickWidth = 20; + int counter = 0; + for(int k = 0; k < numY;k++){ + for(int i = 0; i < numX; i++){ + + bricks.push_back(ofRectangle(i*(brickLength + motar), + k*(brickWidth + motar), + brickLength, + brickWidth)); + brickColor.push_back(ofRandom(0, 220)); + } + } +} + +// Don't do any drawing here +void BrickSource::update(){ + if (ofGetFrameNum()%30 == 0) { + for(int i = 0; i < bricks.size(); i++){ + brickColor[i] = ofRandom(0, 220); + } + } // Move quads +} + +// No need to take care of fbo.begin() and fbo.end() here. +// All within draw() is being rendered into fbo; +void BrickSource::draw(){ + // Fill FBO with our quads + ofClear(0); + //ofBackground(0); + ofFill(); + + for(int i = 0; i < bricks.size(); i++){ + //ofSetLineWidth(ofRandom(5)); + ofSetColor(brickColor[i]); + ofDrawRectangle(bricks[i]); + } +} diff --git a/example_fbo-sources/src/BrickSource/BrickSource.h b/example_fbo-sources/src/BrickSource/BrickSource.h index eaa6ec8..dcbd6b7 100644 --- a/example_fbo-sources/src/BrickSource/BrickSource.h +++ b/example_fbo-sources/src/BrickSource/BrickSource.h @@ -1,15 +1,15 @@ -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -class BrickSource : public ofx::piMapper::FboSource { - public: - void setup(); - void update(); - void draw(); - - std::vector bricks; - std::vector brickColor; - int counter; -}; +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +class BrickSource : public ofx::piMapper::FboSource { + public: + void setup(); + void update(); + void draw(); + + std::vector bricks; + std::vector brickColor; + int counter; +}; diff --git a/example_fbo-sources/src/CircleSource/CircleSource.cpp b/example_fbo-sources/src/CircleSource/CircleSource.cpp index 138f535..1d3815a 100644 --- a/example_fbo-sources/src/CircleSource/CircleSource.cpp +++ b/example_fbo-sources/src/CircleSource/CircleSource.cpp @@ -1,43 +1,43 @@ -#include "CircleSource.h" - -bool col = true; - -void CircleSource::setup(){ - // Give our source a decent name - name = "Circle Source"; - - // Allocate our FBO source, decide how big it should be - allocate(500, 500); - ofSetCircleResolution(50); - - // Genereate rects to be rendered into the FBO - int numCircles = 10; // change this to add more or less rects - for(int i = 0; i < numCircles; i++){ - circlesRadius.push_back(ofRandom(fbo->getHeight()/2)); - circlesSpeeds.push_back((1.0f + ofRandom(2))); - } -} - -// Don't do any drawing here -void CircleSource::update(){ - // Move rects - for(int i = 0; i < circlesRadius.size(); i++){ - circlesRadius[i] += circlesSpeeds[i]; - if(circlesRadius[i] > fbo->getHeight()/2){ - circlesRadius[i] = fbo->getHeight()/2*(-1); - } - } -} - -// No need to take care of fbo.begin() and fbo.end() here. -// All within draw() is being rendered into fbo; -void CircleSource::draw(){ - // Fill FBO with our rects - ofClear(0); - ofSetColor(255); - ofSetLineWidth(ofRandom(3)); - ofNoFill(); - for(int i = 0; i < circlesRadius.size(); i++){ - ofDrawCircle(fbo->getHeight()/2,fbo->getHeight()/2,circlesRadius[i]); - } -} +#include "CircleSource.h" + +bool col = true; + +void CircleSource::setup(){ + // Give our source a decent name + name = "Circle Source"; + + // Allocate our FBO source, decide how big it should be + allocate(500, 500); + ofSetCircleResolution(50); + + // Genereate rects to be rendered into the FBO + int numCircles = 10; // change this to add more or less rects + for(int i = 0; i < numCircles; i++){ + circlesRadius.push_back(ofRandom(fbo->getHeight()/2)); + circlesSpeeds.push_back((1.0f + ofRandom(2))); + } +} + +// Don't do any drawing here +void CircleSource::update(){ + // Move rects + for(int i = 0; i < circlesRadius.size(); i++){ + circlesRadius[i] += circlesSpeeds[i]; + if(circlesRadius[i] > fbo->getHeight()/2){ + circlesRadius[i] = fbo->getHeight()/2*(-1); + } + } +} + +// No need to take care of fbo.begin() and fbo.end() here. +// All within draw() is being rendered into fbo; +void CircleSource::draw(){ + // Fill FBO with our rects + ofClear(0); + ofSetColor(255); + ofSetLineWidth(ofRandom(3)); + ofNoFill(); + for(int i = 0; i < circlesRadius.size(); i++){ + ofDrawCircle(fbo->getHeight()/2,fbo->getHeight()/2,circlesRadius[i]); + } +} diff --git a/example_fbo-sources/src/CircleSource/CircleSource.h b/example_fbo-sources/src/CircleSource/CircleSource.h index 905b113..978e6e1 100644 --- a/example_fbo-sources/src/CircleSource/CircleSource.h +++ b/example_fbo-sources/src/CircleSource/CircleSource.h @@ -1,14 +1,14 @@ -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -class CircleSource : public ofx::piMapper::FboSource { - public: - void setup(); - void update(); - void draw(); - - std::vector circlesRadius; - std::vector circlesSpeeds; -}; +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +class CircleSource : public ofx::piMapper::FboSource { + public: + void setup(); + void update(); + void draw(); + + std::vector circlesRadius; + std::vector circlesSpeeds; +}; diff --git a/example_fbo-sources/src/QuadSource/QuadSource.cpp b/example_fbo-sources/src/QuadSource/QuadSource.cpp index 9c060dc..e0c6efc 100644 --- a/example_fbo-sources/src/QuadSource/QuadSource.cpp +++ b/example_fbo-sources/src/QuadSource/QuadSource.cpp @@ -1,62 +1,62 @@ -#include "QuadSource.h" - -void QuadSource::setup(){ - // Give our source a decent name - name = "Quad Source"; - - // Allocate our FBO source, decide how big it should be - allocate(500, 500); - - // Genereate rects to be rendered into the FBO - int numQuads = 20; // change this to add more or less rects - for(int i = 0; i < numQuads; i++){ - float qsize = ofRandom(fbo->getWidth()); - float fbosize = fbo->getWidth(); - - quads.push_back(ofRectangle(fbosize/2 - qsize/2, - fbosize/2 - qsize/2, - qsize, - qsize)); - - quadSpeeds.push_back((1.0f + ofRandom(5))); - } -} - -// Don't do any drawing here -void QuadSource::update(){ - // Move quads - for(int i = 0; i < quads.size(); i++){ - quads[i].x -= quadSpeeds[i]/2; - quads[i].y -= quadSpeeds[i]/2; - quads[i].width += quadSpeeds[i]; - quads[i].height += quadSpeeds[i]; - - if(quads[i].width > fbo->getHeight()){ - quads[i].x = fbo->getWidth()/2; - quads[i].y = fbo->getWidth()/2; - quads[i].width = 0.0f; - quads[i].height = 0.0f; - } - } -} - -// No need to take care of fbo.begin() and fbo.end() here. -// All within draw() is being rendered into fbo; -void QuadSource::draw(){ - // Fill FBO with our quads - ofClear(0); - //ofBackground(0); - ofNoFill(); - ofSetColor(255); - - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - for(int i = 0; i < quads.size(); i++){ - ofSetLineWidth(ofRandom(5)); - ofDrawRectangle(quads[i]); - } - #else - for(int i = 0; i < quads.size(); i++){ - ofRect(quads[i]); - } - #endif -} +#include "QuadSource.h" + +void QuadSource::setup(){ + // Give our source a decent name + name = "Quad Source"; + + // Allocate our FBO source, decide how big it should be + allocate(500, 500); + + // Genereate rects to be rendered into the FBO + int numQuads = 20; // change this to add more or less rects + for(int i = 0; i < numQuads; i++){ + float qsize = ofRandom(fbo->getWidth()); + float fbosize = fbo->getWidth(); + + quads.push_back(ofRectangle(fbosize/2 - qsize/2, + fbosize/2 - qsize/2, + qsize, + qsize)); + + quadSpeeds.push_back((1.0f + ofRandom(5))); + } +} + +// Don't do any drawing here +void QuadSource::update(){ + // Move quads + for(int i = 0; i < quads.size(); i++){ + quads[i].x -= quadSpeeds[i]/2; + quads[i].y -= quadSpeeds[i]/2; + quads[i].width += quadSpeeds[i]; + quads[i].height += quadSpeeds[i]; + + if(quads[i].width > fbo->getHeight()){ + quads[i].x = fbo->getWidth()/2; + quads[i].y = fbo->getWidth()/2; + quads[i].width = 0.0f; + quads[i].height = 0.0f; + } + } +} + +// No need to take care of fbo.begin() and fbo.end() here. +// All within draw() is being rendered into fbo; +void QuadSource::draw(){ + // Fill FBO with our quads + ofClear(0); + //ofBackground(0); + ofNoFill(); + ofSetColor(255); + + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + for(int i = 0; i < quads.size(); i++){ + ofSetLineWidth(ofRandom(5)); + ofDrawRectangle(quads[i]); + } + #else + for(int i = 0; i < quads.size(); i++){ + ofRect(quads[i]); + } + #endif +} diff --git a/example_fbo-sources/src/QuadSource/QuadSource.h b/example_fbo-sources/src/QuadSource/QuadSource.h index bb3309e..3e33f27 100644 --- a/example_fbo-sources/src/QuadSource/QuadSource.h +++ b/example_fbo-sources/src/QuadSource/QuadSource.h @@ -1,14 +1,14 @@ -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -class QuadSource : public ofx::piMapper::FboSource { - public: - void setup(); - void update(); - void draw(); - - std::vector quads; - std::vector quadSpeeds; -}; +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +class QuadSource : public ofx::piMapper::FboSource { + public: + void setup(); + void update(); + void draw(); + + std::vector quads; + std::vector quadSpeeds; +}; diff --git a/example_fbo-sources/src/ScanLineSource/ScanlineSource.cpp b/example_fbo-sources/src/ScanLineSource/ScanlineSource.cpp index edd68fb..1b57f22 100644 --- a/example_fbo-sources/src/ScanLineSource/ScanlineSource.cpp +++ b/example_fbo-sources/src/ScanLineSource/ScanlineSource.cpp @@ -1,48 +1,48 @@ -#include "ScanlineSource.h" - -void ScanlineSource::setup(){ - // Give our source a decent name - name = "Scanline Source"; - - // Allocate our FBO source, decide how big it should be - allocate(500, 500); - - // Genereate rects to be rendered into the FBO - int numRects = 20; // change this to add more or less rects - for(int i = 0; i < numRects; i++){ - rects.push_back(ofRectangle(0, - ofRandom(fbo->getHeight()), - fbo->getWidth(), - ofRandom(20))); - rectSpeeds.push_back((1.0f + ofRandom(5))); - } -} - -// Don't do any drawing here -void ScanlineSource::update(){ - // Move rects - for(int i = 0; i < rects.size(); i++){ - rects[i].y += rectSpeeds[i]; - if(rects[i].y > fbo->getHeight()){ - rects[i].y = -rects[i].getHeight(); - } - } -} - -// No need to take care of fbo.begin() and fbo.end() here. -// All within draw() is being rendered into fbo; -void ScanlineSource::draw(){ - // Fill FBO with our rects - ofClear(0); - //ofBackground(0); - ofSetColor(255); - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - for(int i = 0; i < rects.size(); i++){ - ofDrawRectangle(rects[i]); - } - #else - for(int i = 0; i < rects.size(); i++){ - ofRect(rects[i]); - } - #endif -} +#include "ScanlineSource.h" + +void ScanlineSource::setup(){ + // Give our source a decent name + name = "Scanline Source"; + + // Allocate our FBO source, decide how big it should be + allocate(500, 500); + + // Genereate rects to be rendered into the FBO + int numRects = 20; // change this to add more or less rects + for(int i = 0; i < numRects; i++){ + rects.push_back(ofRectangle(0, + ofRandom(fbo->getHeight()), + fbo->getWidth(), + ofRandom(20))); + rectSpeeds.push_back((1.0f + ofRandom(5))); + } +} + +// Don't do any drawing here +void ScanlineSource::update(){ + // Move rects + for(int i = 0; i < rects.size(); i++){ + rects[i].y += rectSpeeds[i]; + if(rects[i].y > fbo->getHeight()){ + rects[i].y = -rects[i].getHeight(); + } + } +} + +// No need to take care of fbo.begin() and fbo.end() here. +// All within draw() is being rendered into fbo; +void ScanlineSource::draw(){ + // Fill FBO with our rects + ofClear(0); + //ofBackground(0); + ofSetColor(255); + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + for(int i = 0; i < rects.size(); i++){ + ofDrawRectangle(rects[i]); + } + #else + for(int i = 0; i < rects.size(); i++){ + ofRect(rects[i]); + } + #endif +} diff --git a/example_fbo-sources/src/ScanLineSource/ScanlineSource.h b/example_fbo-sources/src/ScanLineSource/ScanlineSource.h index 255aead..fc267ba 100644 --- a/example_fbo-sources/src/ScanLineSource/ScanlineSource.h +++ b/example_fbo-sources/src/ScanLineSource/ScanlineSource.h @@ -1,14 +1,14 @@ -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -class ScanlineSource : public ofx::piMapper::FboSource { - public: - void setup(); - void update(); - void draw(); - - std::vector rects; - std::vector rectSpeeds; -}; +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +class ScanlineSource : public ofx::piMapper::FboSource { + public: + void setup(); + void update(); + void draw(); + + std::vector rects; + std::vector rectSpeeds; +}; diff --git a/example_fbo-sources/src/SlideShowSource/magSlide.cpp b/example_fbo-sources/src/SlideShowSource/magSlide.cpp index adffed8..0a8639f 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlide.cpp +++ b/example_fbo-sources/src/SlideShowSource/magSlide.cpp @@ -1,201 +1,201 @@ -// -// magSlide.cpp -// Copyright (c) 2017 Cristobal Mendoza -// http://cuppetellimendoza.com -// - -#include "magSlide.h" -#include "magSlideTransition.h" - -#pragma mark magSlide - -int magSlide::idCount = 0; - -magSlide::magSlide(std::string type) -{ - this->type = type; - position = ofPoint(0, 0); - id = magSlide::idCount; - magSlide::idCount++; -} - -void magSlide::update(uint64_t deltaTime) -{ - transition->update(deltaTime); - runningTime += deltaTime; - - switch (slideState){ -// case SlideState::BuildIn: -// if (runningTime >= buildInDuration) -// { -// setState(Normal); -// activeTransition = nullptr; -// } -// break; - - case SlideState::Normal: - if (runningTime >= buildOutStartTime){ - setState(BuildOut); - } - break; - - case SlideState::BuildOut: - if (runningTime >= endTime){ - setState(Complete); - } - break; - default: - break; - } -} - -void magSlide::setSize(float w, float h) -{ - width = w; - height = h; -} - -void magSlide::setResizeOption(magSlide::ResizeOptions resizeOption) -{ - this->resizeOption = resizeOption; -} - -magSlide::ResizeOptions magSlide::getResizeOption() const -{ - return resizeOption; -} - -void magSlide::setDuration(uint64_t duration) -{ - this->duration = duration; -} - -void magSlide::setState(SlideState state) -{ - // Don't do anything if the new state is the same - // as the current one: - if (slideState == state) return; - - slideState = state; - ofEventArgs args; - ofNotifyEvent(slideStateChangedEvent, args, this); - - if (slideState == Complete) - { - ofNotifyEvent(slideCompleteEvent, args, this); - } -} - -void magSlide::setTransitionDuration(uint64_t tDuration) -{ - buildOutDuration = tDuration; -} - -const std::string magSlide::getSlideStateName() -{ - switch (slideState) - { -// case SlideState::BuildIn: -// return "BuildIn"; - case SlideState::BuildOut: - return "BuildOut"; - case Normal: - return "Normal"; - case SlideState::Complete: - return "Complete"; - case SlideState::Off: - return "Off"; - } - - return "unknown"; -} - -void magSlide::start(uint64_t startTime) -{ - this->startTime = startTime; - runningTime = 0; - endTime = duration + (buildOutDuration*2); // *2 because we take into account transition in and out - buildOutStartTime = duration + buildOutDuration; - slideState = magSlide::SlideState::Normal; - position.set(0, 0); - opacity = 255; - isComplete = false; -} - -void magSlide::draw() -{ - ofSetColor(255, opacity); - if(transition->isActive()) - { - transition->draw(); - } -} - - -//////////////////////////////////////////////////////// -#pragma mark MAG_IMAGE_SLIDE -//////////////////////////////////////////////////////// - -magImageSlide::magImageSlide() : magSlide("magImageSlide") {} - -magImageSlide::~magImageSlide() {} - -void magImageSlide::setup(ofImage &image) -{ - // Make a copy of the image: - this->image = ofImage(image); - image.setAnchorPercent(0.5, 0.5); - width = image.getWidth(); - height = image.getHeight(); -} - -void magImageSlide::draw() -{ - magSlide::draw(); - image.draw(position, width, height); -} - -//////////////////////////////////////////////////////// -#pragma mark MAG_VIDEO_SLIDE -//////////////////////////////////////////////////////// - -magVideoSlide::magVideoSlide() : magSlide("magVideoSlide") -{} - -magVideoSlide::~magVideoSlide() -{ - videoPlayer.stop(); -} - -bool magVideoSlide::setup(ofFile &file, bool useVideoDuration) -{ - - bool success = videoPlayer.load(file.getAbsolutePath()); - - if (success) - { - videoPlayer.setAnchorPercent(0.5, 0.5); - if (useVideoDuration) - { - useVideoForDuration(); - } - } - - return success; -} - -void magVideoSlide::update() -{ - videoPlayer.update(); -} - -void magVideoSlide::draw() -{ - magSlide::draw(); - videoPlayer.draw(position.x, position.y, width, height); -} - -void magVideoSlide::useVideoForDuration() -{ - duration = uint64_t((videoPlayer.getDuration()*1000)) - buildOutDuration; -} +// +// magSlide.cpp +// Copyright (c) 2017 Cristobal Mendoza +// http://cuppetellimendoza.com +// + +#include "magSlide.h" +#include "magSlideTransition.h" + +#pragma mark magSlide + +int magSlide::idCount = 0; + +magSlide::magSlide(std::string type) +{ + this->type = type; + position = ofPoint(0, 0); + id = magSlide::idCount; + magSlide::idCount++; +} + +void magSlide::update(uint64_t deltaTime) +{ + transition->update(deltaTime); + runningTime += deltaTime; + + switch (slideState){ +// case SlideState::BuildIn: +// if (runningTime >= buildInDuration) +// { +// setState(Normal); +// activeTransition = nullptr; +// } +// break; + + case SlideState::Normal: + if (runningTime >= buildOutStartTime){ + setState(BuildOut); + } + break; + + case SlideState::BuildOut: + if (runningTime >= endTime){ + setState(Complete); + } + break; + default: + break; + } +} + +void magSlide::setSize(float w, float h) +{ + width = w; + height = h; +} + +void magSlide::setResizeOption(magSlide::ResizeOptions resizeOption) +{ + this->resizeOption = resizeOption; +} + +magSlide::ResizeOptions magSlide::getResizeOption() const +{ + return resizeOption; +} + +void magSlide::setDuration(uint64_t duration) +{ + this->duration = duration; +} + +void magSlide::setState(SlideState state) +{ + // Don't do anything if the new state is the same + // as the current one: + if (slideState == state) return; + + slideState = state; + ofEventArgs args; + ofNotifyEvent(slideStateChangedEvent, args, this); + + if (slideState == Complete) + { + ofNotifyEvent(slideCompleteEvent, args, this); + } +} + +void magSlide::setTransitionDuration(uint64_t tDuration) +{ + buildOutDuration = tDuration; +} + +const std::string magSlide::getSlideStateName() +{ + switch (slideState) + { +// case SlideState::BuildIn: +// return "BuildIn"; + case SlideState::BuildOut: + return "BuildOut"; + case Normal: + return "Normal"; + case SlideState::Complete: + return "Complete"; + case SlideState::Off: + return "Off"; + } + + return "unknown"; +} + +void magSlide::start(uint64_t startTime) +{ + this->startTime = startTime; + runningTime = 0; + endTime = duration + (buildOutDuration*2); // *2 because we take into account transition in and out + buildOutStartTime = duration + buildOutDuration; + slideState = magSlide::SlideState::Normal; + position.set(0, 0); + opacity = 255; + isComplete = false; +} + +void magSlide::draw() +{ + ofSetColor(255, opacity); + if(transition->isActive()) + { + transition->draw(); + } +} + + +//////////////////////////////////////////////////////// +#pragma mark MAG_IMAGE_SLIDE +//////////////////////////////////////////////////////// + +magImageSlide::magImageSlide() : magSlide("magImageSlide") {} + +magImageSlide::~magImageSlide() {} + +void magImageSlide::setup(ofImage &image) +{ + // Make a copy of the image: + this->image = ofImage(image); + image.setAnchorPercent(0.5, 0.5); + width = image.getWidth(); + height = image.getHeight(); +} + +void magImageSlide::draw() +{ + magSlide::draw(); + image.draw(position, width, height); +} + +//////////////////////////////////////////////////////// +#pragma mark MAG_VIDEO_SLIDE +//////////////////////////////////////////////////////// + +magVideoSlide::magVideoSlide() : magSlide("magVideoSlide") +{} + +magVideoSlide::~magVideoSlide() +{ + videoPlayer.stop(); +} + +bool magVideoSlide::setup(ofFile &file, bool useVideoDuration) +{ + + bool success = videoPlayer.load(file.getAbsolutePath()); + + if (success) + { + videoPlayer.setAnchorPercent(0.5, 0.5); + if (useVideoDuration) + { + useVideoForDuration(); + } + } + + return success; +} + +void magVideoSlide::update() +{ + videoPlayer.update(); +} + +void magVideoSlide::draw() +{ + magSlide::draw(); + videoPlayer.draw(position.x, position.y, width, height); +} + +void magVideoSlide::useVideoForDuration() +{ + duration = uint64_t((videoPlayer.getDuration()*1000)) - buildOutDuration; +} diff --git a/example_fbo-sources/src/SlideShowSource/magSlide.h b/example_fbo-sources/src/SlideShowSource/magSlide.h index f0aa175..e876501 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlide.h +++ b/example_fbo-sources/src/SlideShowSource/magSlide.h @@ -1,263 +1,263 @@ -// -// Created by Cristobal Mendoza on 11/9/17. -// - -#ifndef MAGSLIDE_H -#define MAGSLIDE_H - -#include "ofMain.h" - -class magSlideTransition; - -class magSlide -{ -public: - magSlide(std::string type); -// ~magSlide(); - virtual void update(uint64_t deltaTime); - virtual void draw(); - - /** - * Sets the slide up for playback. This method must be - * called before displaying the slide. - * @param startTime - */ - void start(uint64_t startTime); - - enum ResizeOptions : short - { - /** - * No resizing applied, displays the slide in its native pixel dimensions. - * This is the default behavior. - */ - NoResize = 0, - /** - * Explicitly set a slide to display in its native dimension. - * None and NoResize result in the same output, but if you specify - * a default resizing option in your slideshow and you want a particular - * slide not to resize, you must specify this option. Otherwise the - * slide show option will apply. - */ - Native, - - /** - * Sets width and height to match the source's. - * This will distort the slide if the aspect ratios - * don't match. - */ - Fit, - - /** - * Resizes the largest dimension to the source's max, - * the other dimension is resized proportionally. - */ - FitProportionally, - - /** - * Resizes the shortest dimensions to the source's max, - */ - FillProportionally, - }; - - enum SlideState : short - { - Off = 0, -// BuildIn, - Normal, - BuildOut, - Complete - }; - - const std::string &getType() - { return type; } - - float getWidth() - { return width; } - - float getHeight() - { return height; } - - float getOpacity() const - { - return opacity; - } - - void setOpacity(float opacity) - { - magSlide::opacity = opacity; - } - - /** - * Change the display size of a slide. This will implicitly - * set resizeOptions to ResizeOption.NoResize. - * This method does not resize the pixel source of the slide. - * @param w The new width - * @param h The new height - */ - virtual void setSize(float w, float h); - - uint64_t getDuration() - { - return duration; - } - - /** - * Sets the display time of the slide, excluding - * builds (in or out) - * @param duration in milliseconds. - */ - void setDuration(uint64_t duration); - - /** - * Sets the duration of the buildIn and buildOut - * transitions. Transition times are added to the - * duration of the slide. - * @param tDuration in milliseconds. - */ - void setTransitionDuration(uint64_t tDuration); - - ResizeOptions getResizeOption() const; - void setResizeOption(ResizeOptions resizeOption); - - SlideState getSlideState() const - { - return slideState; - } - - bool isSlideComplete() - { return isComplete; } - - int getId() - { return id; } - - const std::string getSlideStateName(); - - ////////////////////////////// - /// Events - ////////////////////////////// - ofEvent slideCompleteEvent; - ofEvent slideStateChangedEvent; - - friend class magSlideShowSource; - -protected: - int id; - std::string type; - float width; - float height; - ofPoint position; -public: - const ofPoint &getPosition() const - { - return position; - } - - void setPosition(const ofPoint &position) - { - magSlide::position = position; - } - - void setPosition(float x, float y) - { - position.set(x, y); - } - - -protected: - float opacity = 255; - ResizeOptions resizeOption = NoResize; - SlideState slideState = Off; - bool isComplete = false; - -// std::shared_ptr buildIn = nullptr; -// std::shared_ptr buildOut = nullptr; - std::shared_ptr transition = nullptr; -public: - const shared_ptr &getTransition() const - { - return transition; - } - -protected: - /** - * The duration of the slide in millis, not counting builds - */ - uint64_t duration; - - /** - * The start time of the slide in milliseconds, in "local time". - * In practice, this means that the start time is always 0. - */ - uint64_t startTime; - - /** - * The end time of the slide in milliseconds, in "local time". - * The endTime is startTime + buildInDuration + duration + buildOutDuration. - */ - uint64_t endTime; - - /** - * The duration of the build in transition or effect, in milliseconds. - */ -// uint64_t buildInDuration; - - /** - * The duration of the build out transition or effect, in milliseconds. - */ - uint64_t buildOutDuration; - - /** - * The "local time" start of the build out transition. This time should also - * signal the enqueuing of the next slide, if applicable. - */ - uint64_t buildOutStartTime; - - /** - * The amount of time the slide has been displayed, in milliseconds. - * This constitutes the "local time" of the slide. - */ - uint64_t runningTime; - - void setState(SlideState state); - - static int idCount; -}; - -class magImageSlide : public magSlide -{ -public: - magImageSlide(); - ~ magImageSlide(); - /** - * Sets up an image slide. - * @param image is copied into the member magImageSlide::image and is - * not modified in any way. - */ - void setup(ofImage &image); - - void draw(); - -protected: - ofImage image; -}; - -class magVideoSlide : public magSlide -{ -public: - magVideoSlide(); - ~magVideoSlide(); - bool setup(ofFile &file, bool useVideoDuration = false); - void update(); - void draw(); - - /** - * Sets the slide duration to the duration of the video. - * magSlide::duration will be changed by this call, so if you later - * change your mind you'll have to use magSlide::setDuration. - */ - void useVideoForDuration(); -protected: - ofVideoPlayer videoPlayer; -}; - -#endif +// +// Created by Cristobal Mendoza on 11/9/17. +// + +#ifndef MAGSLIDE_H +#define MAGSLIDE_H + +#include "ofMain.h" + +class magSlideTransition; + +class magSlide +{ +public: + magSlide(std::string type); +// ~magSlide(); + virtual void update(uint64_t deltaTime); + virtual void draw(); + + /** + * Sets the slide up for playback. This method must be + * called before displaying the slide. + * @param startTime + */ + void start(uint64_t startTime); + + enum ResizeOptions : short + { + /** + * No resizing applied, displays the slide in its native pixel dimensions. + * This is the default behavior. + */ + NoResize = 0, + /** + * Explicitly set a slide to display in its native dimension. + * None and NoResize result in the same output, but if you specify + * a default resizing option in your slideshow and you want a particular + * slide not to resize, you must specify this option. Otherwise the + * slide show option will apply. + */ + Native, + + /** + * Sets width and height to match the source's. + * This will distort the slide if the aspect ratios + * don't match. + */ + Fit, + + /** + * Resizes the largest dimension to the source's max, + * the other dimension is resized proportionally. + */ + FitProportionally, + + /** + * Resizes the shortest dimensions to the source's max, + */ + FillProportionally, + }; + + enum SlideState : short + { + Off = 0, +// BuildIn, + Normal, + BuildOut, + Complete + }; + + const std::string &getType() + { return type; } + + float getWidth() + { return width; } + + float getHeight() + { return height; } + + float getOpacity() const + { + return opacity; + } + + void setOpacity(float opacity) + { + magSlide::opacity = opacity; + } + + /** + * Change the display size of a slide. This will implicitly + * set resizeOptions to ResizeOption.NoResize. + * This method does not resize the pixel source of the slide. + * @param w The new width + * @param h The new height + */ + virtual void setSize(float w, float h); + + uint64_t getDuration() + { + return duration; + } + + /** + * Sets the display time of the slide, excluding + * builds (in or out) + * @param duration in milliseconds. + */ + void setDuration(uint64_t duration); + + /** + * Sets the duration of the buildIn and buildOut + * transitions. Transition times are added to the + * duration of the slide. + * @param tDuration in milliseconds. + */ + void setTransitionDuration(uint64_t tDuration); + + ResizeOptions getResizeOption() const; + void setResizeOption(ResizeOptions resizeOption); + + SlideState getSlideState() const + { + return slideState; + } + + bool isSlideComplete() + { return isComplete; } + + int getId() + { return id; } + + const std::string getSlideStateName(); + + ////////////////////////////// + /// Events + ////////////////////////////// + ofEvent slideCompleteEvent; + ofEvent slideStateChangedEvent; + + friend class magSlideShowSource; + +protected: + int id; + std::string type; + float width; + float height; + ofPoint position; +public: + const ofPoint &getPosition() const + { + return position; + } + + void setPosition(const ofPoint &position) + { + magSlide::position = position; + } + + void setPosition(float x, float y) + { + position.set(x, y); + } + + +protected: + float opacity = 255; + ResizeOptions resizeOption = NoResize; + SlideState slideState = Off; + bool isComplete = false; + +// std::shared_ptr buildIn = nullptr; +// std::shared_ptr buildOut = nullptr; + std::shared_ptr transition = nullptr; +public: + const shared_ptr &getTransition() const + { + return transition; + } + +protected: + /** + * The duration of the slide in millis, not counting builds + */ + uint64_t duration; + + /** + * The start time of the slide in milliseconds, in "local time". + * In practice, this means that the start time is always 0. + */ + uint64_t startTime; + + /** + * The end time of the slide in milliseconds, in "local time". + * The endTime is startTime + buildInDuration + duration + buildOutDuration. + */ + uint64_t endTime; + + /** + * The duration of the build in transition or effect, in milliseconds. + */ +// uint64_t buildInDuration; + + /** + * The duration of the build out transition or effect, in milliseconds. + */ + uint64_t buildOutDuration; + + /** + * The "local time" start of the build out transition. This time should also + * signal the enqueuing of the next slide, if applicable. + */ + uint64_t buildOutStartTime; + + /** + * The amount of time the slide has been displayed, in milliseconds. + * This constitutes the "local time" of the slide. + */ + uint64_t runningTime; + + void setState(SlideState state); + + static int idCount; +}; + +class magImageSlide : public magSlide +{ +public: + magImageSlide(); + ~ magImageSlide(); + /** + * Sets up an image slide. + * @param image is copied into the member magImageSlide::image and is + * not modified in any way. + */ + void setup(ofImage &image); + + void draw(); + +protected: + ofImage image; +}; + +class magVideoSlide : public magSlide +{ +public: + magVideoSlide(); + ~magVideoSlide(); + bool setup(ofFile &file, bool useVideoDuration = false); + void update(); + void draw(); + + /** + * Sets the slide duration to the duration of the video. + * magSlide::duration will be changed by this call, so if you later + * change your mind you'll have to use magSlide::setDuration. + */ + void useVideoForDuration(); +protected: + ofVideoPlayer videoPlayer; +}; + +#endif diff --git a/example_fbo-sources/src/SlideShowSource/magSlideShowSource.cpp b/example_fbo-sources/src/SlideShowSource/magSlideShowSource.cpp index a26b003..64ec990 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideShowSource.cpp +++ b/example_fbo-sources/src/SlideShowSource/magSlideShowSource.cpp @@ -1,529 +1,529 @@ -// -// magSlideShowSource.cpp -// Copyright (c) 2017 Cristobal Mendoza -// http://cuppetellimendoza.com -// - - -#include "magSlideShowSource.h" -#include "magSlideTransition.h" -#include "SettingsLoader.h" -#include "magSlideTransitionFactory.h" - -const std::string magSlideShowSource::SettingsFileName = "magslideshow_settings.xml"; - -magSlideShowSource::magSlideShowSource() { - name = "Slide Show Source"; - currentSlideIndex = 0; - isPlaying = false; - directoryWatcher = 0; - doInit = false; - if (!loadFromXml(SettingsFileName)) - { - ofLogError("magSlideShowSource") << "Could not find slide show settings file " << SettingsFileName; - Settings sets; - initialize(sets); - } -} - -magSlideShowSource::~magSlideShowSource(){ - if(directoryWatcher != 0){ - delete directoryWatcher; - } -} - -bool magSlideShowSource::initialize(magSlideShowSource::Settings settings) { - this->settings = settings; - bool success = true; - - if (settings.width <= 0 || settings.height <= 0) - { - ofLogError("magSlideShowSource::initialize") << "Invalid value for width or height. Width and height " - "must be assigned in your Settings struct!"; - return false; - } - - // Allocate the FBO: - allocate(settings.width, settings.height); - - // If there is a path in slidesFolderPath, attempt - // to load the folder and any files in it: - if (!settings.slidesFolderPath.empty()) - { -// ofDirectory dir = ofDirectory(settings.slidesFolderPath); - success = createFromFolderContents(settings.slidesFolderPath); - - if (!success) - { - ofLogError("magSlideShowSource::initialize") << "Failed to create slide show from folder " - << settings.slidesFolderPath; - return success; - } - { - if (directoryWatcher == 0) - { - - using namespace ofx::piMapper; - directoryWatcher = new DirectoryWatcher(settings.slidesFolderPath, - SourceTypeHelper::GetSourceTypeHelperEnum( - SOURCE_TYPE_NAME_IMAGE)); - ofAddListener(directoryWatcher->directoryFileAddedEvent, this, &magSlideShowSource::fileAddedListener); - ofAddListener(directoryWatcher->directoryFileRemovedEvent, this, - &magSlideShowSource::fileRemovedListener); - directoryWatcher->beginWatch(); - } - } - - } - else if (!settings.slideshowFilePath.empty()) - { - success = false; - } - - return success; -} - -void magSlideShowSource::setup() { - ofx::piMapper::FboSource::setup(); -} - -void magSlideShowSource::update() { - - // Perform re-initialization if the DirectoryWatcher - // detects file changes: - if (doInit) - { - initialize(settings); - doInit = false; - } - - if (!isPlaying) return; - - auto nowTime = ofGetElapsedTimeMillis(); - deltaTime = nowTime-lastTime; - runningTime += deltaTime; - lastTime = nowTime; - - for (auto &slide : activeSlides) - { - slide->update(deltaTime); - } - - // Queue the next slide if it is time - if (doPlayNextSlide) - { - playNextSlide(); - if (activeSlides.size() > 1) - { - activeSlides[1]->transition->start(activeSlides[0]); - } - doPlayNextSlide = false; - } - - // Erase any complete slides: - auto iter = activeSlides.begin(); - for (; iter < activeSlides.end(); iter++) - { - if ((*iter)->isSlideComplete()) - { -// ofLogVerbose() << "Removing from active slides id: " << (*iter)->getId(); - activeSlides.erase(iter); - --iter; - } - } - - if (activeSlides.size() == 0 && isPlaying) - { - ofEventArgs args; - isPlaying = false; - ofNotifyEvent(slideshowCompleteEvent, args, this); - } -} - -void magSlideShowSource::draw() { - ofBackground(0, 0); - ofPushMatrix(); - ofPushStyle(); - ofTranslate(getWidth()/2.0f, getHeight()/2.0f); - //ofEnableAlphaBlending(); - ofSetRectMode(OF_RECTMODE_CENTER); - ofFill(); - ofSetColor(255, 255); - for (auto &slide : activeSlides) - { - slide->draw(); - } - ofPopStyle(); - ofPopMatrix(); - //ofDisableAlphaBlending(); -} - -bool magSlideShowSource::createFromFolderContents(std::string path) { - ofDirectory dir = ofDirectory(path); - slides.clear(); - - if (!dir.isDirectory()) - { - ofLogError("magSlideShowSource::createFromFolderContents") << "Folder path " << dir.getAbsolutePath() - << " is not a directory"; - return false; - } - - ofDirectory sortedDir = dir.getSorted(); - std::vector files = sortedDir.getFiles(); - - if (files.size() < 1){ - ofLogError("magSlideShowSource::createFromFolderContents") << "Folder " << dir.getAbsolutePath() << " is empty"; - return false; - } - - ofImage tempImage; - for(ofFile &file : files){ - if (tempImage.load(file.getFileName())){ - - // make a new image slide - auto slide = std::make_shared(); - slide->setup(tempImage); - slide->setDuration(static_cast(settings.slideDuration*1000)); - slide->setTransitionDuration(static_cast(settings.transitionDuration*1000)); -// if (settings.transitionName == "") - addSlide(slide); - }else{ - auto ext = ofToLower(file.getExtension()); - - static std::vector movieExtensions = { - "mov", "qt", // Mac - "mp4", "m4p", "m4v", // MPEG - "mpg", "mp2", "mpeg", "mpe", "mpv", "m2v", // MPEG - "3gp", // Phones - "avi", "wmv", "asf", // Windows - "webm", "mkv", "flv", "vob", // Other containers - "ogv", "ogg", - "drc", "mxf" - }; - - // Check if the extension matches known movie formats: - if (ofContains(movieExtensions, ext)) - { - // Make a new video slide - auto slide = std::make_shared(); - if (slide->setup(file)) - { - slide->setDuration(settings.slideDuration*1000.0); - slide->setTransitionDuration(settings.transitionDuration*1000.0); - addSlide(slide); - } - else - { - ofLogError("magSlideShowSource") << "Failed loading video: " << file.getAbsolutePath(); - } - } - - } - } - - if (slides.size() > 0) - { - return true; - } - else - { - return false; - } -} - -bool magSlideShowSource::loadFromXml(std::string path) { - auto xml = ofxXmlSettings(); - Settings settings; - - if (!xml.load(path)) - { - ofLogError("magSlideShowSource") << "Could not load settings file " << path; - return false; - } - -// xml.pushTag("surfaces"); - if (!xml.pushTag("magSlideShow")) - { - ofLogError("magSlideShowSource") << "Slide show settings not found in " << path; - return false; - } - - settings.width = xml.getValue("Width", settings.width); - settings.height = xml.getValue("Height", settings.height); - - // Default slide duration: - settings.slideDuration = xml.getValue("SlideDuration", settings.slideDuration); - - // Default loop: - if (xml.pushTag("Loop")) - { - auto type = xml.getValue("Type", ""); - if (type == "NONE") - { - settings.loopType = LoopType::NONE; - } - else if (type == "NORMAL") - { - settings.loopType = LoopType::NORMAL; - } - else if (type == "PING-PONG") - { - settings.loopType = LoopType::PING_PONG; - } - - settings.numLoops = xml.getValue("Count", settings.numLoops); - xml.popTag(); - } - - if (xml.pushTag("Transition")) - { - settings.transitionName = xml.getValue("Type", settings.transitionName); - settings.transitionDuration = xml.getValue("Duration", settings.transitionDuration); - xml.popTag(); - } - - // Default resize options: - auto ropts = xml.getValue("ResizeOption", ""); - if (ropts == "NoResize") - { - settings.resizeOption = magSlide::NoResize; - } - else if (ropts == "Native") - { - settings.resizeOption = magSlide::Native; - } - else if (ropts == "Fit") - { - settings.resizeOption = magSlide::Fit; - } - else if (ropts == "FitProportionally") - { - settings.resizeOption = magSlide::FitProportionally; - } - else if (ropts == "FillProportionally") - { - settings.resizeOption = magSlide::FillProportionally; - } - - initialize(settings); - return true; -} - -void magSlideShowSource::addSlide(std::shared_ptr slide) { -// ofLogVerbose("addSlide") << slide->getId(); - slides.insert(slides.begin(), slide); - auto rOption = slide->getResizeOption(); - - // If the slide does not have a resize option assign - // the slide show's option - if (rOption == magSlide::ResizeOptions::NoResize) - { - rOption = settings.resizeOption; - } - - // Resize the slide according to the resize option: - switch (rOption){ - float sw, sh, ratio; - - case magSlide::ResizeOptions::FitProportionally: - sw = slide->getWidth(); - sh = slide->getHeight(); - - if (sw > sh) - { - ratio = (float) getWidth()/sw; - } - else - { - ratio = (float) getHeight()/sh; - } - - slide->setSize(sw*ratio, sh*ratio); - break; - - case magSlide::ResizeOptions::FillProportionally: - sw = slide->getWidth(); - sh = slide->getHeight(); - - if (sw > sh) - { - ratio = (float) getHeight()/sh; - } - else - { - ratio = (float) getWidth()/sw; - } - - slide->setSize(sw*ratio, sh*ratio); - break; - - case magSlide::Fit: - slide->setSize(getWidth(), getHeight()); - break; - - default: - break; - } - - // Add transitions: - - static ofParameterGroup bogusParamGroup; // This is temporary so that things compile - - auto tf = magSlideTransitionFactory::instance(); -// slide->buildIn = tf->createTransition(settings.transitionName, -// slide, -// bogusParamGroup, -// slide->buildInDuration); - slide->transition = tf->createTransition(settings.transitionName, - slide, - bogusParamGroup, - slide->buildOutDuration); - - //// void method(const void * sender, ArgumentsType &args) - ofAddListener(slide->slideStateChangedEvent, this, &magSlideShowSource::slideStateChanged); - ofAddListener(slide->slideCompleteEvent, this, &magSlideShowSource::slideComplete); - -} - -void magSlideShowSource::play() { - if (!isPlaying && slides.size()){ - runningTime = 0; - lastTime = ofGetElapsedTimeMillis(); - isPlaying = true; - auto currentSlide = slides[currentSlideIndex]; - enqueueSlide(currentSlide, ofGetElapsedTimeMillis()); - } -} - -void magSlideShowSource::pause() { - isPlaying = false; -} - -void magSlideShowSource::playNextSlide() { - //TODO - // I should check here to see if there are less than two slides. - // If so, we should probably return - - currentSlideIndex += direction; - ofEventArgs args; - - // This makes sure that we are doing a signed integer comparison, - // otherwise things get weird - int num = slides.size(); - switch (settings.loopType) - { - case LoopType::NONE: - if (currentSlideIndex >= slides.size() || currentSlideIndex < 0) - { - // If we are not looping and we are out of bounds, return - // without enqueueing a slide. This will cause the slide show - // to end once the last slide builds out. - return; - } - break; - case LoopType::NORMAL: - if (currentSlideIndex >= num) - { - loopCount++; - if (loopCount == settings.numLoops) - { - // Return without enqueueing a new slide if we have - // reached the max number of loops. - return; - } - currentSlideIndex = 0; - ofNotifyEvent(slideshowWillLoopEvent, args, this); - } - else if (currentSlideIndex < 0) - { - loopCount++; - if (loopCount == settings.numLoops) - { - // Return without enqueueing a new slide if we have - // reached the max number of loops. - return; - } - currentSlideIndex = slides.size()-1; - ofNotifyEvent(slideshowWillLoopEvent, args, this); - } - break; - case LoopType::PING_PONG: - - int num = slides.size(); - if (currentSlideIndex >= num) - { - loopCount++; - if (loopCount == settings.numLoops) - { - // Return without enqueueing a new slide if we have - // reached the max number of loops. - return; - } - - direction = -1; - currentSlideIndex = slides.size()-2; - ofNotifyEvent(slideshowWillLoopEvent, args, this); - } - else if (currentSlideIndex < 0) - { - loopCount++; - if (loopCount == settings.numLoops) - { - // Return without enqueueing a new slide if we have - // reached the max number of loops. - return; - } - - direction = 1; - currentSlideIndex = 1; - ofNotifyEvent(slideshowWillLoopEvent, args, this); - } - break; - } - - enqueueSlide(slides[currentSlideIndex], ofGetElapsedTimeMillis()); -} - -void magSlideShowSource::playPrevSlide() { - currentSlideIndex -= (direction*2); - playNextSlide(); -} - -void magSlideShowSource::playSlide(int slideIndex) { - currentSlideIndex = slideIndex-direction; - playNextSlide(); -} - -void magSlideShowSource::enqueueSlide(std::shared_ptr slide, uint64_t startTime) { -// ofLogVerbose() << "Enqueuing slide " << currentSlideIndex << " slide id: " << slide->getId(); - slide->start(startTime); - activeSlides.insert(activeSlides.begin(), slide); -} - -void magSlideShowSource::slideStateChanged(const void *sender, ofEventArgs &args) { - magSlide *slide = (magSlide *) sender; - -// ofLogVerbose("slideStateChanged") << "Slide id: " << slide->getId() << " Slide state: " -// << slide->getSlideStateName(); - if (slide->getSlideState() == magSlide::SlideState::BuildOut) - { - // Flag that we need to load the next slide: - doPlayNextSlide = true; - } - -} - -void magSlideShowSource::slideComplete(const void *sender, ofEventArgs &args) { - magSlide *slide = (magSlide *) sender; -// ofLogVerbose() << "Slide Complete. id: " << slide->getId(); - slide->isComplete = true; -} - -void magSlideShowSource::fileAddedListener(const void *sender) { - doInit = true; -} - -void magSlideShowSource::fileRemovedListener(const void *sender) { - doInit = true; -} +// +// magSlideShowSource.cpp +// Copyright (c) 2017 Cristobal Mendoza +// http://cuppetellimendoza.com +// + + +#include "magSlideShowSource.h" +#include "magSlideTransition.h" +#include "SettingsLoader.h" +#include "magSlideTransitionFactory.h" + +const std::string magSlideShowSource::SettingsFileName = "magslideshow_settings.xml"; + +magSlideShowSource::magSlideShowSource() { + name = "Slide Show Source"; + currentSlideIndex = 0; + isPlaying = false; + directoryWatcher = 0; + doInit = false; + if (!loadFromXml(SettingsFileName)) + { + ofLogError("magSlideShowSource") << "Could not find slide show settings file " << SettingsFileName; + Settings sets; + initialize(sets); + } +} + +magSlideShowSource::~magSlideShowSource(){ + if(directoryWatcher != 0){ + delete directoryWatcher; + } +} + +bool magSlideShowSource::initialize(magSlideShowSource::Settings settings) { + this->settings = settings; + bool success = true; + + if (settings.width <= 0 || settings.height <= 0) + { + ofLogError("magSlideShowSource::initialize") << "Invalid value for width or height. Width and height " + "must be assigned in your Settings struct!"; + return false; + } + + // Allocate the FBO: + allocate(settings.width, settings.height); + + // If there is a path in slidesFolderPath, attempt + // to load the folder and any files in it: + if (!settings.slidesFolderPath.empty()) + { +// ofDirectory dir = ofDirectory(settings.slidesFolderPath); + success = createFromFolderContents(settings.slidesFolderPath); + + if (!success) + { + ofLogError("magSlideShowSource::initialize") << "Failed to create slide show from folder " + << settings.slidesFolderPath; + return success; + } + { + if (directoryWatcher == 0) + { + + using namespace ofx::piMapper; + directoryWatcher = new DirectoryWatcher(settings.slidesFolderPath, + SourceTypeHelper::GetSourceTypeHelperEnum( + SOURCE_TYPE_NAME_IMAGE)); + ofAddListener(directoryWatcher->directoryFileAddedEvent, this, &magSlideShowSource::fileAddedListener); + ofAddListener(directoryWatcher->directoryFileRemovedEvent, this, + &magSlideShowSource::fileRemovedListener); + directoryWatcher->beginWatch(); + } + } + + } + else if (!settings.slideshowFilePath.empty()) + { + success = false; + } + + return success; +} + +void magSlideShowSource::setup() { + ofx::piMapper::FboSource::setup(); +} + +void magSlideShowSource::update() { + + // Perform re-initialization if the DirectoryWatcher + // detects file changes: + if (doInit) + { + initialize(settings); + doInit = false; + } + + if (!isPlaying) return; + + auto nowTime = ofGetElapsedTimeMillis(); + deltaTime = nowTime-lastTime; + runningTime += deltaTime; + lastTime = nowTime; + + for (auto &slide : activeSlides) + { + slide->update(deltaTime); + } + + // Queue the next slide if it is time + if (doPlayNextSlide) + { + playNextSlide(); + if (activeSlides.size() > 1) + { + activeSlides[1]->transition->start(activeSlides[0]); + } + doPlayNextSlide = false; + } + + // Erase any complete slides: + auto iter = activeSlides.begin(); + for (; iter < activeSlides.end(); iter++) + { + if ((*iter)->isSlideComplete()) + { +// ofLogVerbose() << "Removing from active slides id: " << (*iter)->getId(); + activeSlides.erase(iter); + --iter; + } + } + + if (activeSlides.size() == 0 && isPlaying) + { + ofEventArgs args; + isPlaying = false; + ofNotifyEvent(slideshowCompleteEvent, args, this); + } +} + +void magSlideShowSource::draw() { + ofBackground(0, 0); + ofPushMatrix(); + ofPushStyle(); + ofTranslate(getWidth()/2.0f, getHeight()/2.0f); + //ofEnableAlphaBlending(); + ofSetRectMode(OF_RECTMODE_CENTER); + ofFill(); + ofSetColor(255, 255); + for (auto &slide : activeSlides) + { + slide->draw(); + } + ofPopStyle(); + ofPopMatrix(); + //ofDisableAlphaBlending(); +} + +bool magSlideShowSource::createFromFolderContents(std::string path) { + ofDirectory dir = ofDirectory(path); + slides.clear(); + + if (!dir.isDirectory()) + { + ofLogError("magSlideShowSource::createFromFolderContents") << "Folder path " << dir.getAbsolutePath() + << " is not a directory"; + return false; + } + + ofDirectory sortedDir = dir.getSorted(); + std::vector files = sortedDir.getFiles(); + + if (files.size() < 1){ + ofLogError("magSlideShowSource::createFromFolderContents") << "Folder " << dir.getAbsolutePath() << " is empty"; + return false; + } + + ofImage tempImage; + for(ofFile &file : files){ + if (tempImage.load(file.getFileName())){ + + // make a new image slide + auto slide = std::make_shared(); + slide->setup(tempImage); + slide->setDuration(static_cast(settings.slideDuration*1000)); + slide->setTransitionDuration(static_cast(settings.transitionDuration*1000)); +// if (settings.transitionName == "") + addSlide(slide); + }else{ + auto ext = ofToLower(file.getExtension()); + + static std::vector movieExtensions = { + "mov", "qt", // Mac + "mp4", "m4p", "m4v", // MPEG + "mpg", "mp2", "mpeg", "mpe", "mpv", "m2v", // MPEG + "3gp", // Phones + "avi", "wmv", "asf", // Windows + "webm", "mkv", "flv", "vob", // Other containers + "ogv", "ogg", + "drc", "mxf" + }; + + // Check if the extension matches known movie formats: + if (ofContains(movieExtensions, ext)) + { + // Make a new video slide + auto slide = std::make_shared(); + if (slide->setup(file)) + { + slide->setDuration(settings.slideDuration*1000.0); + slide->setTransitionDuration(settings.transitionDuration*1000.0); + addSlide(slide); + } + else + { + ofLogError("magSlideShowSource") << "Failed loading video: " << file.getAbsolutePath(); + } + } + + } + } + + if (slides.size() > 0) + { + return true; + } + else + { + return false; + } +} + +bool magSlideShowSource::loadFromXml(std::string path) { + auto xml = ofxXmlSettings(); + Settings settings; + + if (!xml.load(path)) + { + ofLogError("magSlideShowSource") << "Could not load settings file " << path; + return false; + } + +// xml.pushTag("surfaces"); + if (!xml.pushTag("magSlideShow")) + { + ofLogError("magSlideShowSource") << "Slide show settings not found in " << path; + return false; + } + + settings.width = xml.getValue("Width", settings.width); + settings.height = xml.getValue("Height", settings.height); + + // Default slide duration: + settings.slideDuration = xml.getValue("SlideDuration", settings.slideDuration); + + // Default loop: + if (xml.pushTag("Loop")) + { + auto type = xml.getValue("Type", ""); + if (type == "NONE") + { + settings.loopType = LoopType::NONE; + } + else if (type == "NORMAL") + { + settings.loopType = LoopType::NORMAL; + } + else if (type == "PING-PONG") + { + settings.loopType = LoopType::PING_PONG; + } + + settings.numLoops = xml.getValue("Count", settings.numLoops); + xml.popTag(); + } + + if (xml.pushTag("Transition")) + { + settings.transitionName = xml.getValue("Type", settings.transitionName); + settings.transitionDuration = xml.getValue("Duration", settings.transitionDuration); + xml.popTag(); + } + + // Default resize options: + auto ropts = xml.getValue("ResizeOption", ""); + if (ropts == "NoResize") + { + settings.resizeOption = magSlide::NoResize; + } + else if (ropts == "Native") + { + settings.resizeOption = magSlide::Native; + } + else if (ropts == "Fit") + { + settings.resizeOption = magSlide::Fit; + } + else if (ropts == "FitProportionally") + { + settings.resizeOption = magSlide::FitProportionally; + } + else if (ropts == "FillProportionally") + { + settings.resizeOption = magSlide::FillProportionally; + } + + initialize(settings); + return true; +} + +void magSlideShowSource::addSlide(std::shared_ptr slide) { +// ofLogVerbose("addSlide") << slide->getId(); + slides.insert(slides.begin(), slide); + auto rOption = slide->getResizeOption(); + + // If the slide does not have a resize option assign + // the slide show's option + if (rOption == magSlide::ResizeOptions::NoResize) + { + rOption = settings.resizeOption; + } + + // Resize the slide according to the resize option: + switch (rOption){ + float sw, sh, ratio; + + case magSlide::ResizeOptions::FitProportionally: + sw = slide->getWidth(); + sh = slide->getHeight(); + + if (sw > sh) + { + ratio = (float) getWidth()/sw; + } + else + { + ratio = (float) getHeight()/sh; + } + + slide->setSize(sw*ratio, sh*ratio); + break; + + case magSlide::ResizeOptions::FillProportionally: + sw = slide->getWidth(); + sh = slide->getHeight(); + + if (sw > sh) + { + ratio = (float) getHeight()/sh; + } + else + { + ratio = (float) getWidth()/sw; + } + + slide->setSize(sw*ratio, sh*ratio); + break; + + case magSlide::Fit: + slide->setSize(getWidth(), getHeight()); + break; + + default: + break; + } + + // Add transitions: + + static ofParameterGroup bogusParamGroup; // This is temporary so that things compile + + auto tf = magSlideTransitionFactory::instance(); +// slide->buildIn = tf->createTransition(settings.transitionName, +// slide, +// bogusParamGroup, +// slide->buildInDuration); + slide->transition = tf->createTransition(settings.transitionName, + slide, + bogusParamGroup, + slide->buildOutDuration); + + //// void method(const void * sender, ArgumentsType &args) + ofAddListener(slide->slideStateChangedEvent, this, &magSlideShowSource::slideStateChanged); + ofAddListener(slide->slideCompleteEvent, this, &magSlideShowSource::slideComplete); + +} + +void magSlideShowSource::play() { + if (!isPlaying && slides.size()){ + runningTime = 0; + lastTime = ofGetElapsedTimeMillis(); + isPlaying = true; + auto currentSlide = slides[currentSlideIndex]; + enqueueSlide(currentSlide, ofGetElapsedTimeMillis()); + } +} + +void magSlideShowSource::pause() { + isPlaying = false; +} + +void magSlideShowSource::playNextSlide() { + //TODO + // I should check here to see if there are less than two slides. + // If so, we should probably return + + currentSlideIndex += direction; + ofEventArgs args; + + // This makes sure that we are doing a signed integer comparison, + // otherwise things get weird + int num = slides.size(); + switch (settings.loopType) + { + case LoopType::NONE: + if (currentSlideIndex >= slides.size() || currentSlideIndex < 0) + { + // If we are not looping and we are out of bounds, return + // without enqueueing a slide. This will cause the slide show + // to end once the last slide builds out. + return; + } + break; + case LoopType::NORMAL: + if (currentSlideIndex >= num) + { + loopCount++; + if (loopCount == settings.numLoops) + { + // Return without enqueueing a new slide if we have + // reached the max number of loops. + return; + } + currentSlideIndex = 0; + ofNotifyEvent(slideshowWillLoopEvent, args, this); + } + else if (currentSlideIndex < 0) + { + loopCount++; + if (loopCount == settings.numLoops) + { + // Return without enqueueing a new slide if we have + // reached the max number of loops. + return; + } + currentSlideIndex = slides.size()-1; + ofNotifyEvent(slideshowWillLoopEvent, args, this); + } + break; + case LoopType::PING_PONG: + + int num = slides.size(); + if (currentSlideIndex >= num) + { + loopCount++; + if (loopCount == settings.numLoops) + { + // Return without enqueueing a new slide if we have + // reached the max number of loops. + return; + } + + direction = -1; + currentSlideIndex = slides.size()-2; + ofNotifyEvent(slideshowWillLoopEvent, args, this); + } + else if (currentSlideIndex < 0) + { + loopCount++; + if (loopCount == settings.numLoops) + { + // Return without enqueueing a new slide if we have + // reached the max number of loops. + return; + } + + direction = 1; + currentSlideIndex = 1; + ofNotifyEvent(slideshowWillLoopEvent, args, this); + } + break; + } + + enqueueSlide(slides[currentSlideIndex], ofGetElapsedTimeMillis()); +} + +void magSlideShowSource::playPrevSlide() { + currentSlideIndex -= (direction*2); + playNextSlide(); +} + +void magSlideShowSource::playSlide(int slideIndex) { + currentSlideIndex = slideIndex-direction; + playNextSlide(); +} + +void magSlideShowSource::enqueueSlide(std::shared_ptr slide, uint64_t startTime) { +// ofLogVerbose() << "Enqueuing slide " << currentSlideIndex << " slide id: " << slide->getId(); + slide->start(startTime); + activeSlides.insert(activeSlides.begin(), slide); +} + +void magSlideShowSource::slideStateChanged(const void *sender, ofEventArgs &args) { + magSlide *slide = (magSlide *) sender; + +// ofLogVerbose("slideStateChanged") << "Slide id: " << slide->getId() << " Slide state: " +// << slide->getSlideStateName(); + if (slide->getSlideState() == magSlide::SlideState::BuildOut) + { + // Flag that we need to load the next slide: + doPlayNextSlide = true; + } + +} + +void magSlideShowSource::slideComplete(const void *sender, ofEventArgs &args) { + magSlide *slide = (magSlide *) sender; +// ofLogVerbose() << "Slide Complete. id: " << slide->getId(); + slide->isComplete = true; +} + +void magSlideShowSource::fileAddedListener(const void *sender) { + doInit = true; +} + +void magSlideShowSource::fileRemovedListener(const void *sender) { + doInit = true; +} diff --git a/example_fbo-sources/src/SlideShowSource/magSlideShowSource.h b/example_fbo-sources/src/SlideShowSource/magSlideShowSource.h index 47b4cd5..4ea817c 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideShowSource.h +++ b/example_fbo-sources/src/SlideShowSource/magSlideShowSource.h @@ -1,167 +1,167 @@ -// -// magSlideShowSource.h -// Copyright (c) 2017 Cristobal Mendoza -// http://cuppetellimendoza.com -// - -#ifndef MAGSLIDESHOWSOURCE_H -#define MAGSLIDESHOWSOURCE_H - -#include "FboSource.h" -#include "magSlide.h" -#include "DirectoryWatcher.h" - -class magSlide; - -class magSlideShowSource : public ofx::piMapper::FboSource { - public: - magSlideShowSource(); - - /** - * Default settings file name. - */ - static const std::string SettingsFileName; - struct Settings; // forward declaration - bool initialize(magSlideShowSource::Settings settings); - void setup() override; - void update() override; - void draw() override; - - /** - * Removes all slides and then attempts to create a new slide show - * based on the contents of the ofDirectory specified. The files may - * be images or videos, which will be transformed into the appropriate slide type. - * Any other file type in the directory is ignored (including other directories). - * The slide order is alphabetical according to filename. - * - * @param dir The ofDirectory to use as a source for a slide show. - * @return true if at least one slide was created. false is returned - * otherwise. Check the console for the specific error. - */ - bool createFromFolderContents(std::string path); - bool loadFromXml(std::string path); - void addSlide(std::shared_ptr slide); - void play(); - void pause(); - void playNextSlide(); - void playPrevSlide(); - void playSlide(int slideIndex); - - enum LoopType : int { - NONE = 0, - NORMAL, - PING_PONG - }; - - struct Settings { - /** - * The pixel width of the FBO. - */ - float width = 1280; - - /** - * The pixel height of the FBO. - */ - float height = 720; - /** - * An optional default slide duration, in seconds. - * If a slide specifies a duration this value is ignored. - */ - float slideDuration = 5; - - /** - * The default transition for the slide show. - */ - std::string transitionName = "Dissolve"; - - /** - * Default transition duration. - */ - float transitionDuration = 1; - - /** - * If specified, all applicable files in the folder will - * be used as slides in the slide show. They will be ordered - * alphabetically according to their file names. - * - * If path is relative, the root will likely be the Data folder. - */ - std::string slidesFolderPath = "sources/images"; - - /** - * If specified, - */ - std::string slideshowFilePath; - - - /** - * Loop type for the slide show. See @code LoopType for options. - * The default is @code LoopType:None. - */ - LoopType loopType = LoopType::NONE; - - /** - * The number of loops to perform, if the loopType is not NONE. - * If the value is 0 or less than 0, the slide show loops forever. - */ - int numLoops = 0; - - /** - * The resizing option for the slide show. The default is FitProportionally. - * If a slide already has a resizing option applied, that option will be - * respected and this resizeOption will not be used. - */ - magSlide::ResizeOptions resizeOption = magSlide::ResizeOptions::FitProportionally; - }; - - //////////////////////////////////////////// - //// Event Listeners - //////////////////////////////////////////// - void slideStateChanged(const void *sender, ofEventArgs &args); - void slideComplete(const void *sender, ofEventArgs &args); - virtual ~magSlideShowSource(); - - - /** - * Fires when the slide show is done, which happens when - * the loop count is equal to Settings::numLoops, or when - * the last slide is played when @code LoopType::NONE is specified. - * Sender is this slide show. - */ - ofEvent slideshowCompleteEvent; - - - /** - * Fires when the slide show reaches the last slide - * and will perform a loop in the next call. - * Sender is this slide show. - */ - ofEvent slideshowWillLoopEvent; - - protected: - Settings settings; - std::vector> slides; - - private: -// std::shared_ptr currentSlide; - std::vector> activeSlides; - void enqueueSlide(std::shared_ptr slide, uint64_t startTime); - - uint64_t lastTime; - uint64_t deltaTime; - uint64_t runningTime; - - bool isInitialized = false; - bool isPlaying = false; - int currentSlideIndex = 0; - int direction = 1; - int loopCount = 0; - ofx::piMapper::DirectoryWatcher * directoryWatcher; - void fileAddedListener(const void * sender); - void fileRemovedListener(const void * sender); - bool doInit; - bool doPlayNextSlide = false; -}; - - -#endif +// +// magSlideShowSource.h +// Copyright (c) 2017 Cristobal Mendoza +// http://cuppetellimendoza.com +// + +#ifndef MAGSLIDESHOWSOURCE_H +#define MAGSLIDESHOWSOURCE_H + +#include "FboSource.h" +#include "magSlide.h" +#include "DirectoryWatcher.h" + +class magSlide; + +class magSlideShowSource : public ofx::piMapper::FboSource { + public: + magSlideShowSource(); + + /** + * Default settings file name. + */ + static const std::string SettingsFileName; + struct Settings; // forward declaration + bool initialize(magSlideShowSource::Settings settings); + void setup() override; + void update() override; + void draw() override; + + /** + * Removes all slides and then attempts to create a new slide show + * based on the contents of the ofDirectory specified. The files may + * be images or videos, which will be transformed into the appropriate slide type. + * Any other file type in the directory is ignored (including other directories). + * The slide order is alphabetical according to filename. + * + * @param dir The ofDirectory to use as a source for a slide show. + * @return true if at least one slide was created. false is returned + * otherwise. Check the console for the specific error. + */ + bool createFromFolderContents(std::string path); + bool loadFromXml(std::string path); + void addSlide(std::shared_ptr slide); + void play(); + void pause(); + void playNextSlide(); + void playPrevSlide(); + void playSlide(int slideIndex); + + enum LoopType : int { + NONE = 0, + NORMAL, + PING_PONG + }; + + struct Settings { + /** + * The pixel width of the FBO. + */ + float width = 1280; + + /** + * The pixel height of the FBO. + */ + float height = 720; + /** + * An optional default slide duration, in seconds. + * If a slide specifies a duration this value is ignored. + */ + float slideDuration = 5; + + /** + * The default transition for the slide show. + */ + std::string transitionName = "Dissolve"; + + /** + * Default transition duration. + */ + float transitionDuration = 1; + + /** + * If specified, all applicable files in the folder will + * be used as slides in the slide show. They will be ordered + * alphabetically according to their file names. + * + * If path is relative, the root will likely be the Data folder. + */ + std::string slidesFolderPath = "sources/images"; + + /** + * If specified, + */ + std::string slideshowFilePath; + + + /** + * Loop type for the slide show. See @code LoopType for options. + * The default is @code LoopType:None. + */ + LoopType loopType = LoopType::NONE; + + /** + * The number of loops to perform, if the loopType is not NONE. + * If the value is 0 or less than 0, the slide show loops forever. + */ + int numLoops = 0; + + /** + * The resizing option for the slide show. The default is FitProportionally. + * If a slide already has a resizing option applied, that option will be + * respected and this resizeOption will not be used. + */ + magSlide::ResizeOptions resizeOption = magSlide::ResizeOptions::FitProportionally; + }; + + //////////////////////////////////////////// + //// Event Listeners + //////////////////////////////////////////// + void slideStateChanged(const void *sender, ofEventArgs &args); + void slideComplete(const void *sender, ofEventArgs &args); + virtual ~magSlideShowSource(); + + + /** + * Fires when the slide show is done, which happens when + * the loop count is equal to Settings::numLoops, or when + * the last slide is played when @code LoopType::NONE is specified. + * Sender is this slide show. + */ + ofEvent slideshowCompleteEvent; + + + /** + * Fires when the slide show reaches the last slide + * and will perform a loop in the next call. + * Sender is this slide show. + */ + ofEvent slideshowWillLoopEvent; + + protected: + Settings settings; + std::vector> slides; + + private: +// std::shared_ptr currentSlide; + std::vector> activeSlides; + void enqueueSlide(std::shared_ptr slide, uint64_t startTime); + + uint64_t lastTime; + uint64_t deltaTime; + uint64_t runningTime; + + bool isInitialized = false; + bool isPlaying = false; + int currentSlideIndex = 0; + int direction = 1; + int loopCount = 0; + ofx::piMapper::DirectoryWatcher * directoryWatcher; + void fileAddedListener(const void * sender); + void fileRemovedListener(const void * sender); + bool doInit; + bool doPlayNextSlide = false; +}; + + +#endif diff --git a/example_fbo-sources/src/SlideShowSource/magSlideTransition.cpp b/example_fbo-sources/src/SlideShowSource/magSlideTransition.cpp index 2377702..93f532e 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideTransition.cpp +++ b/example_fbo-sources/src/SlideShowSource/magSlideTransition.cpp @@ -1,60 +1,60 @@ -// -// magSlideTransition.cpp -// Copyright (c) 2017 Cristobal Mendoza -// http://cuppetellimendoza.com -// - -#include "magSlideTransition.h" - -void magSlideTransition::start(std::shared_ptr nextSlide) -{ - runningTime = 0; - active = true; - this->nextSlide = nextSlide; -} - -void magSlideTransition::update(uint64_t timeDelta) -{ - if (!active) return; - - runningTime += timeDelta; - if (runningTime >= duration) - { - ofEventArgs arghh; // arghhhh... - nextSlide->setOpacity(255); - nextSlide->setPosition(0, 0); - end(); - transitionCompleteEvent.notify(this, arghh); - active = false; - } - -} - -uint64_t magSlideTransition::getRunningTime() -{ - return runningTime; -} - -float magSlideTransition::getNormalizedTime() -{ - return (double)runningTime / (double)duration; -} - - -void magDissolveTransition::draw() -{ - slide->setOpacity(255 - (getNormalizedTime() * 255)); - nextSlide->setOpacity(getNormalizedTime()*255); -} - -void magDissolveTransition::start(std::shared_ptr nextSlide) -{ - magSlideTransition::start(nextSlide); - nextSlide->setOpacity(0); -} - -void magDissolveTransition::end() -{ - nextSlide->setOpacity(255); - slide->setOpacity(0); -} +// +// magSlideTransition.cpp +// Copyright (c) 2017 Cristobal Mendoza +// http://cuppetellimendoza.com +// + +#include "magSlideTransition.h" + +void magSlideTransition::start(std::shared_ptr nextSlide) +{ + runningTime = 0; + active = true; + this->nextSlide = nextSlide; +} + +void magSlideTransition::update(uint64_t timeDelta) +{ + if (!active) return; + + runningTime += timeDelta; + if (runningTime >= duration) + { + ofEventArgs arghh; // arghhhh... + nextSlide->setOpacity(255); + nextSlide->setPosition(0, 0); + end(); + transitionCompleteEvent.notify(this, arghh); + active = false; + } + +} + +uint64_t magSlideTransition::getRunningTime() +{ + return runningTime; +} + +float magSlideTransition::getNormalizedTime() +{ + return (double)runningTime / (double)duration; +} + + +void magDissolveTransition::draw() +{ + slide->setOpacity(255 - (getNormalizedTime() * 255)); + nextSlide->setOpacity(getNormalizedTime()*255); +} + +void magDissolveTransition::start(std::shared_ptr nextSlide) +{ + magSlideTransition::start(nextSlide); + nextSlide->setOpacity(0); +} + +void magDissolveTransition::end() +{ + nextSlide->setOpacity(255); + slide->setOpacity(0); +} diff --git a/example_fbo-sources/src/SlideShowSource/magSlideTransition.h b/example_fbo-sources/src/SlideShowSource/magSlideTransition.h index 421b057..524b98d 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideTransition.h +++ b/example_fbo-sources/src/SlideShowSource/magSlideTransition.h @@ -1,129 +1,129 @@ -// -// magSlideTransition.h -// Copyright (c) 2017 Cristobal Mendoza -// http://cuppetellimendoza.com -// - -#ifndef MAGSLIDETRANSITION_H -#define MAGSLIDETRANSITION_H - -#include "magSlide.h" - -class magSlideTransitionFactory; - -class magSlideTransition -{ -public: - /** - * Subclassing notes: Make sure to provide a value for name in your - * magSlideTransition subclass. - */ - magSlideTransition() { name = "Void"; } - /** - * Begins the transition. This needs to be called in order for the - * transition to do anything. - * @param nextSlide The subsequent slide in the slide show needs to be - * passed here. - * - * You can override this call to set any initial conditions to the transition, - * but make sure to call this method in your override. - */ - virtual void start(std::shared_ptr nextSlide); - - /** - * Called automatically when the transition is complete. Useful to set - * end states for the parameters of the slide and nextSlide. Default implementation - * does nothing. - */ - virtual void end(){} - - /** - * NOTE: The transition settings system is not yet implemented. - * Called when the transition is created. Loads settings for magSlideTransition - * subclasses. The default implementation does nothing. - * @param settings ofParameterGroup with settings for your custom magSlideTransition - * subclass. - */ - virtual void loadSettings(ofParameterGroup &settings){} - - /** - * Updates the transition. - * @param timeDelta The elapsed time (in ms.) between the last call to update() and - * this one (i.e. the frame time). - * - * If you need to override update, make sure to call this implementation - * in your subclass. - */ - virtual void update(uint64_t timeDelta); - - /** - * Draws the transition. Default implementation does nothing. - */ - virtual void draw(){ - ofLogNotice("magSlideTransition") << "transition draw - this should be overriden " << getNormalizedTime(); - } - - /** - * Current running time in milliseconds. - * @return uint64_t - */ - uint64_t getRunningTime(); - - /** - * Returns the current time in normalized form. - * 0 = start, 1 = end. - * @return Float between 0 and 1. - */ - float getNormalizedTime(); - - std::string const &getName() const - { - return name; - } - - const shared_ptr &getNextSlide() const - { - return nextSlide; - } - - bool isActive() const - { - return active; - } - - /** - * Sender is a raw pointer to this magSlideTransition - */ - ofEvent transitionCompleteEvent; - -protected: - std::string name; - std::shared_ptr slide; - std::shared_ptr nextSlide; - - uint64_t runningTime; - uint64_t duration; - uint64_t endTime; - bool active = false; - - -protected: - - friend class magSlideTransitionFactory; -}; - -class magDissolveTransition : public magSlideTransition -{ -public: - magDissolveTransition() - { - name = "Dissolve"; - } - - void start(std::shared_ptr nextSlide) override; - - void draw() override; - void end() override; -}; - -#endif +// +// magSlideTransition.h +// Copyright (c) 2017 Cristobal Mendoza +// http://cuppetellimendoza.com +// + +#ifndef MAGSLIDETRANSITION_H +#define MAGSLIDETRANSITION_H + +#include "magSlide.h" + +class magSlideTransitionFactory; + +class magSlideTransition +{ +public: + /** + * Subclassing notes: Make sure to provide a value for name in your + * magSlideTransition subclass. + */ + magSlideTransition() { name = "Void"; } + /** + * Begins the transition. This needs to be called in order for the + * transition to do anything. + * @param nextSlide The subsequent slide in the slide show needs to be + * passed here. + * + * You can override this call to set any initial conditions to the transition, + * but make sure to call this method in your override. + */ + virtual void start(std::shared_ptr nextSlide); + + /** + * Called automatically when the transition is complete. Useful to set + * end states for the parameters of the slide and nextSlide. Default implementation + * does nothing. + */ + virtual void end(){} + + /** + * NOTE: The transition settings system is not yet implemented. + * Called when the transition is created. Loads settings for magSlideTransition + * subclasses. The default implementation does nothing. + * @param settings ofParameterGroup with settings for your custom magSlideTransition + * subclass. + */ + virtual void loadSettings(ofParameterGroup &settings){} + + /** + * Updates the transition. + * @param timeDelta The elapsed time (in ms.) between the last call to update() and + * this one (i.e. the frame time). + * + * If you need to override update, make sure to call this implementation + * in your subclass. + */ + virtual void update(uint64_t timeDelta); + + /** + * Draws the transition. Default implementation does nothing. + */ + virtual void draw(){ + ofLogNotice("magSlideTransition") << "transition draw - this should be overriden " << getNormalizedTime(); + } + + /** + * Current running time in milliseconds. + * @return uint64_t + */ + uint64_t getRunningTime(); + + /** + * Returns the current time in normalized form. + * 0 = start, 1 = end. + * @return Float between 0 and 1. + */ + float getNormalizedTime(); + + std::string const &getName() const + { + return name; + } + + const shared_ptr &getNextSlide() const + { + return nextSlide; + } + + bool isActive() const + { + return active; + } + + /** + * Sender is a raw pointer to this magSlideTransition + */ + ofEvent transitionCompleteEvent; + +protected: + std::string name; + std::shared_ptr slide; + std::shared_ptr nextSlide; + + uint64_t runningTime; + uint64_t duration; + uint64_t endTime; + bool active = false; + + +protected: + + friend class magSlideTransitionFactory; +}; + +class magDissolveTransition : public magSlideTransition +{ +public: + magDissolveTransition() + { + name = "Dissolve"; + } + + void start(std::shared_ptr nextSlide) override; + + void draw() override; + void end() override; +}; + +#endif diff --git a/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.cpp b/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.cpp index ef44d1b..90fffef 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.cpp +++ b/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.cpp @@ -1,76 +1,76 @@ -// -// Created by Cristobal Mendoza on 12/3/17. -// - -#include "magSlideTransitionFactory.h" - -/* - * - * - * -class Base {}; - -class DerivedA : public Base {}; -class DerivedB : public Base {}; -class DerivedC : public Base {}; - -Base* create(const std::string& type) -{ - static std::map> type_creator_map = - { - {"DerivedA", [](){return new DerivedA();}}, - {"DerivedB", [](){return new DerivedB();}}, - {"DerivedC", [](){return new DerivedC();}} - }; - - auto it = type_creator_map.find(type); - if(it != type_creator_map.end()) - { - return it->second(); - } - - return nullptr; -} - */ - -magSlideTransitionFactory* magSlideTransitionFactory::_instance = 0; - -magSlideTransitionFactory::magSlideTransitionFactory() -{ - magSlideTransition voidTransition; - magDissolveTransition dissolve; - - registerTransition(voidTransition); - registerTransition(dissolve); -} - -magSlideTransitionFactory* magSlideTransitionFactory::instance() -{ - if (_instance == 0) - { - _instance = new magSlideTransitionFactory(); - } - - return _instance; -} - -std::shared_ptr -magSlideTransitionFactory::createTransition(std::string transitionName, std::shared_ptr slide, - ofParameterGroup &settings, uint64_t duration) -{ - std::shared_ptr transition; - - if (transitionsMap.count(transitionName) > 0) - { - transition = transitionsMap[transitionName](); - } - else - { - transition = transitionsMap[transition->getName()](); - } - - transition->slide = slide; - transition->duration = duration; - transition->loadSettings(settings); - return transition; -} +// +// Created by Cristobal Mendoza on 12/3/17. +// + +#include "magSlideTransitionFactory.h" + +/* + * + * + * +class Base {}; + +class DerivedA : public Base {}; +class DerivedB : public Base {}; +class DerivedC : public Base {}; + +Base* create(const std::string& type) +{ + static std::map> type_creator_map = + { + {"DerivedA", [](){return new DerivedA();}}, + {"DerivedB", [](){return new DerivedB();}}, + {"DerivedC", [](){return new DerivedC();}} + }; + + auto it = type_creator_map.find(type); + if(it != type_creator_map.end()) + { + return it->second(); + } + + return nullptr; +} + */ + +magSlideTransitionFactory* magSlideTransitionFactory::_instance = 0; + +magSlideTransitionFactory::magSlideTransitionFactory() +{ + magSlideTransition voidTransition; + magDissolveTransition dissolve; + + registerTransition(voidTransition); + registerTransition(dissolve); +} + +magSlideTransitionFactory* magSlideTransitionFactory::instance() +{ + if (_instance == 0) + { + _instance = new magSlideTransitionFactory(); + } + + return _instance; +} + +std::shared_ptr +magSlideTransitionFactory::createTransition(std::string transitionName, std::shared_ptr slide, + ofParameterGroup &settings, uint64_t duration) +{ + std::shared_ptr transition; + + if (transitionsMap.count(transitionName) > 0) + { + transition = transitionsMap[transitionName](); + } + else + { + transition = transitionsMap[transition->getName()](); + } + + transition->slide = slide; + transition->duration = duration; + transition->loadSettings(settings); + return transition; +} diff --git a/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.h b/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.h index 75986e8..6b15d00 100644 --- a/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.h +++ b/example_fbo-sources/src/SlideShowSource/magSlideTransitionFactory.h @@ -1,41 +1,41 @@ -// -// Created by Cristobal Mendoza on 12/3/17. -// - -#ifndef MAGSLIDETRANSITIONFACTORY_H -#define MAGSLIDETRANSITIONFACTORY_H - -#include "magSlide.h" -#include "magSlideTransition.h" - -/** - * Factory class to register and instantiate transitions. - */ -class magSlideTransitionFactory -{ -public: - static magSlideTransitionFactory* instance(); - - std::shared_ptr createTransition(std::string transitionName, - std::shared_ptr slide, - ofParameterGroup &group, - uint64_t duration); - template - void registerTransition(T transition) - { - if (transitionsMap.count(transition.getName()) == 0) - { - transitionsMap[transition.getName()] = [](){ - return std::make_shared(); - }; - } - } - -protected: - std::unordered_map()>> transitionsMap; -private: - static magSlideTransitionFactory* _instance; - magSlideTransitionFactory(); -}; - -#endif //MAGSLIDETRANSITIONFACTORY_H +// +// Created by Cristobal Mendoza on 12/3/17. +// + +#ifndef MAGSLIDETRANSITIONFACTORY_H +#define MAGSLIDETRANSITIONFACTORY_H + +#include "magSlide.h" +#include "magSlideTransition.h" + +/** + * Factory class to register and instantiate transitions. + */ +class magSlideTransitionFactory +{ +public: + static magSlideTransitionFactory* instance(); + + std::shared_ptr createTransition(std::string transitionName, + std::shared_ptr slide, + ofParameterGroup &group, + uint64_t duration); + template + void registerTransition(T transition) + { + if (transitionsMap.count(transition.getName()) == 0) + { + transitionsMap[transition.getName()] = [](){ + return std::make_shared(); + }; + } + } + +protected: + std::unordered_map()>> transitionsMap; +private: + static magSlideTransitionFactory* _instance; + magSlideTransitionFactory(); +}; + +#endif //MAGSLIDETRANSITIONFACTORY_H diff --git a/example_fbo-sources/src/SyphonSource/SyphonSource.cpp b/example_fbo-sources/src/SyphonSource/SyphonSource.cpp index 3392120..be53f86 100644 --- a/example_fbo-sources/src/SyphonSource/SyphonSource.cpp +++ b/example_fbo-sources/src/SyphonSource/SyphonSource.cpp @@ -1,87 +1,87 @@ -// #include "SyphonSource.h" -// -// void SyphonSource::setup(){ -// // Give our source a decent name -// name = "Syphon Source"; -// -// // Allocate our FBO source, decide how big it should be -// allocate(500, 500); -// -// //setup our directory -// dir.setup(); -// //setup our client -// mClient.setup(); -// -// //register for our directory's callbacks -// ofAddListener(dir.events.serverAnnounced, this, &SyphonSource::serverAnnounced); -// // not yet implemented -// //ofAddListener(dir.events.serverUpdated, this, &ofApp::serverUpdated); -// ofAddListener(dir.events.serverRetired, this, &SyphonSource::serverRetired); -// -// dirIdx = -1; -// } -// -// //these are our directory's callbacks -// void SyphonSource::serverAnnounced(ofxSyphonServerDirectoryEventArgs &arg) -// { -// for( auto& dir : arg.servers ){ -// ofLogNotice("ofxSyphonServerDirectory Server Announced")<<" Server Name: "< 0) -// { -// dirIdx++; -// if(dirIdx > dir.size() - 1) -// dirIdx = 0; -// -// mClient.set(dir.getDescription(dirIdx)); -// string serverName = mClient.getServerName(); -// string appName = mClient.getApplicationName(); -// -// if(serverName == ""){ -// serverName = "null"; -// } -// if(appName == ""){ -// appName = "null"; -// } -// ofSetWindowTitle(serverName + ":" + appName); -// } -// else -// { -// ofSetWindowTitle("No Server"); -// } -// } +// #include "SyphonSource.h" +// +// void SyphonSource::setup(){ +// // Give our source a decent name +// name = "Syphon Source"; +// +// // Allocate our FBO source, decide how big it should be +// allocate(500, 500); +// +// //setup our directory +// dir.setup(); +// //setup our client +// mClient.setup(); +// +// //register for our directory's callbacks +// ofAddListener(dir.events.serverAnnounced, this, &SyphonSource::serverAnnounced); +// // not yet implemented +// //ofAddListener(dir.events.serverUpdated, this, &ofApp::serverUpdated); +// ofAddListener(dir.events.serverRetired, this, &SyphonSource::serverRetired); +// +// dirIdx = -1; +// } +// +// //these are our directory's callbacks +// void SyphonSource::serverAnnounced(ofxSyphonServerDirectoryEventArgs &arg) +// { +// for( auto& dir : arg.servers ){ +// ofLogNotice("ofxSyphonServerDirectory Server Announced")<<" Server Name: "< 0) +// { +// dirIdx++; +// if(dirIdx > dir.size() - 1) +// dirIdx = 0; +// +// mClient.set(dir.getDescription(dirIdx)); +// string serverName = mClient.getServerName(); +// string appName = mClient.getApplicationName(); +// +// if(serverName == ""){ +// serverName = "null"; +// } +// if(appName == ""){ +// appName = "null"; +// } +// ofSetWindowTitle(serverName + ":" + appName); +// } +// else +// { +// ofSetWindowTitle("No Server"); +// } +// } diff --git a/example_fbo-sources/src/SyphonSource/SyphonSource.h b/example_fbo-sources/src/SyphonSource/SyphonSource.h index 2f7ca52..9aa95f6 100644 --- a/example_fbo-sources/src/SyphonSource/SyphonSource.h +++ b/example_fbo-sources/src/SyphonSource/SyphonSource.h @@ -1,21 +1,21 @@ -// #pragma once -// -// #include "ofMain.h" -// #include "FboSource.h" -// #include "ofxSyphon.h" -// class SyphonSource : public ofx::piMapper::FboSource { -// public: -// void setup(); -// void update(); -// void draw(); -// -// void keyReleased(int key); -// -// void serverAnnounced(ofxSyphonServerDirectoryEventArgs &arg); -// void serverUpdated(ofxSyphonServerDirectoryEventArgs &args); -// void serverRetired(ofxSyphonServerDirectoryEventArgs &arg); -// -// ofxSyphonServerDirectory dir; -// ofxSyphonClient mClient; -// int dirIdx; -// }; +// #pragma once +// +// #include "ofMain.h" +// #include "FboSource.h" +// #include "ofxSyphon.h" +// class SyphonSource : public ofx::piMapper::FboSource { +// public: +// void setup(); +// void update(); +// void draw(); +// +// void keyReleased(int key); +// +// void serverAnnounced(ofxSyphonServerDirectoryEventArgs &arg); +// void serverUpdated(ofxSyphonServerDirectoryEventArgs &args); +// void serverRetired(ofxSyphonServerDirectoryEventArgs &arg); +// +// ofxSyphonServerDirectory dir; +// ofxSyphonClient mClient; +// int dirIdx; +// }; diff --git a/example_fbo-sources/src/main.cpp b/example_fbo-sources/src/main.cpp index d191606..d80b1de 100644 --- a/example_fbo-sources/src/main.cpp +++ b/example_fbo-sources/src/main.cpp @@ -1,7 +1,7 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1024, 768, OF_WINDOW); - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" + +int main(){ + ofSetupOpenGL(1024, 768, OF_WINDOW); + ofRunApp(new ofApp()); +} diff --git a/example_fbo-sources/src/ofApp.cpp b/example_fbo-sources/src/ofApp.cpp index e2c626c..6f6c763 100644 --- a/example_fbo-sources/src/ofApp.cpp +++ b/example_fbo-sources/src/ofApp.cpp @@ -1,57 +1,57 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - - // Enable or disable audio for video sources globally - // Set this to false to save resources on the Raspberry Pi - ofx::piMapper::VideoSource::enableAudio = true; - ofx::piMapper::VideoSource::useHDMIForAudio = false; - - // Register our sources. - // This should be done before mapper.setup(). - piMapper.registerFboSource(ScanLSource); - piMapper.registerFboSource(QuadiSource); - piMapper.registerFboSource(CircLSource); - piMapper.registerFboSource(BricksSource); - //piMapper.registerFboSource(SyphonClient); - //piMapper.registerFboSource(slideShowSource); - piMapper.setup(); - - // This will set the app fullscreen if compiled on Raspberry Pi. - #ifdef TARGET_RASPBERRY_PI - ofSetFullscreen(true); - #endif - - // Start slideshow. - //slideShowSource.play(); -} - -void ofApp::update(){ - piMapper.update(); -} - -void ofApp::draw(){ - piMapper.draw(); -} - -void ofApp::keyPressed(int key){ - piMapper.keyPressed(key); -} - -void ofApp::keyReleased(int key){ - piMapper.keyReleased(key); -} - -void ofApp::mousePressed(int x, int y, int button){ - - piMapper.mousePressed(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - piMapper.mouseReleased(x, y, button); -} - -void ofApp::mouseDragged(int x, int y, int button){ - piMapper.mouseDragged(x, y, button); -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + + // Enable or disable audio for video sources globally + // Set this to false to save resources on the Raspberry Pi + ofx::piMapper::VideoSource::enableAudio = true; + ofx::piMapper::VideoSource::useHDMIForAudio = false; + + // Register our sources. + // This should be done before mapper.setup(). + piMapper.registerFboSource(ScanLSource); + piMapper.registerFboSource(QuadiSource); + piMapper.registerFboSource(CircLSource); + piMapper.registerFboSource(BricksSource); + //piMapper.registerFboSource(SyphonClient); + //piMapper.registerFboSource(slideShowSource); + piMapper.setup(); + + // This will set the app fullscreen if compiled on Raspberry Pi. + #ifdef TARGET_RASPBERRY_PI + ofSetFullscreen(true); + #endif + + // Start slideshow. + //slideShowSource.play(); +} + +void ofApp::update(){ + piMapper.update(); +} + +void ofApp::draw(){ + piMapper.draw(); +} + +void ofApp::keyPressed(int key){ + piMapper.keyPressed(key); +} + +void ofApp::keyReleased(int key){ + piMapper.keyReleased(key); +} + +void ofApp::mousePressed(int x, int y, int button){ + + piMapper.mousePressed(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + piMapper.mouseReleased(x, y, button); +} + +void ofApp::mouseDragged(int x, int y, int button){ + piMapper.mouseDragged(x, y, button); +} diff --git a/example_fbo-sources/src/ofApp.h b/example_fbo-sources/src/ofApp.h index ff90d55..a5523dd 100644 --- a/example_fbo-sources/src/ofApp.h +++ b/example_fbo-sources/src/ofApp.h @@ -1,37 +1,37 @@ -#pragma once - -#include "ofMain.h" -#include "ofxPiMapper.h" -#include "VideoSource.h" -#include "ScanlineSource.h" -#include "CircleSource.h" -#include "QuadSource.h" -#include "BrickSource.h" -//#include "SyphonSource.h" -#include "magSlideShowSource.h" - -class ofApp : public ofBaseApp{ -public: - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - ofxPiMapper piMapper; - - // By using a custom source that is derived from FboSource - // you will be able to see the source listed in sources editor - ScanlineSource ScanLSource; - QuadSource QuadiSource; - CircleSource CircLSource; - BrickSource BricksSource; - //SyphonSource SyphonClient; - magSlideShowSource slideShowSource; - -}; +#pragma once + +#include "ofMain.h" +#include "ofxPiMapper.h" +#include "VideoSource.h" +#include "ScanlineSource.h" +#include "CircleSource.h" +#include "QuadSource.h" +#include "BrickSource.h" +//#include "SyphonSource.h" +#include "magSlideShowSource.h" + +class ofApp : public ofBaseApp{ +public: + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + ofxPiMapper piMapper; + + // By using a custom source that is derived from FboSource + // you will be able to see the source listed in sources editor + ScanlineSource ScanLSource; + QuadSource QuadiSource; + CircleSource CircLSource; + BrickSource BricksSource; + //SyphonSource SyphonClient; + magSlideShowSource slideShowSource; + +}; diff --git a/example_pocketvj/.gitignore b/example_pocketvj/.gitignore index 4572154..7e10cee 100644 --- a/example_pocketvj/.gitignore +++ b/example_pocketvj/.gitignore @@ -1,6 +1,6 @@ -obj -*.xcworkspace -*.xcuserdatad -*~ -config.make -bin/*.app +obj +*.xcworkspace +*.xcuserdatad +*~ +config.make +bin/*.app diff --git a/example_pocketvj/Makefile b/example_pocketvj/Makefile index 177e172..7012784 100644 --- a/example_pocketvj/Makefile +++ b/example_pocketvj/Makefile @@ -1,13 +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 +# 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/example_pocketvj/addons.make b/example_pocketvj/addons.make index 963941c..596425d 100644 --- a/example_pocketvj/addons.make +++ b/example_pocketvj/addons.make @@ -1,4 +1,4 @@ -ofxGui -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_pocketvj/addons.make.norpi b/example_pocketvj/addons.make.norpi index e72d2dd..69d8f94 100644 --- a/example_pocketvj/addons.make.norpi +++ b/example_pocketvj/addons.make.norpi @@ -1,3 +1,3 @@ -ofxGui -ofxPiMapper -ofxXmlSettings +ofxGui +ofxPiMapper +ofxXmlSettings diff --git a/example_pocketvj/bin/data/ofxpimapper.xml b/example_pocketvj/bin/data/ofxpimapper.xml index 961b490..e3ead7a 100644 --- a/example_pocketvj/bin/data/ofxpimapper.xml +++ b/example_pocketvj/bin/data/ofxpimapper.xml @@ -1,36 +1,36 @@ - - - - - 431.000000000 - 13.000000000 - - - 781.000000000 - 363.000000000 - - - 81.000000000 - 363.000000000 - - - - - 0.500000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - image1.jpg - - - + + + + + 431.000000000 + 13.000000000 + + + 781.000000000 + 363.000000000 + + + 81.000000000 + 363.000000000 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + image1.jpg + + + diff --git a/example_pocketvj/src/main.cpp b/example_pocketvj/src/main.cpp index 17f4ae7..1c5c250 100644 --- a/example_pocketvj/src/main.cpp +++ b/example_pocketvj/src/main.cpp @@ -1,9 +1,9 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofGLFWWindowSettings settings; - settings.windowMode = OF_FULLSCREEN; - ofCreateWindow(settings); - ofRunApp(new ofApp); -} +#include "ofMain.h" +#include "ofApp.h" + +int main(){ + ofGLFWWindowSettings settings; + settings.windowMode = OF_FULLSCREEN; + ofCreateWindow(settings); + ofRunApp(new ofApp); +} diff --git a/example_pocketvj/src/ofApp.cpp b/example_pocketvj/src/ofApp.cpp index d9644c8..d703462 100644 --- a/example_pocketvj/src/ofApp.cpp +++ b/example_pocketvj/src/ofApp.cpp @@ -1,124 +1,124 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - mapper.setup(); - - // Set different info text for PocketVJ - std::string multilineInfoText = - "Custom ofxPiMapper shortcuts\n\n" - "Good day user.\n" - "Shortcuts have been customized.\n" - "Please make sure to provide your own documentation."; - mapper.setInfoText(multilineInfoText); -} - -void ofApp::update(){ - mapper.update(); -} - -void ofApp::draw(){ - mapper.draw(); -} - -void ofApp::keyPressed(int key){ - if(key == '1'){ - mapper.setMode(ofx::piMapper::PRESENTATION_MODE); - }else if(key == '2'){ - mapper.setMode(ofx::piMapper::TEXTURE_MODE); - }else if(key == '3'){ - mapper.setMode(ofx::piMapper::MAPPING_MODE); - }else if(key == '4'){ - mapper.setMode(ofx::piMapper::SOURCE_MODE); - }else if(key == 'c'){ - mapper.toggleInfo(); - }else if(key == 't'){ - mapper.createSurface(ofx::piMapper::TRIANGLE_SURFACE); - }else if(key == 'q'){ - mapper.createSurface(ofx::piMapper::QUAD_SURFACE); - }else if(key == 'r'){ - mapper.createSurface(ofx::piMapper::CIRCLE_SURFACE); - }else if(key == 'x'){ - mapper.createSurface(ofx::piMapper::HEXAGON_SURFACE); - }else if(key == 'g'){ - mapper.createSurface(ofx::piMapper::GRID_WARP_SURFACE); - }else if(key == 'a'){ - mapper.duplicateSurface(); - }else if(key == 'o'){ - mapper.scaleUp(); - }else if(key == 'i'){ - mapper.scaleDown(); - }else if(key == 'p'){ - mapper.togglePerspective(); - }else if(key == 'v'){ - mapper.addGridColumn(); - }else if(key == 'b'){ - mapper.removeGridColumn(); - }else if(key == 'n'){ - mapper.addGridRow(); - }else if(key == 'm'){ - mapper.removeGridRow(); - }else if(key == '.'){ - mapper.selectNextSurface(); - }else if(key == ','){ - mapper.selectPrevSurface(); - }else if(key == 'k'){ - mapper.selectNextVertex(); - }else if(key == 'l'){ - mapper.selectPrevVertex(); - }else if(key == 'h'){ - mapper.moveLayerUp(); - }else if(key == 'j'){ - mapper.moveLayerDown(); - }else if(key == 's'){ - mapper.saveProject(); - }else if(key == 'y'){ - mapper.toggleLayerPanel(); - }else if(key == 'z'){ - mapper.undo(); - }else if(key == 'd'){ - mapper.eraseSurface(mapper.getSelectedSurface()); - }else if(key == 'w'){ - mapper.togglePause(); - }else if(key == '5'){ - mapper.setNextSource(); - }else if(key == '8'){ - mapper.moveSelection(ofx::piMapper::Vec3(0.0f, -1.0f, 0.0f)); - }else if(key == '9'){ - mapper.moveSelection(ofx::piMapper::Vec3(0.0f, 1.0f, 0.0f)); - }else if(key == '7'){ - mapper.moveSelection(ofx::piMapper::Vec3(-1.0f, 0.0f, 0.0f)); - }else if(key == '0'){ - mapper.moveSelection(ofx::piMapper::Vec3(1.0f, 0.0f, 0.0f)); - }else if(key == '/'){ - bool shiftIsDown = mapper.toggleShift(); - if(shiftIsDown){ - ofLogNotice("ofApp") << "Shift key is down"; - }else{ - ofLogNotice("ofApp") << "Shift key is up"; - } - } - - /* For these one has to figure out her own ways. - * rbt Reboot (Raspberry Pi only) - * sdn Shutdown (Raspberry Pi only) - * new Clear composition (remove all surfaces) - * ext Exit application and return to command line - */ -} - -void ofApp::keyReleased(int key){ - mapper.keyReleased(key); -} - -void ofApp::mousePressed(int x, int y, int button){ - mapper.mousePressed(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - mapper.mouseReleased(x, y, button); -} - -void ofApp::mouseDragged(int x, int y, int button){ - mapper.mouseDragged(x, y, button); -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + mapper.setup(); + + // Set different info text for PocketVJ + std::string multilineInfoText = + "Custom ofxPiMapper shortcuts\n\n" + "Good day user.\n" + "Shortcuts have been customized.\n" + "Please make sure to provide your own documentation."; + mapper.setInfoText(multilineInfoText); +} + +void ofApp::update(){ + mapper.update(); +} + +void ofApp::draw(){ + mapper.draw(); +} + +void ofApp::keyPressed(int key){ + if(key == '1'){ + mapper.setMode(ofx::piMapper::PRESENTATION_MODE); + }else if(key == '2'){ + mapper.setMode(ofx::piMapper::TEXTURE_MODE); + }else if(key == '3'){ + mapper.setMode(ofx::piMapper::MAPPING_MODE); + }else if(key == '4'){ + mapper.setMode(ofx::piMapper::SOURCE_MODE); + }else if(key == 'c'){ + mapper.toggleInfo(); + }else if(key == 't'){ + mapper.createSurface(ofx::piMapper::TRIANGLE_SURFACE); + }else if(key == 'q'){ + mapper.createSurface(ofx::piMapper::QUAD_SURFACE); + }else if(key == 'r'){ + mapper.createSurface(ofx::piMapper::CIRCLE_SURFACE); + }else if(key == 'x'){ + mapper.createSurface(ofx::piMapper::HEXAGON_SURFACE); + }else if(key == 'g'){ + mapper.createSurface(ofx::piMapper::GRID_WARP_SURFACE); + }else if(key == 'a'){ + mapper.duplicateSurface(); + }else if(key == 'o'){ + mapper.scaleUp(); + }else if(key == 'i'){ + mapper.scaleDown(); + }else if(key == 'p'){ + mapper.togglePerspective(); + }else if(key == 'v'){ + mapper.addGridColumn(); + }else if(key == 'b'){ + mapper.removeGridColumn(); + }else if(key == 'n'){ + mapper.addGridRow(); + }else if(key == 'm'){ + mapper.removeGridRow(); + }else if(key == '.'){ + mapper.selectNextSurface(); + }else if(key == ','){ + mapper.selectPrevSurface(); + }else if(key == 'k'){ + mapper.selectNextVertex(); + }else if(key == 'l'){ + mapper.selectPrevVertex(); + }else if(key == 'h'){ + mapper.moveLayerUp(); + }else if(key == 'j'){ + mapper.moveLayerDown(); + }else if(key == 's'){ + mapper.saveProject(); + }else if(key == 'y'){ + mapper.toggleLayerPanel(); + }else if(key == 'z'){ + mapper.undo(); + }else if(key == 'd'){ + mapper.eraseSurface(mapper.getSelectedSurface()); + }else if(key == 'w'){ + mapper.togglePause(); + }else if(key == '5'){ + mapper.setNextSource(); + }else if(key == '8'){ + mapper.moveSelection(ofx::piMapper::Vec3(0.0f, -1.0f, 0.0f)); + }else if(key == '9'){ + mapper.moveSelection(ofx::piMapper::Vec3(0.0f, 1.0f, 0.0f)); + }else if(key == '7'){ + mapper.moveSelection(ofx::piMapper::Vec3(-1.0f, 0.0f, 0.0f)); + }else if(key == '0'){ + mapper.moveSelection(ofx::piMapper::Vec3(1.0f, 0.0f, 0.0f)); + }else if(key == '/'){ + bool shiftIsDown = mapper.toggleShift(); + if(shiftIsDown){ + ofLogNotice("ofApp") << "Shift key is down"; + }else{ + ofLogNotice("ofApp") << "Shift key is up"; + } + } + + /* For these one has to figure out her own ways. + * rbt Reboot (Raspberry Pi only) + * sdn Shutdown (Raspberry Pi only) + * new Clear composition (remove all surfaces) + * ext Exit application and return to command line + */ +} + +void ofApp::keyReleased(int key){ + mapper.keyReleased(key); +} + +void ofApp::mousePressed(int x, int y, int button){ + mapper.mousePressed(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + mapper.mouseReleased(x, y, button); +} + +void ofApp::mouseDragged(int x, int y, int button){ + mapper.mouseDragged(x, y, button); +} diff --git a/example_pocketvj/src/ofApp.h b/example_pocketvj/src/ofApp.h index 63be198..271ec45 100644 --- a/example_pocketvj/src/ofApp.h +++ b/example_pocketvj/src/ofApp.h @@ -1,21 +1,21 @@ -#pragma once - -#include "ofMain.h" -#include "ofxPiMapper.h" -#include "Vec3.h" - -class ofApp : public ofBaseApp { - public: - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - ofxPiMapper mapper; -}; +#pragma once + +#include "ofMain.h" +#include "ofxPiMapper.h" +#include "Vec3.h" + +class ofApp : public ofBaseApp { + public: + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + ofxPiMapper mapper; +}; diff --git a/example_remote-client/Makefile b/example_remote-client/Makefile index 8d8e4c0..c83af71 100644 --- a/example_remote-client/Makefile +++ b/example_remote-client/Makefile @@ -1,13 +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 +# 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/example_remote-client/README.md b/example_remote-client/README.md index 9957c03..89b10c4 100644 --- a/example_remote-client/README.md +++ b/example_remote-client/README.md @@ -1,22 +1,22 @@ -# Remote Control Client for ofxPiMapper - -This example demonstrates a TCP **client** for ofxPiMapper remote control. The other part of this is the [Remote Control Server](../example_remote-server). What it does is the following. - -- Reads IP address and port defined in `bin/data/config.json`. -- Connects to server by using the IP address and port. -- Once connected, ofxPiMapper configuration is received. -- Instance of ofxPiMapper class is being set up. -- TCP messages are sent on every keyboard and mouse event. - -In reality this example should be used as the remote control residing on your laptop computa. Set up your Raspberry Pi, connect it to the same network as your laptop and get to know the IP address of the Raspberry Pi. Update `bin/data/config.json` with the IP address of your Raspberry Pi and launch the app! - -**Warning!** Sources are not being sent. Click once with the mouse after the application launches to see the borders of the surfaces. There should be a green rectangle visible in the top left corner of the screen if the connection is successfull. - -## Dependencies - -JSON is used as the data format between ofxPiMapper remote control server and client, therefore additionally [ofxJSON](https://github.com/jeffcrouse/ofxJSON) addon is used. Install it by using the following lines of bash code. - -``` -cd openFrameworks/addons -git clone --depth=1 https://github.com/jeffcrouse/ofxJSON -``` +# Remote Control Client for ofxPiMapper + +This example demonstrates a TCP **client** for ofxPiMapper remote control. The other part of this is the [Remote Control Server](../example_remote-server). What it does is the following. + +- Reads IP address and port defined in `bin/data/config.json`. +- Connects to server by using the IP address and port. +- Once connected, ofxPiMapper configuration is received. +- Instance of ofxPiMapper class is being set up. +- TCP messages are sent on every keyboard and mouse event. + +In reality this example should be used as the remote control residing on your laptop computa. Set up your Raspberry Pi, connect it to the same network as your laptop and get to know the IP address of the Raspberry Pi. Update `bin/data/config.json` with the IP address of your Raspberry Pi and launch the app! + +**Warning!** Sources are not being sent. Click once with the mouse after the application launches to see the borders of the surfaces. There should be a green rectangle visible in the top left corner of the screen if the connection is successfull. + +## Dependencies + +JSON is used as the data format between ofxPiMapper remote control server and client, therefore additionally [ofxJSON](https://github.com/jeffcrouse/ofxJSON) addon is used. Install it by using the following lines of bash code. + +``` +cd openFrameworks/addons +git clone --depth=1 https://github.com/jeffcrouse/ofxJSON +``` diff --git a/example_remote-client/addons.make b/example_remote-client/addons.make index 4205a02..9819b47 100644 --- a/example_remote-client/addons.make +++ b/example_remote-client/addons.make @@ -1,6 +1,6 @@ -ofxGui -ofxJSON -ofxNetwork -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxJSON +ofxNetwork +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_remote-client/addons.make.norpi b/example_remote-client/addons.make.norpi index cd0471e..35de469 100644 --- a/example_remote-client/addons.make.norpi +++ b/example_remote-client/addons.make.norpi @@ -1,5 +1,5 @@ -ofxGui -ofxJSON -ofxNetwork -ofxPiMapper -ofxXmlSettings +ofxGui +ofxJSON +ofxNetwork +ofxPiMapper +ofxXmlSettings diff --git a/example_remote-client/bin/data/config.json b/example_remote-client/bin/data/config.json index 1eed9ca..308cf46 100644 --- a/example_remote-client/bin/data/config.json +++ b/example_remote-client/bin/data/config.json @@ -1,4 +1,4 @@ -{ - "ip":"127.0.0.1", - "port":9999 -} +{ + "ip":"127.0.0.1", + "port":9999 +} diff --git a/example_remote-client/bin/data/ofxpimapper.xml b/example_remote-client/bin/data/ofxpimapper.xml index a11fe2e..8cc5e99 100644 --- a/example_remote-client/bin/data/ofxpimapper.xml +++ b/example_remote-client/bin/data/ofxpimapper.xml @@ -1,36 +1,36 @@ - - - - - 640.000000000 - 50.000000000 - - - 1230.000000000 - 750.000000000 - - - 50.000000000 - 750.000000000 - - - - - 0.500000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - video - gene-nsynthesis-loop-b.mp4 - - - + + + + + 640.000000000 + 50.000000000 + + + 1230.000000000 + 750.000000000 + + + 50.000000000 + 750.000000000 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + video + gene-nsynthesis-loop-b.mp4 + + + diff --git a/example_remote-client/src/TCPClient.cpp b/example_remote-client/src/TCPClient.cpp index cdc4dfe..649e19d 100644 --- a/example_remote-client/src/TCPClient.cpp +++ b/example_remote-client/src/TCPClient.cpp @@ -1,49 +1,49 @@ -#include "TCPClient.h" - -shared_ptr TCPClient::_instance = 0; - -shared_ptr TCPClient::instance(){ - if(_instance == 0){ - _instance = shared_ptr(new TCPClient); - } - return _instance; -} - -TCPClient::TCPClient(){ - -} - -void TCPClient::setup(string ip, int port){ - _tcpClient.setup(ip, port); -} - -void TCPClient::update(){ - if(_tcpClient.isConnected()){ - string rx = _tcpClient.receive(); - if(rx.length() > 0){ - ofxJSONElement json; - json["event"] = "received"; - json["data"] = rx; - - ofMessage m(json.getRawString()); - ofSendMessage(m); - } - } -} - -void TCPClient::draw(){ - if(_tcpClient.isConnected()){ - ofSetColor(0, 255, 0); - }else{ - ofSetColor(255, 0, 0); - } - - ofPushMatrix(); - ofTranslate(10, 10); - ofDrawRectangle(0, 0, 10, 10); - ofPopMatrix(); -} - -void TCPClient::send(string message){ - _tcpClient.send(message); -} +#include "TCPClient.h" + +shared_ptr TCPClient::_instance = 0; + +shared_ptr TCPClient::instance(){ + if(_instance == 0){ + _instance = shared_ptr(new TCPClient); + } + return _instance; +} + +TCPClient::TCPClient(){ + +} + +void TCPClient::setup(string ip, int port){ + _tcpClient.setup(ip, port); +} + +void TCPClient::update(){ + if(_tcpClient.isConnected()){ + string rx = _tcpClient.receive(); + if(rx.length() > 0){ + ofxJSONElement json; + json["event"] = "received"; + json["data"] = rx; + + ofMessage m(json.getRawString()); + ofSendMessage(m); + } + } +} + +void TCPClient::draw(){ + if(_tcpClient.isConnected()){ + ofSetColor(0, 255, 0); + }else{ + ofSetColor(255, 0, 0); + } + + ofPushMatrix(); + ofTranslate(10, 10); + ofDrawRectangle(0, 0, 10, 10); + ofPopMatrix(); +} + +void TCPClient::send(string message){ + _tcpClient.send(message); +} diff --git a/example_remote-client/src/TCPClient.h b/example_remote-client/src/TCPClient.h index 5d3f655..598f5d9 100644 --- a/example_remote-client/src/TCPClient.h +++ b/example_remote-client/src/TCPClient.h @@ -1,22 +1,22 @@ -#pragma once - -#include "ofMain.h" -#include "ofxNetwork.h" -#include "ofxJSONElement.h" - -class TCPClient{ -public: - static shared_ptr instance(); - - void setup(string ip, int port); - void update(); - void draw(); - - void send(string message); - -private: - TCPClient(); - static shared_ptr _instance; - - ofxTCPClient _tcpClient; -}; +#pragma once + +#include "ofMain.h" +#include "ofxNetwork.h" +#include "ofxJSONElement.h" + +class TCPClient{ +public: + static shared_ptr instance(); + + void setup(string ip, int port); + void update(); + void draw(); + + void send(string message); + +private: + TCPClient(); + static shared_ptr _instance; + + ofxTCPClient _tcpClient; +}; diff --git a/example_remote-client/src/main.cpp b/example_remote-client/src/main.cpp index c696d20..527f84b 100644 --- a/example_remote-client/src/main.cpp +++ b/example_remote-client/src/main.cpp @@ -1,7 +1,7 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1280, 800, OF_WINDOW); - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" + +int main(){ + ofSetupOpenGL(1280, 800, OF_WINDOW); + ofRunApp(new ofApp()); +} diff --git a/example_remote-client/src/ofApp.cpp b/example_remote-client/src/ofApp.cpp index b12b1cc..2cec1a3 100644 --- a/example_remote-client/src/ofApp.cpp +++ b/example_remote-client/src/ofApp.cpp @@ -1,109 +1,109 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - - isMapperSetup = false; - - // Set IP address of your RasPi in data/config.json - ofxJSONElement json; - json.open("config.json"); - TCPClient::instance()->setup(json["ip"].asString(), json["port"].asInt()); -} - -void ofApp::update(){ - TCPClient::instance()->update(); - if(isMapperSetup){ - mapper.update(); - } -} - -void ofApp::draw(){ - TCPClient::instance()->draw(); - if(isMapperSetup){ - mapper.draw(); - } -} - -// This is where we get configuration from the server part of this. -void ofApp::gotMessage(ofMessage m){ - ofxJSONElement json; - bool ok = json.parse(m.message); - if(ok){ - if(json["event"] == "received"){ - std::string buffer = json["data"].asString(); - ofxXmlSettings xml; - xml.loadFromBuffer(buffer); - xml.save("ofxpimapper.xml"); - - mapper.setup(); - isMapperSetup = true; - } - } -} - -void ofApp::keyPressed(int key){ - if(isMapperSetup){ - mapper.keyPressed(key); - - ofxJSONElement json; - json["event"] = "keyPressed"; - json["key"] = key; - - TCPClient::instance()->send(json.getRawString()); - } -} - -void ofApp::keyReleased(int key){ - if(isMapperSetup){ - mapper.keyReleased(key); - - ofxJSONElement json; - json["event"] = "keyReleased"; - json["key"] = key; - - TCPClient::instance()->send(json.getRawString()); - } -} - -void ofApp::mousePressed(int x, int y, int button){ - if(isMapperSetup){ - mapper.mousePressed(x, y, button); - - ofxJSONElement json; - json["event"] = "mousePressed"; - json["x"] = x; - json["y"] = y; - json["button"] = button; - - TCPClient::instance()->send(json.getRawString()); - } -} - -void ofApp::mouseReleased(int x, int y, int button){ - if(isMapperSetup){ - mapper.mouseReleased(x, y, button); - - ofxJSONElement json; - json["event"] = "mouseReleased"; - json["x"] = x; - json["y"] = y; - json["button"] = button; - - TCPClient::instance()->send(json.getRawString()); - } -} - -void ofApp::mouseDragged(int x, int y, int button){ - if(isMapperSetup){ - mapper.mouseDragged(x, y, button); - - ofxJSONElement json; - json["event"] = "mouseDragged"; - json["x"] = x; - json["y"] = y; - json["button"] = button; - - TCPClient::instance()->send(json.getRawString()); - } -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + + isMapperSetup = false; + + // Set IP address of your RasPi in data/config.json + ofxJSONElement json; + json.open("config.json"); + TCPClient::instance()->setup(json["ip"].asString(), json["port"].asInt()); +} + +void ofApp::update(){ + TCPClient::instance()->update(); + if(isMapperSetup){ + mapper.update(); + } +} + +void ofApp::draw(){ + TCPClient::instance()->draw(); + if(isMapperSetup){ + mapper.draw(); + } +} + +// This is where we get configuration from the server part of this. +void ofApp::gotMessage(ofMessage m){ + ofxJSONElement json; + bool ok = json.parse(m.message); + if(ok){ + if(json["event"] == "received"){ + std::string buffer = json["data"].asString(); + ofxXmlSettings xml; + xml.loadFromBuffer(buffer); + xml.save("ofxpimapper.xml"); + + mapper.setup(); + isMapperSetup = true; + } + } +} + +void ofApp::keyPressed(int key){ + if(isMapperSetup){ + mapper.keyPressed(key); + + ofxJSONElement json; + json["event"] = "keyPressed"; + json["key"] = key; + + TCPClient::instance()->send(json.getRawString()); + } +} + +void ofApp::keyReleased(int key){ + if(isMapperSetup){ + mapper.keyReleased(key); + + ofxJSONElement json; + json["event"] = "keyReleased"; + json["key"] = key; + + TCPClient::instance()->send(json.getRawString()); + } +} + +void ofApp::mousePressed(int x, int y, int button){ + if(isMapperSetup){ + mapper.mousePressed(x, y, button); + + ofxJSONElement json; + json["event"] = "mousePressed"; + json["x"] = x; + json["y"] = y; + json["button"] = button; + + TCPClient::instance()->send(json.getRawString()); + } +} + +void ofApp::mouseReleased(int x, int y, int button){ + if(isMapperSetup){ + mapper.mouseReleased(x, y, button); + + ofxJSONElement json; + json["event"] = "mouseReleased"; + json["x"] = x; + json["y"] = y; + json["button"] = button; + + TCPClient::instance()->send(json.getRawString()); + } +} + +void ofApp::mouseDragged(int x, int y, int button){ + if(isMapperSetup){ + mapper.mouseDragged(x, y, button); + + ofxJSONElement json; + json["event"] = "mouseDragged"; + json["x"] = x; + json["y"] = y; + json["button"] = button; + + TCPClient::instance()->send(json.getRawString()); + } +} diff --git a/example_remote-client/src/ofApp.h b/example_remote-client/src/ofApp.h index df387f4..bfc5889 100644 --- a/example_remote-client/src/ofApp.h +++ b/example_remote-client/src/ofApp.h @@ -1,25 +1,25 @@ -#pragma once - -#include "ofMain.h" -#include "TCPClient.h" -#include "ofxPiMapper.h" -#include "ofxJSONElement.h" - -class ofApp : public ofBaseApp{ -public: - void setup(); - void update(); - void draw(); - - void gotMessage(ofMessage m); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - ofxPiMapper mapper; - bool isMapperSetup; -}; +#pragma once + +#include "ofMain.h" +#include "TCPClient.h" +#include "ofxPiMapper.h" +#include "ofxJSONElement.h" + +class ofApp : public ofBaseApp{ +public: + void setup(); + void update(); + void draw(); + + void gotMessage(ofMessage m); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + ofxPiMapper mapper; + bool isMapperSetup; +}; diff --git a/example_remote-server/Makefile b/example_remote-server/Makefile index 8d8e4c0..c83af71 100644 --- a/example_remote-server/Makefile +++ b/example_remote-server/Makefile @@ -1,13 +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 +# 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/example_remote-server/README.md b/example_remote-server/README.md index 2db8db4..0e7285d 100644 --- a/example_remote-server/README.md +++ b/example_remote-server/README.md @@ -1,25 +1,25 @@ -# Remote Control Server for ofxPiMapper - -This example demonstrates a TCP server for ofxPiMapper remote control. The other part of this is the [Remote Control Client](../example_remote-client). What it does is the following. - -- It creates a `TCPServer` singleton. -- Waits for a client to connect via TCP. -- Sends ofxPiMapper configuration once client is connected. -- Accepts keyboard and mouse events from client after. -- Forwards events to ofxPiMapper instance. - -In a real-world scenario, the server should reside on the Raspberry Pi side of your installation. The Raspberry Pi should be connected to wired or wireless network. An IP address should be set. - -The client should know the following. - -- The **IP address** of the Raspberry Pi with the server. -- The port, which is **9999** in this case. - -## Dependencies - -JSON is used as the data format between ofxPiMapper remote control server and client, therefore additionally [ofxJSON](https://github.com/jeffcrouse/ofxJSON) addon is used. Install it by using the following lines of bash code. - -``` -cd openFrameworks/addons -git clone --depth=1 https://github.com/jeffcrouse/ofxJSON -``` +# Remote Control Server for ofxPiMapper + +This example demonstrates a TCP server for ofxPiMapper remote control. The other part of this is the [Remote Control Client](../example_remote-client). What it does is the following. + +- It creates a `TCPServer` singleton. +- Waits for a client to connect via TCP. +- Sends ofxPiMapper configuration once client is connected. +- Accepts keyboard and mouse events from client after. +- Forwards events to ofxPiMapper instance. + +In a real-world scenario, the server should reside on the Raspberry Pi side of your installation. The Raspberry Pi should be connected to wired or wireless network. An IP address should be set. + +The client should know the following. + +- The **IP address** of the Raspberry Pi with the server. +- The port, which is **9999** in this case. + +## Dependencies + +JSON is used as the data format between ofxPiMapper remote control server and client, therefore additionally [ofxJSON](https://github.com/jeffcrouse/ofxJSON) addon is used. Install it by using the following lines of bash code. + +``` +cd openFrameworks/addons +git clone --depth=1 https://github.com/jeffcrouse/ofxJSON +``` diff --git a/example_remote-server/addons.make b/example_remote-server/addons.make index 4205a02..9819b47 100644 --- a/example_remote-server/addons.make +++ b/example_remote-server/addons.make @@ -1,6 +1,6 @@ -ofxGui -ofxJSON -ofxNetwork -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxJSON +ofxNetwork +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_remote-server/addons.make.norpi b/example_remote-server/addons.make.norpi index cd0471e..35de469 100644 --- a/example_remote-server/addons.make.norpi +++ b/example_remote-server/addons.make.norpi @@ -1,5 +1,5 @@ -ofxGui -ofxJSON -ofxNetwork -ofxPiMapper -ofxXmlSettings +ofxGui +ofxJSON +ofxNetwork +ofxPiMapper +ofxXmlSettings diff --git a/example_remote-server/bin/data/ofxpimapper.xml b/example_remote-server/bin/data/ofxpimapper.xml index 54f551c..340d7df 100644 --- a/example_remote-server/bin/data/ofxpimapper.xml +++ b/example_remote-server/bin/data/ofxpimapper.xml @@ -1,36 +1,36 @@ - - - - - 640.000000000 - 50.000000000 - - - 1230.000000000 - 750.000000000 - - - 50.000000000 - 750.000000000 - - - - - 0.500000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - gene-nsynthesis.jpg - - - + + + + + 640.000000000 + 50.000000000 + + + 1230.000000000 + 750.000000000 + + + 50.000000000 + 750.000000000 + + + + + 0.500000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + gene-nsynthesis.jpg + + + diff --git a/example_remote-server/src/TCPServer.cpp b/example_remote-server/src/TCPServer.cpp index 2bfa21a..7487f08 100644 --- a/example_remote-server/src/TCPServer.cpp +++ b/example_remote-server/src/TCPServer.cpp @@ -1,95 +1,95 @@ -#include "TCPServer.h" - -shared_ptr TCPServer::_instance = 0; - -shared_ptr TCPServer::instance(){ - if(_instance == 0){ - _instance = shared_ptr(new TCPServer); - } - return _instance; -} - -TCPServer::TCPServer(){ - std::cout << "TCPServer initialized" << std::endl; -} - -void TCPServer::setup(int port){ - _tcpServer.setup(port); -} - -void TCPServer::update(){ - int numClients = _tcpServer.getLastID(); - for(auto i = 0; i < numClients; ++i){ - if(_tcpServer.isClientConnected(i)){ - - // Notify application when new client connects - if(!_tcpConnections[i]){ - ofxJSONElement json; - json["ip"] = _tcpServer.getClientIP(i); - json["port"] = _tcpServer.getClientPort(i); - json["id"] = i; - json["event"] = "connected"; - - ofMessage message(json.getRawString()); - ofSendMessage(message); - - _tcpConnections[i] = true; - } - - // Receive messages - string rx = _tcpServer.receive(i); - if(rx.length() > 0){ - ofxJSONElement json; - bool ok = json.parse(rx); - - if(!ok){ - json["ip"] = _tcpServer.getClientIP(i); - json["port"] = _tcpServer.getClientPort(i); - json["id"] = i; - json["event"] = "received"; - json["data"] = rx; - } - - ofMessage message(json.getRawString()); - ofSendMessage(message); - } - }else{ - - // Notify application when client disconnects - if(_tcpConnections[i]){ - ofxJSONElement json; - json["ip"] = _tcpServer.getClientIP(i); - json["port"] = _tcpServer.getClientPort(i); - json["id"] = i; - json["event"] = "disconnected"; - - ofMessage message(json.getRawString()); - ofSendMessage(message); - - _tcpConnections[i] = false; - } - } - } -} - -void TCPServer::draw(){ - int numClients = _tcpServer.getLastID(); - int clientsConnected = 0; - for(auto i = 0; i < numClients; ++i){ - if(_tcpServer.isClientConnected(i)){ - ofPushMatrix(); - ofTranslate(10, 10); - ofPushStyle(); - ofSetColor(0, 255, 0); - ofDrawRectangle(clientsConnected * 20, 0, 10, 10); - ofPopStyle(); - ofPopMatrix(); - clientsConnected++; - } - } -} - -void TCPServer::send(int clientID, std::string message){ - _tcpServer.send(clientID, message); -} - +#include "TCPServer.h" + +shared_ptr TCPServer::_instance = 0; + +shared_ptr TCPServer::instance(){ + if(_instance == 0){ + _instance = shared_ptr(new TCPServer); + } + return _instance; +} + +TCPServer::TCPServer(){ + std::cout << "TCPServer initialized" << std::endl; +} + +void TCPServer::setup(int port){ + _tcpServer.setup(port); +} + +void TCPServer::update(){ + int numClients = _tcpServer.getLastID(); + for(auto i = 0; i < numClients; ++i){ + if(_tcpServer.isClientConnected(i)){ + + // Notify application when new client connects + if(!_tcpConnections[i]){ + ofxJSONElement json; + json["ip"] = _tcpServer.getClientIP(i); + json["port"] = _tcpServer.getClientPort(i); + json["id"] = i; + json["event"] = "connected"; + + ofMessage message(json.getRawString()); + ofSendMessage(message); + + _tcpConnections[i] = true; + } + + // Receive messages + string rx = _tcpServer.receive(i); + if(rx.length() > 0){ + ofxJSONElement json; + bool ok = json.parse(rx); + + if(!ok){ + json["ip"] = _tcpServer.getClientIP(i); + json["port"] = _tcpServer.getClientPort(i); + json["id"] = i; + json["event"] = "received"; + json["data"] = rx; + } + + ofMessage message(json.getRawString()); + ofSendMessage(message); + } + }else{ + + // Notify application when client disconnects + if(_tcpConnections[i]){ + ofxJSONElement json; + json["ip"] = _tcpServer.getClientIP(i); + json["port"] = _tcpServer.getClientPort(i); + json["id"] = i; + json["event"] = "disconnected"; + + ofMessage message(json.getRawString()); + ofSendMessage(message); + + _tcpConnections[i] = false; + } + } + } +} + +void TCPServer::draw(){ + int numClients = _tcpServer.getLastID(); + int clientsConnected = 0; + for(auto i = 0; i < numClients; ++i){ + if(_tcpServer.isClientConnected(i)){ + ofPushMatrix(); + ofTranslate(10, 10); + ofPushStyle(); + ofSetColor(0, 255, 0); + ofDrawRectangle(clientsConnected * 20, 0, 10, 10); + ofPopStyle(); + ofPopMatrix(); + clientsConnected++; + } + } +} + +void TCPServer::send(int clientID, std::string message){ + _tcpServer.send(clientID, message); +} + diff --git a/example_remote-server/src/TCPServer.h b/example_remote-server/src/TCPServer.h index a6be1c2..837720d 100644 --- a/example_remote-server/src/TCPServer.h +++ b/example_remote-server/src/TCPServer.h @@ -1,23 +1,23 @@ -#pragma once - -#include "ofMain.h" -#include "ofxNetwork.h" -#include "ofxJSONElement.h" - -class TCPServer { -public: - static shared_ptr instance(); - - void setup(int port); - void update(); - void draw(); - - void send(int clientID, std::string message); - -private: - TCPServer(); - static shared_ptr _instance; - - ofxTCPServer _tcpServer; - std::map _tcpConnections; -}; +#pragma once + +#include "ofMain.h" +#include "ofxNetwork.h" +#include "ofxJSONElement.h" + +class TCPServer { +public: + static shared_ptr instance(); + + void setup(int port); + void update(); + void draw(); + + void send(int clientID, std::string message); + +private: + TCPServer(); + static shared_ptr _instance; + + ofxTCPServer _tcpServer; + std::map _tcpConnections; +}; diff --git a/example_remote-server/src/main.cpp b/example_remote-server/src/main.cpp index c696d20..527f84b 100644 --- a/example_remote-server/src/main.cpp +++ b/example_remote-server/src/main.cpp @@ -1,7 +1,7 @@ -#include "ofMain.h" -#include "ofApp.h" - -int main(){ - ofSetupOpenGL(1280, 800, OF_WINDOW); - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" + +int main(){ + ofSetupOpenGL(1280, 800, OF_WINDOW); + ofRunApp(new ofApp()); +} diff --git a/example_remote-server/src/ofApp.cpp b/example_remote-server/src/ofApp.cpp index 7532328..8c62ad9 100644 --- a/example_remote-server/src/ofApp.cpp +++ b/example_remote-server/src/ofApp.cpp @@ -1,84 +1,84 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - mapper.setup(); - TCPServer::instance()->setup(9999); - -#ifdef TARGET_RASPBERRY_PI - ofSetFullscreen(true); -#endif -} - -void ofApp::update(){ - mapper.update(); - TCPServer::instance()->update(); -} - -void ofApp::draw(){ - mapper.draw(); - TCPServer::instance()->draw(); -} - -// Here is where we process messages received from TCPServer instance -void ofApp::gotMessage(ofMessage m){ - std::cout << m.message << std::endl; - - ofxJSONElement json; - bool ok = json.parse(m.message); - if(ok){ - if(json["event"].asString() == "connected"){ - // Save Mapper composition and get config as string - std::cout << "Sending mapper config" << std::endl; - mapper.saveProject(); - - ofFile file; - file.open(ofToDataPath("ofxpimapper.xml"), ofFile::ReadOnly, false); - ofBuffer buff = file.readToBuffer(); - string text = buff.getText(); - - TCPServer::instance()->send(json["id"].asInt(), text); - } - - if(json["event"].asString() == "keyPressed"){ - mapper.keyPressed(json["key"].asInt()); - } - - if(json["event"].asString() == "keyReleased"){ - mapper.keyReleased(json["key"].asInt()); - } - - if(json["event"].asString() == "mousePressed"){ - mapper.mousePressed(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); - } - - if(json["event"].asString() == "mouseReleased"){ - mapper.mouseReleased(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); - } - - if(json["event"].asString() == "mouseDragged"){ - mapper.mouseDragged(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); - } - } -} - -void ofApp::keyPressed(int key){ - mapper.keyPressed(key); -} - -void ofApp::keyReleased(int key){ - mapper.keyReleased(key); -} - -void ofApp::mousePressed(int x, int y, int button){ - mapper.mousePressed(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - mapper.mouseReleased(x, y, button); -} - -void ofApp::mouseDragged(int x, int y, int button){ - mapper.mouseDragged(x, y, button); -} - +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + mapper.setup(); + TCPServer::instance()->setup(9999); + +#ifdef TARGET_RASPBERRY_PI + ofSetFullscreen(true); +#endif +} + +void ofApp::update(){ + mapper.update(); + TCPServer::instance()->update(); +} + +void ofApp::draw(){ + mapper.draw(); + TCPServer::instance()->draw(); +} + +// Here is where we process messages received from TCPServer instance +void ofApp::gotMessage(ofMessage m){ + std::cout << m.message << std::endl; + + ofxJSONElement json; + bool ok = json.parse(m.message); + if(ok){ + if(json["event"].asString() == "connected"){ + // Save Mapper composition and get config as string + std::cout << "Sending mapper config" << std::endl; + mapper.saveProject(); + + ofFile file; + file.open(ofToDataPath("ofxpimapper.xml"), ofFile::ReadOnly, false); + ofBuffer buff = file.readToBuffer(); + string text = buff.getText(); + + TCPServer::instance()->send(json["id"].asInt(), text); + } + + if(json["event"].asString() == "keyPressed"){ + mapper.keyPressed(json["key"].asInt()); + } + + if(json["event"].asString() == "keyReleased"){ + mapper.keyReleased(json["key"].asInt()); + } + + if(json["event"].asString() == "mousePressed"){ + mapper.mousePressed(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); + } + + if(json["event"].asString() == "mouseReleased"){ + mapper.mouseReleased(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); + } + + if(json["event"].asString() == "mouseDragged"){ + mapper.mouseDragged(json["x"].asInt(), json["y"].asInt(), json["button"].asInt()); + } + } +} + +void ofApp::keyPressed(int key){ + mapper.keyPressed(key); +} + +void ofApp::keyReleased(int key){ + mapper.keyReleased(key); +} + +void ofApp::mousePressed(int x, int y, int button){ + mapper.mousePressed(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + mapper.mouseReleased(x, y, button); +} + +void ofApp::mouseDragged(int x, int y, int button){ + mapper.mouseDragged(x, y, button); +} + diff --git a/example_remote-server/src/ofApp.h b/example_remote-server/src/ofApp.h index 6c95a21..9abbc0d 100644 --- a/example_remote-server/src/ofApp.h +++ b/example_remote-server/src/ofApp.h @@ -1,23 +1,23 @@ -#pragma once - -#include "ofMain.h" -#include "TCPServer.h" -#include "ofxPiMapper.h" -#include "ofxJSONElement.h" - -class ofApp : public ofBaseApp{ -public: - void setup(); - void update(); - void draw(); - - void gotMessage(ofMessage m); - - void keyPressed(int key); - void keyReleased(int key); - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - ofxPiMapper mapper; -}; +#pragma once + +#include "ofMain.h" +#include "TCPServer.h" +#include "ofxPiMapper.h" +#include "ofxJSONElement.h" + +class ofApp : public ofBaseApp{ +public: + void setup(); + void update(); + void draw(); + + void gotMessage(ofMessage m); + + void keyPressed(int key); + void keyReleased(int key); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + ofxPiMapper mapper; +}; diff --git a/example_simpler/.gitignore b/example_simpler/.gitignore index e4d4b5d..ad71cfd 100644 --- a/example_simpler/.gitignore +++ b/example_simpler/.gitignore @@ -1,5 +1,5 @@ -obj -*.xcworkspace -*.xcuserdatad -*~ -config.make +obj +*.xcworkspace +*.xcuserdatad +*~ +config.make diff --git a/example_simpler/Makefile b/example_simpler/Makefile index 8d8e4c0..c83af71 100644 --- a/example_simpler/Makefile +++ b/example_simpler/Makefile @@ -1,13 +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 +# 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/example_simpler/addons.make b/example_simpler/addons.make index 963941c..596425d 100644 --- a/example_simpler/addons.make +++ b/example_simpler/addons.make @@ -1,4 +1,4 @@ -ofxGui -ofxPiMapper -ofxXmlSettings -ofxOMXPlayer +ofxGui +ofxPiMapper +ofxXmlSettings +ofxOMXPlayer diff --git a/example_simpler/addons.make.norpi b/example_simpler/addons.make.norpi index e72d2dd..69d8f94 100644 --- a/example_simpler/addons.make.norpi +++ b/example_simpler/addons.make.norpi @@ -1,3 +1,3 @@ -ofxGui -ofxPiMapper -ofxXmlSettings +ofxGui +ofxPiMapper +ofxXmlSettings diff --git a/example_simpler/bin/data/ofxpimapper.xml b/example_simpler/bin/data/ofxpimapper.xml index 1c44003..c75d65b 100644 --- a/example_simpler/bin/data/ofxpimapper.xml +++ b/example_simpler/bin/data/ofxpimapper.xml @@ -1,81 +1,81 @@ - - - - - 193.000000000 - 58.187255859 - - - 466.000000000 - 413.000000000 - - - 39.374511719 - 211.812774658 - - - - - -0.006000000 - -0.014000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - image - image4.jpg - - - - - - 758.067382812 - 360.033691406 - - - 1125.932617188 - 360.033691406 - - - 1129.000000000 - 719.000000000 - - - 759.000000000 - 721.000000000 - - - - - 0.000000000 - 0.000000000 - - - 1.000000000 - 0.000000000 - - - 1.000000000 - 1.000000000 - - - 0.000000000 - 1.000000000 - - - - fbo - Custom FBO Source - - - 1 - - - + + + + + 193.000000000 + 58.187255859 + + + 466.000000000 + 413.000000000 + + + 39.374511719 + 211.812774658 + + + + + -0.006000000 + -0.014000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + image + image4.jpg + + + + + + 758.067382812 + 360.033691406 + + + 1125.932617188 + 360.033691406 + + + 1129.000000000 + 719.000000000 + + + 759.000000000 + 721.000000000 + + + + + 0.000000000 + 0.000000000 + + + 1.000000000 + 0.000000000 + + + 1.000000000 + 1.000000000 + + + 0.000000000 + 1.000000000 + + + + fbo + Custom FBO Source + + + 1 + + + diff --git a/example_simpler/src/CustomSource.cpp b/example_simpler/src/CustomSource.cpp index f5eb1d0..4840bbc 100644 --- a/example_simpler/src/CustomSource.cpp +++ b/example_simpler/src/CustomSource.cpp @@ -1,41 +1,41 @@ -#include "CustomSource.h" - -void CustomSource::setup(){ - // Give our source a decent name - name = "Custom FBO Source"; - - // Allocate our FBO source, decide how big it should be - allocate(500, 500); - - // Genereate rects to be rendered into the FBO - int numRects = 20; // change this to add more or less rects - for(int i = 0; i < numRects; i++){ - rects.push_back(ofRectangle(0, - ofRandom(fbo->getHeight()), - fbo->getWidth(), - ofRandom(20))); - rectSpeeds.push_back((1.0f + ofRandom(5))); - } -} - -// Don't do any drawing here -void CustomSource::update(){ - // Move rects - for(int i = 0; i < rects.size(); i++){ - rects[i].y += rectSpeeds[i]; - if(rects[i].y > fbo->getHeight()){ - rects[i].y = -rects[i].getHeight(); - } - } -} - -// No need to take care of fbo.begin() and fbo.end() here. -// All within draw() is being rendered into fbo; -void CustomSource::draw(){ - // Fill FBO with our rects - ofClear(0); - ofSetColor(255); - for(int i = 0; i < rects.size(); i++){ - ofDrawRectangle(rects[i]); - } -} +#include "CustomSource.h" + +void CustomSource::setup(){ + // Give our source a decent name + name = "Custom FBO Source"; + + // Allocate our FBO source, decide how big it should be + allocate(500, 500); + + // Genereate rects to be rendered into the FBO + int numRects = 20; // change this to add more or less rects + for(int i = 0; i < numRects; i++){ + rects.push_back(ofRectangle(0, + ofRandom(fbo->getHeight()), + fbo->getWidth(), + ofRandom(20))); + rectSpeeds.push_back((1.0f + ofRandom(5))); + } +} + +// Don't do any drawing here +void CustomSource::update(){ + // Move rects + for(int i = 0; i < rects.size(); i++){ + rects[i].y += rectSpeeds[i]; + if(rects[i].y > fbo->getHeight()){ + rects[i].y = -rects[i].getHeight(); + } + } +} + +// No need to take care of fbo.begin() and fbo.end() here. +// All within draw() is being rendered into fbo; +void CustomSource::draw(){ + // Fill FBO with our rects + ofClear(0); + ofSetColor(255); + for(int i = 0; i < rects.size(); i++){ + ofDrawRectangle(rects[i]); + } +} diff --git a/example_simpler/src/CustomSource.h b/example_simpler/src/CustomSource.h index a473d73..9506198 100644 --- a/example_simpler/src/CustomSource.h +++ b/example_simpler/src/CustomSource.h @@ -1,14 +1,14 @@ -#pragma once - -#include "ofMain.h" -#include "FboSource.h" - -class CustomSource : public ofx::piMapper::FboSource { - public: - void setup(); - void update(); - void draw(); - - std::vector rects; - std::vector rectSpeeds; +#pragma once + +#include "ofMain.h" +#include "FboSource.h" + +class CustomSource : public ofx::piMapper::FboSource { + public: + void setup(); + void update(); + void draw(); + + std::vector rects; + std::vector rectSpeeds; }; \ No newline at end of file diff --git a/example_simpler/src/Settings.cpp b/example_simpler/src/Settings.cpp index 509371e..0d9dd73 100644 --- a/example_simpler/src/Settings.cpp +++ b/example_simpler/src/Settings.cpp @@ -1,22 +1,22 @@ -#include "Settings.h" - -Settings * Settings::_instance = 0; - -Settings * Settings::instance(){ - if(_instance == 0){ - _instance = new Settings(); - } - return _instance; -} - -Settings::Settings(){ - _fullscreen = false; -} - -void Settings::setFullscreen(bool f){ - _fullscreen = f; -} - -bool Settings::getFullscreen(){ - return _fullscreen; +#include "Settings.h" + +Settings * Settings::_instance = 0; + +Settings * Settings::instance(){ + if(_instance == 0){ + _instance = new Settings(); + } + return _instance; +} + +Settings::Settings(){ + _fullscreen = false; +} + +void Settings::setFullscreen(bool f){ + _fullscreen = f; +} + +bool Settings::getFullscreen(){ + return _fullscreen; } \ No newline at end of file diff --git a/example_simpler/src/Settings.h b/example_simpler/src/Settings.h index db3db66..7adbab2 100644 --- a/example_simpler/src/Settings.h +++ b/example_simpler/src/Settings.h @@ -1,18 +1,18 @@ -#pragma once - -#include "ofMain.h" - -class Settings { - public: - static Settings * instance(); - - void setFullscreen(bool f); - bool getFullscreen(); - - private: - static Settings * _instance; - - Settings(); - - bool _fullscreen; -}; +#pragma once + +#include "ofMain.h" + +class Settings { + public: + static Settings * instance(); + + void setFullscreen(bool f); + bool getFullscreen(); + + private: + static Settings * _instance; + + Settings(); + + bool _fullscreen; +}; diff --git a/example_simpler/src/main.cpp b/example_simpler/src/main.cpp index 764dcff..3f1cdc4 100644 --- a/example_simpler/src/main.cpp +++ b/example_simpler/src/main.cpp @@ -1,22 +1,22 @@ -#include "ofMain.h" -#include "ofApp.h" -#include -#include -#include "Settings.h" - -int main(int argc, char * argv[]){ - bool fullscreen = false; - - std::vector arguments = std::vector(argv, argv + argc); - for(int i = 0; i < arguments.size(); ++i){ - if(arguments.at(i) == "-f"){ - fullscreen = true; - break; - } - } - - Settings::instance()->setFullscreen(fullscreen); - - ofSetupOpenGL(800, 450, OF_WINDOW); - ofRunApp(new ofApp()); -} +#include "ofMain.h" +#include "ofApp.h" +#include +#include +#include "Settings.h" + +int main(int argc, char * argv[]){ + bool fullscreen = false; + + std::vector arguments = std::vector(argv, argv + argc); + for(int i = 0; i < arguments.size(); ++i){ + if(arguments.at(i) == "-f"){ + fullscreen = true; + break; + } + } + + Settings::instance()->setFullscreen(fullscreen); + + ofSetupOpenGL(800, 450, OF_WINDOW); + ofRunApp(new ofApp()); +} diff --git a/example_simpler/src/ofApp.cpp b/example_simpler/src/ofApp.cpp index 02ba925..f39d1a7 100644 --- a/example_simpler/src/ofApp.cpp +++ b/example_simpler/src/ofApp.cpp @@ -1,55 +1,55 @@ -#include "ofApp.h" - -void ofApp::setup(){ - ofBackground(0); - - // Enable or disable audio for video sources globally - // Set this to false to save resources on the Raspberry Pi - ofx::piMapper::VideoSource::enableAudio = true; - ofx::piMapper::VideoSource::useHDMIForAudio = false; - - // Add our CustomSource to list of fbo sources of the piMapper - // FBO sources should be added before piMapper.setup() so the - // piMapper is able to load the source if it is assigned to - // a surface in XML settings. - customSource = new CustomSource(); - piMapper.registerFboSource(customSource); - piMapper.setup(); - - // The info layer is hidden by default, press to toggle - // piMapper.showInfo(); - - ofSetFullscreen(Settings::instance()->getFullscreen()); - ofSetEscapeQuitsApp(false); - - dummyObjects.load("dummy-objects.png"); -} - -void ofApp::update(){ - piMapper.update(); -} - -void ofApp::draw(){ - dummyObjects.draw(200,200); - piMapper.draw(); -} - -void ofApp::keyPressed(int key){ - piMapper.keyPressed(key); -} - -void ofApp::keyReleased(int key){ - piMapper.keyReleased(key); -} - -void ofApp::mousePressed(int x, int y, int button){ - piMapper.mousePressed(x, y, button); -} - -void ofApp::mouseReleased(int x, int y, int button){ - piMapper.mouseReleased(x, y, button); -} - -void ofApp::mouseDragged(int x, int y, int button){ - piMapper.mouseDragged(x, y, button); -} +#include "ofApp.h" + +void ofApp::setup(){ + ofBackground(0); + + // Enable or disable audio for video sources globally + // Set this to false to save resources on the Raspberry Pi + ofx::piMapper::VideoSource::enableAudio = true; + ofx::piMapper::VideoSource::useHDMIForAudio = false; + + // Add our CustomSource to list of fbo sources of the piMapper + // FBO sources should be added before piMapper.setup() so the + // piMapper is able to load the source if it is assigned to + // a surface in XML settings. + customSource = new CustomSource(); + piMapper.registerFboSource(customSource); + piMapper.setup(); + + // The info layer is hidden by default, press to toggle + // piMapper.showInfo(); + + ofSetFullscreen(Settings::instance()->getFullscreen()); + ofSetEscapeQuitsApp(false); + + dummyObjects.load("dummy-objects.png"); +} + +void ofApp::update(){ + piMapper.update(); +} + +void ofApp::draw(){ + dummyObjects.draw(200,200); + piMapper.draw(); +} + +void ofApp::keyPressed(int key){ + piMapper.keyPressed(key); +} + +void ofApp::keyReleased(int key){ + piMapper.keyReleased(key); +} + +void ofApp::mousePressed(int x, int y, int button){ + piMapper.mousePressed(x, y, button); +} + +void ofApp::mouseReleased(int x, int y, int button){ + piMapper.mouseReleased(x, y, button); +} + +void ofApp::mouseDragged(int x, int y, int button){ + piMapper.mouseDragged(x, y, button); +} diff --git a/example_simpler/src/ofApp.h b/example_simpler/src/ofApp.h index 75c7f10..4915c6f 100644 --- a/example_simpler/src/ofApp.h +++ b/example_simpler/src/ofApp.h @@ -1,28 +1,28 @@ -#pragma once - -#include "ofMain.h" -#include "Settings.h" -#include "ofxPiMapper.h" -#include "CustomSource.h" -#include "VideoSource.h" - -class ofApp : public ofBaseApp { - public: - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - ofxPiMapper piMapper; - - // By using a custom source that is derived from FboSource - // you will be able to see the source listed in sources editor - CustomSource * customSource; - ofImage dummyObjects; -}; +#pragma once + +#include "ofMain.h" +#include "Settings.h" +#include "ofxPiMapper.h" +#include "CustomSource.h" +#include "VideoSource.h" + +class ofApp : public ofBaseApp { + public: + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + ofxPiMapper piMapper; + + // By using a custom source that is derived from FboSource + // you will be able to see the source listed in sources editor + CustomSource * customSource; + ofImage dummyObjects; +}; diff --git a/patches/msys2/makefileCommon/config.addons.mk b/patches/msys2/makefileCommon/config.addons.mk index 4b38a3d..68ecdf6 100644 --- a/patches/msys2/makefileCommon/config.addons.mk +++ b/patches/msys2/makefileCommon/config.addons.mk @@ -1,266 +1,266 @@ -######################################################################## -# PROCESS VALID ADDONS IF AVAILABLE -######################################################################## - - -# parses addons includes, in PARSED_ADDON_INCLUDES receives full PATHS to addons -define parse_addons_includes - $(eval ADDONS_INCLUDES_FILTER = $(addprefix $1/, $(ADDON_INCLUDES_EXCLUDE))) \ - $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ - $(eval PARSED_ADDONS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_FILTERED_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_SOURCE_INCLUDES))) \ - $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ - $(eval PARSED_ADDONS_LIBS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_SOURCE_INCLUDES))) \ - $(eval PARSED_ADDONS_LIBS_INCLUDES_PATHS = $(addsuffix /libs/*/include, $1)) \ - $(eval PARSED_ADDONS_LIBS_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_INCLUDES_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_FILTERED_LIBS_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_INCLUDES))) \ - $(eval PARSED_ADDONS_INCLUDES = $(PARSED_ADDONS_FILTERED_INCLUDE_PATHS)) \ - $(eval PARSED_ADDONS_INCLUDES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS)) \ - $(eval PARSED_ADDONS_INCLUDES += $(PARSED_ADDONS_FILTERED_LIBS_INCLUDE_PATHS)) -endef - -# parses addons sources, in PARSED_ADDON_SOURCES receives full PATHS to addons -define parse_addons_sources - $(eval ADDONS_SOURCES_FILTER = $(addprefix $1/, $(ADDON_SOURCES_EXCLUDE))) \ - $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ - $(eval PARSED_ADDONS_OFX_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_FILTERED_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_OFX_SOURCES))) \ - $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ - $(eval PARSED_ADDONS_LIBS_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_LIBS_SOURCES))) \ - $(eval PARSED_ADDONS_SOURCE_FILES = $(PARSED_ADDONS_FILTERED_SOURCE_PATHS)) \ - $(eval PARSED_ADDONS_SOURCE_FILES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS)) -endef - -# parses addons libraries, in PARSED_ADDON_LIBS receives full PATHS to addons and libs_exclude -define parse_addons_libraries - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS = $(filter-out $(ADDON_LIBS_EXCLUDE),$(addsuffix /libs/*/lib/$(ABI_LIB_SUBPATH), $1))) \ - $(eval PARSED_ALL_PLATFORM_LIBS = $(shell $(FIND) $(PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(if $(PARSED_ALL_PLATFORM_LIBS), \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.a 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.so 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dylib 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dll 2> /dev/null | grep -v "/\.[^\.]" )) \ - $(eval PARSED_ADDONS_LIBS = $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS)) \ - $(eval PARSED_ADDONS_LIBS += $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED)) \ - ) -endef - - -space := -space += - -define src_to_obj - $(addsuffix .o,$(basename $(filter %.c %.cpp %.cc %.cxx %.cc %.s %.S, $(addprefix $3,$(addprefix $2,$1))))) -endef - -define rwildcard - $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)$(filter $(subst *,%,$2),$d)) -endef - -# PARSE addon_config.mk FILES -# -# 1. read the addon_config.mk file for each adddon that has it -# 2. read each line of the addon by converting \n to \t since makefiles treat \n as spaces -# also convert spaces to ? so foreach works for each line instead of each word -# 3. unscape ? to space inside the loop -# 4. if the line matches common: or platform: set the PROCESS_NEXT flag to true -# 5. if the line matches %: but it's not common or platform: set PROCESS_NEXT to false -# 6: if PROCESS_NEXT eval the line to put the variable in the makefile space -define parse_addon - $(if $(wildcard $(PROJECT_ROOT)/$1), \ - $(eval addon=$(realpath $(addprefix $(PROJECT_ROOT)/, $1))) \ - $(eval addon_obj_path=$(PROJECT_ROOT)) \ - $(eval ADDON_PATHS+= $(dir $(addon))) \ - $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)addons/) \ - , \ - $(eval addon=$(realpath $(addprefix $(OF_ADDONS_PATH)/, $1))) \ - $(eval addon_obj_path=$(OF_ADDONS_PATH)) \ - $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)) \ - ) \ - $(eval ADDON_DEPENDENCIES= ) \ - $(eval ADDON_DATA= ) \ - $(eval ADDON_CFLAGS= ) \ - $(eval ADDON_CPPFLAGS= ) \ - $(eval ADDON_LDFLAGS= ) \ - $(eval ADDON_PKG_CONFIG_LIBRARIES= ) \ - $(eval ADDON_FRAMEWORKS= ) \ - $(eval ADDON_LIBS_EXCLUDE= ) \ - $(eval ADDON_SOURCES_EXCLUDE= ) \ - $(call parse_addons_includes, $(addon)) \ - $(eval ADDON_INCLUDES=$(PARSED_ADDONS_INCLUDES)) \ - $(call parse_addons_libraries, $(addon)) \ - $(eval ADDON_LIBS=$(PARSED_ADDONS_LIBS)) \ - $(call parse_addons_sources, $(addon)) \ - $(eval ADDON_SOURCES=$(PARSED_ADDONS_SOURCE_FILES)) \ - $(eval PROCESS_NEXT=0) \ - $(if $(wildcard $(addon)/addon_config.mk), \ - $(foreach var_line, $(shell cat $(addon)/addon_config.mk | tr '\n ' '\t?'), \ - $(eval unscaped_var_line=$(strip $(subst ?, ,$(var_line)))) \ - $(if $(filter $(PROCESS_NEXT),1), $(eval $(unscaped_var_line))) \ - $(if $(filter %:,$(unscaped_var_line)), \ - $(if $(filter common:,$(unscaped_var_line)), \ - $(eval PROCESS_NEXT=1), \ - $(if $(filter $(ABI_LIB_SUBPATH):,$(unscaped_var_line)), \ - $(eval PROCESS_NEXT=1), \ - $(eval PROCESS_NEXT=0) \ - ) \ - ) \ - ) \ - ) \ - ) \ - $(if $(strip $(ADDON_INCLUDES)), \ - $(eval ADDON_INCLUDES_FILTERED = $(filter-out $(addprefix $(addon)/,$(ADDON_INCLUDES_EXCLUDE)),$(ADDON_INCLUDES))) \ - $(foreach addon_include, $(strip $(ADDON_INCLUDES_FILTERED)), \ - $(if $(wildcard $(addon)/$(addon_include)), \ - $(eval TMP_PROJECT_ADDONS_INCLUDES += $(addon)/$(addon_include)) \ - ) \ - $(if $(wildcard $(addon_include)), \ - $(eval TMP_PROJECT_ADDONS_INCLUDES += $(addon_include)) \ - ) \ - ) \ - ) \ - $(eval TMP_PROJECT_ADDONS_CFLAGS += $(ADDON_CFLAGS)) \ - $(eval TMP_PROJECT_ADDONS_CFLAGS += $(ADDON_CPPFLAGS)) \ - $(if $(strip $(ADDON_LIBS)), \ - $(foreach addon_lib, $(strip $(ADDON_LIBS)), \ - $(if $(wildcard $(addon)/$(addon_lib)), \ - $(eval TMP_PROJECT_ADDONS_LIBS += $(addon)/$(addon_lib)) \ - ) \ - $(if $(wildcard $(addon_lib)), \ - $(eval TMP_PROJECT_ADDONS_LIBS += $(addon_lib)) \ - ) \ - ) \ - ) \ - $(eval TMP_PROJECT_ADDONS_LDFLAGS += $(ADDON_LDFLAGS)) \ - $(eval TMP_PROJECT_ADDONS_PKG_CONFIG_LIBRARIES += $(ADDON_PKG_CONFIG_LIBRARIES)) \ - $(eval TMP_PROJECT_ADDONS_FRAMEWORKS += $(ADDON_FRAMEWORKS)) \ - $(eval PROJECT_AFTER += $(ADDON_AFTER)) \ - $(if $(strip $(ADDON_SOURCES)), \ - $(eval ADDON_SOURCES_FILTERED = $(filter-out $(addprefix $(addon)/,$(ADDON_SOURCES_EXCLUDE)),$(ADDON_SOURCES))) \ - $(foreach addon_src, $(strip $(ADDON_SOURCES_FILTERED)), \ - $(if $(filter $(addon)%, $(addon_src)), \ - $(eval addon_path=$(subst %,*,$(addon_src))) \ - $(if $(findstring *,$(addon_path)), \ - $(eval addon_dir=$(dir $(addon_path))) \ - $(eval addon_rest=$(notdir $(addon_path))) \ - $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ - $(foreach expanded_addon_src, $(addon_files), \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ - $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(expanded_addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - , \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ - $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - , \ - $(if $(filter $(OF_ROOT)%, $(addon_src)), \ - $(eval addon_path=$(subst %,*,$(addon_src))) \ - $(if $(findstring *,$(addon_path)), \ - $(eval addon_dir=$(dir $(addon_src))) \ - $(eval addon_rest=$(notdir $(addon_src))) \ - $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ - $(foreach expanded_addon_src, $(addon_files), \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ - $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(expanded_addon_src:$(OF_ROOT)/%=%),,$(obj_prefix)))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - , \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ - $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(addon_src:$(OF_ROOT)/%=%),,$(obj_prefix)))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - ,$(if $(filter-out /%, $(addon_src)), \ - $(eval addon_path=$(addon)/$(subst %,*,$(addon_src))) \ - $(if $(findstring *,$(addon_path)), \ - $(eval addon_dir=$(dir $(addon_path))) \ - $(eval addon_rest=$(notdir $(addon_path))) \ - $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ - $(foreach expanded_addon_src, $(addon_files), \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ - $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(expanded_addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - , \ - $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_path)) \ - $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(addon_path:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ - $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ - ) \ - ,$(error cannot find addon source file $(addon_src))) \ - ) \ - ) \ - ) \ - ) \ - $(if $(strip $(ADDON_DATA)), \ - $(eval TMP_PROJECT_ADDONS_DATA += $(addprefix $(addon)/,$(ADDON_DATA))) \ - ) \ - $(foreach addon_dep, $(strip $(ADDON_DEPENDENCIES)), \ - $(if $(filter %$(addon_dep), $(PROJECT_ADDONS)), \ - , \ - $(eval PROJECT_ADDONS += $(addon_dep)) \ - $(call parse_addon,$(addon_dep)) \ - ) \ - ) -endef - - -$(foreach addon_to_parse, $(PROJECT_ADDONS), \ - $(call parse_addon,$(addon_to_parse)) \ -) - -#define uniq = -# $(eval seen :=) -# $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_))) -# ${seen} -#endef - - -uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) - - -PROJECT_ADDONS_CFLAGS = $(call uniq,$(TMP_PROJECT_ADDONS_CFLAGS)) -PROJECT_ADDONS_INCLUDES = $(call uniq,$(TMP_PROJECT_ADDONS_INCLUDES)) -PROJECT_ADDONS_LIBS = $(call uniq,$(TMP_PROJECT_ADDONS_LIBS)) -PROJECT_ADDONS_LDFLAGS = $(call uniq,$(TMP_PROJECT_ADDONS_LDFLAGS)) -PROJECT_ADDONS_PKG_CONFIG_LIBRARIES = $(call uniq,$(TMP_PROJECT_ADDONS_PKG_CONFIG_LIBRARIES)) -PROJECT_ADDONS_FRAMEWORKS = $(call uniq,$(TMP_PROJECT_ADDONS_FRAMEWORKS)) -PROJECT_ADDONS_SOURCE_FILES = $(call uniq,$(TMP_PROJECT_ADDONS_SOURCE_FILES)) -PROJECT_ADDONS_OBJ_FILES = $(call uniq,$(TMP_PROJECT_ADDONS_OBJ_FILES)) -PROJECT_ADDONS_DATA = $(call uniq,$(TMP_PROJECT_ADDONS_DATA)) -VPATH += $(call uniq, $(ADDON_PATHS)) - - -OF_PROJECT_ADDONS_OBJS = $(PROJECT_ADDONS_OBJ_FILES) -OF_PROJECT_ADDONS_DEPS = $(patsubst %.o,%.d,$(PROJECT_ADDONS_OBJ_FILES)) - -######################################################################## -# DEBUGGING -######################################################################## -# print debug information if so instructed -ifdef MAKEFILE_DEBUG - $(info ---PROJECT_ADDONS_PATHS---) - $(foreach v, $(PROJECT_ADDONS_PATHS),$(info $(v))) - $(info ---PROJECT_ADDONS_WITH_CONFIG---) - $(foreach v, $(PROJECT_ADDONS_WITH_CONFIG),$(info $(v))) - $(info ---PROJECT_ADDONS_INCLUDES---) - $(foreach v, $(PROJECT_ADDONS_INCLUDES),$(info $(v))) - $(info ---PROJECT_ADDONS_SOURCE_FILES---) - $(foreach v, $(PROJECT_ADDONS_SOURCE_FILES),$(info $(v))) - $(info ---PROJECT_ADDONS_LIBS---) - $(foreach v, $(PROJECT_ADDONS_LIBS),$(info $(v))) - $(info ---PROJECT_ADDONS_OBJFILES---) - $(foreach v, $(PROJECT_ADDONS_OBJFILES),$(info $(v))) - $(info ---PROJECT_ADDONS_BASE_CFLAGS---) - $(foreach v, $(PROJECT_ADDONS_BASE_CFLAGS),$(info $(v))) - $(info ---PROJECT_ADDONS_DEFINES_CFLAGS---) - $(foreach v, $(PROJECT_ADDONS_DEFINES_CFLAGS),$(info $(v))) - $(info ---PROJECT_ADDONS_INCLUDES_CFLAGS---) - $(foreach v, $(PROJECT_ADDONS_INCLUDES_CFLAGS),$(info $(v))) - $(info ---PROJECT_ADDONS_LDFLAGS---) - $(foreach v, $(PROJECT_ADDONS_LDFLAGS),$(info $(v))) - $(info ---PROJECT_ADDONS_DATA---) - $(foreach v, $(PROJECT_ADDONS_DATA),$(info $(v))) -endif +######################################################################## +# PROCESS VALID ADDONS IF AVAILABLE +######################################################################## + + +# parses addons includes, in PARSED_ADDON_INCLUDES receives full PATHS to addons +define parse_addons_includes + $(eval ADDONS_INCLUDES_FILTER = $(addprefix $1/, $(ADDON_INCLUDES_EXCLUDE))) \ + $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ + $(eval PARSED_ADDONS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_FILTERED_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_SOURCE_INCLUDES))) \ + $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ + $(eval PARSED_ADDONS_LIBS_SOURCE_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_SOURCE_INCLUDES))) \ + $(eval PARSED_ADDONS_LIBS_INCLUDES_PATHS = $(addsuffix /libs/*/include, $1)) \ + $(eval PARSED_ADDONS_LIBS_INCLUDES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_INCLUDES_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_FILTERED_LIBS_INCLUDE_PATHS = $(filter-out $(ADDONS_INCLUDES_FILTER),$(PARSED_ADDONS_LIBS_INCLUDES))) \ + $(eval PARSED_ADDONS_INCLUDES = $(PARSED_ADDONS_FILTERED_INCLUDE_PATHS)) \ + $(eval PARSED_ADDONS_INCLUDES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_INCLUDE_PATHS)) \ + $(eval PARSED_ADDONS_INCLUDES += $(PARSED_ADDONS_FILTERED_LIBS_INCLUDE_PATHS)) +endef + +# parses addons sources, in PARSED_ADDON_SOURCES receives full PATHS to addons +define parse_addons_sources + $(eval ADDONS_SOURCES_FILTER = $(addprefix $1/, $(ADDON_SOURCES_EXCLUDE))) \ + $(eval PARSED_ADDONS_SOURCE_PATHS = $(addsuffix /src, $1)) \ + $(eval PARSED_ADDONS_OFX_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_FILTERED_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_OFX_SOURCES))) \ + $(eval PARSED_ADDONS_LIBS_SOURCE_PATHS = $(addsuffix /libs, $1)) \ + $(eval PARSED_ADDONS_LIBS_SOURCES = $(shell $(FIND) $(PARSED_ADDONS_LIBS_SOURCE_PATHS) -type f \( -name "*.cpp" -or -name "*.c" -or -name "*.cc" -or -name "*.cxx" \) 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS = $(filter-out $(ADDONS_SOURCES_FILTER),$(PARSED_ADDONS_LIBS_SOURCES))) \ + $(eval PARSED_ADDONS_SOURCE_FILES = $(PARSED_ADDONS_FILTERED_SOURCE_PATHS)) \ + $(eval PARSED_ADDONS_SOURCE_FILES += $(PARSED_ADDONS_FILTERED_LIBS_SOURCE_PATHS)) +endef + +# parses addons libraries, in PARSED_ADDON_LIBS receives full PATHS to addons and libs_exclude +define parse_addons_libraries + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS = $(filter-out $(ADDON_LIBS_EXCLUDE),$(addsuffix /libs/*/lib/$(ABI_LIB_SUBPATH), $1))) \ + $(eval PARSED_ALL_PLATFORM_LIBS = $(shell $(FIND) $(PARSED_ADDONS_LIBS_PLATFORM_LIB_PATHS) -type d 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(if $(PARSED_ALL_PLATFORM_LIBS), \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.a 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED = $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.so 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dylib 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED += $(shell $(FIND) $(PARSED_ALL_PLATFORM_LIBS) -name *.dll 2> /dev/null | grep -v "/\.[^\.]" )) \ + $(eval PARSED_ADDONS_LIBS = $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_STATICS)) \ + $(eval PARSED_ADDONS_LIBS += $(PARSED_ADDONS_LIBS_PLATFORM_LIBS_SHARED)) \ + ) +endef + + +space := +space += + +define src_to_obj + $(addsuffix .o,$(basename $(filter %.c %.cpp %.cc %.cxx %.cc %.s %.S, $(addprefix $3,$(addprefix $2,$1))))) +endef + +define rwildcard + $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)$(filter $(subst *,%,$2),$d)) +endef + +# PARSE addon_config.mk FILES +# +# 1. read the addon_config.mk file for each adddon that has it +# 2. read each line of the addon by converting \n to \t since makefiles treat \n as spaces +# also convert spaces to ? so foreach works for each line instead of each word +# 3. unscape ? to space inside the loop +# 4. if the line matches common: or platform: set the PROCESS_NEXT flag to true +# 5. if the line matches %: but it's not common or platform: set PROCESS_NEXT to false +# 6: if PROCESS_NEXT eval the line to put the variable in the makefile space +define parse_addon + $(if $(wildcard $(PROJECT_ROOT)/$1), \ + $(eval addon=$(realpath $(addprefix $(PROJECT_ROOT)/, $1))) \ + $(eval addon_obj_path=$(PROJECT_ROOT)) \ + $(eval ADDON_PATHS+= $(dir $(addon))) \ + $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)addons/) \ + , \ + $(eval addon=$(realpath $(addprefix $(OF_ADDONS_PATH)/, $1))) \ + $(eval addon_obj_path=$(OF_ADDONS_PATH)) \ + $(eval obj_prefix=$(OF_PROJECT_OBJ_OUTPUT_PATH)) \ + ) \ + $(eval ADDON_DEPENDENCIES= ) \ + $(eval ADDON_DATA= ) \ + $(eval ADDON_CFLAGS= ) \ + $(eval ADDON_CPPFLAGS= ) \ + $(eval ADDON_LDFLAGS= ) \ + $(eval ADDON_PKG_CONFIG_LIBRARIES= ) \ + $(eval ADDON_FRAMEWORKS= ) \ + $(eval ADDON_LIBS_EXCLUDE= ) \ + $(eval ADDON_SOURCES_EXCLUDE= ) \ + $(call parse_addons_includes, $(addon)) \ + $(eval ADDON_INCLUDES=$(PARSED_ADDONS_INCLUDES)) \ + $(call parse_addons_libraries, $(addon)) \ + $(eval ADDON_LIBS=$(PARSED_ADDONS_LIBS)) \ + $(call parse_addons_sources, $(addon)) \ + $(eval ADDON_SOURCES=$(PARSED_ADDONS_SOURCE_FILES)) \ + $(eval PROCESS_NEXT=0) \ + $(if $(wildcard $(addon)/addon_config.mk), \ + $(foreach var_line, $(shell cat $(addon)/addon_config.mk | tr '\n ' '\t?'), \ + $(eval unscaped_var_line=$(strip $(subst ?, ,$(var_line)))) \ + $(if $(filter $(PROCESS_NEXT),1), $(eval $(unscaped_var_line))) \ + $(if $(filter %:,$(unscaped_var_line)), \ + $(if $(filter common:,$(unscaped_var_line)), \ + $(eval PROCESS_NEXT=1), \ + $(if $(filter $(ABI_LIB_SUBPATH):,$(unscaped_var_line)), \ + $(eval PROCESS_NEXT=1), \ + $(eval PROCESS_NEXT=0) \ + ) \ + ) \ + ) \ + ) \ + ) \ + $(if $(strip $(ADDON_INCLUDES)), \ + $(eval ADDON_INCLUDES_FILTERED = $(filter-out $(addprefix $(addon)/,$(ADDON_INCLUDES_EXCLUDE)),$(ADDON_INCLUDES))) \ + $(foreach addon_include, $(strip $(ADDON_INCLUDES_FILTERED)), \ + $(if $(wildcard $(addon)/$(addon_include)), \ + $(eval TMP_PROJECT_ADDONS_INCLUDES += $(addon)/$(addon_include)) \ + ) \ + $(if $(wildcard $(addon_include)), \ + $(eval TMP_PROJECT_ADDONS_INCLUDES += $(addon_include)) \ + ) \ + ) \ + ) \ + $(eval TMP_PROJECT_ADDONS_CFLAGS += $(ADDON_CFLAGS)) \ + $(eval TMP_PROJECT_ADDONS_CFLAGS += $(ADDON_CPPFLAGS)) \ + $(if $(strip $(ADDON_LIBS)), \ + $(foreach addon_lib, $(strip $(ADDON_LIBS)), \ + $(if $(wildcard $(addon)/$(addon_lib)), \ + $(eval TMP_PROJECT_ADDONS_LIBS += $(addon)/$(addon_lib)) \ + ) \ + $(if $(wildcard $(addon_lib)), \ + $(eval TMP_PROJECT_ADDONS_LIBS += $(addon_lib)) \ + ) \ + ) \ + ) \ + $(eval TMP_PROJECT_ADDONS_LDFLAGS += $(ADDON_LDFLAGS)) \ + $(eval TMP_PROJECT_ADDONS_PKG_CONFIG_LIBRARIES += $(ADDON_PKG_CONFIG_LIBRARIES)) \ + $(eval TMP_PROJECT_ADDONS_FRAMEWORKS += $(ADDON_FRAMEWORKS)) \ + $(eval PROJECT_AFTER += $(ADDON_AFTER)) \ + $(if $(strip $(ADDON_SOURCES)), \ + $(eval ADDON_SOURCES_FILTERED = $(filter-out $(addprefix $(addon)/,$(ADDON_SOURCES_EXCLUDE)),$(ADDON_SOURCES))) \ + $(foreach addon_src, $(strip $(ADDON_SOURCES_FILTERED)), \ + $(if $(filter $(addon)%, $(addon_src)), \ + $(eval addon_path=$(subst %,*,$(addon_src))) \ + $(if $(findstring *,$(addon_path)), \ + $(eval addon_dir=$(dir $(addon_path))) \ + $(eval addon_rest=$(notdir $(addon_path))) \ + $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ + $(foreach expanded_addon_src, $(addon_files), \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ + $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(expanded_addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + , \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ + $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + , \ + $(if $(filter $(OF_ROOT)%, $(addon_src)), \ + $(eval addon_path=$(subst %,*,$(addon_src))) \ + $(if $(findstring *,$(addon_path)), \ + $(eval addon_dir=$(dir $(addon_src))) \ + $(eval addon_rest=$(notdir $(addon_src))) \ + $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ + $(foreach expanded_addon_src, $(addon_files), \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ + $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(expanded_addon_src:$(OF_ROOT)/%=%),,$(obj_prefix)))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + , \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_src)) \ + $(eval SRC_OBJ_FILE=$(strip $(call src_to_obj, $(addon_src:$(OF_ROOT)/%=%),,$(obj_prefix)))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + ,$(if $(filter-out /%, $(addon_src)), \ + $(eval addon_path=$(addon)/$(subst %,*,$(addon_src))) \ + $(if $(findstring *,$(addon_path)), \ + $(eval addon_dir=$(dir $(addon_path))) \ + $(eval addon_rest=$(notdir $(addon_path))) \ + $(eval addon_files=$(strip $(call rwildcard,$(addon_dir),$(addon_rest)))) \ + $(foreach expanded_addon_src, $(addon_files), \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(expanded_addon_src)) \ + $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(expanded_addon_src:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + , \ + $(eval TMP_PROJECT_ADDONS_SOURCE_FILES += $(addon_path)) \ + $(eval SRC_OBJ_FILE=$(addprefix $(addon_obj_path)/,$(strip $(call src_to_obj, $(addon_path:$(addon)/%=%),$(notdir $1)/,$(obj_prefix))))) \ + $(eval TMP_PROJECT_ADDONS_OBJ_FILES += $(SRC_OBJ_FILE)) \ + ) \ + ,$(error cannot find addon source file $(addon_src))) \ + ) \ + ) \ + ) \ + ) \ + $(if $(strip $(ADDON_DATA)), \ + $(eval TMP_PROJECT_ADDONS_DATA += $(addprefix $(addon)/,$(ADDON_DATA))) \ + ) \ + $(foreach addon_dep, $(strip $(ADDON_DEPENDENCIES)), \ + $(if $(filter %$(addon_dep), $(PROJECT_ADDONS)), \ + , \ + $(eval PROJECT_ADDONS += $(addon_dep)) \ + $(call parse_addon,$(addon_dep)) \ + ) \ + ) +endef + + +$(foreach addon_to_parse, $(PROJECT_ADDONS), \ + $(call parse_addon,$(addon_to_parse)) \ +) + +#define uniq = +# $(eval seen :=) +# $(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_))) +# ${seen} +#endef + + +uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) + + +PROJECT_ADDONS_CFLAGS = $(call uniq,$(TMP_PROJECT_ADDONS_CFLAGS)) +PROJECT_ADDONS_INCLUDES = $(call uniq,$(TMP_PROJECT_ADDONS_INCLUDES)) +PROJECT_ADDONS_LIBS = $(call uniq,$(TMP_PROJECT_ADDONS_LIBS)) +PROJECT_ADDONS_LDFLAGS = $(call uniq,$(TMP_PROJECT_ADDONS_LDFLAGS)) +PROJECT_ADDONS_PKG_CONFIG_LIBRARIES = $(call uniq,$(TMP_PROJECT_ADDONS_PKG_CONFIG_LIBRARIES)) +PROJECT_ADDONS_FRAMEWORKS = $(call uniq,$(TMP_PROJECT_ADDONS_FRAMEWORKS)) +PROJECT_ADDONS_SOURCE_FILES = $(call uniq,$(TMP_PROJECT_ADDONS_SOURCE_FILES)) +PROJECT_ADDONS_OBJ_FILES = $(call uniq,$(TMP_PROJECT_ADDONS_OBJ_FILES)) +PROJECT_ADDONS_DATA = $(call uniq,$(TMP_PROJECT_ADDONS_DATA)) +VPATH += $(call uniq, $(ADDON_PATHS)) + + +OF_PROJECT_ADDONS_OBJS = $(PROJECT_ADDONS_OBJ_FILES) +OF_PROJECT_ADDONS_DEPS = $(patsubst %.o,%.d,$(PROJECT_ADDONS_OBJ_FILES)) + +######################################################################## +# DEBUGGING +######################################################################## +# print debug information if so instructed +ifdef MAKEFILE_DEBUG + $(info ---PROJECT_ADDONS_PATHS---) + $(foreach v, $(PROJECT_ADDONS_PATHS),$(info $(v))) + $(info ---PROJECT_ADDONS_WITH_CONFIG---) + $(foreach v, $(PROJECT_ADDONS_WITH_CONFIG),$(info $(v))) + $(info ---PROJECT_ADDONS_INCLUDES---) + $(foreach v, $(PROJECT_ADDONS_INCLUDES),$(info $(v))) + $(info ---PROJECT_ADDONS_SOURCE_FILES---) + $(foreach v, $(PROJECT_ADDONS_SOURCE_FILES),$(info $(v))) + $(info ---PROJECT_ADDONS_LIBS---) + $(foreach v, $(PROJECT_ADDONS_LIBS),$(info $(v))) + $(info ---PROJECT_ADDONS_OBJFILES---) + $(foreach v, $(PROJECT_ADDONS_OBJFILES),$(info $(v))) + $(info ---PROJECT_ADDONS_BASE_CFLAGS---) + $(foreach v, $(PROJECT_ADDONS_BASE_CFLAGS),$(info $(v))) + $(info ---PROJECT_ADDONS_DEFINES_CFLAGS---) + $(foreach v, $(PROJECT_ADDONS_DEFINES_CFLAGS),$(info $(v))) + $(info ---PROJECT_ADDONS_INCLUDES_CFLAGS---) + $(foreach v, $(PROJECT_ADDONS_INCLUDES_CFLAGS),$(info $(v))) + $(info ---PROJECT_ADDONS_LDFLAGS---) + $(foreach v, $(PROJECT_ADDONS_LDFLAGS),$(info $(v))) + $(info ---PROJECT_ADDONS_DATA---) + $(foreach v, $(PROJECT_ADDONS_DATA),$(info $(v))) +endif diff --git a/patches/msys2/patch.sh b/patches/msys2/patch.sh index b51f9fa..53e974a 100755 --- a/patches/msys2/patch.sh +++ b/patches/msys2/patch.sh @@ -1,8 +1,8 @@ -#!/usr/bin/bash - -echo "This script should be run from the patches/msys2 directory" - -cp --force ./sound/ofOpenALSoundPlayer.* ../../../../libs/openFrameworks/sound/ -cp --force ./makefileCommon/config.addons.mk ../../../../libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk - -echo "Patch for msys2 complete" +#!/usr/bin/bash + +echo "This script should be run from the patches/msys2 directory" + +cp --force ./sound/ofOpenALSoundPlayer.* ../../../../libs/openFrameworks/sound/ +cp --force ./makefileCommon/config.addons.mk ../../../../libs/openFrameworksCompiled/project/makefileCommon/config.addons.mk + +echo "Patch for msys2 complete" diff --git a/patches/msys2/sound/ofOpenALSoundPlayer.cpp b/patches/msys2/sound/ofOpenALSoundPlayer.cpp index 9ae533e..e23b444 100644 --- a/patches/msys2/sound/ofOpenALSoundPlayer.cpp +++ b/patches/msys2/sound/ofOpenALSoundPlayer.cpp @@ -1,1076 +1,1076 @@ -#include "ofOpenALSoundPlayer.h" - -#ifdef OF_SOUND_PLAYER_OPENAL - -#include "ofConstants.h" -#include "glm/gtc/constants.hpp" -#include "glm/common.hpp" -#include "ofLog.h" -#include "ofEvents.h" -#include - -#if defined (TARGET_OF_IOS) || defined (TARGET_OSX) -#include -#include -#else -#include -#include -#endif - -#ifdef OF_USING_MPG123 -#include -#endif - -using namespace std; - -static ALCdevice * alDevice = nullptr; -static ALCcontext * alContext = nullptr; -vector ofOpenALSoundPlayer::window; -float ofOpenALSoundPlayer::windowSum = 0.f; - - -kiss_fftr_cfg ofOpenALSoundPlayer::systemFftCfg=0; -vector ofOpenALSoundPlayer::systemWindowedSignal; -vector ofOpenALSoundPlayer::systemBins; -vector ofOpenALSoundPlayer::systemCx_out; - -static set & players(){ - static set * players = new set; - return *players; -} - -void ofOpenALSoundUpdate(){ - alcProcessContext(alContext); -} - -// ---------------------------------------------------------------------------- -// from http://devmaster.net/posts/2893/openal-lesson-6-advanced-loading-and-error-handles -static string getALErrorString(ALenum error) { - switch(error) { - case AL_NO_ERROR: - return "AL_NO_ERROR"; - case AL_INVALID_NAME: - return "AL_INVALID_NAME"; - case AL_INVALID_ENUM: - return "AL_INVALID_ENUM"; - case AL_INVALID_VALUE: - return "AL_INVALID_VALUE"; - case AL_INVALID_OPERATION: - return "AL_INVALID_OPERATION"; - case AL_OUT_OF_MEMORY: - return "AL_OUT_OF_MEMORY"; - }; - return "UNKWOWN_ERROR"; -} - -static string getALCErrorString(ALCenum error) { - switch(error) { - case ALC_NO_ERROR: - return "ALC_NO_ERROR"; - case ALC_INVALID_DEVICE: - return "ALC_INVALID_DEVICE"; - case ALC_INVALID_CONTEXT: - return "ALC_INVALID_CONTEXT"; - case ALC_INVALID_ENUM: - return "ALC_INVALID_ENUM"; - case ALC_INVALID_VALUE: - return "ALC_INVALID_VALUE"; - case ALC_OUT_OF_MEMORY: - return "ALC_OUT_OF_MEMORY"; - }; - return "UNKWOWN_ERROR"; -} - -#ifdef OF_USING_MPG123 -static string getMpg123EncodingString(int encoding) { - switch(encoding) { - case MPG123_ENC_16: - return "MPG123_ENC_16"; -#if MPG123_API_VERSION>=36 - case MPG123_ENC_24: - return "MPG123_ENC_24"; -#endif - case MPG123_ENC_32: - return "MPG123_ENC_32"; - case MPG123_ENC_8: - return "MPG123_ENC_8"; - case MPG123_ENC_ALAW_8: - return "MPG123_ENC_ALAW_8"; - case MPG123_ENC_FLOAT: - return "MPG123_ENC_FLOAT"; - case MPG123_ENC_FLOAT_32: - return "MPG123_ENC_FLOAT_32"; - case MPG123_ENC_FLOAT_64: - return "MPG123_ENC_FLOAT_64"; - case MPG123_ENC_SIGNED: - return "MPG123_ENC_SIGNED"; - case MPG123_ENC_SIGNED_16: - return "MPG123_ENC_SIGNED_16"; -#if MPG123_API_VERSION>=36 - case MPG123_ENC_SIGNED_24: - return "MPG123_ENC_SIGNED_24"; -#endif - case MPG123_ENC_SIGNED_32: - return "MPG123_ENC_SIGNED_32"; - case MPG123_ENC_SIGNED_8: - return "MPG123_ENC_SIGNED_8"; - case MPG123_ENC_ULAW_8: - return "MPG123_ENC_ULAW_8"; - case MPG123_ENC_UNSIGNED_16: - return "MPG123_ENC_UNSIGNED_16"; -#if MPG123_API_VERSION>=36 - case MPG123_ENC_UNSIGNED_24: - return "MPG123_ENC_UNSIGNED_24"; -#endif - case MPG123_ENC_UNSIGNED_32: - return "MPG123_ENC_UNSIGNED_32"; - case MPG123_ENC_UNSIGNED_8: - return "MPG123_ENC_UNSIGNED_8"; - default: - return "MPG123_ENC_ANY"; - } -} -#endif - -#define BUFFER_STREAM_SIZE 4096 - -// now, the individual sound player: -//------------------------------------------------------------ -ofOpenALSoundPlayer::ofOpenALSoundPlayer(){ - bLoop = false; - bLoadedOk = false; - pan = 0.0f; // range for oF is -1 to 1, - volume = 1.0f; - internalFreq = 44100; - speed = 1; - bPaused = false; - isStreaming = false; - channels = 0; - duration = 0; - fftCfg = 0; - streamf = 0; -#ifdef OF_USING_MPG123 - mp3streamf = 0; -#endif - players().insert(this); -} - -// ---------------------------------------------------------------------------- -ofOpenALSoundPlayer::~ofOpenALSoundPlayer(){ - unload(); - kiss_fftr_free(fftCfg); - players().erase(this); - if( players().empty() ){ - close(); - } -} - -//--------------------------------------- -// this should only be called once -void ofOpenALSoundPlayer::initialize(){ - if( !alDevice ){ - alDevice = alcOpenDevice( nullptr ); - if( !alDevice ){ - ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't open OpenAL default device"; - return; - }else{ - ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): opening "<< alcGetString( alDevice, ALC_DEVICE_SPECIFIER ); - } - // Create OpenAL context and make it current. If fails, close the OpenAL device that was just opened. - alContext = alcCreateContext( alDevice, nullptr ); - if( !alContext ){ - ALCenum err = alcGetError( alDevice ); - ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not create OpenAL context : "<< getALCErrorString( err ); - close(); - return; - } - - if( alcMakeContextCurrent( alContext )==ALC_FALSE ){ - ALCenum err = alcGetError( alDevice ); - ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not make current the create OpenAL context : "<< getALCErrorString( err ); - close(); - return; - }; - alListener3f( AL_POSITION, 0,0,0 ); -#ifdef OF_USING_MPG123 - mpg123_init(); -#endif - - } - ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): Done"; -} - -//--------------------------------------- -void ofOpenALSoundPlayer::createWindow(int size){ - if(int(window.size())!=size){ - windowSum = 0; - window.resize(size); - // hanning window - for(int i = 0; i < size; i++){ - window[i] = .54 - .46 * cos((glm::two_pi() * i) / (size - 1)); - windowSum += window[i]; - } - } -} - -//--------------------------------------- -void ofOpenALSoundPlayer::close(){ - // Destroy the OpenAL context (if any) before closing the device - if( alDevice ){ - if( alContext ){ -#ifdef OF_USING_MPG123 - mpg123_exit(); -#endif - alcMakeContextCurrent(nullptr); - alcDestroyContext(alContext); - alContext = nullptr; - } - if( alcCloseDevice( alDevice )==ALC_FALSE ){ - ofLogNotice("ofOpenALSoundPlayer") << "initialize(): error closing OpenAL device."; - } - alDevice = nullptr; - } -} - -// ---------------------------------------------------------------------------- -bool ofOpenALSoundPlayer::sfReadFile(const std::filesystem::path& path, vector & buffer, vector & fftAuxBuffer){ - SF_INFO sfInfo; - SNDFILE* f = sf_open(path.string().c_str(),SFM_READ,&sfInfo); - if(!f){ - ofLogError("ofOpenALSoundPlayer") << "sfReadFile(): couldn't read \"" << path << "\""; - return false; - } - - buffer.resize(sfInfo.frames*sfInfo.channels); - fftAuxBuffer.resize(sfInfo.frames*sfInfo.channels); - - int subformat = sfInfo.format & SF_FORMAT_SUBMASK ; - if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE){ - double scale ; - sf_command (f, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; - if (scale < 1e-10) - scale = 1.0 ; - else - scale = 32700.0 / scale ; - - sf_count_t samples_read = sf_read_float (f, &fftAuxBuffer[0], fftAuxBuffer.size()); - if(samples_read<(int)fftAuxBuffer.size()){ - ofLogWarning("ofOpenALSoundPlayer") << "sfReadFile(): read " << samples_read << " float samples, expected " - << fftAuxBuffer.size() << " for \"" << path << "\""; - } - for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){ - fftAuxBuffer[i] *= scale ; - buffer[i] = 32565.0 * fftAuxBuffer[i]; - } - }else{ - sf_count_t frames_read = sf_readf_short(f,&buffer[0],sfInfo.frames); - if(frames_read & buffer,vector & fftAuxBuffer){ - int err = MPG123_OK; - mpg123_handle * f = mpg123_new(nullptr,&err); - if(mpg123_open(f,path.string().c_str())!=MPG123_OK){ - ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): couldn't read \"" << path << "\""; - return false; - } - - mpg123_enc_enum encoding; - long int rate; - mpg123_getformat(f,&rate,&channels,(int*)&encoding); - if(encoding!=MPG123_ENC_SIGNED_16){ - ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): " << getMpg123EncodingString(encoding) - << " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16"; - return false; - } - samplerate = rate; - - size_t done=0; - size_t buffer_size = mpg123_outblock( f ); - buffer.resize(buffer_size/2); - while(mpg123_read(f,(unsigned char*)&buffer[buffer.size()-buffer_size/2],buffer_size,&done)!=MPG123_DONE){ - buffer.resize(buffer.size()+buffer_size/2); - }; - buffer.resize(buffer.size()-(buffer_size/2-done/2)); - mpg123_close(f); - mpg123_delete(f); - - fftAuxBuffer.resize(buffer.size()); - for(int i=0;i<(int)buffer.size();i++){ - fftAuxBuffer[i] = float(buffer[i])/32565.f; - } - duration = float(buffer.size()/channels) / float(samplerate); - return true; -} -#endif - -//------------------------------------------------------------ -bool ofOpenALSoundPlayer::sfStream(const std::filesystem::path& path,vector & buffer,vector & fftAuxBuffer){ - if(!streamf){ - SF_INFO sfInfo; - streamf = sf_open(path.string().c_str(),SFM_READ,&sfInfo); - if(!streamf){ - ofLogError("ofOpenALSoundPlayer") << "sfStream(): couldn't read \"" << path << "\""; - return false; - } - - stream_subformat = sfInfo.format & SF_FORMAT_SUBMASK ; - if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){ - sf_command (streamf, SFC_CALC_SIGNAL_MAX, &stream_scale, sizeof (stream_scale)) ; - if (stream_scale < 1e-10) - stream_scale = 1.0 ; - else - stream_scale = 32700.0 / stream_scale ; - } - channels = sfInfo.channels; - duration = float(sfInfo.frames) / float(sfInfo.samplerate); - samplerate = sfInfo.samplerate; - stream_samples_read = 0; - } - - int curr_buffer_size = BUFFER_STREAM_SIZE*channels; - if(speed>1) curr_buffer_size *= (int)round(speed); - buffer.resize(curr_buffer_size); - fftAuxBuffer.resize(buffer.size()); - if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){ - sf_count_t samples_read = sf_read_float (streamf, &fftAuxBuffer[0], fftAuxBuffer.size()); - stream_samples_read += samples_read; - if(samples_read<(int)fftAuxBuffer.size()){ - fftAuxBuffer.resize(samples_read); - buffer.resize(samples_read); - setPosition(0); - if(!bLoop) stopThread(); - stream_samples_read = 0; - stream_end = true; - } - for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){ - fftAuxBuffer[i] *= stream_scale ; - buffer[i] = 32565.0 * fftAuxBuffer[i]; - } - }else{ - sf_count_t frames_read = sf_readf_short(streamf,&buffer[0],curr_buffer_size/channels); - stream_samples_read += frames_read*channels; - if(frames_read & buffer,vector & fftAuxBuffer){ - if(!mp3streamf){ - int err = MPG123_OK; - mp3streamf = mpg123_new(nullptr,&err); - if(mpg123_open(mp3streamf,path.string().c_str())!=MPG123_OK){ - mpg123_close(mp3streamf); - mpg123_delete(mp3streamf); - ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): couldn't read \"" << path << "\""; - return false; - } - - long int rate; - mpg123_getformat(mp3streamf,&rate,&channels,(int*)&stream_encoding); - if(stream_encoding!=MPG123_ENC_SIGNED_16){ - ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): " << getMpg123EncodingString(stream_encoding) - << " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16"; - return false; - } - samplerate = rate; - mp3_buffer_size = mpg123_outblock( mp3streamf ); - - - mpg123_seek(mp3streamf,0,SEEK_END); - off_t samples = mpg123_tell(mp3streamf); - duration = float(samples/channels) / float(samplerate); - mpg123_seek(mp3streamf,0,SEEK_SET); - } - - int curr_buffer_size = mp3_buffer_size; - if(speed>1) curr_buffer_size *= (int)round(speed); - buffer.resize(curr_buffer_size); - fftAuxBuffer.resize(buffer.size()); - size_t done=0; - if(mpg123_read(mp3streamf,(unsigned char*)&buffer[0],curr_buffer_size*2,&done)==MPG123_DONE){ - setPosition(0); - buffer.resize(done/2); - fftAuxBuffer.resize(done/2); - if(!bLoop) stopThread(); - stream_end = true; - } - - - for(int i=0;i<(int)buffer.size();i++){ - fftAuxBuffer[i] = float(buffer[i])/32565.f; - } - - return true; -} -#endif - -//------------------------------------------------------------ -bool ofOpenALSoundPlayer::stream(const std::filesystem::path& fileName, vector & buffer){ -#ifdef OF_USING_MPG123 - if(ofFilePath::getFileExt(fileName)=="mp3" || ofFilePath::getFileExt(fileName)=="MP3" || mp3streamf){ - if(!mpg123Stream(fileName,buffer,fftAuxBuffer)) return false; - }else -#endif - if(!sfStream(fileName,buffer,fftAuxBuffer)) return false; - - fftBuffers.resize(channels); - int numFrames = buffer.size()/channels; - - for(int i=0;i & buffer){ -#ifdef OF_USING_MPG123 - if(ofFilePath::getFileExt(fileName)!="mp3" && ofFilePath::getFileExt(fileName)!="MP3"){ - if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false; - }else{ - if(!mpg123ReadFile(fileName,buffer,fftAuxBuffer)) return false; - } -#else - if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false; -#endif - fftBuffers.resize(channels); - int numFrames = buffer.size()/channels; - - for(int i=0;i > multibuffer; - multibuffer.resize(channels); - sources.resize(channels); - alGenSources(channels, &sources[0]); - if(isStreaming){ - for(int s=0; s<2;s++){ - for(int i=0;i > multibuffer; - multibuffer.resize(channels); - while(isThreadRunning()){ - std::unique_lock lock(mutex); - for(int i=0; i1){ - for(int j=0;j lock(mutex); - - // Delete sources before buffers. - alDeleteSources(sources.size(),&sources[0]); - alDeleteBuffers(buffers.size(),&buffers[0]); - - sources.clear(); - buffers.clear(); - } - - // Free resources and close file descriptors. -#ifdef OF_USING_MPG123 - if(mp3streamf){ - mpg123_close(mp3streamf); - mpg123_delete(mp3streamf); - } - mp3streamf = 0; -#endif - - if(streamf){ - sf_close(streamf); - } - streamf = 0; - - bLoadedOk = false; -} - -//------------------------------------------------------------ -bool ofOpenALSoundPlayer::isPlaying() const{ - if(sources.empty()) return false; - if(isStreaming) return isThreadRunning(); - ALint state; - bool playing=false; - for(int i=0;i<(int)sources.size();i++){ - alGetSourcei(sources[i],AL_SOURCE_STATE,&state); - playing |= (state == AL_PLAYING); - } - return playing; -} - -//------------------------------------------------------------ -bool ofOpenALSoundPlayer::isPaused() const{ - if(sources.empty()) return false; - ALint state; - bool paused=true; - for(int i=0;i<(int)sources.size();i++){ - alGetSourcei(sources[i],AL_SOURCE_STATE,&state); - paused &= (state == AL_PAUSED); - } - return paused; -} - -//------------------------------------------------------------ -float ofOpenALSoundPlayer::getSpeed() const{ - return speed; -} - -//------------------------------------------------------------ -float ofOpenALSoundPlayer::getPan() const{ - return pan; -} - -//------------------------------------------------------------ -float ofOpenALSoundPlayer::getVolume() const{ - return volume; -} - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setVolume(float vol){ - volume = vol; - if(sources.empty()) return; - if(channels==1){ - alSourcef (sources[sources.size()-1], AL_GAIN, vol); - }else{ - setPan(pan); - } -} - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setPosition(float pct){ - setPositionMS(duration*pct*1000.f); -} - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setPositionMS(int ms){ - if(sources.empty()) return; -#ifdef OF_USING_MPG123 - if(mp3streamf){ - mpg123_seek(mp3streamf,float(ms)/1000.f*samplerate,SEEK_SET); - }else -#endif - if(streamf){ - stream_samples_read = sf_seek(streamf,float(ms)/1000.f*samplerate,SEEK_SET) * channels; - }else{ - for(int i=0;i<(int)channels;i++){ - alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,float(ms)/1000.f); - } - } -} - -//------------------------------------------------------------ -float ofOpenALSoundPlayer::getPosition() const{ - if(duration==0 || sources.empty()) - return 0; - else - return getPositionMS()/(1000.f*duration); -} - -//------------------------------------------------------------ -int ofOpenALSoundPlayer::getPositionMS() const{ - if(sources.empty()) return 0; - float pos; -#ifdef OF_USING_MPG123 - if(mp3streamf){ - pos = float(mpg123_tell(mp3streamf)) / float(samplerate); - }else -#endif - if(streamf){ - pos = float(stream_samples_read) / float(channels) / float(samplerate); - }else{ - alGetSourcef(sources[sources.size()-1],AL_SEC_OFFSET,&pos); - } - return pos * 1000.f; -} - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setPan(float p){ - if(sources.empty()) return; - p = glm::clamp(p, -1.f, 1.f); - pan = p; - if(channels==1){ - float pos[3] = {p,0,0}; - alSourcefv(sources[sources.size()-1],AL_POSITION,pos); - }else{ - // calculates left/right volumes from pan-value (constant panning law) - // see: Curtis Roads: Computer Music Tutorial p 460 - // thanks to jasch - float angle = p * 0.7853981633974483f; // in radians from -45. to +45. - float cosAngle = cos(angle); - float sinAngle = sin(angle); - float leftVol = (cosAngle - sinAngle) * 0.7071067811865475; // multiplied by sqrt(2)/2 - float rightVol = (cosAngle + sinAngle) * 0.7071067811865475; // multiplied by sqrt(2)/2 - for(int i=0;i<(int)channels;i++){ - if(i==0){ - alSourcef(sources[sources.size()-channels+i],AL_GAIN,leftVol*volume); - }else{ - alSourcef(sources[sources.size()-channels+i],AL_GAIN,rightVol*volume); - } - } - } -} - - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setPaused(bool bP){ - if(sources.empty()) return; - std::unique_lock lock(mutex); - if(bP){ - alSourcePausev(sources.size(),&sources[0]); - if(isStreaming){ - stopThread(); - } - }else{ - alSourcePlayv(sources.size(),&sources[0]); - if(isStreaming){ - startThread(); - } - } - - bPaused = bP; -} - - -//------------------------------------------------------------ -void ofOpenALSoundPlayer::setSpeed(float spd){ - for(int i=0;i lock(mutex); - int err = alGetError(); - - // if the sound is set to multiplay, then create new sources, - // do not multiplay on loop or we won't be able to stop it - if (bMultiPlay && !bLoop){ - sources.resize(sources.size()+channels); - alGetError(); // Clear error. - alGenSources(channels, &sources[sources.size()-channels]); - err = alGetError(); - if (err != AL_NO_ERROR){ - ofLogError("ofOpenALSoundPlayer") << "play(): couldn't create multiplay stereo sources: " - << (int) err << " " << getALErrorString(err); - return; - } - for(int i=0;i lock(mutex); - alSourceStopv(channels,&sources[sources.size()-channels]); - if(isStreaming){ - setPosition(0); - stopThread(); - } -} - -// ---------------------------------------------------------------------------- -void ofOpenALSoundPlayer::initFFT(int bands){ - if(int(bins.size())==bands) return; - int signalSize = (bands-1)*2; - if(fftCfg!=0) kiss_fftr_free(fftCfg); - fftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr); - cx_out.resize(bands); - bins.resize(bands); - createWindow(signalSize); -} - -// ---------------------------------------------------------------------------- -void ofOpenALSoundPlayer::initSystemFFT(int bands){ - if(int(systemBins.size())==bands) return; - int signalSize = (bands-1)*2; - if(systemFftCfg!=0) kiss_fftr_free(systemFftCfg); - systemFftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr); - systemCx_out.resize(bands); - systemBins.resize(bands); - createWindow(signalSize); -} - -float * ofOpenALSoundPlayer::getCurrentBufferSum(int size){ - if(int(windowedSignal.size())!=size){ - windowedSignal.resize(size); - } - windowedSignal.assign(windowedSignal.size(),0); - for(int k=0;k=(int)fftBuffers[0].size()) continue; - for(int i=0;i::iterator it; - for(it=players().begin();it!=players().end();it++){ - if(!(*it)->isPlaying()) continue; - float * buffer = (*it)->getCurrentBufferSum(signalSize); - for(int i=0;i & signal){ - for(int i = 0; i < (int)signal.size(); i++) - signal[i] *= window[i]; -} - - -#endif +#include "ofOpenALSoundPlayer.h" + +#ifdef OF_SOUND_PLAYER_OPENAL + +#include "ofConstants.h" +#include "glm/gtc/constants.hpp" +#include "glm/common.hpp" +#include "ofLog.h" +#include "ofEvents.h" +#include + +#if defined (TARGET_OF_IOS) || defined (TARGET_OSX) +#include +#include +#else +#include +#include +#endif + +#ifdef OF_USING_MPG123 +#include +#endif + +using namespace std; + +static ALCdevice * alDevice = nullptr; +static ALCcontext * alContext = nullptr; +vector ofOpenALSoundPlayer::window; +float ofOpenALSoundPlayer::windowSum = 0.f; + + +kiss_fftr_cfg ofOpenALSoundPlayer::systemFftCfg=0; +vector ofOpenALSoundPlayer::systemWindowedSignal; +vector ofOpenALSoundPlayer::systemBins; +vector ofOpenALSoundPlayer::systemCx_out; + +static set & players(){ + static set * players = new set; + return *players; +} + +void ofOpenALSoundUpdate(){ + alcProcessContext(alContext); +} + +// ---------------------------------------------------------------------------- +// from http://devmaster.net/posts/2893/openal-lesson-6-advanced-loading-and-error-handles +static string getALErrorString(ALenum error) { + switch(error) { + case AL_NO_ERROR: + return "AL_NO_ERROR"; + case AL_INVALID_NAME: + return "AL_INVALID_NAME"; + case AL_INVALID_ENUM: + return "AL_INVALID_ENUM"; + case AL_INVALID_VALUE: + return "AL_INVALID_VALUE"; + case AL_INVALID_OPERATION: + return "AL_INVALID_OPERATION"; + case AL_OUT_OF_MEMORY: + return "AL_OUT_OF_MEMORY"; + }; + return "UNKWOWN_ERROR"; +} + +static string getALCErrorString(ALCenum error) { + switch(error) { + case ALC_NO_ERROR: + return "ALC_NO_ERROR"; + case ALC_INVALID_DEVICE: + return "ALC_INVALID_DEVICE"; + case ALC_INVALID_CONTEXT: + return "ALC_INVALID_CONTEXT"; + case ALC_INVALID_ENUM: + return "ALC_INVALID_ENUM"; + case ALC_INVALID_VALUE: + return "ALC_INVALID_VALUE"; + case ALC_OUT_OF_MEMORY: + return "ALC_OUT_OF_MEMORY"; + }; + return "UNKWOWN_ERROR"; +} + +#ifdef OF_USING_MPG123 +static string getMpg123EncodingString(int encoding) { + switch(encoding) { + case MPG123_ENC_16: + return "MPG123_ENC_16"; +#if MPG123_API_VERSION>=36 + case MPG123_ENC_24: + return "MPG123_ENC_24"; +#endif + case MPG123_ENC_32: + return "MPG123_ENC_32"; + case MPG123_ENC_8: + return "MPG123_ENC_8"; + case MPG123_ENC_ALAW_8: + return "MPG123_ENC_ALAW_8"; + case MPG123_ENC_FLOAT: + return "MPG123_ENC_FLOAT"; + case MPG123_ENC_FLOAT_32: + return "MPG123_ENC_FLOAT_32"; + case MPG123_ENC_FLOAT_64: + return "MPG123_ENC_FLOAT_64"; + case MPG123_ENC_SIGNED: + return "MPG123_ENC_SIGNED"; + case MPG123_ENC_SIGNED_16: + return "MPG123_ENC_SIGNED_16"; +#if MPG123_API_VERSION>=36 + case MPG123_ENC_SIGNED_24: + return "MPG123_ENC_SIGNED_24"; +#endif + case MPG123_ENC_SIGNED_32: + return "MPG123_ENC_SIGNED_32"; + case MPG123_ENC_SIGNED_8: + return "MPG123_ENC_SIGNED_8"; + case MPG123_ENC_ULAW_8: + return "MPG123_ENC_ULAW_8"; + case MPG123_ENC_UNSIGNED_16: + return "MPG123_ENC_UNSIGNED_16"; +#if MPG123_API_VERSION>=36 + case MPG123_ENC_UNSIGNED_24: + return "MPG123_ENC_UNSIGNED_24"; +#endif + case MPG123_ENC_UNSIGNED_32: + return "MPG123_ENC_UNSIGNED_32"; + case MPG123_ENC_UNSIGNED_8: + return "MPG123_ENC_UNSIGNED_8"; + default: + return "MPG123_ENC_ANY"; + } +} +#endif + +#define BUFFER_STREAM_SIZE 4096 + +// now, the individual sound player: +//------------------------------------------------------------ +ofOpenALSoundPlayer::ofOpenALSoundPlayer(){ + bLoop = false; + bLoadedOk = false; + pan = 0.0f; // range for oF is -1 to 1, + volume = 1.0f; + internalFreq = 44100; + speed = 1; + bPaused = false; + isStreaming = false; + channels = 0; + duration = 0; + fftCfg = 0; + streamf = 0; +#ifdef OF_USING_MPG123 + mp3streamf = 0; +#endif + players().insert(this); +} + +// ---------------------------------------------------------------------------- +ofOpenALSoundPlayer::~ofOpenALSoundPlayer(){ + unload(); + kiss_fftr_free(fftCfg); + players().erase(this); + if( players().empty() ){ + close(); + } +} + +//--------------------------------------- +// this should only be called once +void ofOpenALSoundPlayer::initialize(){ + if( !alDevice ){ + alDevice = alcOpenDevice( nullptr ); + if( !alDevice ){ + ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't open OpenAL default device"; + return; + }else{ + ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): opening "<< alcGetString( alDevice, ALC_DEVICE_SPECIFIER ); + } + // Create OpenAL context and make it current. If fails, close the OpenAL device that was just opened. + alContext = alcCreateContext( alDevice, nullptr ); + if( !alContext ){ + ALCenum err = alcGetError( alDevice ); + ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not create OpenAL context : "<< getALCErrorString( err ); + close(); + return; + } + + if( alcMakeContextCurrent( alContext )==ALC_FALSE ){ + ALCenum err = alcGetError( alDevice ); + ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not make current the create OpenAL context : "<< getALCErrorString( err ); + close(); + return; + }; + alListener3f( AL_POSITION, 0,0,0 ); +#ifdef OF_USING_MPG123 + mpg123_init(); +#endif + + } + ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): Done"; +} + +//--------------------------------------- +void ofOpenALSoundPlayer::createWindow(int size){ + if(int(window.size())!=size){ + windowSum = 0; + window.resize(size); + // hanning window + for(int i = 0; i < size; i++){ + window[i] = .54 - .46 * cos((glm::two_pi() * i) / (size - 1)); + windowSum += window[i]; + } + } +} + +//--------------------------------------- +void ofOpenALSoundPlayer::close(){ + // Destroy the OpenAL context (if any) before closing the device + if( alDevice ){ + if( alContext ){ +#ifdef OF_USING_MPG123 + mpg123_exit(); +#endif + alcMakeContextCurrent(nullptr); + alcDestroyContext(alContext); + alContext = nullptr; + } + if( alcCloseDevice( alDevice )==ALC_FALSE ){ + ofLogNotice("ofOpenALSoundPlayer") << "initialize(): error closing OpenAL device."; + } + alDevice = nullptr; + } +} + +// ---------------------------------------------------------------------------- +bool ofOpenALSoundPlayer::sfReadFile(const std::filesystem::path& path, vector & buffer, vector & fftAuxBuffer){ + SF_INFO sfInfo; + SNDFILE* f = sf_open(path.string().c_str(),SFM_READ,&sfInfo); + if(!f){ + ofLogError("ofOpenALSoundPlayer") << "sfReadFile(): couldn't read \"" << path << "\""; + return false; + } + + buffer.resize(sfInfo.frames*sfInfo.channels); + fftAuxBuffer.resize(sfInfo.frames*sfInfo.channels); + + int subformat = sfInfo.format & SF_FORMAT_SUBMASK ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE){ + double scale ; + sf_command (f, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + + sf_count_t samples_read = sf_read_float (f, &fftAuxBuffer[0], fftAuxBuffer.size()); + if(samples_read<(int)fftAuxBuffer.size()){ + ofLogWarning("ofOpenALSoundPlayer") << "sfReadFile(): read " << samples_read << " float samples, expected " + << fftAuxBuffer.size() << " for \"" << path << "\""; + } + for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){ + fftAuxBuffer[i] *= scale ; + buffer[i] = 32565.0 * fftAuxBuffer[i]; + } + }else{ + sf_count_t frames_read = sf_readf_short(f,&buffer[0],sfInfo.frames); + if(frames_read & buffer,vector & fftAuxBuffer){ + int err = MPG123_OK; + mpg123_handle * f = mpg123_new(nullptr,&err); + if(mpg123_open(f,path.string().c_str())!=MPG123_OK){ + ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): couldn't read \"" << path << "\""; + return false; + } + + mpg123_enc_enum encoding; + long int rate; + mpg123_getformat(f,&rate,&channels,(int*)&encoding); + if(encoding!=MPG123_ENC_SIGNED_16){ + ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): " << getMpg123EncodingString(encoding) + << " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16"; + return false; + } + samplerate = rate; + + size_t done=0; + size_t buffer_size = mpg123_outblock( f ); + buffer.resize(buffer_size/2); + while(mpg123_read(f,(unsigned char*)&buffer[buffer.size()-buffer_size/2],buffer_size,&done)!=MPG123_DONE){ + buffer.resize(buffer.size()+buffer_size/2); + }; + buffer.resize(buffer.size()-(buffer_size/2-done/2)); + mpg123_close(f); + mpg123_delete(f); + + fftAuxBuffer.resize(buffer.size()); + for(int i=0;i<(int)buffer.size();i++){ + fftAuxBuffer[i] = float(buffer[i])/32565.f; + } + duration = float(buffer.size()/channels) / float(samplerate); + return true; +} +#endif + +//------------------------------------------------------------ +bool ofOpenALSoundPlayer::sfStream(const std::filesystem::path& path,vector & buffer,vector & fftAuxBuffer){ + if(!streamf){ + SF_INFO sfInfo; + streamf = sf_open(path.string().c_str(),SFM_READ,&sfInfo); + if(!streamf){ + ofLogError("ofOpenALSoundPlayer") << "sfStream(): couldn't read \"" << path << "\""; + return false; + } + + stream_subformat = sfInfo.format & SF_FORMAT_SUBMASK ; + if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){ + sf_command (streamf, SFC_CALC_SIGNAL_MAX, &stream_scale, sizeof (stream_scale)) ; + if (stream_scale < 1e-10) + stream_scale = 1.0 ; + else + stream_scale = 32700.0 / stream_scale ; + } + channels = sfInfo.channels; + duration = float(sfInfo.frames) / float(sfInfo.samplerate); + samplerate = sfInfo.samplerate; + stream_samples_read = 0; + } + + int curr_buffer_size = BUFFER_STREAM_SIZE*channels; + if(speed>1) curr_buffer_size *= (int)round(speed); + buffer.resize(curr_buffer_size); + fftAuxBuffer.resize(buffer.size()); + if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){ + sf_count_t samples_read = sf_read_float (streamf, &fftAuxBuffer[0], fftAuxBuffer.size()); + stream_samples_read += samples_read; + if(samples_read<(int)fftAuxBuffer.size()){ + fftAuxBuffer.resize(samples_read); + buffer.resize(samples_read); + setPosition(0); + if(!bLoop) stopThread(); + stream_samples_read = 0; + stream_end = true; + } + for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){ + fftAuxBuffer[i] *= stream_scale ; + buffer[i] = 32565.0 * fftAuxBuffer[i]; + } + }else{ + sf_count_t frames_read = sf_readf_short(streamf,&buffer[0],curr_buffer_size/channels); + stream_samples_read += frames_read*channels; + if(frames_read & buffer,vector & fftAuxBuffer){ + if(!mp3streamf){ + int err = MPG123_OK; + mp3streamf = mpg123_new(nullptr,&err); + if(mpg123_open(mp3streamf,path.string().c_str())!=MPG123_OK){ + mpg123_close(mp3streamf); + mpg123_delete(mp3streamf); + ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): couldn't read \"" << path << "\""; + return false; + } + + long int rate; + mpg123_getformat(mp3streamf,&rate,&channels,(int*)&stream_encoding); + if(stream_encoding!=MPG123_ENC_SIGNED_16){ + ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): " << getMpg123EncodingString(stream_encoding) + << " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16"; + return false; + } + samplerate = rate; + mp3_buffer_size = mpg123_outblock( mp3streamf ); + + + mpg123_seek(mp3streamf,0,SEEK_END); + off_t samples = mpg123_tell(mp3streamf); + duration = float(samples/channels) / float(samplerate); + mpg123_seek(mp3streamf,0,SEEK_SET); + } + + int curr_buffer_size = mp3_buffer_size; + if(speed>1) curr_buffer_size *= (int)round(speed); + buffer.resize(curr_buffer_size); + fftAuxBuffer.resize(buffer.size()); + size_t done=0; + if(mpg123_read(mp3streamf,(unsigned char*)&buffer[0],curr_buffer_size*2,&done)==MPG123_DONE){ + setPosition(0); + buffer.resize(done/2); + fftAuxBuffer.resize(done/2); + if(!bLoop) stopThread(); + stream_end = true; + } + + + for(int i=0;i<(int)buffer.size();i++){ + fftAuxBuffer[i] = float(buffer[i])/32565.f; + } + + return true; +} +#endif + +//------------------------------------------------------------ +bool ofOpenALSoundPlayer::stream(const std::filesystem::path& fileName, vector & buffer){ +#ifdef OF_USING_MPG123 + if(ofFilePath::getFileExt(fileName)=="mp3" || ofFilePath::getFileExt(fileName)=="MP3" || mp3streamf){ + if(!mpg123Stream(fileName,buffer,fftAuxBuffer)) return false; + }else +#endif + if(!sfStream(fileName,buffer,fftAuxBuffer)) return false; + + fftBuffers.resize(channels); + int numFrames = buffer.size()/channels; + + for(int i=0;i & buffer){ +#ifdef OF_USING_MPG123 + if(ofFilePath::getFileExt(fileName)!="mp3" && ofFilePath::getFileExt(fileName)!="MP3"){ + if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false; + }else{ + if(!mpg123ReadFile(fileName,buffer,fftAuxBuffer)) return false; + } +#else + if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false; +#endif + fftBuffers.resize(channels); + int numFrames = buffer.size()/channels; + + for(int i=0;i > multibuffer; + multibuffer.resize(channels); + sources.resize(channels); + alGenSources(channels, &sources[0]); + if(isStreaming){ + for(int s=0; s<2;s++){ + for(int i=0;i > multibuffer; + multibuffer.resize(channels); + while(isThreadRunning()){ + std::unique_lock lock(mutex); + for(int i=0; i1){ + for(int j=0;j lock(mutex); + + // Delete sources before buffers. + alDeleteSources(sources.size(),&sources[0]); + alDeleteBuffers(buffers.size(),&buffers[0]); + + sources.clear(); + buffers.clear(); + } + + // Free resources and close file descriptors. +#ifdef OF_USING_MPG123 + if(mp3streamf){ + mpg123_close(mp3streamf); + mpg123_delete(mp3streamf); + } + mp3streamf = 0; +#endif + + if(streamf){ + sf_close(streamf); + } + streamf = 0; + + bLoadedOk = false; +} + +//------------------------------------------------------------ +bool ofOpenALSoundPlayer::isPlaying() const{ + if(sources.empty()) return false; + if(isStreaming) return isThreadRunning(); + ALint state; + bool playing=false; + for(int i=0;i<(int)sources.size();i++){ + alGetSourcei(sources[i],AL_SOURCE_STATE,&state); + playing |= (state == AL_PLAYING); + } + return playing; +} + +//------------------------------------------------------------ +bool ofOpenALSoundPlayer::isPaused() const{ + if(sources.empty()) return false; + ALint state; + bool paused=true; + for(int i=0;i<(int)sources.size();i++){ + alGetSourcei(sources[i],AL_SOURCE_STATE,&state); + paused &= (state == AL_PAUSED); + } + return paused; +} + +//------------------------------------------------------------ +float ofOpenALSoundPlayer::getSpeed() const{ + return speed; +} + +//------------------------------------------------------------ +float ofOpenALSoundPlayer::getPan() const{ + return pan; +} + +//------------------------------------------------------------ +float ofOpenALSoundPlayer::getVolume() const{ + return volume; +} + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setVolume(float vol){ + volume = vol; + if(sources.empty()) return; + if(channels==1){ + alSourcef (sources[sources.size()-1], AL_GAIN, vol); + }else{ + setPan(pan); + } +} + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setPosition(float pct){ + setPositionMS(duration*pct*1000.f); +} + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setPositionMS(int ms){ + if(sources.empty()) return; +#ifdef OF_USING_MPG123 + if(mp3streamf){ + mpg123_seek(mp3streamf,float(ms)/1000.f*samplerate,SEEK_SET); + }else +#endif + if(streamf){ + stream_samples_read = sf_seek(streamf,float(ms)/1000.f*samplerate,SEEK_SET) * channels; + }else{ + for(int i=0;i<(int)channels;i++){ + alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,float(ms)/1000.f); + } + } +} + +//------------------------------------------------------------ +float ofOpenALSoundPlayer::getPosition() const{ + if(duration==0 || sources.empty()) + return 0; + else + return getPositionMS()/(1000.f*duration); +} + +//------------------------------------------------------------ +int ofOpenALSoundPlayer::getPositionMS() const{ + if(sources.empty()) return 0; + float pos; +#ifdef OF_USING_MPG123 + if(mp3streamf){ + pos = float(mpg123_tell(mp3streamf)) / float(samplerate); + }else +#endif + if(streamf){ + pos = float(stream_samples_read) / float(channels) / float(samplerate); + }else{ + alGetSourcef(sources[sources.size()-1],AL_SEC_OFFSET,&pos); + } + return pos * 1000.f; +} + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setPan(float p){ + if(sources.empty()) return; + p = glm::clamp(p, -1.f, 1.f); + pan = p; + if(channels==1){ + float pos[3] = {p,0,0}; + alSourcefv(sources[sources.size()-1],AL_POSITION,pos); + }else{ + // calculates left/right volumes from pan-value (constant panning law) + // see: Curtis Roads: Computer Music Tutorial p 460 + // thanks to jasch + float angle = p * 0.7853981633974483f; // in radians from -45. to +45. + float cosAngle = cos(angle); + float sinAngle = sin(angle); + float leftVol = (cosAngle - sinAngle) * 0.7071067811865475; // multiplied by sqrt(2)/2 + float rightVol = (cosAngle + sinAngle) * 0.7071067811865475; // multiplied by sqrt(2)/2 + for(int i=0;i<(int)channels;i++){ + if(i==0){ + alSourcef(sources[sources.size()-channels+i],AL_GAIN,leftVol*volume); + }else{ + alSourcef(sources[sources.size()-channels+i],AL_GAIN,rightVol*volume); + } + } + } +} + + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setPaused(bool bP){ + if(sources.empty()) return; + std::unique_lock lock(mutex); + if(bP){ + alSourcePausev(sources.size(),&sources[0]); + if(isStreaming){ + stopThread(); + } + }else{ + alSourcePlayv(sources.size(),&sources[0]); + if(isStreaming){ + startThread(); + } + } + + bPaused = bP; +} + + +//------------------------------------------------------------ +void ofOpenALSoundPlayer::setSpeed(float spd){ + for(int i=0;i lock(mutex); + int err = alGetError(); + + // if the sound is set to multiplay, then create new sources, + // do not multiplay on loop or we won't be able to stop it + if (bMultiPlay && !bLoop){ + sources.resize(sources.size()+channels); + alGetError(); // Clear error. + alGenSources(channels, &sources[sources.size()-channels]); + err = alGetError(); + if (err != AL_NO_ERROR){ + ofLogError("ofOpenALSoundPlayer") << "play(): couldn't create multiplay stereo sources: " + << (int) err << " " << getALErrorString(err); + return; + } + for(int i=0;i lock(mutex); + alSourceStopv(channels,&sources[sources.size()-channels]); + if(isStreaming){ + setPosition(0); + stopThread(); + } +} + +// ---------------------------------------------------------------------------- +void ofOpenALSoundPlayer::initFFT(int bands){ + if(int(bins.size())==bands) return; + int signalSize = (bands-1)*2; + if(fftCfg!=0) kiss_fftr_free(fftCfg); + fftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr); + cx_out.resize(bands); + bins.resize(bands); + createWindow(signalSize); +} + +// ---------------------------------------------------------------------------- +void ofOpenALSoundPlayer::initSystemFFT(int bands){ + if(int(systemBins.size())==bands) return; + int signalSize = (bands-1)*2; + if(systemFftCfg!=0) kiss_fftr_free(systemFftCfg); + systemFftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr); + systemCx_out.resize(bands); + systemBins.resize(bands); + createWindow(signalSize); +} + +float * ofOpenALSoundPlayer::getCurrentBufferSum(int size){ + if(int(windowedSignal.size())!=size){ + windowedSignal.resize(size); + } + windowedSignal.assign(windowedSignal.size(),0); + for(int k=0;k=(int)fftBuffers[0].size()) continue; + for(int i=0;i::iterator it; + for(it=players().begin();it!=players().end();it++){ + if(!(*it)->isPlaying()) continue; + float * buffer = (*it)->getCurrentBufferSum(signalSize); + for(int i=0;i & signal){ + for(int i = 0; i < (int)signal.size(); i++) + signal[i] *= window[i]; +} + + +#endif diff --git a/patches/msys2/sound/ofOpenALSoundPlayer.h b/patches/msys2/sound/ofOpenALSoundPlayer.h index 042f7b3..9c0adde 100644 --- a/patches/msys2/sound/ofOpenALSoundPlayer.h +++ b/patches/msys2/sound/ofOpenALSoundPlayer.h @@ -1,157 +1,157 @@ -#pragma once - -#include "ofConstants.h" - -#ifdef OF_SOUND_PLAYER_OPENAL -#include "ofSoundBaseTypes.h" -#include "ofThread.h" - - - -typedef unsigned int ALuint; - -#include "kiss_fft.h" -#include "kiss_fftr.h" - - - -typedef struct SNDFILE_tag SNDFILE ; - - -#ifdef OF_USING_MPG123 - typedef struct mpg123_handle_struct mpg123_handle; -#endif - -class ofEventArgs; - -// TO DO : -// --------------------------- -// -fft via fmod, as in the last time... -// -close fmod if it's up -// -loadSoundForStreaming(char * fileName); -// --------------------------- - -// interesting: -// http://www.compuphase.com/mp3/mp3loops.htm - - -// ---------------------------------------------------------------------------- SOUND SYSTEM FMOD - -// --------------------- global functions: -void ofFmodSoundStopAll(); -void ofFmodSoundSetVolume(float vol); -void ofOpenALSoundUpdate(); // calls FMOD update. -float * ofFmodSoundGetSpectrum(int nBands); // max 512... - - -// --------------------- player functions: -class ofOpenALSoundPlayer : public ofBaseSoundPlayer, public ofThread { - - public: - - ofOpenALSoundPlayer(); - virtual ~ofOpenALSoundPlayer(); - - bool load(const std::filesystem::path& fileName, bool stream = false); - void unload(); - void play(); - void stop(); - - void setVolume(float vol); - void setPan(float vol); // -1 to 1 - void setSpeed(float spd); - void setPaused(bool bP); - void setLoop(bool bLp); - void setMultiPlay(bool bMp); - void setPosition(float pct); // 0 = start, 1 = end; - void setPositionMS(int ms); - - - float getPosition() const; - int getPositionMS() const; - bool isPlaying() const; - float getSpeed() const; - float getPan() const; - float getVolume() const; - bool isPaused() const; - bool isLoaded() const; - - static void initialize(); - static void close(); - - float * getSpectrum(int bands); - - static float * getSystemSpectrum(int bands); - - protected: - void threadedFunction(); - - private: - friend void ofOpenALSoundUpdate(); - void update(ofEventArgs & args); - void initFFT(int bands); - float * getCurrentBufferSum(int size); - - static void createWindow(int size); - static void runWindow(std::vector & signal); - static void initSystemFFT(int bands); - - bool sfReadFile(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); - bool sfStream(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); -#ifdef OF_USING_MPG123 - bool mpg123ReadFile(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); - bool mpg123Stream(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); -#endif - - bool readFile(const std::filesystem::path& fileName,std::vector & buffer); - bool stream(const std::filesystem::path& fileName, std::vector & buffer); - - bool isStreaming; - bool bMultiPlay; - bool bLoop; - bool bLoadedOk; - bool bPaused; - float pan; // 0 - 1 - float volume; // 0 - 1 - float internalFreq; // 44100 ? - float speed; // -n to n, 1 = normal, -1 backwards - unsigned int length; // in samples; - - static std::vector window; - static float windowSum; - - int channels; - float duration; //in secs - int samplerate; - std::vector buffers; - std::vector sources; - - // fft structures - std::vector > fftBuffers; - kiss_fftr_cfg fftCfg; - std::vector windowedSignal; - std::vector bins; - std::vector cx_out; - - - static kiss_fftr_cfg systemFftCfg; - static std::vector systemWindowedSignal; - static std::vector systemBins; - static std::vector systemCx_out; - - SNDFILE* streamf; - size_t stream_samples_read; -#ifdef OF_USING_MPG123 - mpg123_handle * mp3streamf; - int stream_encoding; -#endif - int mp3_buffer_size; - int stream_subformat; - double stream_scale; - std::vector buffer; - std::vector fftAuxBuffer; - - bool stream_end; -}; - -#endif +#pragma once + +#include "ofConstants.h" + +#ifdef OF_SOUND_PLAYER_OPENAL +#include "ofSoundBaseTypes.h" +#include "ofThread.h" + + + +typedef unsigned int ALuint; + +#include "kiss_fft.h" +#include "kiss_fftr.h" + + + +typedef struct SNDFILE_tag SNDFILE ; + + +#ifdef OF_USING_MPG123 + typedef struct mpg123_handle_struct mpg123_handle; +#endif + +class ofEventArgs; + +// TO DO : +// --------------------------- +// -fft via fmod, as in the last time... +// -close fmod if it's up +// -loadSoundForStreaming(char * fileName); +// --------------------------- + +// interesting: +// http://www.compuphase.com/mp3/mp3loops.htm + + +// ---------------------------------------------------------------------------- SOUND SYSTEM FMOD + +// --------------------- global functions: +void ofFmodSoundStopAll(); +void ofFmodSoundSetVolume(float vol); +void ofOpenALSoundUpdate(); // calls FMOD update. +float * ofFmodSoundGetSpectrum(int nBands); // max 512... + + +// --------------------- player functions: +class ofOpenALSoundPlayer : public ofBaseSoundPlayer, public ofThread { + + public: + + ofOpenALSoundPlayer(); + virtual ~ofOpenALSoundPlayer(); + + bool load(const std::filesystem::path& fileName, bool stream = false); + void unload(); + void play(); + void stop(); + + void setVolume(float vol); + void setPan(float vol); // -1 to 1 + void setSpeed(float spd); + void setPaused(bool bP); + void setLoop(bool bLp); + void setMultiPlay(bool bMp); + void setPosition(float pct); // 0 = start, 1 = end; + void setPositionMS(int ms); + + + float getPosition() const; + int getPositionMS() const; + bool isPlaying() const; + float getSpeed() const; + float getPan() const; + float getVolume() const; + bool isPaused() const; + bool isLoaded() const; + + static void initialize(); + static void close(); + + float * getSpectrum(int bands); + + static float * getSystemSpectrum(int bands); + + protected: + void threadedFunction(); + + private: + friend void ofOpenALSoundUpdate(); + void update(ofEventArgs & args); + void initFFT(int bands); + float * getCurrentBufferSum(int size); + + static void createWindow(int size); + static void runWindow(std::vector & signal); + static void initSystemFFT(int bands); + + bool sfReadFile(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); + bool sfStream(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); +#ifdef OF_USING_MPG123 + bool mpg123ReadFile(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); + bool mpg123Stream(const std::filesystem::path& path,std::vector & buffer,std::vector & fftAuxBuffer); +#endif + + bool readFile(const std::filesystem::path& fileName,std::vector & buffer); + bool stream(const std::filesystem::path& fileName, std::vector & buffer); + + bool isStreaming; + bool bMultiPlay; + bool bLoop; + bool bLoadedOk; + bool bPaused; + float pan; // 0 - 1 + float volume; // 0 - 1 + float internalFreq; // 44100 ? + float speed; // -n to n, 1 = normal, -1 backwards + unsigned int length; // in samples; + + static std::vector window; + static float windowSum; + + int channels; + float duration; //in secs + int samplerate; + std::vector buffers; + std::vector sources; + + // fft structures + std::vector > fftBuffers; + kiss_fftr_cfg fftCfg; + std::vector windowedSignal; + std::vector bins; + std::vector cx_out; + + + static kiss_fftr_cfg systemFftCfg; + static std::vector systemWindowedSignal; + static std::vector systemBins; + static std::vector systemCx_out; + + SNDFILE* streamf; + size_t stream_samples_read; +#ifdef OF_USING_MPG123 + mpg123_handle * mp3streamf; + int stream_encoding; +#endif + int mp3_buffer_size; + int stream_subformat; + double stream_scale; + std::vector buffer; + std::vector fftAuxBuffer; + + bool stream_end; +}; + +#endif diff --git a/patches/ofAppEGLWindow.cpp b/patches/ofAppEGLWindow.cpp index 7db2803..01a270d 100644 --- a/patches/ofAppEGLWindow.cpp +++ b/patches/ofAppEGLWindow.cpp @@ -1,2265 +1,2265 @@ -#include "ofAppEGLWindow.h" - -#include "ofGraphics.h" // used in runAppViaInfiniteLoop() -#include "ofAppRunner.h" -#include "ofUtils.h" -#include "ofFileUtils.h" -#include "ofGLProgrammableRenderer.h" -#include "ofGLRenderer.h" -#include - -using namespace std; - -// native events -struct udev* udev; -struct udev_device* dev; -struct udev_monitor* mon; -static int udev_fd = -1; - -static int keyboard_fd = -1; // defaults to 0 ie console - -// minimal map -const int lowercase_map[] = { - 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', - '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', - 'j', 'k', 'l', ';', '\'', '\n', 0, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r' - -}; - -// minimal keyboard map -const int uppercase_map[] = { - 0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', - '_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H', - 'J', 'K', 'L', ':', '"', '\n', 0, '\\', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r' -}; - -// keep track of a few things ... -typedef struct { - bool shiftPressed; - bool capsLocked; -} KeyboardState; - -static KeyboardState kb; - -static struct termios tc; -static struct termios ots; - -typedef struct { - int mouseButtonState; -} MouseState; - -// TODO, make this match the upcoming additions to ofWindow -#define MOUSE_BUTTON_LEFT_MASK 1 -#define MOUSE_BUTTON_MIDDLE_MASK 1 << 1 -#define MOUSE_BUTTON_RIGHT_MASK 2 << 1 - -static MouseState mb; -ofAppEGLWindow* ofAppEGLWindow::instance = NULL; - -static int string_ends_with(const char *str, const char *suffix) { - if (!str || !suffix) - return 0; - size_t lenstr = strlen(str); - size_t lensuffix = strlen(suffix); - if (lensuffix > lenstr) - return 0; - return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; -} - -static int string_begins_with(const char *str, const char *prefix) { - if (!str || !prefix) - return 0; - size_t lenstr = strlen(str); - size_t lenprefix = strlen(prefix); - if (lenprefix > lenstr) - return 0; - return strncmp(str, prefix, lenprefix) == 0; -} - -static int dummy_sort(const struct dirent **a,const struct dirent **b) { - return 1; // dummy sort -} - -static int filter_kbd(const struct dirent *d) { - if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-kbd")) { - return 1; - } else { - return 0; - } -} - -static int filter_mouse(const struct dirent *d) { - if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-mouse")) { - return 1; - } else { - return 0; - } -} - -static int filter_event(const struct dirent *d) { - if(d->d_type != DT_DIR && string_begins_with(d->d_name,"event")) { - return 1; - } else { - return 0; - } -} - -// native -#define MOUSE_CURSOR_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \ - { unsigned int __bpp; unsigned char *__ip; const unsigned char *__il, *__rd; \ - __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \ - __rd = (rle_data); \ - while (__ip < __il) { unsigned int __l = *(__rd++); \ - if (__l & 128) { __l = __l - 128; \ - do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \ - } else { __l *= 4; memcpy (__ip, __rd, __l); \ - __ip += __l; __rd += __l; } } \ - } while (0) -static const struct { - unsigned int width; - unsigned int height; - unsigned int bpp; /* 2:RGB16, 3:RGB, 4:RGBA */ - unsigned char rle_pixel_data[382 + 1]; -} mouse_cursor_data = { - 12, 19, 4, - "\1\0\0\0\377\213\377\377\377\0\202\0\0\0\377\212\377\377\377\0\3\0\0\0\377" - "\377\377\377\377\0\0\0\377\211\377\377\377\0\1\0\0\0\377\202\377\377\377" - "\377\1\0\0\0\377\210\377\377\377\0\1\0\0\0\377\203\377\377\377\377\1\0\0" - "\0\377\207\377\377\377\0\1\0\0\0\377\204\377\377\377\377\1\0\0\0\377\206" - "\377\377\377\0\1\0\0\0\377\205\377\377\377\377\1\0\0\0\377\205\377\377\377" - "\0\1\0\0\0\377\206\377\377\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0" - "\377\207\377\377\377\377\1\0\0\0\377\203\377\377\377\0\1\0\0\0\377\210\377" - "\377\377\377\1\0\0\0\377\202\377\377\377\0\1\0\0\0\377\211\377\377\377\377" - "\3\0\0\0\377\377\377\377\0\0\0\0\377\212\377\377\377\377\202\0\0\0\377\206" - "\377\377\377\377\206\0\0\0\377\203\377\377\377\377\1\0\0\0\377\202\377\377" - "\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0\377\202\377\377\377\377\3" - "\0\0\0\377\377\377\377\0\0\0\0\377\202\377\377\377\377\1\0\0\0\377\203\377" - "\377\377\0\3\0\0\0\377\377\377\377\377\0\0\0\377\202\377\377\377\0\1\0\0" - "\0\377\202\377\377\377\377\1\0\0\0\377\203\377\377\377\0\202\0\0\0\377\204" - "\377\377\377\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\210\377\377\377" - "\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\211\377\377\377\0\202\0\0" - "\0\377\203\377\377\377\0", -}; - -// from http://cantuna.googlecode.com/svn-history/r16/trunk/src/screen.cpp -#define CASE_STR(x,y) case x: str = y; break - -static const char* eglErrorString(EGLint err) { - string str; - switch (err) { - CASE_STR(EGL_SUCCESS, "no error"); - CASE_STR(EGL_NOT_INITIALIZED, "EGL not, or could not be, initialized"); - CASE_STR(EGL_BAD_ACCESS, "access violation"); - CASE_STR(EGL_BAD_ALLOC, "could not allocate resources"); - CASE_STR(EGL_BAD_ATTRIBUTE, "invalid attribute"); - CASE_STR(EGL_BAD_CONTEXT, "invalid context specified"); - CASE_STR(EGL_BAD_CONFIG, "invald frame buffer configuration specified"); - CASE_STR(EGL_BAD_CURRENT_SURFACE, "current window, pbuffer or pixmap surface is no longer valid"); - CASE_STR(EGL_BAD_DISPLAY, "invalid display specified"); - CASE_STR(EGL_BAD_SURFACE, "invalid surface specified"); - CASE_STR(EGL_BAD_MATCH, "bad argument match"); - CASE_STR(EGL_BAD_PARAMETER, "invalid paramater"); - CASE_STR(EGL_BAD_NATIVE_PIXMAP, "invalid NativePixmap"); - CASE_STR(EGL_BAD_NATIVE_WINDOW, "invalid NativeWindow"); - CASE_STR(EGL_CONTEXT_LOST, "APM event caused context loss"); - default: str = "unknown error " + err; break; - } - return str.c_str(); -} - - -// X11 events -#include - - -#ifdef TARGET_RASPBERRY_PI -// TODO: remove these when they enter system headers -// From : https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.h -#ifndef ELEMENT_CHANGE_LAYER -#define ELEMENT_CHANGE_LAYER (1<<0) -#endif -#ifndef ELEMENT_CHANGE_OPACITY -#define ELEMENT_CHANGE_OPACITY (1<<1) -#endif -#ifndef ELEMENT_CHANGE_DEST_RECT -#define ELEMENT_CHANGE_DEST_RECT (1<<2) -#endif -#ifndef ELEMENT_CHANGE_SRC_RECT -#define ELEMENT_CHANGE_SRC_RECT (1<<3) -#endif -#ifndef ELEMENT_CHANGE_MASK_RESOURCE -#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4) -#endif -#ifndef ELEMENT_CHANGE_TRANSFORM -#define ELEMENT_CHANGE_TRANSFORM (1<<5) -#endif -#endif - - -//------------------------------------------------------------------------------------- -ofAppEGLWindow::Settings::Settings() -:ofGLESWindowSettings(){ - eglWindowPreference = OF_APP_WINDOW_AUTO; - eglWindowOpacity = 255; - - // these are usually set as default, but set them here just to be sure - frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red - frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green - frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue - frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha - frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha - frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth - frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil - frameBufferAttributes[EGL_SAMPLES] = 1; - - initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255); - - screenNum = 0; /* 0 = LCD on the raspberry pi */ - layer = 0; -} - -ofAppEGLWindow::Settings::Settings(const ofGLESWindowSettings & settings) -:ofGLESWindowSettings(settings){ - eglWindowPreference = OF_APP_WINDOW_AUTO; - eglWindowOpacity = 255; - - // these are usually set as default, but set them here just to be sure - frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red - frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green - frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue - frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha - frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha - frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth - frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil - frameBufferAttributes[EGL_SAMPLES] = 1; - - initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255); - - screenNum = 0; /* 0 = LCD on the raspberry pi */ - layer = 0; -} - -//------------------------------------------------------------ -ofAppEGLWindow::ofAppEGLWindow() { - keyboardDetected = false; - mouseDetected = false; - threadTimeout = ofThread::INFINITE_JOIN_TIMEOUT; - bNewScreenMode = false; - buttonInUse = -1; - bEnableSetupScreen = false; - bShowCursor = true; - nFramesSinceWindowResized = 0; - mouseScaleX = 2.0f; - mouseScaleY = 2.0f; - isUsingX11 = false; - isWindowInited = false; - isSurfaceInited = false; - x11Display = NULL; - x11Screen = NULL; - x11ScreenNum = 0l; - glesVersion = 1; - - if(instance!=NULL){ - ofLogError("ofAppEGLWindow") << "trying to create more than one instance"; - } - instance = this; -} - -//------------------------------------------------------------ -ofAppEGLWindow::~ofAppEGLWindow() { - close(); -} - -//------------------------------------------------------------ -EGLDisplay ofAppEGLWindow::getEglDisplay() const { - return eglDisplay; -} - -//------------------------------------------------------------ -EGLSurface ofAppEGLWindow::getEglSurface() const { - return eglSurface; -} - -//------------------------------------------------------------ -EGLContext ofAppEGLWindow::getEglContext() const { - return eglContext; -} - -#ifndef TARGET_RASPBERRY_PI -//------------------------------------------------------------ -Display* ofAppEGLWindow::getX11Display(){ - return x11Display; -} - -//------------------------------------------------------------ -Window ofAppEGLWindow::getX11Window(){ - return x11Window; -} -#endif -//------------------------------------------------------------ -EGLConfig ofAppEGLWindow::getEglConfig() const { - return eglConfig; -} - -//------------------------------------------------------------ -EGLint ofAppEGLWindow::getEglVersionMajor () const { - return eglVersionMajor; -} - -//------------------------------------------------------------ -EGLint ofAppEGLWindow::getEglVersionMinor() const { - return eglVersionMinor; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::initNative() { -#ifdef TARGET_RASPBERRY_PI - initRPiNative(); -#endif -} - -//------------------------------------------------------------ -void ofAppEGLWindow::exitNative() { -#ifdef TARGET_RASPBERRY_PI - exitRPiNative(); -#endif -} - -//------------------------------------------------------------ -EGLNativeWindowType ofAppEGLWindow::getNativeWindow() { - if(!isWindowInited) { - ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL"; - return NULL; - } - - if(isUsingX11) { - return (EGLNativeWindowType)x11Window; - } else { -#ifdef TARGET_RASPBERRY_PI - return (EGLNativeWindowType)&dispman_native_window; -#else - ofLogNotice("ofAppEGLWindow") << "getNativeWindow(): no native window type for this system, perhaps try X11?"; - return NULL; -#endif - } -} - -//------------------------------------------------------------ -EGLNativeDisplayType ofAppEGLWindow::getNativeDisplay() { - if(!isWindowInited) { - ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL"; - return 0; - } - - if(isUsingX11) { - return (EGLNativeDisplayType)x11Display; - } else { -#ifdef TARGET_RASPBERRY_PI - return (EGLNativeDisplayType)NULL; -#else - ofLogNotice("ofAppEGLWindow") << "getNativeDisplay(): no native window type for this system, perhaps try X11?"; - return 0; -#endif - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setup(const ofGLESWindowSettings & settings){ - const Settings * glSettings = dynamic_cast(&settings); - if(glSettings){ - setup(*glSettings); - }else{ - setup(Settings(settings)); - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setup(const Settings & _settings) { - settings = _settings; - windowMode = OF_WINDOW; - bNewScreenMode = true; - nFramesSinceWindowResized = 0; - buttonInUse = 0; - bEnableSetupScreen = true; - eglDisplayString = ""; - orientation = OF_ORIENTATION_DEFAULT; - - //TODO: 2.0f is an arbitrary factor that makes mouse speed ok at 1024x768, - // to be totally correct we might need to take into account screen size - // and add acceleration - mouseScaleX = 2.0f; - mouseScaleY = 2.0f; - - isUsingX11 = false; - isWindowInited = false; - isSurfaceInited = false; - - eglDisplay = NULL; - eglSurface = NULL; - eglContext = NULL; - eglConfig = NULL; - eglVersionMajor = -1; - eglVersionMinor = -1; - glesVersion = 1; - - // X11 check - // char * pDisplay; - // pDisplay = getenv ("DISPLAY"); - // bool bIsX11Available = (pDisplay != NULL); - - bool bIsX11Available = getenv("DISPLAY") != NULL; - - if(settings.eglWindowPreference == OF_APP_WINDOW_AUTO) { - if(bIsX11Available) { - isUsingX11 = true; - } else { - isUsingX11 = false; - } - } else if(settings.eglWindowPreference == OF_APP_WINDOW_NATIVE) { - isUsingX11 = false; - } else if(settings.eglWindowPreference == OF_APP_WINDOW_X11) { - isUsingX11 = true; - if(!bIsX11Available) { - isUsingX11 = false; - ofLogError("ofAppEGLWindow") << "init(): X11 window requested, but X11 is not available"; - } - } - - //////////////// - // TODO remove the following ifdef once x11 is accelerated on RPI -#ifdef TARGET_RASPBERRY_PI - if(isUsingX11) { - isUsingX11 = false; - ofLogWarning("ofAppEGLWindow") << "init(): X11 not availble on RPI yet, using a native window instead"; - } -#endif - //////////////// - - initNative(); - - glesVersion = settings.glesVersion; - // we set this here, and if we need to make a fullscreen - // app, we do it during the first loop. - windowMode = settings.windowMode; - bShowCursor = true; - - nonFullscreenWindowRect.set(0,0,settings.width,settings.height); - nonFullscreenWindowRect.standardize(); - - ofRectangle startRect = nonFullscreenWindowRect; - bNewScreenMode = false; - - if(windowMode == OF_GAME_MODE) { - ofLogWarning("ofAppEGLWindow") << "setupOpenGL(): OF_GAME_MODE not supported, using OF_WINDOW"; - startRect = nonFullscreenWindowRect; - } else if(windowMode == OF_FULLSCREEN) { - startRect = getScreenRect(); - } - - isWindowInited = createWindow(startRect); - isSurfaceInited = createSurface(); - - if(!isWindowInited) { - ofLogError("ofAppEGLWindow") << "setupOpenGL(): screen creation failed, window not inited"; - } - - setupPeripherals(); - - nFramesSinceWindowResized = 0; - - if(settings.glesVersion>1){ - currentRenderer = make_shared(this); - }else{ - currentRenderer = make_shared(this); - } - - makeCurrent(); - if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){ - static_cast(currentRenderer.get())->setup(settings.glesVersion,0); - }else{ - static_cast(currentRenderer.get())->setup(); - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setupPeripherals() { - if(!isUsingX11) { - // roll our own cursor! - mouseCursor.allocate(mouse_cursor_data.width,mouse_cursor_data.height,OF_IMAGE_COLOR_ALPHA); - MOUSE_CURSOR_RUN_LENGTH_DECODE(mouseCursor.getPixels().getData(),mouse_cursor_data.rle_pixel_data,mouse_cursor_data.width*mouse_cursor_data.height,mouse_cursor_data.bpp); - mouseCursor.update(); - ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): peripheral setup complete"; - setupNativeEvents(); - ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): native event setup complete"; - - } else { - ofLogError("ofAppEGLWindow") << "setupPeripherals(): peripherals not supported on X11"; - } -} - -//------------------------------------------------------------ -bool ofAppEGLWindow::createSurface() { - - EGLNativeWindowType nativeWindow = getNativeWindow(); - EGLNativeDisplayType display = getNativeDisplay(); - - ofLogNotice("ofAppEGLWindow") << "createSurface(): setting up EGL Display"; - // get an EGL eglDisplay connection - - isSurfaceInited = false; - - EGLint result; - - if(display==0){ - eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - }else{ - eglDisplay = eglGetDisplay(display); - } - - if(eglDisplay == EGL_NO_DISPLAY) { - ofLogNotice("ofAppEGLWindow") << "createSurface(): eglGetDisplay returned: " << eglDisplay; - return false; - }else{ - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL Display correctly set " << eglDisplay; - } - - // initialize the EGL eglDisplay connection - result = eglInitialize(eglDisplay, - &eglVersionMajor, - &eglVersionMinor); - - if(result == EGL_BAD_DISPLAY) { - // eglDisplay is not an EGL connection - ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_BAD_DISPLAY"; - return false; - } else if(result == EGL_NOT_INITIALIZED) { - // eglDisplay cannot be intitialized - ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_NOT_INITIALIZED"; - return false; - } else if(result == EGL_FALSE) { - // eglinitialize was not initialiezd - ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_FALSE"; - return false; - } else { - // result == EGL_TRUE - // success! - } - - EGLint glesVersion; - int glesVersionForContext; - - if(ofGetCurrentRenderer()) { - ofLogNotice("ofAppEGLWindow") << "createSurface(): current renderer type: " << ofGetCurrentRenderer()->getType(); - } else { - ofLogNotice("ofAppEGLWindow") << "createSurface(): no current renderer selected"; - } - - if(this->glesVersion==2){ - glesVersion = EGL_OPENGL_ES2_BIT; - glesVersionForContext = 2; - ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES2 renderer detected"; - }else{ - glesVersion = EGL_OPENGL_ES_BIT; - glesVersionForContext = 1; - ofLogNotice("ofAppEGLWindow") << "createSurface(): default renderer detected"; - } - - ofEGLAttributeListIterator iter, iterEnd; - int i; - - // each attribute has 2 values, and we need one extra for the EGL_NONE terminator - EGLint attribute_list_framebuffer_config[settings.frameBufferAttributes.size() * 2 + 3]; - - iter = settings.frameBufferAttributes.begin(); - iterEnd = settings.frameBufferAttributes.end(); - i = 0; - for(; iter != iterEnd; iter++) { - attribute_list_framebuffer_config[i++] = iter->first; - attribute_list_framebuffer_config[i++] = iter->second; - } - attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE; - attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version - attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator - - EGLint num_configs; - - // get an appropriate EGL frame buffer configuration - // http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html - result = eglChooseConfig(eglDisplay, - attribute_list_framebuffer_config, - &eglConfig, - 1, // we only want the first one. if we want more, - // we need to pass in an array. - // we are optimistic and don't give it more chances - // to find a good configuration - &num_configs); - - if(result == EGL_FALSE) { - EGLint error = eglGetError(); - ofLogError("ofAppEGLWindow") << "createSurface(): error finding valid configuration based on settings: " << eglErrorString(error); - return false; - } - - if(num_configs <= 0 || eglConfig == NULL) { - ofLogError("ofAppEGLWindow") << "createSurface(): no matching configs were found, num_configs: " << num_configs; - return false; - } - - - // each attribute has 2 values, and we need one extra for the EGL_NONE terminator - EGLint attribute_list_window_surface[settings.windowSurfaceAttributes.size() * 2 + 1]; - - iter = settings.windowSurfaceAttributes.begin(); - iterEnd = settings.windowSurfaceAttributes.end(); - - i = 0; - for(; iter != iterEnd; iter++) { - attribute_list_window_surface[i++] = iter->first; - attribute_list_window_surface[i++] = iter->second; - } - attribute_list_window_surface[i] = EGL_NONE; // add the terminator - - // create a surface - eglSurface = eglCreateWindowSurface( eglDisplay, // our display handle - eglConfig, // our first config - nativeWindow, // our native window - attribute_list_window_surface); // surface attribute list - - if(eglSurface == EGL_NO_SURFACE) { - EGLint error = eglGetError(); - switch(error) { - case EGL_BAD_MATCH: - ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_MATCH " << eglErrorString(error); - ofLogError("ofAppEGLWindow") << "createSurface(): check window and EGLConfig attributes to determine compatibility, "; - ofLogError("ofAppEGLWindow") << "createSurface(): or verify that the EGLConfig supports rendering to a window"; - break; - case EGL_BAD_CONFIG: - ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_CONFIG " << eglErrorString(error); - ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLConfig is valid"; - break; - case EGL_BAD_NATIVE_WINDOW: - ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_NATIVE_WINDOW " << eglErrorString(error); - ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLNativeWindow is valid"; - break; - case EGL_BAD_ALLOC: - ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_ALLOC " << eglErrorString(error); - ofLogError("ofAppEGLWindow") << "createSurface(): not enough resources available"; - break; - default: - ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: << " << error << eglErrorString(error); - } - - return false; - }else{ - ofLogNotice("ofAppEGLWindow") << "createSurface(): surface created correctly"; - } - - // get an appropriate EGL frame buffer configuration - result = eglBindAPI(EGL_OPENGL_ES_API); - - if(result == EGL_FALSE) { - ofLogError("ofAppEGLWindow") << "createSurface(): error binding API: " << eglErrorString(eglGetError()); - return false; - }else{ - ofLogNotice("ofAppEGLWindow") << "createSurface(): API bound correctly"; - } - - // create an EGL rendering eglContext - EGLint attribute_list_surface_context[] = { - EGL_CONTEXT_CLIENT_VERSION, glesVersionForContext, - EGL_NONE - }; - - eglContext = eglCreateContext(eglDisplay, - eglConfig, - EGL_NO_CONTEXT, - attribute_list_surface_context); - - if(eglContext == EGL_NO_CONTEXT) { - EGLint error = eglGetError(); - if(error == EGL_BAD_CONFIG) { - ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: EGL_BAD_CONFIG " << eglErrorString(error); - return false; - } else { - ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: " << error << " " << eglErrorString(error); - return false; - } - } - - // connect the eglContext to the eglSurface - result = eglMakeCurrent(eglDisplay, - eglSurface, // draw surface - eglSurface, // read surface - eglContext); - - if(eglContext == EGL_FALSE) { - EGLint error = eglGetError(); - ofLogError("ofAppEGLWindow") << "createSurface(): couldn't making current surface: " << eglErrorString(error); - return false; - } - - // Set background color and clear buffers - glClearColor(settings.initialClearColor.r / 255.0f, - settings.initialClearColor.g / 255.0f, - settings.initialClearColor.b / 255.0f, - settings.initialClearColor.a / 255.0f); - glClear( GL_COLOR_BUFFER_BIT ); - glClear( GL_DEPTH_BUFFER_BIT ); - - ofLogNotice("ofAppEGLWindow") << "createSurface(): -----EGL-----"; - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MAJOR = " << eglVersionMajor; - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MINOR = " << eglVersionMinor; - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_CLIENT_APIS = " << eglQueryString(eglDisplay, EGL_CLIENT_APIS); - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VENDOR = " << eglQueryString(eglDisplay, EGL_VENDOR); - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION = " << eglQueryString(eglDisplay, EGL_VERSION); - ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_EXTENSIONS = " << eglQueryString(eglDisplay, EGL_EXTENSIONS); - ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_RENDERER = " << glGetString(GL_RENDERER); - ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VERSION = " << glGetString(GL_VERSION); - ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VENDOR = " << glGetString(GL_VENDOR); - ofLogNotice("ofAppEGLWindow") << "createSurface(): -------------"; - - isSurfaceInited = true; - - return true; -} - -//------------------------------------------------------------ -bool ofAppEGLWindow::destroySurface() { - if(isSurfaceInited) { - ofLogNotice("ofAppEGLWindow") << "destroySurface(): destroying EGL surface"; - eglSwapBuffers(eglDisplay, eglSurface); - eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(eglDisplay, eglSurface); - eglDestroyContext(eglDisplay, eglContext); - eglTerminate(eglDisplay); - isSurfaceInited = false; - - eglDisplay = NULL; - eglSurface = NULL; - eglContext = NULL; - eglConfig = NULL; - eglVersionMinor = -1; - eglVersionMinor = -1; - - return true; - } else { - ofLogError("ofAppEGLWindow") << "destroySurface(): attempted to destroy uninitialized window"; - return false; - } -} - -//------------------------------------------------------------ -bool ofAppEGLWindow::destroyWindow() { - if(isWindowInited) { - if(isUsingX11) { - // TODO: double check - XDestroyWindow(x11Display,x11Window); // or XCloseWindow? - XFree(x11Screen); - } else { -#ifdef TARGET_RASPBERRY_PI - dispman_update = vc_dispmanx_update_start(0); - if (dispman_element != DISPMANX_NO_HANDLE) { - vc_dispmanx_element_remove(dispman_update, dispman_element); - dispman_element = DISPMANX_NO_HANDLE; - } - - vc_dispmanx_update_submit_sync(dispman_update); - - if (dispman_display != DISPMANX_NO_HANDLE) { - vc_dispmanx_display_close(dispman_display); - dispman_display = DISPMANX_NO_HANDLE; - } -#else - ofLogNotice("ofAppEGLWindow") << "destroyWindow(): no native window type for this system, perhaps try X11?"; -#endif - } - - } else { - ofLogNotice("ofAppEGLWindow") << "destroyWindow(): destroying (uninited) native window (not implemented yet)"; - } - - return true; -} - - -void ofAppEGLWindow::close(){ - if(!isUsingX11) { - destroyNativeEvents(); - } - - // we got a terminate ... so clean up. - destroySurface(); - destroyWindow(); - - exitNative(); - events().notifyExit(); - events().disable(); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::makeCurrent(){ - eglMakeCurrent(eglDisplay, - eglSurface, // draw surface - eglSurface, // read surface - eglContext); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::swapBuffers(){ - EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface); - if(!success) { - GLint error = eglGetError(); - ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error); - } -} - -//-------------------------------------------- -void ofAppEGLWindow::startRender() { - renderer()->startRender(); -} - -//-------------------------------------------- -void ofAppEGLWindow::finishRender() { - renderer()->finishRender(); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::update() { - coreEvents.notifyUpdate(); -} - - -//------------------------------------------------------------ -void ofAppEGLWindow::draw() { - // take care of any requests for a new screen mode - if (windowMode != OF_GAME_MODE && bNewScreenMode){ - if( windowMode == OF_FULLSCREEN){ - setWindowRect(getScreenRect()); - } else if( windowMode == OF_WINDOW ){ - setWindowRect(nonFullscreenWindowRect); - } - bNewScreenMode = false; - } - - currentRenderer->startRender(); - if( bEnableSetupScreen ) currentRenderer->setupScreen(); - - coreEvents.notifyDraw(); - - if(!isUsingX11) { - if(bShowCursor){ - GLboolean bIsDepthTestEnabled = GL_FALSE; - glGetBooleanv(GL_DEPTH_TEST, &bIsDepthTestEnabled); - - if(bIsDepthTestEnabled == GL_TRUE) { - glDisable(GL_DEPTH_TEST); - } - - bool isUsingNormalizedTexCoords = ofGetUsingNormalizedTexCoords(); - if(isUsingNormalizedTexCoords) { - ofDisableNormalizedTexCoords(); - } - - currentRenderer->pushStyle(); - currentRenderer->setBlendMode(OF_BLENDMODE_ADD); - currentRenderer->setColor(255); - mouseCursor.draw(ofGetMouseX(),ofGetMouseY()); - - currentRenderer->popStyle(); - - if(bIsDepthTestEnabled == GL_TRUE) { - glEnable(GL_DEPTH_TEST); - } - - if(isUsingNormalizedTexCoords) { - ofEnableNormalizedTexCoords(); - } - } - } - currentRenderer->finishRender(); - - EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface); - if(!success) { - GLint error = eglGetError(); - ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error); - } - - nFramesSinceWindowResized++; - -} - -//------------------------------------------------------------ -ofCoreEvents & ofAppEGLWindow::events(){ - return coreEvents; -} - -//------------------------------------------------------------ -shared_ptr & ofAppEGLWindow::renderer(){ - return currentRenderer; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setupNativeEvents() { - setupNativeUDev(); - setupNativeMouse(); - setupNativeKeyboard(); - startThread(); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::destroyNativeEvents() { - destroyNativeUDev(); - destroyNativeMouse(); - destroyNativeKeyboard(); - waitForThread(true, threadTimeout); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setWindowRect(const ofRectangle& requestedWindowRect) { - if(!isWindowInited) { - ofLogError("ofAppEGLWindow") << "setWindowRect(): window not inited"; - return; - } - - ofRectangle newRect = requestedWindowRect.getStandardized(); - - if(newRect != currentWindowRect) { - ofRectangle oldWindowRect = currentWindowRect; - - if(isUsingX11) { - int ret = XMoveResizeWindow(x11Display, - x11Window, - (int)newRect.x, - (int)newRect.y, - (unsigned int)newRect.width, - (unsigned int)newRect.height); - if(ret == BadValue) { - ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadValue"; - } else if(ret == BadWindow) { - ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadWindow"; - } else { - // all is good - currentWindowRect = newRect; - } - } else { -#ifdef TARGET_RASPBERRY_PI - - VC_RECT_T dst_rect; - dst_rect.x = (int32_t)newRect.x; - dst_rect.y = (int32_t)newRect.y; - dst_rect.width = (int32_t)newRect.width; - dst_rect.height = (int32_t)newRect.height; - - VC_RECT_T src_rect; - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = (int32_t)newRect.width << 16; - src_rect.height = (int32_t)newRect.height << 16; - - DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0); - - vc_dispmanx_element_change_attributes(dispman_update, - dispman_element, - ELEMENT_CHANGE_SRC_RECT|ELEMENT_CHANGE_DEST_RECT, // we do both when resizing - 0, // layer (we aren't changing it here) - 0, // opactiy (we aren't changing it here) - &dst_rect, - &src_rect, - 0, // mask (we aren't changing it here) - (DISPMANX_TRANSFORM_T)0); - - - vc_dispmanx_update_submit_sync(dispman_update); - - // next time swapBuffers is called, it will be resized based on this eglwindow size data - dispman_native_window.element = dispman_element; - dispman_native_window.width = (int32_t)newRect.width; - dispman_native_window.height = (int32_t)newRect.height; // don't forget! - - currentWindowRect = newRect; - -#else - ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?"; -#endif - } - - if(oldWindowRect.width != currentWindowRect.width || oldWindowRect.height != currentWindowRect.height) { - coreEvents.notifyWindowResized(currentWindowRect.width, currentWindowRect.height); - nFramesSinceWindowResized = 0; - } - } -} - - -//------------------------------------------------------------ -bool ofAppEGLWindow::createWindow(const ofRectangle& requestedWindowRect) { - if(isUsingX11) { - return createX11NativeWindow(requestedWindowRect); - } else { -#ifdef TARGET_RASPBERRY_PI - return createRPiNativeWindow(requestedWindowRect); -#else - ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?"; - return false; -#endif - } -} - -//------------------------------------------------------------ -int ofAppEGLWindow::getWindowWidth() { - return currentWindowRect.width; -} - -//------------------------------------------------------------ -int ofAppEGLWindow::getWindowHeight() { - return currentWindowRect.height; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::pollEvents(){ - if(!instance) return; - if(instance->isUsingX11) { - while(1){ - XEvent event; - if (::XCheckWindowEvent(instance->x11Display, instance->x11Window, -1, &event)){ - handleX11Event(event); - }else if (::XCheckTypedEvent(instance->x11Display, ClientMessage, &event)){ - handleX11Event(event); - }else{ - break; - } - } - } else { - queue mouseEventsCopy; - instance->lock(); - mouseEventsCopy = instance->mouseEvents; - while(!instance->mouseEvents.empty()){ - instance->mouseEvents.pop(); - } - instance->unlock(); - while(!mouseEventsCopy.empty()){ - instance->coreEvents.notifyMouseEvent(mouseEventsCopy.front()); - mouseEventsCopy.pop(); - } - - // KEYBOARD EVENTS - queue keyEventsCopy; - instance->lock(); - keyEventsCopy = instance->keyEvents; - while(!instance->keyEvents.empty()){ - instance->keyEvents.pop(); - } - instance->unlock(); - while(!keyEventsCopy.empty()){ - instance->coreEvents.notifyKeyEvent(keyEventsCopy.front()); - keyEventsCopy.pop(); - } - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::hideCursor(){ - bShowCursor = false; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::showCursor(){ - bShowCursor = true; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setWindowTitle(string title) { - ofLogNotice("ofAppEGLWindow") << "setWindowTitle(): not implemented"; -} - -//------------------------------------------------------------ -glm::vec2 ofAppEGLWindow::getWindowSize(){ - return {currentWindowRect.width, currentWindowRect.height}; -} - -//------------------------------------------------------------ -glm::vec2 ofAppEGLWindow::getWindowPosition(){ - return currentWindowRect.getPosition().xy(); -} - -//------------------------------------------------------------ -glm::vec2 ofAppEGLWindow::getScreenSize(){ - unsigned int screenWidth = 0; - unsigned int screenHeight = 0; - - if(isUsingX11) { - // TODO, there must be a way to get screensize if the window is not inited - if(isWindowInited && x11Screen) { - screenWidth = XWidthOfScreen(x11Screen); - screenHeight = XHeightOfScreen(x11Screen); - } else { - ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed, x11Screen is not inited"; - } - - } else { -#ifdef TARGET_RASPBERRY_PI - int success = graphics_get_display_size(settings.screenNum, &screenWidth, &screenHeight); - if(success < 0) { - ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed"; - } - -#else - ofLogError("ofAppEGLWindow") << "getScreenSize(): no native window type for this system, perhaps try X11?"; -#endif - - } - - return {screenWidth, screenHeight}; -} - -//------------------------------------------------------------ -int ofAppEGLWindow::getWidth(){ - if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){ - return currentWindowRect.width; - } - return currentWindowRect.height; -} - -//------------------------------------------------------------ -int ofAppEGLWindow::getHeight(){ - if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){ - return currentWindowRect.height; - } - return currentWindowRect.width; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setOrientation(ofOrientation orientationIn){ - orientation = orientationIn; -} - -//------------------------------------------------------------ -ofOrientation ofAppEGLWindow::getOrientation(){ - return orientation; -} - -//------------------------------------------------------------ -bool ofAppEGLWindow::doesHWOrientation() { - return false; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setWindowPosition(int x, int y){ - if(!isWindowInited) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited"; - return; - } - - if(isUsingX11) { - int ret = XMoveWindow(x11Display, - x11Window, - x, - y); - if(ret == BadValue) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue"; - } else if(ret == BadWindow) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow"; - } else { - currentWindowRect.x = x; - currentWindowRect.y = y; - nonFullscreenWindowRect = currentWindowRect; - } - } else { -#ifdef TARGET_RASPBERRY_PI - - // keep it in bounds - auto screenSize = getScreenSize(); - x = ofClamp(x, 0, screenSize.x - currentWindowRect.width); - y = ofClamp(y, 0, screenSize.y - currentWindowRect.height); - - VC_RECT_T dst_rect; - dst_rect.x = (int32_t)x; - dst_rect.y = (int32_t)y; - dst_rect.width = (int32_t)currentWindowRect.width; - dst_rect.height = (int32_t)currentWindowRect.height; - - dispman_update = vc_dispmanx_update_start(0); - - vc_dispmanx_element_change_attributes(dispman_update, - dispman_native_window.element, - ELEMENT_CHANGE_DEST_RECT, - 0, - 0, - &dst_rect, - NULL, - 0, - (DISPMANX_TRANSFORM_T)0); - - -vc_dispmanx_update_submit_sync(dispman_update); - -currentWindowRect.x = x; -currentWindowRect.y = y; -nonFullscreenWindowRect = currentWindowRect; - -#else - ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?"; -#endif - } - -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setWindowShape(int w, int h){ - if(!isWindowInited) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited"; - return; - } - - if(isUsingX11) { - int ret = XResizeWindow(x11Display, - x11Window, - (unsigned int)w, - (unsigned int)h); - if(ret == BadValue) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue"; - } else if(ret == BadWindow) { - ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow"; - } else { - currentWindowRect.width = w; - currentWindowRect.height = h; - nonFullscreenWindowRect = currentWindowRect; - } - } else { -#ifdef TARGET_RASPBERRY_PI - setWindowRect(ofRectangle(currentWindowRect.x,currentWindowRect.y,w,h)); - nonFullscreenWindowRect = currentWindowRect; -#else - ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?"; -#endif - } -} - -//------------------------------------------------------------ -ofWindowMode ofAppEGLWindow::getWindowMode(){ - return windowMode; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::toggleFullscreen(){ - if( windowMode == OF_GAME_MODE) return; - - if( windowMode == OF_WINDOW ){ - setFullscreen(true); - }else{ - setFullscreen(false); - } - -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setFullscreen(bool fullscreen){ - if( windowMode == OF_GAME_MODE) return; - - if(fullscreen && windowMode != OF_FULLSCREEN){ - bNewScreenMode = true; - windowMode = OF_FULLSCREEN; - }else if(!fullscreen && windowMode != OF_WINDOW) { - bNewScreenMode = true; - windowMode = OF_WINDOW; - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::enableSetupScreen(){ - bEnableSetupScreen = true; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::disableSetupScreen(){ - bEnableSetupScreen = false; -} - -//------------------------------------------------------------ -ofRectangle ofAppEGLWindow::getScreenRect(){ - auto screenSize = getScreenSize(); - return ofRectangle(0,0,screenSize.x,screenSize.y); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setVerticalSync(bool enabled){ - eglSwapInterval(eglDisplay, enabled ? 1 : 0); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::threadedFunction(){ - // TODO: a way to setup mouse and keyboard if - // they are not plugged in upon start - // This can be done with our udev device callbacks - - while(isThreadRunning()) { - readNativeUDevEvents(); - readNativeMouseEvents(); - readNativeKeyboardEvents(); - - // sleep briefly - ofSleepMillis(20); - } -} - -//------------------------------------------------------------ -// PLATFORM SPECIFIC RPI -//------------------------------------------------------------ - -//------------------------------------------------------------ -void ofAppEGLWindow::setupNativeUDev() { - - udev = udev_new(); // create new udev object - if(!udev) { - ofLogError("ofAppEGLWindow") << "setupNativeUDev(): couldn't create udev object"; - } else { - ofLogNotice("ofAppEGLWindow") << "setupNativeUDev(): created udev object"; - // setup udev to monitor for input devices - mon = udev_monitor_new_from_netlink(udev, "udev"); - // just listen for input devices - udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL); - udev_monitor_enable_receiving(mon); - // get the file descriptor for the mon (used w/ select); - udev_fd = udev_monitor_get_fd(mon); - } - - if(udev_fd < 0) { - ofLogError("ofAppEGLWindow") << "setupNativeUDev(): did not create udev object, udev_fd < 0"; - } - -} - -//------------------------------------------------------------ -void ofAppEGLWindow::destroyNativeUDev() { - udev_unref(udev); // clean up -} - - -//------------------------------------------------------------ -void ofAppEGLWindow::setupNativeMouse() { - struct dirent **eps; // What eps is supposed to mean? - - // fallback to /dev/input/eventX since some vnc servers use uinput to - // handle mouse & keyboard. - typedef int (*filter_ptr)(const struct dirent *d); - filter_ptr mouse_filters[2] = { filter_mouse, filter_event }; - string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" }; - - // Examine available input devices in directories at devicePathBuffers. - for(auto i = 0; i < 2; i++){ - - // Get number of devices in the current input device directory. - int n = scandir(devicePathBuffers[i].c_str(), &eps, mouse_filters[i], dummy_sort); - - // Open the appropriate entries, - // we want to get all mouse device events. - if(n >= 0 && eps != 0 && eps[0] != 0) { - for(auto j = 0; j < n; ++j){ - string devicePathBuffer; - devicePathBuffer.append(devicePathBuffers[i]); - devicePathBuffer.append(eps[j]->d_name); - - ofLogNotice("ofAppEGLWindow::setupNativeMouse()") - << "attempt to open " << devicePathBuffer; - - // TODO: create a vector out of fildes entries - int fildes = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); - - // No file descriptor, stop the current iteration of the nested loop here, - // continue with the next value of j. - if(fildes < 0){ - ofLogError("ofAppEGLWindow::setupNativeMouse()") - << "failed to open mouse device"; - continue; - } - - // Seems that we got a mouse device open! - // Get all the parameters. - ofAppEGLWindowMouseArgs mouseArgs; - mouseArgs.fildes = fildes; - - // TODO: consider a more reasonable way for calculating these. - mouseArgs.scaleX = 2.0f; - mouseArgs.scaleY = 2.0f; - - // Find out if input device is a absolute positioning device - // set the minimum and maximum values of the axes. - // Do this for the x axis. EVIOCGABS(0): 0 stands for x axis. - struct input_absinfo mabsx; - if (ioctl(fildes, EVIOCGABS(0), &mabsx) < 0){ - ofLogError("ofAppEGLWindow::setupNativeMouse()") - << "failed to get absolute limits of input x axis"; - mouseArgs.absXMin = 0; - mouseArgs.absXMax = 0; - } else { - mouseArgs.absXMin = mabsx.minimum; - mouseArgs.absXMax = mabsx.maximum; - ofLogNotice("ofAppEGLWindow::setupNativeMouse()") - << "mouse x axis min, max: " << mouseArgs.absXMin - << ", " << mouseArgs.absXMax; - } - - // Do that for the y axis. EVIOCGABS(1): 1 stands for y axis. - struct input_absinfo mabsy; - if (ioctl(fildes, EVIOCGABS(1), &mabsy) < 0){ - ofLogError("ofAppEGLWindow::setupNativeMouse()") - << "failed to get absolute limits of input y axis"; - mouseArgs.absYMin = 0; - mouseArgs.absYMax = 0; - } else { - mouseArgs.absYMin = mabsy.minimum; - mouseArgs.absYMax = mabsy.maximum; - ofLogNotice("ofAppEGLWindow::setupNativeMouse()") - << "mouse y axis min, max: " << mouseArgs.absYMin - << ", " << mouseArgs.absYMax; - } - - // Get input device name. - char deviceNameBuffer[256] = "Unknown Device"; - ioctl(fildes, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer); - mouseArgs.deviceName = string(deviceNameBuffer); - ofLogNotice("ofAppEGLWindow::setupNativeMouse()") - << "setting up mouse device with name " - << mouseArgs.deviceName; - - mice.push_back(mouseArgs); - - ofLogNotice("ofAppEGLWindow") << "setupMouse(): fildes=" - << fildes << " devicePath=" << devicePathBuffer; - } // Nested for loop - } - - // Do not examine other input device directories if we found some mice here. - // This breaks the main for loop of setupNativeMouse(). - if(mice.size()){ - break; - } - } // Main for loop - - mb.mouseButtonState = 0; - - if(mice.size() <= 0) { - mouseDetected = false; - ofLogWrning("ofAppEGLWindow::setupNativeMouse()") - << "no mouse found"; - } else { - mouseDetected = true; - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::setupNativeKeyboard() { - struct dirent **eps; - typedef int (*filter_ptr)(const struct dirent *d); - filter_ptr kbd_filters[2] = { filter_kbd, filter_event }; - string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" }; - - for(int i=0; i<2; i++){ - int n = scandir(devicePathBuffers[i].c_str(), &eps, kbd_filters[i], dummy_sort); - - // make sure that we found an appropriate entry - if(n >= 0 && eps != 0 && eps[0] != 0) { - string devicePathBuffer; - devicePathBuffer.append(devicePathBuffers[i]); - devicePathBuffer.append(eps[0]->d_name); - keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); - ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd=" << keyboard_fd << " devicePath=" << devicePathBuffer; - break; - } - } - - if (keyboard_fd >= 0) { - char deviceNameBuffer[256] = "Unknown Device"; - ioctl(keyboard_fd, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer); - ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard device name = " << deviceNameBuffer; - - - // save current terminal settings - tcgetattr (STDIN_FILENO, &tc); - ots = tc; - // disable echo on our temporary settings - tc.c_lflag &= ~ECHO; - tc.c_lflag |= ECHONL; - tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc); - - } else { - ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard"; - } - - kb.shiftPressed = false; - kb.capsLocked = false; - - if(keyboard_fd < 0) { - ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard, keyboard_fd < 0"; - } else { - keyboardDetected = true; - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::destroyNativeMouse() { - for(auto i = 0; i < mice.size(); ++i){ - int retval = close(mice[i].fildes); - if(retval < 0){ - ofLogError("ofAppEGLWindow::destroyNativeMouse()") - << "Failed to close mouse device: " - << mice[i].deviceName; - } - } - mice.clear(); -} - -//------------------------------------------------------------ -void ofAppEGLWindow::destroyNativeKeyboard() { - ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard()"; - - if (keyboard_fd >= 0) { - tcsetattr (STDIN_FILENO, TCSAFLUSH, &ots); - } else { - ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard(): unable to reset terminal"; - } -} - - -//------------------------------------------------------------ -void ofAppEGLWindow::readNativeUDevEvents() { - // look for devices being attatched / detatched - - fd_set fds; - struct timeval tv; - int ret; - - FD_ZERO(&fds); - FD_SET(udev_fd, &fds); - tv.tv_sec = 0; - tv.tv_usec = 0; - - ret = select(udev_fd+1, &fds, NULL, NULL, &tv); - - /* Check if our file descriptor has received data. */ - if (ret > 0 && FD_ISSET(udev_fd, &fds)) { - /* Make the call to receive the device. - select() ensured that this will not block. */ - dev = udev_monitor_receive_device(mon); - if (dev) { - // TODO: finish auto connect - ofLogNotice() << "Got device"; - ofLogNotice() << " node: %s\n", udev_device_get_devnode(dev); - ofLogNotice() << " subsystem: %s\n", udev_device_get_subsystem(dev); - ofLogNotice() << " devtype: %s\n", udev_device_get_devtype(dev); - ofLogNotice() << " action: %s\n", udev_device_get_action(dev); - udev_device_unref(dev); - } - else { - ofLogNotice("ofAppEGLWindow") << "readNativeUDevEvents(): device returned by receive_device() is NULL"; - } - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::readNativeKeyboardEvents() { - // http://www.diegm.uniud.it/loghi/CE2/kbd.pdf - // http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c - // https://strcpy.net/b/archives/2010/11/17/abusing_the_linux_input_subsystem/index.html - struct input_event ev; - char key = 0; - - int nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event)); - - static ofKeyEventArgs keyEvent; - bool pushKeyEvent = false; - - while(nBytesRead >= 0) { - - if (ev.type==EV_KEY) { - if(ev.value == 0) { - // key released - keyEvent.type = ofKeyEventArgs::Released; - } else if(ev.value == 1) { - // key pressed - keyEvent.type = ofKeyEventArgs::Pressed; - } else if(ev.value == 2) { - // key repeated - keyEvent.type = ofKeyEventArgs::Pressed; - } else { - // unknown ev.value - } - - switch (ev.code) { - case KEY_RIGHTSHIFT: - case KEY_LEFTSHIFT: - kb.shiftPressed = ev.value; - break; - case KEY_RIGHTCTRL: - case KEY_LEFTCTRL: - break; - case KEY_CAPSLOCK: - if (ev.value == 1) { - if (kb.capsLocked) { - kb.capsLocked = 0; - } else { - kb.capsLocked = 1; - } - } - break; - - case KEY_ESC: - pushKeyEvent = true; - keyEvent.key = OF_KEY_ESC; - break; - case KEY_BACKSPACE: - pushKeyEvent = true; - keyEvent.key = OF_KEY_BACKSPACE; - break; - case KEY_DELETE: - pushKeyEvent = true; - keyEvent.key = OF_KEY_DEL; - break; - case KEY_F1: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F1; - break; - case KEY_F2: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F2; - break; - case KEY_F3: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F3; - break; - case KEY_F4: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F4; - break; - case KEY_F5: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F5; - break; - case KEY_F6: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F6; - break; - case KEY_F7: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F7; - break; - case KEY_F8: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F8; - break; - case KEY_F9: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F9; - break; - case KEY_F10: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F10; - break; - case KEY_F11: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F11; - break; - case KEY_F12: - pushKeyEvent = true; - keyEvent.key = OF_KEY_F12; - break; - case KEY_LEFT: - pushKeyEvent = true; - keyEvent.key = OF_KEY_LEFT; - break; - case KEY_UP: - pushKeyEvent = true; - keyEvent.key = OF_KEY_UP; - break; - case KEY_RIGHT: - pushKeyEvent = true; - keyEvent.key = OF_KEY_RIGHT; - break; - case KEY_DOWN: - pushKeyEvent = true; - keyEvent.key = OF_KEY_DOWN; - break; - case KEY_PAGEUP: - pushKeyEvent = true; - keyEvent.key = OF_KEY_PAGE_UP; - break; - case KEY_PAGEDOWN: - pushKeyEvent = true; - keyEvent.key = OF_KEY_PAGE_DOWN; - break; - case KEY_HOME: - pushKeyEvent = true; - keyEvent.key = OF_KEY_HOME; - break; - case KEY_END: - pushKeyEvent = true; - keyEvent.key = OF_KEY_END; - break; - case KEY_INSERT: - pushKeyEvent = true; - keyEvent.key = OF_KEY_INSERT; - break; - case KEY_ENTER: - case KEY_KPENTER: - pushKeyEvent = true; - keyEvent.key = OF_KEY_RETURN; - break; - - default: - // VERY RUDIMENTARY KEY MAPPING WITH MAPS ABOVE - if(ev.code < sizeof(lowercase_map)) { - if (kb.shiftPressed) { - key = uppercase_map[ev.code]; - if (kb.capsLocked) keyEvent.key = tolower(key); - keyEvent.key = key; - pushKeyEvent = true; - } else { - key = lowercase_map[ev.code]; - if (kb.capsLocked) key = toupper(key); - keyEvent.key = key; - pushKeyEvent = true; - } - } else { - ofLogNotice("ofAppEGLWindow") << "readKeyboardEvents(): input_event.code is outside of our small range"; - } - } - } else if(ev.type == EV_MSC) { - // EV_MSC events are used for input and output events that - // do not fall under other categories. - // ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_MSC"; - } else if(ev.type == EV_SYN ) { - // EV_SYN Used as markers to separate events. Events may be - // separated in time or in space, such as with the multitouch protocol. - // ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_SYN"; - } else { - // unhandled type - } - - // do we have a mouse svent to push? - if(pushKeyEvent){ - lock(); - keyEvents.push(keyEvent); - unlock(); - pushKeyEvent = false; - } - - nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event)); - } -} - -//------------------------------------------------------------ -void ofAppEGLWindow::readNativeMouseEvents() { - // http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c - struct input_event ev; - static ofMouseEventArgs mouseEvent; - bool pushMouseEvent = false; - - for(auto i = 0; i < mice.size(); ++i){ - // Loop through all open mouse devices - -// ------------- - int nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event)); - - bool axisValuePending = false; - - while(nBytesRead >= 0) { - - if(ev.type == EV_REL || ev.type == EV_ABS) { - int axis = ev.code; - int amount = ev.value; - - switch(axis) { - case 0: - if(ev.type == EV_REL) { - mouseEvent.x += amount * mouseScaleX; - } else { - mouseEvent.x = amount * (float)currentWindowRect.width / (float)mouseAbsXMax; - } - - mouseEvent.x = ofClamp(mouseEvent.x, 0, currentWindowRect.width); - axisValuePending = true; - break; - case 1: - if(ev.type == EV_REL) { - mouseEvent.y += amount * mouseScaleY; - } else { - mouseEvent.y = amount * (float)currentWindowRect.height / (float)mouseAbsYMax; - } - - mouseEvent.y = ofClamp(mouseEvent.y, 0, currentWindowRect.height); - axisValuePending = true; - break; - default: - ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): unknown mouse axis (perhaps it's the scroll wheel?)"; - break; - } - - } else if(ev.type == EV_KEY) { - // only tracking three buttons now ... - if(ev.code == BTN_LEFT) { - if(ev.value == 0) { // release - mouseEvent.button = OF_MOUSE_BUTTON_LEFT; - mouseEvent.type = ofMouseEventArgs::Released; - mb.mouseButtonState &= ~MOUSE_BUTTON_LEFT_MASK; - pushMouseEvent = true; - } else if(ev.value == 1) { // press - mb.mouseButtonState |= MOUSE_BUTTON_LEFT_MASK; - mouseEvent.type = ofMouseEventArgs::Pressed; - mouseEvent.button = OF_MOUSE_BUTTON_LEFT; - pushMouseEvent = true; - } else { // unknown - ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; - } - } else if(ev.code == BTN_MIDDLE) { - if(ev.value == 0) { // release - mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE; - mouseEvent.type = ofMouseEventArgs::Released; - mb.mouseButtonState &= ~MOUSE_BUTTON_MIDDLE_MASK; - pushMouseEvent = true; - } else if(ev.value == 1) { // press - mb.mouseButtonState |= MOUSE_BUTTON_MIDDLE_MASK; - mouseEvent.type = ofMouseEventArgs::Pressed; - mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE; - pushMouseEvent = true; - } else { // unknown - ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; - } - } else if(ev.code == BTN_RIGHT) { - if(ev.value == 0) { // release - mouseEvent.button = OF_MOUSE_BUTTON_RIGHT; - mouseEvent.type = ofMouseEventArgs::Released; - mb.mouseButtonState &= ~MOUSE_BUTTON_RIGHT_MASK; - pushMouseEvent = true; - } else if(ev.value == 1) { // press - mb.mouseButtonState |= MOUSE_BUTTON_RIGHT_MASK; - mouseEvent.type = ofMouseEventArgs::Pressed; - mouseEvent.button = OF_MOUSE_BUTTON_RIGHT; - pushMouseEvent = true; - } else { - ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; - } - } else { - ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.code = " << ev.code; - } - // not sure why we are getting that event here - } else if(ev.type == EV_MSC) { - // EV_MSC events are used for input and output events that - // do not fall under other categories. - // ofLogVerbose("ofAppEGLWindow") << "readMouseEvents() : EV_MSC"; - } else if(ev.type == EV_SYN ) { - // EV_SYN Used as markers to separate events. Events may be - // separated in time or in space, such as with the multitouch protocol. - - // EV_SYN events are sent when axis value (one or a pair) are changed - if(axisValuePending) { - // TODO, this state doesn't make as much sense when the mouse is not dragging - if(mb.mouseButtonState > 0) { - // dragging (what if dragging w/ more than one button?) - mouseEvent.type = ofMouseEventArgs::Dragged; - } else { - // just moving - mouseEvent.type = ofMouseEventArgs::Moved; - } - - mouseEvent.button = mb.mouseButtonState; - - pushMouseEvent = true; - axisValuePending = false; - } - - //ofLogVerbose("ofAppEGLWindow") << "readMouseEvents(): EV_SYN"; - } else { - // unhandled type - } - - // do we have a mouse event to push? - if(pushMouseEvent){ - // lock the thread for a moment while we copy the data - lock(); - mouseEvents.push(mouseEvent); - unlock(); - pushMouseEvent = false; - } - - // Why another read? - nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event)); - } // While loop -// ------------ - } // For loop - -} - -#ifdef TARGET_RASPBERRY_PI -//------------------------------------------------------------ -void ofAppEGLWindow::initRPiNative() { - bcm_host_init(); - - memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T)); - dispman_element = DISPMANX_NO_HANDLE; - dispman_display = DISPMANX_NO_HANDLE; - dispman_update = DISPMANX_NO_HANDLE; - memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T)); - dispman_transform = DISPMANX_NO_ROTATE; - memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha - -} - -//------------------------------------------------------------ -void ofAppEGLWindow::exitRPiNative() { - bcm_host_deinit(); -} - -//------------------------------------------------------------ -bool ofAppEGLWindow::createRPiNativeWindow(const ofRectangle& requestedWindowRect){ - - ofRectangle screenRect = getScreenRect(); - - // make sure our requested window rectangle does not exceed the native - // screen size, or start outside of it. - ofRectangle windowRect = screenRect.getIntersection(requestedWindowRect); - - ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): screenRect: " << screenRect.width << "x" << screenRect.height; - ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): windowRect: " << windowRect.width << "x" << windowRect.height; - - ////////////////////////// - VC_RECT_T dst_rect; - - dst_rect.x = (int32_t)windowRect.x; - dst_rect.y = (int32_t)windowRect.y; - dst_rect.width = (int32_t)windowRect.width; - dst_rect.height = (int32_t)windowRect.height; - - VC_RECT_T src_rect; - - src_rect.x = 0; - src_rect.y = 0; - src_rect.width = dst_rect.width << 16; - src_rect.height = dst_rect.height << 16; - - memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha - dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; - dispman_alpha.opacity = ofClamp(settings.eglWindowOpacity,0,255); - dispman_alpha.mask = 0; - - memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T)); - - // there are other values for dispman_transform, but they do not seem to have an effect - dispman_transform = DISPMANX_NO_ROTATE; - - // get the zero display - dispman_display = vc_dispmanx_display_open(settings.screenNum); - - // begin the display manager interaction - dispman_update = vc_dispmanx_update_start( 0 ); - - // add a "display manager element" with our parameters so - // that it can fill in the structures. we will pass this - // filled dispman_element to our native window, which will - // be used to construct the EGL surface, etc. - dispman_element = vc_dispmanx_element_add ( dispman_update, - dispman_display, - settings.layer, // layer - &dst_rect, // dst rect - (DISPMANX_RESOURCE_HANDLE_T)0, // src - &src_rect, // src rect - DISPMANX_PROTECTION_NONE, // ? - &dispman_alpha, // alpha - &dispman_clamp, // clamp - dispman_transform // transform - ); - - if(dispman_element == DISPMANX_NO_HANDLE) { - ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_NO_HANDLE"; - return false; - } else if(dispman_element == (unsigned)DISPMANX_INVALID) { - ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_INVALID"; - return false; - } - - // set dispman_native_window to zero - memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T)); - dispman_native_window.element = dispman_element; - dispman_native_window.width = (int32_t)windowRect.width; - dispman_native_window.height = (int32_t)windowRect.height; - - // set background to black (not required) - vc_dispmanx_display_set_background(dispman_update, dispman_display, 0x00, 0x00, 0x00); - - // finished with display manager update, so sync - vc_dispmanx_update_submit_sync( dispman_update ); - - currentWindowRect = windowRect; - - return true; -} -#endif - -//------------------------------------------------------------ -// X11 BELOW -//------------------------------------------------------------ -bool ofAppEGLWindow::createX11NativeWindow(const ofRectangle& requestedWindowRect){ - - // X11 variables - x11Window = 0; - x11Display = 0; - x11ScreenNum = 0; // TODO: settings.screenNum? - x11Screen = 0; - XVisualInfo* x11Visual = 0; // TODO does this need to be deleted? - Colormap x11Colormap = 0; - - /* - Step 0 - Create a NativeWindowType that we can use it for OpenGL ES output - */ - Window sRootWindow; - XSetWindowAttributes sWA; - unsigned int ui32Mask; - int i32Depth; - - //ofRectangle screenRect = getScreenRect(); - - // make sure our requested window rectangle does not exceed the native - // screen size, or start outside of it. - ofRectangle windowRect = requestedWindowRect.getStandardized();//screenRect.getIntersection(requestedWindowRect); - - // Initializes the display and screen - x11Display = XOpenDisplay( 0 ); - if (!x11Display) { - ofLogError("ofAppEGLWindow") << "unable to open X display"; - return false; - } - - x11ScreenNum = XDefaultScreen( x11Display ); - - x11Screen = XDefaultScreenOfDisplay(x11Display); - - // Gets the window parameters - sRootWindow = RootWindow(x11Display, x11ScreenNum); - i32Depth = DefaultDepth(x11Display, x11ScreenNum); - x11Visual = new XVisualInfo(); - - XMatchVisualInfo( x11Display, - x11ScreenNum, - i32Depth, - TrueColor, - x11Visual); - - if (!x11Visual) { - ofLogError("ofAppEGLWindow") << "unable to acquire XVisualInfo"; - return false; - } - - x11Colormap = XCreateColormap( x11Display, sRootWindow, x11Visual->visual, AllocNone ); - - delete x11Visual; - - // set the colormap window attribuet - sWA.colormap = x11Colormap; - - // Add to these for handling other events - sWA.event_mask = 0; - sWA.event_mask |= StructureNotifyMask; - sWA.event_mask |= ExposureMask; - sWA.event_mask |= ButtonPressMask; - sWA.event_mask |= ButtonReleaseMask; - sWA.event_mask |= PointerMotionMask; - sWA.event_mask |= KeyPressMask; - sWA.event_mask |= KeyReleaseMask; - - // setup background pixel attributes - ui32Mask = 0; - ui32Mask |= CWBackPixel; - ui32Mask |= CWBorderPixel; - ui32Mask |= CWEventMask; - ui32Mask |= CWColormap; - - // Creates the X11 window - x11Window = XCreateWindow(x11Display, // Specifies the connection to the X server. - sRootWindow, // Specifies the parent window. - (int)windowRect.x, (int)windowRect.y, // Specify the x and y coordinates, - // which are the top-left outside corner - // of the window's borders and are relative - // to the inside of the parent window's borders. - (unsigned int)windowRect.width, (unsigned int)windowRect.height, // Specify the width and height, which are the - // created window's inside dimensions and do - // not include the created window's borders. - 0, // Specifies the width of the created - // window's border in pixels. - CopyFromParent, // Specifies the window's depth. - // A depth of CopyFromParent means - // the depth is taken from the parent. - InputOutput, // Specifies the created window's class. - // You can pass InputOutput, InputOnly, - // or CopyFromParent. A class of CopyFromParent - // means the class is taken from the parent. - CopyFromParent, // Specifies the visual type. - // A visual of CopyFromParent means the visual type - // is taken from the parent. - ui32Mask, // Specifies which window attributes are - // defined in the attributes argument. This mask is - // the bitwise inclusive OR of the valid attribute - // mask bits. If valuemask is zero, the attributes - // are ignored and are not referenced. - &sWA //Specifies the background pixel value of the window. - ); - - XMapWindow(x11Display, x11Window); - XFlush(x11Display); - - // check success? - currentWindowRect = windowRect; - - return true; -} - -//------------------------------------------------------------ -static KeySym KeyCodeToKeySym(Display * display, KeyCode keycode, unsigned int event_mask) { - KeySym keysym = NoSymbol; - - //Get the map - XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd); - if (keyboard_map) { - //What is diff between XkbKeyGroupInfo and XkbKeyNumGroups? - unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode); - unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode); - - //Get the group - unsigned int group = 0x00; - switch (XkbOutOfRangeGroupAction(info)) { - case XkbRedirectIntoRange: - /* If the RedirectIntoRange flag is set, the four least significant - * bits of the groups wrap control specify the index of a group to - * which all illegal groups correspond. If the specified group is - * also out of range, all illegal groups map to Group1. - */ - group = XkbOutOfRangeGroupInfo(info); - if (group >= num_groups) { - group = 0; - } - break; - - case XkbClampIntoRange: - /* If the ClampIntoRange flag is set, out-of-range groups correspond - * to the nearest legal group. Effective groups larger than the - * highest supported group are mapped to the highest supported group; - * effective groups less than Group1 are mapped to Group1 . For - * example, a key with two groups of symbols uses Group2 type and - * symbols if the global effective group is either Group3 or Group4. - */ - group = num_groups - 1; - break; - - case XkbWrapIntoRange: - /* If neither flag is set, group is wrapped into range using integer - * modulus. For example, a key with two groups of symbols for which - * groups wrap uses Group1 symbols if the global effective group is - * Group3 or Group2 symbols if the global effective group is Group4. - */ - default: - if (num_groups != 0) { - group %= num_groups; - } - break; - } - - XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group); - unsigned int active_mods = event_mask & key_type->mods.mask; - - int i, level = 0; - for (i = 0; i < key_type->map_count; i++) { - if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) { - level = key_type->map[i].level; - } - } - - keysym = XkbKeySymEntry(keyboard_map, keycode, level, group); - XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true); - } - - return keysym; -} - -//------------------------------------------------------------ -void ofAppEGLWindow::handleX11Event(const XEvent& event){ - ofMouseEventArgs mouseEvent; - ofKeyEventArgs keyEvent; - switch (event.type){ - case KeyPress: - case KeyRelease: - { - KeySym key = KeyCodeToKeySym(instance->x11Display,event.xkey.keycode,event.xkey.state); - keyEvent.key = key; - if (event.type == KeyPress) { - keyEvent.type = ofKeyEventArgs::Pressed; - if(key == 65307){ - keyEvent.key = OF_KEY_ESC; - } - } else if (event.type == KeyRelease){ - keyEvent.type = ofKeyEventArgs::Released; - } - - instance->coreEvents.notifyKeyEvent(keyEvent); - } - break; - case ButtonPress: - case ButtonRelease: - mouseEvent.x = static_cast(event.xbutton.x); - mouseEvent.y = static_cast(event.xbutton.y); - mouseEvent.button = event.xbutton.button; - if (event.type == ButtonPress){ - mouseEvent.type = ofMouseEventArgs::Pressed; - } else { - mouseEvent.type = ofMouseEventArgs::Released; - } - - instance->coreEvents.notifyMouseEvent(mouseEvent); - break; - case MotionNotify: - //cout << "motion notify" << endl; - mouseEvent.x = static_cast(event.xmotion.x); - mouseEvent.y = static_cast(event.xmotion.y); - mouseEvent.button = event.xbutton.button; - if(ofGetMousePressed()) { - mouseEvent.type = ofMouseEventArgs::Dragged; - } else { - mouseEvent.type = ofMouseEventArgs::Moved; - } - - instance->coreEvents.notifyMouseEvent(mouseEvent); - break; - case ConfigureNotify: - instance->currentWindowRect.x = event.xconfigure.x; - instance->currentWindowRect.y = event.xconfigure.y; - instance->currentWindowRect.width = event.xconfigure.width; - instance->currentWindowRect.height = event.xconfigure.height; - instance->nonFullscreenWindowRect = instance->currentWindowRect; - instance->coreEvents.notifyWindowResized(event.xconfigure.width,event.xconfigure.height); - break; - /*case ClientMessage:{ - if (event.xclient.message_type == wmProtocols_ && - event.xclient.format == 32 && - event.xclient.data.l[0] == (long) wmDeleteWindow_) - { - if (listener()) - { - if (listener()->onClose(wrapper() ? *wrapper() : *(WindowInterface*)this)) - isShuttingDown_ = true; - } - else - { - isShuttingDown_ = true; - } - } - break; - }*/ - } -} +#include "ofAppEGLWindow.h" + +#include "ofGraphics.h" // used in runAppViaInfiniteLoop() +#include "ofAppRunner.h" +#include "ofUtils.h" +#include "ofFileUtils.h" +#include "ofGLProgrammableRenderer.h" +#include "ofGLRenderer.h" +#include + +using namespace std; + +// native events +struct udev* udev; +struct udev_device* dev; +struct udev_monitor* mon; +static int udev_fd = -1; + +static int keyboard_fd = -1; // defaults to 0 ie console + +// minimal map +const int lowercase_map[] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', + 'j', 'k', 'l', ';', '\'', '\n', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r' + +}; + +// minimal keyboard map +const int uppercase_map[] = { + 0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H', + 'J', 'K', 'L', ':', '"', '\n', 0, '\\', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r' +}; + +// keep track of a few things ... +typedef struct { + bool shiftPressed; + bool capsLocked; +} KeyboardState; + +static KeyboardState kb; + +static struct termios tc; +static struct termios ots; + +typedef struct { + int mouseButtonState; +} MouseState; + +// TODO, make this match the upcoming additions to ofWindow +#define MOUSE_BUTTON_LEFT_MASK 1 +#define MOUSE_BUTTON_MIDDLE_MASK 1 << 1 +#define MOUSE_BUTTON_RIGHT_MASK 2 << 1 + +static MouseState mb; +ofAppEGLWindow* ofAppEGLWindow::instance = NULL; + +static int string_ends_with(const char *str, const char *suffix) { + if (!str || !suffix) + return 0; + size_t lenstr = strlen(str); + size_t lensuffix = strlen(suffix); + if (lensuffix > lenstr) + return 0; + return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; +} + +static int string_begins_with(const char *str, const char *prefix) { + if (!str || !prefix) + return 0; + size_t lenstr = strlen(str); + size_t lenprefix = strlen(prefix); + if (lenprefix > lenstr) + return 0; + return strncmp(str, prefix, lenprefix) == 0; +} + +static int dummy_sort(const struct dirent **a,const struct dirent **b) { + return 1; // dummy sort +} + +static int filter_kbd(const struct dirent *d) { + if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-kbd")) { + return 1; + } else { + return 0; + } +} + +static int filter_mouse(const struct dirent *d) { + if(d->d_type != DT_DIR && string_ends_with(d->d_name,"event-mouse")) { + return 1; + } else { + return 0; + } +} + +static int filter_event(const struct dirent *d) { + if(d->d_type != DT_DIR && string_begins_with(d->d_name,"event")) { + return 1; + } else { + return 0; + } +} + +// native +#define MOUSE_CURSOR_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \ + { unsigned int __bpp; unsigned char *__ip; const unsigned char *__il, *__rd; \ + __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \ + __rd = (rle_data); \ + while (__ip < __il) { unsigned int __l = *(__rd++); \ + if (__l & 128) { __l = __l - 128; \ + do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \ + } else { __l *= 4; memcpy (__ip, __rd, __l); \ + __ip += __l; __rd += __l; } } \ + } while (0) +static const struct { + unsigned int width; + unsigned int height; + unsigned int bpp; /* 2:RGB16, 3:RGB, 4:RGBA */ + unsigned char rle_pixel_data[382 + 1]; +} mouse_cursor_data = { + 12, 19, 4, + "\1\0\0\0\377\213\377\377\377\0\202\0\0\0\377\212\377\377\377\0\3\0\0\0\377" + "\377\377\377\377\0\0\0\377\211\377\377\377\0\1\0\0\0\377\202\377\377\377" + "\377\1\0\0\0\377\210\377\377\377\0\1\0\0\0\377\203\377\377\377\377\1\0\0" + "\0\377\207\377\377\377\0\1\0\0\0\377\204\377\377\377\377\1\0\0\0\377\206" + "\377\377\377\0\1\0\0\0\377\205\377\377\377\377\1\0\0\0\377\205\377\377\377" + "\0\1\0\0\0\377\206\377\377\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0" + "\377\207\377\377\377\377\1\0\0\0\377\203\377\377\377\0\1\0\0\0\377\210\377" + "\377\377\377\1\0\0\0\377\202\377\377\377\0\1\0\0\0\377\211\377\377\377\377" + "\3\0\0\0\377\377\377\377\0\0\0\0\377\212\377\377\377\377\202\0\0\0\377\206" + "\377\377\377\377\206\0\0\0\377\203\377\377\377\377\1\0\0\0\377\202\377\377" + "\377\377\1\0\0\0\377\204\377\377\377\0\1\0\0\0\377\202\377\377\377\377\3" + "\0\0\0\377\377\377\377\0\0\0\0\377\202\377\377\377\377\1\0\0\0\377\203\377" + "\377\377\0\3\0\0\0\377\377\377\377\377\0\0\0\377\202\377\377\377\0\1\0\0" + "\0\377\202\377\377\377\377\1\0\0\0\377\203\377\377\377\0\202\0\0\0\377\204" + "\377\377\377\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\210\377\377\377" + "\0\1\0\0\0\377\202\377\377\377\377\1\0\0\0\377\211\377\377\377\0\202\0\0" + "\0\377\203\377\377\377\0", +}; + +// from http://cantuna.googlecode.com/svn-history/r16/trunk/src/screen.cpp +#define CASE_STR(x,y) case x: str = y; break + +static const char* eglErrorString(EGLint err) { + string str; + switch (err) { + CASE_STR(EGL_SUCCESS, "no error"); + CASE_STR(EGL_NOT_INITIALIZED, "EGL not, or could not be, initialized"); + CASE_STR(EGL_BAD_ACCESS, "access violation"); + CASE_STR(EGL_BAD_ALLOC, "could not allocate resources"); + CASE_STR(EGL_BAD_ATTRIBUTE, "invalid attribute"); + CASE_STR(EGL_BAD_CONTEXT, "invalid context specified"); + CASE_STR(EGL_BAD_CONFIG, "invald frame buffer configuration specified"); + CASE_STR(EGL_BAD_CURRENT_SURFACE, "current window, pbuffer or pixmap surface is no longer valid"); + CASE_STR(EGL_BAD_DISPLAY, "invalid display specified"); + CASE_STR(EGL_BAD_SURFACE, "invalid surface specified"); + CASE_STR(EGL_BAD_MATCH, "bad argument match"); + CASE_STR(EGL_BAD_PARAMETER, "invalid paramater"); + CASE_STR(EGL_BAD_NATIVE_PIXMAP, "invalid NativePixmap"); + CASE_STR(EGL_BAD_NATIVE_WINDOW, "invalid NativeWindow"); + CASE_STR(EGL_CONTEXT_LOST, "APM event caused context loss"); + default: str = "unknown error " + err; break; + } + return str.c_str(); +} + + +// X11 events +#include + + +#ifdef TARGET_RASPBERRY_PI +// TODO: remove these when they enter system headers +// From : https://github.com/raspberrypi/userland/blob/master/interface/vmcs_host/vc_vchi_dispmanx.h +#ifndef ELEMENT_CHANGE_LAYER +#define ELEMENT_CHANGE_LAYER (1<<0) +#endif +#ifndef ELEMENT_CHANGE_OPACITY +#define ELEMENT_CHANGE_OPACITY (1<<1) +#endif +#ifndef ELEMENT_CHANGE_DEST_RECT +#define ELEMENT_CHANGE_DEST_RECT (1<<2) +#endif +#ifndef ELEMENT_CHANGE_SRC_RECT +#define ELEMENT_CHANGE_SRC_RECT (1<<3) +#endif +#ifndef ELEMENT_CHANGE_MASK_RESOURCE +#define ELEMENT_CHANGE_MASK_RESOURCE (1<<4) +#endif +#ifndef ELEMENT_CHANGE_TRANSFORM +#define ELEMENT_CHANGE_TRANSFORM (1<<5) +#endif +#endif + + +//------------------------------------------------------------------------------------- +ofAppEGLWindow::Settings::Settings() +:ofGLESWindowSettings(){ + eglWindowPreference = OF_APP_WINDOW_AUTO; + eglWindowOpacity = 255; + + // these are usually set as default, but set them here just to be sure + frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red + frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green + frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue + frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha + frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha + frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth + frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil + frameBufferAttributes[EGL_SAMPLES] = 1; + + initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255); + + screenNum = 0; /* 0 = LCD on the raspberry pi */ + layer = 0; +} + +ofAppEGLWindow::Settings::Settings(const ofGLESWindowSettings & settings) +:ofGLESWindowSettings(settings){ + eglWindowPreference = OF_APP_WINDOW_AUTO; + eglWindowOpacity = 255; + + // these are usually set as default, but set them here just to be sure + frameBufferAttributes[EGL_RED_SIZE] = 8; // 8 bits for red + frameBufferAttributes[EGL_GREEN_SIZE] = 8; // 8 bits for green + frameBufferAttributes[EGL_BLUE_SIZE] = 8; // 8 bits for blue + frameBufferAttributes[EGL_ALPHA_SIZE] = 8; // 8 bits for alpha + frameBufferAttributes[EGL_LUMINANCE_SIZE] = EGL_DONT_CARE; // 8 bits for alpha + frameBufferAttributes[EGL_DEPTH_SIZE] = 24; // 24 bits for depth + frameBufferAttributes[EGL_STENCIL_SIZE] = 8; // 8 bits for stencil + frameBufferAttributes[EGL_SAMPLES] = 1; + + initialClearColor = ofColor(0.15 * 255, 0.15 * 255, 0.15 * 255, 255); + + screenNum = 0; /* 0 = LCD on the raspberry pi */ + layer = 0; +} + +//------------------------------------------------------------ +ofAppEGLWindow::ofAppEGLWindow() { + keyboardDetected = false; + mouseDetected = false; + threadTimeout = ofThread::INFINITE_JOIN_TIMEOUT; + bNewScreenMode = false; + buttonInUse = -1; + bEnableSetupScreen = false; + bShowCursor = true; + nFramesSinceWindowResized = 0; + mouseScaleX = 2.0f; + mouseScaleY = 2.0f; + isUsingX11 = false; + isWindowInited = false; + isSurfaceInited = false; + x11Display = NULL; + x11Screen = NULL; + x11ScreenNum = 0l; + glesVersion = 1; + + if(instance!=NULL){ + ofLogError("ofAppEGLWindow") << "trying to create more than one instance"; + } + instance = this; +} + +//------------------------------------------------------------ +ofAppEGLWindow::~ofAppEGLWindow() { + close(); +} + +//------------------------------------------------------------ +EGLDisplay ofAppEGLWindow::getEglDisplay() const { + return eglDisplay; +} + +//------------------------------------------------------------ +EGLSurface ofAppEGLWindow::getEglSurface() const { + return eglSurface; +} + +//------------------------------------------------------------ +EGLContext ofAppEGLWindow::getEglContext() const { + return eglContext; +} + +#ifndef TARGET_RASPBERRY_PI +//------------------------------------------------------------ +Display* ofAppEGLWindow::getX11Display(){ + return x11Display; +} + +//------------------------------------------------------------ +Window ofAppEGLWindow::getX11Window(){ + return x11Window; +} +#endif +//------------------------------------------------------------ +EGLConfig ofAppEGLWindow::getEglConfig() const { + return eglConfig; +} + +//------------------------------------------------------------ +EGLint ofAppEGLWindow::getEglVersionMajor () const { + return eglVersionMajor; +} + +//------------------------------------------------------------ +EGLint ofAppEGLWindow::getEglVersionMinor() const { + return eglVersionMinor; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::initNative() { +#ifdef TARGET_RASPBERRY_PI + initRPiNative(); +#endif +} + +//------------------------------------------------------------ +void ofAppEGLWindow::exitNative() { +#ifdef TARGET_RASPBERRY_PI + exitRPiNative(); +#endif +} + +//------------------------------------------------------------ +EGLNativeWindowType ofAppEGLWindow::getNativeWindow() { + if(!isWindowInited) { + ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL"; + return NULL; + } + + if(isUsingX11) { + return (EGLNativeWindowType)x11Window; + } else { +#ifdef TARGET_RASPBERRY_PI + return (EGLNativeWindowType)&dispman_native_window; +#else + ofLogNotice("ofAppEGLWindow") << "getNativeWindow(): no native window type for this system, perhaps try X11?"; + return NULL; +#endif + } +} + +//------------------------------------------------------------ +EGLNativeDisplayType ofAppEGLWindow::getNativeDisplay() { + if(!isWindowInited) { + ofLogWarning("ofAppEGLWindow") << "getNativeDisplay(): window not initialized, returning NULL"; + return 0; + } + + if(isUsingX11) { + return (EGLNativeDisplayType)x11Display; + } else { +#ifdef TARGET_RASPBERRY_PI + return (EGLNativeDisplayType)NULL; +#else + ofLogNotice("ofAppEGLWindow") << "getNativeDisplay(): no native window type for this system, perhaps try X11?"; + return 0; +#endif + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setup(const ofGLESWindowSettings & settings){ + const Settings * glSettings = dynamic_cast(&settings); + if(glSettings){ + setup(*glSettings); + }else{ + setup(Settings(settings)); + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setup(const Settings & _settings) { + settings = _settings; + windowMode = OF_WINDOW; + bNewScreenMode = true; + nFramesSinceWindowResized = 0; + buttonInUse = 0; + bEnableSetupScreen = true; + eglDisplayString = ""; + orientation = OF_ORIENTATION_DEFAULT; + + //TODO: 2.0f is an arbitrary factor that makes mouse speed ok at 1024x768, + // to be totally correct we might need to take into account screen size + // and add acceleration + mouseScaleX = 2.0f; + mouseScaleY = 2.0f; + + isUsingX11 = false; + isWindowInited = false; + isSurfaceInited = false; + + eglDisplay = NULL; + eglSurface = NULL; + eglContext = NULL; + eglConfig = NULL; + eglVersionMajor = -1; + eglVersionMinor = -1; + glesVersion = 1; + + // X11 check + // char * pDisplay; + // pDisplay = getenv ("DISPLAY"); + // bool bIsX11Available = (pDisplay != NULL); + + bool bIsX11Available = getenv("DISPLAY") != NULL; + + if(settings.eglWindowPreference == OF_APP_WINDOW_AUTO) { + if(bIsX11Available) { + isUsingX11 = true; + } else { + isUsingX11 = false; + } + } else if(settings.eglWindowPreference == OF_APP_WINDOW_NATIVE) { + isUsingX11 = false; + } else if(settings.eglWindowPreference == OF_APP_WINDOW_X11) { + isUsingX11 = true; + if(!bIsX11Available) { + isUsingX11 = false; + ofLogError("ofAppEGLWindow") << "init(): X11 window requested, but X11 is not available"; + } + } + + //////////////// + // TODO remove the following ifdef once x11 is accelerated on RPI +#ifdef TARGET_RASPBERRY_PI + if(isUsingX11) { + isUsingX11 = false; + ofLogWarning("ofAppEGLWindow") << "init(): X11 not availble on RPI yet, using a native window instead"; + } +#endif + //////////////// + + initNative(); + + glesVersion = settings.glesVersion; + // we set this here, and if we need to make a fullscreen + // app, we do it during the first loop. + windowMode = settings.windowMode; + bShowCursor = true; + + nonFullscreenWindowRect.set(0,0,settings.width,settings.height); + nonFullscreenWindowRect.standardize(); + + ofRectangle startRect = nonFullscreenWindowRect; + bNewScreenMode = false; + + if(windowMode == OF_GAME_MODE) { + ofLogWarning("ofAppEGLWindow") << "setupOpenGL(): OF_GAME_MODE not supported, using OF_WINDOW"; + startRect = nonFullscreenWindowRect; + } else if(windowMode == OF_FULLSCREEN) { + startRect = getScreenRect(); + } + + isWindowInited = createWindow(startRect); + isSurfaceInited = createSurface(); + + if(!isWindowInited) { + ofLogError("ofAppEGLWindow") << "setupOpenGL(): screen creation failed, window not inited"; + } + + setupPeripherals(); + + nFramesSinceWindowResized = 0; + + if(settings.glesVersion>1){ + currentRenderer = make_shared(this); + }else{ + currentRenderer = make_shared(this); + } + + makeCurrent(); + if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){ + static_cast(currentRenderer.get())->setup(settings.glesVersion,0); + }else{ + static_cast(currentRenderer.get())->setup(); + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setupPeripherals() { + if(!isUsingX11) { + // roll our own cursor! + mouseCursor.allocate(mouse_cursor_data.width,mouse_cursor_data.height,OF_IMAGE_COLOR_ALPHA); + MOUSE_CURSOR_RUN_LENGTH_DECODE(mouseCursor.getPixels().getData(),mouse_cursor_data.rle_pixel_data,mouse_cursor_data.width*mouse_cursor_data.height,mouse_cursor_data.bpp); + mouseCursor.update(); + ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): peripheral setup complete"; + setupNativeEvents(); + ofLogNotice("ofAppEGLWindow") << "setupPeripherals(): native event setup complete"; + + } else { + ofLogError("ofAppEGLWindow") << "setupPeripherals(): peripherals not supported on X11"; + } +} + +//------------------------------------------------------------ +bool ofAppEGLWindow::createSurface() { + + EGLNativeWindowType nativeWindow = getNativeWindow(); + EGLNativeDisplayType display = getNativeDisplay(); + + ofLogNotice("ofAppEGLWindow") << "createSurface(): setting up EGL Display"; + // get an EGL eglDisplay connection + + isSurfaceInited = false; + + EGLint result; + + if(display==0){ + eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + }else{ + eglDisplay = eglGetDisplay(display); + } + + if(eglDisplay == EGL_NO_DISPLAY) { + ofLogNotice("ofAppEGLWindow") << "createSurface(): eglGetDisplay returned: " << eglDisplay; + return false; + }else{ + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL Display correctly set " << eglDisplay; + } + + // initialize the EGL eglDisplay connection + result = eglInitialize(eglDisplay, + &eglVersionMajor, + &eglVersionMinor); + + if(result == EGL_BAD_DISPLAY) { + // eglDisplay is not an EGL connection + ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_BAD_DISPLAY"; + return false; + } else if(result == EGL_NOT_INITIALIZED) { + // eglDisplay cannot be intitialized + ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_NOT_INITIALIZED"; + return false; + } else if(result == EGL_FALSE) { + // eglinitialize was not initialiezd + ofLogError("ofAppEGLWindow") << "createSurface(): eglInitialize returned EGL_FALSE"; + return false; + } else { + // result == EGL_TRUE + // success! + } + + EGLint glesVersion; + int glesVersionForContext; + + if(ofGetCurrentRenderer()) { + ofLogNotice("ofAppEGLWindow") << "createSurface(): current renderer type: " << ofGetCurrentRenderer()->getType(); + } else { + ofLogNotice("ofAppEGLWindow") << "createSurface(): no current renderer selected"; + } + + if(this->glesVersion==2){ + glesVersion = EGL_OPENGL_ES2_BIT; + glesVersionForContext = 2; + ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES2 renderer detected"; + }else{ + glesVersion = EGL_OPENGL_ES_BIT; + glesVersionForContext = 1; + ofLogNotice("ofAppEGLWindow") << "createSurface(): default renderer detected"; + } + + ofEGLAttributeListIterator iter, iterEnd; + int i; + + // each attribute has 2 values, and we need one extra for the EGL_NONE terminator + EGLint attribute_list_framebuffer_config[settings.frameBufferAttributes.size() * 2 + 3]; + + iter = settings.frameBufferAttributes.begin(); + iterEnd = settings.frameBufferAttributes.end(); + i = 0; + for(; iter != iterEnd; iter++) { + attribute_list_framebuffer_config[i++] = iter->first; + attribute_list_framebuffer_config[i++] = iter->second; + } + attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE; + attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version + attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator + + EGLint num_configs; + + // get an appropriate EGL frame buffer configuration + // http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglChooseConfig.html + result = eglChooseConfig(eglDisplay, + attribute_list_framebuffer_config, + &eglConfig, + 1, // we only want the first one. if we want more, + // we need to pass in an array. + // we are optimistic and don't give it more chances + // to find a good configuration + &num_configs); + + if(result == EGL_FALSE) { + EGLint error = eglGetError(); + ofLogError("ofAppEGLWindow") << "createSurface(): error finding valid configuration based on settings: " << eglErrorString(error); + return false; + } + + if(num_configs <= 0 || eglConfig == NULL) { + ofLogError("ofAppEGLWindow") << "createSurface(): no matching configs were found, num_configs: " << num_configs; + return false; + } + + + // each attribute has 2 values, and we need one extra for the EGL_NONE terminator + EGLint attribute_list_window_surface[settings.windowSurfaceAttributes.size() * 2 + 1]; + + iter = settings.windowSurfaceAttributes.begin(); + iterEnd = settings.windowSurfaceAttributes.end(); + + i = 0; + for(; iter != iterEnd; iter++) { + attribute_list_window_surface[i++] = iter->first; + attribute_list_window_surface[i++] = iter->second; + } + attribute_list_window_surface[i] = EGL_NONE; // add the terminator + + // create a surface + eglSurface = eglCreateWindowSurface( eglDisplay, // our display handle + eglConfig, // our first config + nativeWindow, // our native window + attribute_list_window_surface); // surface attribute list + + if(eglSurface == EGL_NO_SURFACE) { + EGLint error = eglGetError(); + switch(error) { + case EGL_BAD_MATCH: + ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_MATCH " << eglErrorString(error); + ofLogError("ofAppEGLWindow") << "createSurface(): check window and EGLConfig attributes to determine compatibility, "; + ofLogError("ofAppEGLWindow") << "createSurface(): or verify that the EGLConfig supports rendering to a window"; + break; + case EGL_BAD_CONFIG: + ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_CONFIG " << eglErrorString(error); + ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLConfig is valid"; + break; + case EGL_BAD_NATIVE_WINDOW: + ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_NATIVE_WINDOW " << eglErrorString(error); + ofLogError("ofAppEGLWindow") << "createSurface(): verify that provided EGLNativeWindow is valid"; + break; + case EGL_BAD_ALLOC: + ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: EGL_BAD_ALLOC " << eglErrorString(error); + ofLogError("ofAppEGLWindow") << "createSurface(): not enough resources available"; + break; + default: + ofLogError("ofAppEGLWindow") << "createSurface(): error creating surface: << " << error << eglErrorString(error); + } + + return false; + }else{ + ofLogNotice("ofAppEGLWindow") << "createSurface(): surface created correctly"; + } + + // get an appropriate EGL frame buffer configuration + result = eglBindAPI(EGL_OPENGL_ES_API); + + if(result == EGL_FALSE) { + ofLogError("ofAppEGLWindow") << "createSurface(): error binding API: " << eglErrorString(eglGetError()); + return false; + }else{ + ofLogNotice("ofAppEGLWindow") << "createSurface(): API bound correctly"; + } + + // create an EGL rendering eglContext + EGLint attribute_list_surface_context[] = { + EGL_CONTEXT_CLIENT_VERSION, glesVersionForContext, + EGL_NONE + }; + + eglContext = eglCreateContext(eglDisplay, + eglConfig, + EGL_NO_CONTEXT, + attribute_list_surface_context); + + if(eglContext == EGL_NO_CONTEXT) { + EGLint error = eglGetError(); + if(error == EGL_BAD_CONFIG) { + ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: EGL_BAD_CONFIG " << eglErrorString(error); + return false; + } else { + ofLogError("ofAppEGLWindow") << "createSurface(): error creating context: " << error << " " << eglErrorString(error); + return false; + } + } + + // connect the eglContext to the eglSurface + result = eglMakeCurrent(eglDisplay, + eglSurface, // draw surface + eglSurface, // read surface + eglContext); + + if(eglContext == EGL_FALSE) { + EGLint error = eglGetError(); + ofLogError("ofAppEGLWindow") << "createSurface(): couldn't making current surface: " << eglErrorString(error); + return false; + } + + // Set background color and clear buffers + glClearColor(settings.initialClearColor.r / 255.0f, + settings.initialClearColor.g / 255.0f, + settings.initialClearColor.b / 255.0f, + settings.initialClearColor.a / 255.0f); + glClear( GL_COLOR_BUFFER_BIT ); + glClear( GL_DEPTH_BUFFER_BIT ); + + ofLogNotice("ofAppEGLWindow") << "createSurface(): -----EGL-----"; + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MAJOR = " << eglVersionMajor; + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION_MINOR = " << eglVersionMinor; + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_CLIENT_APIS = " << eglQueryString(eglDisplay, EGL_CLIENT_APIS); + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VENDOR = " << eglQueryString(eglDisplay, EGL_VENDOR); + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_VERSION = " << eglQueryString(eglDisplay, EGL_VERSION); + ofLogNotice("ofAppEGLWindow") << "createSurface(): EGL_EXTENSIONS = " << eglQueryString(eglDisplay, EGL_EXTENSIONS); + ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_RENDERER = " << glGetString(GL_RENDERER); + ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VERSION = " << glGetString(GL_VERSION); + ofLogNotice("ofAppEGLWindow") << "createSurface(): GL_VENDOR = " << glGetString(GL_VENDOR); + ofLogNotice("ofAppEGLWindow") << "createSurface(): -------------"; + + isSurfaceInited = true; + + return true; +} + +//------------------------------------------------------------ +bool ofAppEGLWindow::destroySurface() { + if(isSurfaceInited) { + ofLogNotice("ofAppEGLWindow") << "destroySurface(): destroying EGL surface"; + eglSwapBuffers(eglDisplay, eglSurface); + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglSurface); + eglDestroyContext(eglDisplay, eglContext); + eglTerminate(eglDisplay); + isSurfaceInited = false; + + eglDisplay = NULL; + eglSurface = NULL; + eglContext = NULL; + eglConfig = NULL; + eglVersionMinor = -1; + eglVersionMinor = -1; + + return true; + } else { + ofLogError("ofAppEGLWindow") << "destroySurface(): attempted to destroy uninitialized window"; + return false; + } +} + +//------------------------------------------------------------ +bool ofAppEGLWindow::destroyWindow() { + if(isWindowInited) { + if(isUsingX11) { + // TODO: double check + XDestroyWindow(x11Display,x11Window); // or XCloseWindow? + XFree(x11Screen); + } else { +#ifdef TARGET_RASPBERRY_PI + dispman_update = vc_dispmanx_update_start(0); + if (dispman_element != DISPMANX_NO_HANDLE) { + vc_dispmanx_element_remove(dispman_update, dispman_element); + dispman_element = DISPMANX_NO_HANDLE; + } + + vc_dispmanx_update_submit_sync(dispman_update); + + if (dispman_display != DISPMANX_NO_HANDLE) { + vc_dispmanx_display_close(dispman_display); + dispman_display = DISPMANX_NO_HANDLE; + } +#else + ofLogNotice("ofAppEGLWindow") << "destroyWindow(): no native window type for this system, perhaps try X11?"; +#endif + } + + } else { + ofLogNotice("ofAppEGLWindow") << "destroyWindow(): destroying (uninited) native window (not implemented yet)"; + } + + return true; +} + + +void ofAppEGLWindow::close(){ + if(!isUsingX11) { + destroyNativeEvents(); + } + + // we got a terminate ... so clean up. + destroySurface(); + destroyWindow(); + + exitNative(); + events().notifyExit(); + events().disable(); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::makeCurrent(){ + eglMakeCurrent(eglDisplay, + eglSurface, // draw surface + eglSurface, // read surface + eglContext); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::swapBuffers(){ + EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface); + if(!success) { + GLint error = eglGetError(); + ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error); + } +} + +//-------------------------------------------- +void ofAppEGLWindow::startRender() { + renderer()->startRender(); +} + +//-------------------------------------------- +void ofAppEGLWindow::finishRender() { + renderer()->finishRender(); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::update() { + coreEvents.notifyUpdate(); +} + + +//------------------------------------------------------------ +void ofAppEGLWindow::draw() { + // take care of any requests for a new screen mode + if (windowMode != OF_GAME_MODE && bNewScreenMode){ + if( windowMode == OF_FULLSCREEN){ + setWindowRect(getScreenRect()); + } else if( windowMode == OF_WINDOW ){ + setWindowRect(nonFullscreenWindowRect); + } + bNewScreenMode = false; + } + + currentRenderer->startRender(); + if( bEnableSetupScreen ) currentRenderer->setupScreen(); + + coreEvents.notifyDraw(); + + if(!isUsingX11) { + if(bShowCursor){ + GLboolean bIsDepthTestEnabled = GL_FALSE; + glGetBooleanv(GL_DEPTH_TEST, &bIsDepthTestEnabled); + + if(bIsDepthTestEnabled == GL_TRUE) { + glDisable(GL_DEPTH_TEST); + } + + bool isUsingNormalizedTexCoords = ofGetUsingNormalizedTexCoords(); + if(isUsingNormalizedTexCoords) { + ofDisableNormalizedTexCoords(); + } + + currentRenderer->pushStyle(); + currentRenderer->setBlendMode(OF_BLENDMODE_ADD); + currentRenderer->setColor(255); + mouseCursor.draw(ofGetMouseX(),ofGetMouseY()); + + currentRenderer->popStyle(); + + if(bIsDepthTestEnabled == GL_TRUE) { + glEnable(GL_DEPTH_TEST); + } + + if(isUsingNormalizedTexCoords) { + ofEnableNormalizedTexCoords(); + } + } + } + currentRenderer->finishRender(); + + EGLBoolean success = eglSwapBuffers(eglDisplay, eglSurface); + if(!success) { + GLint error = eglGetError(); + ofLogNotice("ofAppEGLWindow") << "display(): eglSwapBuffers failed: " << eglErrorString(error); + } + + nFramesSinceWindowResized++; + +} + +//------------------------------------------------------------ +ofCoreEvents & ofAppEGLWindow::events(){ + return coreEvents; +} + +//------------------------------------------------------------ +shared_ptr & ofAppEGLWindow::renderer(){ + return currentRenderer; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setupNativeEvents() { + setupNativeUDev(); + setupNativeMouse(); + setupNativeKeyboard(); + startThread(); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::destroyNativeEvents() { + destroyNativeUDev(); + destroyNativeMouse(); + destroyNativeKeyboard(); + waitForThread(true, threadTimeout); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setWindowRect(const ofRectangle& requestedWindowRect) { + if(!isWindowInited) { + ofLogError("ofAppEGLWindow") << "setWindowRect(): window not inited"; + return; + } + + ofRectangle newRect = requestedWindowRect.getStandardized(); + + if(newRect != currentWindowRect) { + ofRectangle oldWindowRect = currentWindowRect; + + if(isUsingX11) { + int ret = XMoveResizeWindow(x11Display, + x11Window, + (int)newRect.x, + (int)newRect.y, + (unsigned int)newRect.width, + (unsigned int)newRect.height); + if(ret == BadValue) { + ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadValue"; + } else if(ret == BadWindow) { + ofLogError("ofAppEGLWindow") << "setWindowRect(): XMoveResizeWindow returned BadWindow"; + } else { + // all is good + currentWindowRect = newRect; + } + } else { +#ifdef TARGET_RASPBERRY_PI + + VC_RECT_T dst_rect; + dst_rect.x = (int32_t)newRect.x; + dst_rect.y = (int32_t)newRect.y; + dst_rect.width = (int32_t)newRect.width; + dst_rect.height = (int32_t)newRect.height; + + VC_RECT_T src_rect; + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = (int32_t)newRect.width << 16; + src_rect.height = (int32_t)newRect.height << 16; + + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0); + + vc_dispmanx_element_change_attributes(dispman_update, + dispman_element, + ELEMENT_CHANGE_SRC_RECT|ELEMENT_CHANGE_DEST_RECT, // we do both when resizing + 0, // layer (we aren't changing it here) + 0, // opactiy (we aren't changing it here) + &dst_rect, + &src_rect, + 0, // mask (we aren't changing it here) + (DISPMANX_TRANSFORM_T)0); + + + vc_dispmanx_update_submit_sync(dispman_update); + + // next time swapBuffers is called, it will be resized based on this eglwindow size data + dispman_native_window.element = dispman_element; + dispman_native_window.width = (int32_t)newRect.width; + dispman_native_window.height = (int32_t)newRect.height; // don't forget! + + currentWindowRect = newRect; + +#else + ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?"; +#endif + } + + if(oldWindowRect.width != currentWindowRect.width || oldWindowRect.height != currentWindowRect.height) { + coreEvents.notifyWindowResized(currentWindowRect.width, currentWindowRect.height); + nFramesSinceWindowResized = 0; + } + } +} + + +//------------------------------------------------------------ +bool ofAppEGLWindow::createWindow(const ofRectangle& requestedWindowRect) { + if(isUsingX11) { + return createX11NativeWindow(requestedWindowRect); + } else { +#ifdef TARGET_RASPBERRY_PI + return createRPiNativeWindow(requestedWindowRect); +#else + ofLogError("ofAppEGLWindow") << "createEGLWindow(): no native window type for this system, perhaps try X11?"; + return false; +#endif + } +} + +//------------------------------------------------------------ +int ofAppEGLWindow::getWindowWidth() { + return currentWindowRect.width; +} + +//------------------------------------------------------------ +int ofAppEGLWindow::getWindowHeight() { + return currentWindowRect.height; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::pollEvents(){ + if(!instance) return; + if(instance->isUsingX11) { + while(1){ + XEvent event; + if (::XCheckWindowEvent(instance->x11Display, instance->x11Window, -1, &event)){ + handleX11Event(event); + }else if (::XCheckTypedEvent(instance->x11Display, ClientMessage, &event)){ + handleX11Event(event); + }else{ + break; + } + } + } else { + queue mouseEventsCopy; + instance->lock(); + mouseEventsCopy = instance->mouseEvents; + while(!instance->mouseEvents.empty()){ + instance->mouseEvents.pop(); + } + instance->unlock(); + while(!mouseEventsCopy.empty()){ + instance->coreEvents.notifyMouseEvent(mouseEventsCopy.front()); + mouseEventsCopy.pop(); + } + + // KEYBOARD EVENTS + queue keyEventsCopy; + instance->lock(); + keyEventsCopy = instance->keyEvents; + while(!instance->keyEvents.empty()){ + instance->keyEvents.pop(); + } + instance->unlock(); + while(!keyEventsCopy.empty()){ + instance->coreEvents.notifyKeyEvent(keyEventsCopy.front()); + keyEventsCopy.pop(); + } + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::hideCursor(){ + bShowCursor = false; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::showCursor(){ + bShowCursor = true; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setWindowTitle(string title) { + ofLogNotice("ofAppEGLWindow") << "setWindowTitle(): not implemented"; +} + +//------------------------------------------------------------ +glm::vec2 ofAppEGLWindow::getWindowSize(){ + return {currentWindowRect.width, currentWindowRect.height}; +} + +//------------------------------------------------------------ +glm::vec2 ofAppEGLWindow::getWindowPosition(){ + return currentWindowRect.getPosition().xy(); +} + +//------------------------------------------------------------ +glm::vec2 ofAppEGLWindow::getScreenSize(){ + unsigned int screenWidth = 0; + unsigned int screenHeight = 0; + + if(isUsingX11) { + // TODO, there must be a way to get screensize if the window is not inited + if(isWindowInited && x11Screen) { + screenWidth = XWidthOfScreen(x11Screen); + screenHeight = XHeightOfScreen(x11Screen); + } else { + ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed, x11Screen is not inited"; + } + + } else { +#ifdef TARGET_RASPBERRY_PI + int success = graphics_get_display_size(settings.screenNum, &screenWidth, &screenHeight); + if(success < 0) { + ofLogError("ofAppEGLWindow") << "getScreenSize(): tried to get display size but failed"; + } + +#else + ofLogError("ofAppEGLWindow") << "getScreenSize(): no native window type for this system, perhaps try X11?"; +#endif + + } + + return {screenWidth, screenHeight}; +} + +//------------------------------------------------------------ +int ofAppEGLWindow::getWidth(){ + if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){ + return currentWindowRect.width; + } + return currentWindowRect.height; +} + +//------------------------------------------------------------ +int ofAppEGLWindow::getHeight(){ + if( orientation == OF_ORIENTATION_DEFAULT || orientation == OF_ORIENTATION_180 ){ + return currentWindowRect.height; + } + return currentWindowRect.width; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setOrientation(ofOrientation orientationIn){ + orientation = orientationIn; +} + +//------------------------------------------------------------ +ofOrientation ofAppEGLWindow::getOrientation(){ + return orientation; +} + +//------------------------------------------------------------ +bool ofAppEGLWindow::doesHWOrientation() { + return false; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setWindowPosition(int x, int y){ + if(!isWindowInited) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited"; + return; + } + + if(isUsingX11) { + int ret = XMoveWindow(x11Display, + x11Window, + x, + y); + if(ret == BadValue) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue"; + } else if(ret == BadWindow) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow"; + } else { + currentWindowRect.x = x; + currentWindowRect.y = y; + nonFullscreenWindowRect = currentWindowRect; + } + } else { +#ifdef TARGET_RASPBERRY_PI + + // keep it in bounds + auto screenSize = getScreenSize(); + x = ofClamp(x, 0, screenSize.x - currentWindowRect.width); + y = ofClamp(y, 0, screenSize.y - currentWindowRect.height); + + VC_RECT_T dst_rect; + dst_rect.x = (int32_t)x; + dst_rect.y = (int32_t)y; + dst_rect.width = (int32_t)currentWindowRect.width; + dst_rect.height = (int32_t)currentWindowRect.height; + + dispman_update = vc_dispmanx_update_start(0); + + vc_dispmanx_element_change_attributes(dispman_update, + dispman_native_window.element, + ELEMENT_CHANGE_DEST_RECT, + 0, + 0, + &dst_rect, + NULL, + 0, + (DISPMANX_TRANSFORM_T)0); + + +vc_dispmanx_update_submit_sync(dispman_update); + +currentWindowRect.x = x; +currentWindowRect.y = y; +nonFullscreenWindowRect = currentWindowRect; + +#else + ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?"; +#endif + } + +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setWindowShape(int w, int h){ + if(!isWindowInited) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): window not inited"; + return; + } + + if(isUsingX11) { + int ret = XResizeWindow(x11Display, + x11Window, + (unsigned int)w, + (unsigned int)h); + if(ret == BadValue) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadValue"; + } else if(ret == BadWindow) { + ofLogError("ofAppEGLWindow") << "setWindowPosition(): XMoveWindow returned BadWindow"; + } else { + currentWindowRect.width = w; + currentWindowRect.height = h; + nonFullscreenWindowRect = currentWindowRect; + } + } else { +#ifdef TARGET_RASPBERRY_PI + setWindowRect(ofRectangle(currentWindowRect.x,currentWindowRect.y,w,h)); + nonFullscreenWindowRect = currentWindowRect; +#else + ofLogError("ofAppEGLWindow") << "setWindowPosition(): no native window type for this system, perhaps try X11?"; +#endif + } +} + +//------------------------------------------------------------ +ofWindowMode ofAppEGLWindow::getWindowMode(){ + return windowMode; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::toggleFullscreen(){ + if( windowMode == OF_GAME_MODE) return; + + if( windowMode == OF_WINDOW ){ + setFullscreen(true); + }else{ + setFullscreen(false); + } + +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setFullscreen(bool fullscreen){ + if( windowMode == OF_GAME_MODE) return; + + if(fullscreen && windowMode != OF_FULLSCREEN){ + bNewScreenMode = true; + windowMode = OF_FULLSCREEN; + }else if(!fullscreen && windowMode != OF_WINDOW) { + bNewScreenMode = true; + windowMode = OF_WINDOW; + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::enableSetupScreen(){ + bEnableSetupScreen = true; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::disableSetupScreen(){ + bEnableSetupScreen = false; +} + +//------------------------------------------------------------ +ofRectangle ofAppEGLWindow::getScreenRect(){ + auto screenSize = getScreenSize(); + return ofRectangle(0,0,screenSize.x,screenSize.y); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setVerticalSync(bool enabled){ + eglSwapInterval(eglDisplay, enabled ? 1 : 0); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::threadedFunction(){ + // TODO: a way to setup mouse and keyboard if + // they are not plugged in upon start + // This can be done with our udev device callbacks + + while(isThreadRunning()) { + readNativeUDevEvents(); + readNativeMouseEvents(); + readNativeKeyboardEvents(); + + // sleep briefly + ofSleepMillis(20); + } +} + +//------------------------------------------------------------ +// PLATFORM SPECIFIC RPI +//------------------------------------------------------------ + +//------------------------------------------------------------ +void ofAppEGLWindow::setupNativeUDev() { + + udev = udev_new(); // create new udev object + if(!udev) { + ofLogError("ofAppEGLWindow") << "setupNativeUDev(): couldn't create udev object"; + } else { + ofLogNotice("ofAppEGLWindow") << "setupNativeUDev(): created udev object"; + // setup udev to monitor for input devices + mon = udev_monitor_new_from_netlink(udev, "udev"); + // just listen for input devices + udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL); + udev_monitor_enable_receiving(mon); + // get the file descriptor for the mon (used w/ select); + udev_fd = udev_monitor_get_fd(mon); + } + + if(udev_fd < 0) { + ofLogError("ofAppEGLWindow") << "setupNativeUDev(): did not create udev object, udev_fd < 0"; + } + +} + +//------------------------------------------------------------ +void ofAppEGLWindow::destroyNativeUDev() { + udev_unref(udev); // clean up +} + + +//------------------------------------------------------------ +void ofAppEGLWindow::setupNativeMouse() { + struct dirent **eps; // What eps is supposed to mean? + + // fallback to /dev/input/eventX since some vnc servers use uinput to + // handle mouse & keyboard. + typedef int (*filter_ptr)(const struct dirent *d); + filter_ptr mouse_filters[2] = { filter_mouse, filter_event }; + string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" }; + + // Examine available input devices in directories at devicePathBuffers. + for(auto i = 0; i < 2; i++){ + + // Get number of devices in the current input device directory. + int n = scandir(devicePathBuffers[i].c_str(), &eps, mouse_filters[i], dummy_sort); + + // Open the appropriate entries, + // we want to get all mouse device events. + if(n >= 0 && eps != 0 && eps[0] != 0) { + for(auto j = 0; j < n; ++j){ + string devicePathBuffer; + devicePathBuffer.append(devicePathBuffers[i]); + devicePathBuffer.append(eps[j]->d_name); + + ofLogNotice("ofAppEGLWindow::setupNativeMouse()") + << "attempt to open " << devicePathBuffer; + + // TODO: create a vector out of fildes entries + int fildes = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); + + // No file descriptor, stop the current iteration of the nested loop here, + // continue with the next value of j. + if(fildes < 0){ + ofLogError("ofAppEGLWindow::setupNativeMouse()") + << "failed to open mouse device"; + continue; + } + + // Seems that we got a mouse device open! + // Get all the parameters. + ofAppEGLWindowMouseArgs mouseArgs; + mouseArgs.fildes = fildes; + + // TODO: consider a more reasonable way for calculating these. + mouseArgs.scaleX = 2.0f; + mouseArgs.scaleY = 2.0f; + + // Find out if input device is a absolute positioning device + // set the minimum and maximum values of the axes. + // Do this for the x axis. EVIOCGABS(0): 0 stands for x axis. + struct input_absinfo mabsx; + if (ioctl(fildes, EVIOCGABS(0), &mabsx) < 0){ + ofLogError("ofAppEGLWindow::setupNativeMouse()") + << "failed to get absolute limits of input x axis"; + mouseArgs.absXMin = 0; + mouseArgs.absXMax = 0; + } else { + mouseArgs.absXMin = mabsx.minimum; + mouseArgs.absXMax = mabsx.maximum; + ofLogNotice("ofAppEGLWindow::setupNativeMouse()") + << "mouse x axis min, max: " << mouseArgs.absXMin + << ", " << mouseArgs.absXMax; + } + + // Do that for the y axis. EVIOCGABS(1): 1 stands for y axis. + struct input_absinfo mabsy; + if (ioctl(fildes, EVIOCGABS(1), &mabsy) < 0){ + ofLogError("ofAppEGLWindow::setupNativeMouse()") + << "failed to get absolute limits of input y axis"; + mouseArgs.absYMin = 0; + mouseArgs.absYMax = 0; + } else { + mouseArgs.absYMin = mabsy.minimum; + mouseArgs.absYMax = mabsy.maximum; + ofLogNotice("ofAppEGLWindow::setupNativeMouse()") + << "mouse y axis min, max: " << mouseArgs.absYMin + << ", " << mouseArgs.absYMax; + } + + // Get input device name. + char deviceNameBuffer[256] = "Unknown Device"; + ioctl(fildes, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer); + mouseArgs.deviceName = string(deviceNameBuffer); + ofLogNotice("ofAppEGLWindow::setupNativeMouse()") + << "setting up mouse device with name " + << mouseArgs.deviceName; + + mice.push_back(mouseArgs); + + ofLogNotice("ofAppEGLWindow") << "setupMouse(): fildes=" + << fildes << " devicePath=" << devicePathBuffer; + } // Nested for loop + } + + // Do not examine other input device directories if we found some mice here. + // This breaks the main for loop of setupNativeMouse(). + if(mice.size()){ + break; + } + } // Main for loop + + mb.mouseButtonState = 0; + + if(mice.size() <= 0) { + mouseDetected = false; + ofLogWrning("ofAppEGLWindow::setupNativeMouse()") + << "no mouse found"; + } else { + mouseDetected = true; + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::setupNativeKeyboard() { + struct dirent **eps; + typedef int (*filter_ptr)(const struct dirent *d); + filter_ptr kbd_filters[2] = { filter_kbd, filter_event }; + string devicePathBuffers[2] = { "/dev/input/by-path/", "/dev/input/" }; + + for(int i=0; i<2; i++){ + int n = scandir(devicePathBuffers[i].c_str(), &eps, kbd_filters[i], dummy_sort); + + // make sure that we found an appropriate entry + if(n >= 0 && eps != 0 && eps[0] != 0) { + string devicePathBuffer; + devicePathBuffer.append(devicePathBuffers[i]); + devicePathBuffer.append(eps[0]->d_name); + keyboard_fd = open(devicePathBuffer.c_str(), O_RDONLY | O_NONBLOCK); + ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard_fd=" << keyboard_fd << " devicePath=" << devicePathBuffer; + break; + } + } + + if (keyboard_fd >= 0) { + char deviceNameBuffer[256] = "Unknown Device"; + ioctl(keyboard_fd, EVIOCGNAME(sizeof(deviceNameBuffer)), deviceNameBuffer); + ofLogNotice("ofAppEGLWindow") << "setupKeyboard(): keyboard device name = " << deviceNameBuffer; + + + // save current terminal settings + tcgetattr (STDIN_FILENO, &tc); + ots = tc; + // disable echo on our temporary settings + tc.c_lflag &= ~ECHO; + tc.c_lflag |= ECHONL; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc); + + } else { + ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard"; + } + + kb.shiftPressed = false; + kb.capsLocked = false; + + if(keyboard_fd < 0) { + ofLogError("ofAppEGLWindow") << "setupKeyboard(): did not open keyboard, keyboard_fd < 0"; + } else { + keyboardDetected = true; + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::destroyNativeMouse() { + for(auto i = 0; i < mice.size(); ++i){ + int retval = close(mice[i].fildes); + if(retval < 0){ + ofLogError("ofAppEGLWindow::destroyNativeMouse()") + << "Failed to close mouse device: " + << mice[i].deviceName; + } + } + mice.clear(); +} + +//------------------------------------------------------------ +void ofAppEGLWindow::destroyNativeKeyboard() { + ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard()"; + + if (keyboard_fd >= 0) { + tcsetattr (STDIN_FILENO, TCSAFLUSH, &ots); + } else { + ofLogNotice("ofAppEGLWindow") << "destroyNativeKeyboard(): unable to reset terminal"; + } +} + + +//------------------------------------------------------------ +void ofAppEGLWindow::readNativeUDevEvents() { + // look for devices being attatched / detatched + + fd_set fds; + struct timeval tv; + int ret; + + FD_ZERO(&fds); + FD_SET(udev_fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + ret = select(udev_fd+1, &fds, NULL, NULL, &tv); + + /* Check if our file descriptor has received data. */ + if (ret > 0 && FD_ISSET(udev_fd, &fds)) { + /* Make the call to receive the device. + select() ensured that this will not block. */ + dev = udev_monitor_receive_device(mon); + if (dev) { + // TODO: finish auto connect + ofLogNotice() << "Got device"; + ofLogNotice() << " node: %s\n", udev_device_get_devnode(dev); + ofLogNotice() << " subsystem: %s\n", udev_device_get_subsystem(dev); + ofLogNotice() << " devtype: %s\n", udev_device_get_devtype(dev); + ofLogNotice() << " action: %s\n", udev_device_get_action(dev); + udev_device_unref(dev); + } + else { + ofLogNotice("ofAppEGLWindow") << "readNativeUDevEvents(): device returned by receive_device() is NULL"; + } + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::readNativeKeyboardEvents() { + // http://www.diegm.uniud.it/loghi/CE2/kbd.pdf + // http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c + // https://strcpy.net/b/archives/2010/11/17/abusing_the_linux_input_subsystem/index.html + struct input_event ev; + char key = 0; + + int nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event)); + + static ofKeyEventArgs keyEvent; + bool pushKeyEvent = false; + + while(nBytesRead >= 0) { + + if (ev.type==EV_KEY) { + if(ev.value == 0) { + // key released + keyEvent.type = ofKeyEventArgs::Released; + } else if(ev.value == 1) { + // key pressed + keyEvent.type = ofKeyEventArgs::Pressed; + } else if(ev.value == 2) { + // key repeated + keyEvent.type = ofKeyEventArgs::Pressed; + } else { + // unknown ev.value + } + + switch (ev.code) { + case KEY_RIGHTSHIFT: + case KEY_LEFTSHIFT: + kb.shiftPressed = ev.value; + break; + case KEY_RIGHTCTRL: + case KEY_LEFTCTRL: + break; + case KEY_CAPSLOCK: + if (ev.value == 1) { + if (kb.capsLocked) { + kb.capsLocked = 0; + } else { + kb.capsLocked = 1; + } + } + break; + + case KEY_ESC: + pushKeyEvent = true; + keyEvent.key = OF_KEY_ESC; + break; + case KEY_BACKSPACE: + pushKeyEvent = true; + keyEvent.key = OF_KEY_BACKSPACE; + break; + case KEY_DELETE: + pushKeyEvent = true; + keyEvent.key = OF_KEY_DEL; + break; + case KEY_F1: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F1; + break; + case KEY_F2: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F2; + break; + case KEY_F3: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F3; + break; + case KEY_F4: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F4; + break; + case KEY_F5: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F5; + break; + case KEY_F6: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F6; + break; + case KEY_F7: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F7; + break; + case KEY_F8: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F8; + break; + case KEY_F9: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F9; + break; + case KEY_F10: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F10; + break; + case KEY_F11: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F11; + break; + case KEY_F12: + pushKeyEvent = true; + keyEvent.key = OF_KEY_F12; + break; + case KEY_LEFT: + pushKeyEvent = true; + keyEvent.key = OF_KEY_LEFT; + break; + case KEY_UP: + pushKeyEvent = true; + keyEvent.key = OF_KEY_UP; + break; + case KEY_RIGHT: + pushKeyEvent = true; + keyEvent.key = OF_KEY_RIGHT; + break; + case KEY_DOWN: + pushKeyEvent = true; + keyEvent.key = OF_KEY_DOWN; + break; + case KEY_PAGEUP: + pushKeyEvent = true; + keyEvent.key = OF_KEY_PAGE_UP; + break; + case KEY_PAGEDOWN: + pushKeyEvent = true; + keyEvent.key = OF_KEY_PAGE_DOWN; + break; + case KEY_HOME: + pushKeyEvent = true; + keyEvent.key = OF_KEY_HOME; + break; + case KEY_END: + pushKeyEvent = true; + keyEvent.key = OF_KEY_END; + break; + case KEY_INSERT: + pushKeyEvent = true; + keyEvent.key = OF_KEY_INSERT; + break; + case KEY_ENTER: + case KEY_KPENTER: + pushKeyEvent = true; + keyEvent.key = OF_KEY_RETURN; + break; + + default: + // VERY RUDIMENTARY KEY MAPPING WITH MAPS ABOVE + if(ev.code < sizeof(lowercase_map)) { + if (kb.shiftPressed) { + key = uppercase_map[ev.code]; + if (kb.capsLocked) keyEvent.key = tolower(key); + keyEvent.key = key; + pushKeyEvent = true; + } else { + key = lowercase_map[ev.code]; + if (kb.capsLocked) key = toupper(key); + keyEvent.key = key; + pushKeyEvent = true; + } + } else { + ofLogNotice("ofAppEGLWindow") << "readKeyboardEvents(): input_event.code is outside of our small range"; + } + } + } else if(ev.type == EV_MSC) { + // EV_MSC events are used for input and output events that + // do not fall under other categories. + // ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_MSC"; + } else if(ev.type == EV_SYN ) { + // EV_SYN Used as markers to separate events. Events may be + // separated in time or in space, such as with the multitouch protocol. + // ofLogVerbose("ofAppEGLWindow") << "readKeyboardEvents(): EV_SYN"; + } else { + // unhandled type + } + + // do we have a mouse svent to push? + if(pushKeyEvent){ + lock(); + keyEvents.push(keyEvent); + unlock(); + pushKeyEvent = false; + } + + nBytesRead = read(keyboard_fd, &ev,sizeof(struct input_event)); + } +} + +//------------------------------------------------------------ +void ofAppEGLWindow::readNativeMouseEvents() { + // http://cgit.freedesktop.org/~whot/evtest/plain/evtest.c + struct input_event ev; + static ofMouseEventArgs mouseEvent; + bool pushMouseEvent = false; + + for(auto i = 0; i < mice.size(); ++i){ + // Loop through all open mouse devices + +// ------------- + int nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event)); + + bool axisValuePending = false; + + while(nBytesRead >= 0) { + + if(ev.type == EV_REL || ev.type == EV_ABS) { + int axis = ev.code; + int amount = ev.value; + + switch(axis) { + case 0: + if(ev.type == EV_REL) { + mouseEvent.x += amount * mouseScaleX; + } else { + mouseEvent.x = amount * (float)currentWindowRect.width / (float)mouseAbsXMax; + } + + mouseEvent.x = ofClamp(mouseEvent.x, 0, currentWindowRect.width); + axisValuePending = true; + break; + case 1: + if(ev.type == EV_REL) { + mouseEvent.y += amount * mouseScaleY; + } else { + mouseEvent.y = amount * (float)currentWindowRect.height / (float)mouseAbsYMax; + } + + mouseEvent.y = ofClamp(mouseEvent.y, 0, currentWindowRect.height); + axisValuePending = true; + break; + default: + ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): unknown mouse axis (perhaps it's the scroll wheel?)"; + break; + } + + } else if(ev.type == EV_KEY) { + // only tracking three buttons now ... + if(ev.code == BTN_LEFT) { + if(ev.value == 0) { // release + mouseEvent.button = OF_MOUSE_BUTTON_LEFT; + mouseEvent.type = ofMouseEventArgs::Released; + mb.mouseButtonState &= ~MOUSE_BUTTON_LEFT_MASK; + pushMouseEvent = true; + } else if(ev.value == 1) { // press + mb.mouseButtonState |= MOUSE_BUTTON_LEFT_MASK; + mouseEvent.type = ofMouseEventArgs::Pressed; + mouseEvent.button = OF_MOUSE_BUTTON_LEFT; + pushMouseEvent = true; + } else { // unknown + ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; + } + } else if(ev.code == BTN_MIDDLE) { + if(ev.value == 0) { // release + mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE; + mouseEvent.type = ofMouseEventArgs::Released; + mb.mouseButtonState &= ~MOUSE_BUTTON_MIDDLE_MASK; + pushMouseEvent = true; + } else if(ev.value == 1) { // press + mb.mouseButtonState |= MOUSE_BUTTON_MIDDLE_MASK; + mouseEvent.type = ofMouseEventArgs::Pressed; + mouseEvent.button = OF_MOUSE_BUTTON_MIDDLE; + pushMouseEvent = true; + } else { // unknown + ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; + } + } else if(ev.code == BTN_RIGHT) { + if(ev.value == 0) { // release + mouseEvent.button = OF_MOUSE_BUTTON_RIGHT; + mouseEvent.type = ofMouseEventArgs::Released; + mb.mouseButtonState &= ~MOUSE_BUTTON_RIGHT_MASK; + pushMouseEvent = true; + } else if(ev.value == 1) { // press + mb.mouseButtonState |= MOUSE_BUTTON_RIGHT_MASK; + mouseEvent.type = ofMouseEventArgs::Pressed; + mouseEvent.button = OF_MOUSE_BUTTON_RIGHT; + pushMouseEvent = true; + } else { + ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.value = " << ev.value; + } + } else { + ofLogNotice("ofAppEGLWindow") << "readMouseEvents(): EV_KEY : unknown ev.code = " << ev.code; + } + // not sure why we are getting that event here + } else if(ev.type == EV_MSC) { + // EV_MSC events are used for input and output events that + // do not fall under other categories. + // ofLogVerbose("ofAppEGLWindow") << "readMouseEvents() : EV_MSC"; + } else if(ev.type == EV_SYN ) { + // EV_SYN Used as markers to separate events. Events may be + // separated in time or in space, such as with the multitouch protocol. + + // EV_SYN events are sent when axis value (one or a pair) are changed + if(axisValuePending) { + // TODO, this state doesn't make as much sense when the mouse is not dragging + if(mb.mouseButtonState > 0) { + // dragging (what if dragging w/ more than one button?) + mouseEvent.type = ofMouseEventArgs::Dragged; + } else { + // just moving + mouseEvent.type = ofMouseEventArgs::Moved; + } + + mouseEvent.button = mb.mouseButtonState; + + pushMouseEvent = true; + axisValuePending = false; + } + + //ofLogVerbose("ofAppEGLWindow") << "readMouseEvents(): EV_SYN"; + } else { + // unhandled type + } + + // do we have a mouse event to push? + if(pushMouseEvent){ + // lock the thread for a moment while we copy the data + lock(); + mouseEvents.push(mouseEvent); + unlock(); + pushMouseEvent = false; + } + + // Why another read? + nBytesRead = read(mice[i].fildes, &ev,sizeof(struct input_event)); + } // While loop +// ------------ + } // For loop + +} + +#ifdef TARGET_RASPBERRY_PI +//------------------------------------------------------------ +void ofAppEGLWindow::initRPiNative() { + bcm_host_init(); + + memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T)); + dispman_element = DISPMANX_NO_HANDLE; + dispman_display = DISPMANX_NO_HANDLE; + dispman_update = DISPMANX_NO_HANDLE; + memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T)); + dispman_transform = DISPMANX_NO_ROTATE; + memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha + +} + +//------------------------------------------------------------ +void ofAppEGLWindow::exitRPiNative() { + bcm_host_deinit(); +} + +//------------------------------------------------------------ +bool ofAppEGLWindow::createRPiNativeWindow(const ofRectangle& requestedWindowRect){ + + ofRectangle screenRect = getScreenRect(); + + // make sure our requested window rectangle does not exceed the native + // screen size, or start outside of it. + ofRectangle windowRect = screenRect.getIntersection(requestedWindowRect); + + ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): screenRect: " << screenRect.width << "x" << screenRect.height; + ofLogNotice("ofAppEGLWindow") << "setupRPiNativeWindow(): windowRect: " << windowRect.width << "x" << windowRect.height; + + ////////////////////////// + VC_RECT_T dst_rect; + + dst_rect.x = (int32_t)windowRect.x; + dst_rect.y = (int32_t)windowRect.y; + dst_rect.width = (int32_t)windowRect.width; + dst_rect.height = (int32_t)windowRect.height; + + VC_RECT_T src_rect; + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = dst_rect.width << 16; + src_rect.height = dst_rect.height << 16; + + memset(&dispman_alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T)); // zero dispman_alpha + dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; + dispman_alpha.opacity = ofClamp(settings.eglWindowOpacity,0,255); + dispman_alpha.mask = 0; + + memset(&dispman_clamp, 0x0, sizeof(DISPMANX_CLAMP_T)); + + // there are other values for dispman_transform, but they do not seem to have an effect + dispman_transform = DISPMANX_NO_ROTATE; + + // get the zero display + dispman_display = vc_dispmanx_display_open(settings.screenNum); + + // begin the display manager interaction + dispman_update = vc_dispmanx_update_start( 0 ); + + // add a "display manager element" with our parameters so + // that it can fill in the structures. we will pass this + // filled dispman_element to our native window, which will + // be used to construct the EGL surface, etc. + dispman_element = vc_dispmanx_element_add ( dispman_update, + dispman_display, + settings.layer, // layer + &dst_rect, // dst rect + (DISPMANX_RESOURCE_HANDLE_T)0, // src + &src_rect, // src rect + DISPMANX_PROTECTION_NONE, // ? + &dispman_alpha, // alpha + &dispman_clamp, // clamp + dispman_transform // transform + ); + + if(dispman_element == DISPMANX_NO_HANDLE) { + ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_NO_HANDLE"; + return false; + } else if(dispman_element == (unsigned)DISPMANX_INVALID) { + ofLogError("ofAppEGLWindow") << "setupRPiNativeWindow(): dispman_element == DISPMANX_INVALID"; + return false; + } + + // set dispman_native_window to zero + memset(&dispman_native_window, 0x0, sizeof(EGL_DISPMANX_WINDOW_T)); + dispman_native_window.element = dispman_element; + dispman_native_window.width = (int32_t)windowRect.width; + dispman_native_window.height = (int32_t)windowRect.height; + + // set background to black (not required) + vc_dispmanx_display_set_background(dispman_update, dispman_display, 0x00, 0x00, 0x00); + + // finished with display manager update, so sync + vc_dispmanx_update_submit_sync( dispman_update ); + + currentWindowRect = windowRect; + + return true; +} +#endif + +//------------------------------------------------------------ +// X11 BELOW +//------------------------------------------------------------ +bool ofAppEGLWindow::createX11NativeWindow(const ofRectangle& requestedWindowRect){ + + // X11 variables + x11Window = 0; + x11Display = 0; + x11ScreenNum = 0; // TODO: settings.screenNum? + x11Screen = 0; + XVisualInfo* x11Visual = 0; // TODO does this need to be deleted? + Colormap x11Colormap = 0; + + /* + Step 0 - Create a NativeWindowType that we can use it for OpenGL ES output + */ + Window sRootWindow; + XSetWindowAttributes sWA; + unsigned int ui32Mask; + int i32Depth; + + //ofRectangle screenRect = getScreenRect(); + + // make sure our requested window rectangle does not exceed the native + // screen size, or start outside of it. + ofRectangle windowRect = requestedWindowRect.getStandardized();//screenRect.getIntersection(requestedWindowRect); + + // Initializes the display and screen + x11Display = XOpenDisplay( 0 ); + if (!x11Display) { + ofLogError("ofAppEGLWindow") << "unable to open X display"; + return false; + } + + x11ScreenNum = XDefaultScreen( x11Display ); + + x11Screen = XDefaultScreenOfDisplay(x11Display); + + // Gets the window parameters + sRootWindow = RootWindow(x11Display, x11ScreenNum); + i32Depth = DefaultDepth(x11Display, x11ScreenNum); + x11Visual = new XVisualInfo(); + + XMatchVisualInfo( x11Display, + x11ScreenNum, + i32Depth, + TrueColor, + x11Visual); + + if (!x11Visual) { + ofLogError("ofAppEGLWindow") << "unable to acquire XVisualInfo"; + return false; + } + + x11Colormap = XCreateColormap( x11Display, sRootWindow, x11Visual->visual, AllocNone ); + + delete x11Visual; + + // set the colormap window attribuet + sWA.colormap = x11Colormap; + + // Add to these for handling other events + sWA.event_mask = 0; + sWA.event_mask |= StructureNotifyMask; + sWA.event_mask |= ExposureMask; + sWA.event_mask |= ButtonPressMask; + sWA.event_mask |= ButtonReleaseMask; + sWA.event_mask |= PointerMotionMask; + sWA.event_mask |= KeyPressMask; + sWA.event_mask |= KeyReleaseMask; + + // setup background pixel attributes + ui32Mask = 0; + ui32Mask |= CWBackPixel; + ui32Mask |= CWBorderPixel; + ui32Mask |= CWEventMask; + ui32Mask |= CWColormap; + + // Creates the X11 window + x11Window = XCreateWindow(x11Display, // Specifies the connection to the X server. + sRootWindow, // Specifies the parent window. + (int)windowRect.x, (int)windowRect.y, // Specify the x and y coordinates, + // which are the top-left outside corner + // of the window's borders and are relative + // to the inside of the parent window's borders. + (unsigned int)windowRect.width, (unsigned int)windowRect.height, // Specify the width and height, which are the + // created window's inside dimensions and do + // not include the created window's borders. + 0, // Specifies the width of the created + // window's border in pixels. + CopyFromParent, // Specifies the window's depth. + // A depth of CopyFromParent means + // the depth is taken from the parent. + InputOutput, // Specifies the created window's class. + // You can pass InputOutput, InputOnly, + // or CopyFromParent. A class of CopyFromParent + // means the class is taken from the parent. + CopyFromParent, // Specifies the visual type. + // A visual of CopyFromParent means the visual type + // is taken from the parent. + ui32Mask, // Specifies which window attributes are + // defined in the attributes argument. This mask is + // the bitwise inclusive OR of the valid attribute + // mask bits. If valuemask is zero, the attributes + // are ignored and are not referenced. + &sWA //Specifies the background pixel value of the window. + ); + + XMapWindow(x11Display, x11Window); + XFlush(x11Display); + + // check success? + currentWindowRect = windowRect; + + return true; +} + +//------------------------------------------------------------ +static KeySym KeyCodeToKeySym(Display * display, KeyCode keycode, unsigned int event_mask) { + KeySym keysym = NoSymbol; + + //Get the map + XkbDescPtr keyboard_map = XkbGetMap(display, XkbAllClientInfoMask, XkbUseCoreKbd); + if (keyboard_map) { + //What is diff between XkbKeyGroupInfo and XkbKeyNumGroups? + unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode); + unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode); + + //Get the group + unsigned int group = 0x00; + switch (XkbOutOfRangeGroupAction(info)) { + case XkbRedirectIntoRange: + /* If the RedirectIntoRange flag is set, the four least significant + * bits of the groups wrap control specify the index of a group to + * which all illegal groups correspond. If the specified group is + * also out of range, all illegal groups map to Group1. + */ + group = XkbOutOfRangeGroupInfo(info); + if (group >= num_groups) { + group = 0; + } + break; + + case XkbClampIntoRange: + /* If the ClampIntoRange flag is set, out-of-range groups correspond + * to the nearest legal group. Effective groups larger than the + * highest supported group are mapped to the highest supported group; + * effective groups less than Group1 are mapped to Group1 . For + * example, a key with two groups of symbols uses Group2 type and + * symbols if the global effective group is either Group3 or Group4. + */ + group = num_groups - 1; + break; + + case XkbWrapIntoRange: + /* If neither flag is set, group is wrapped into range using integer + * modulus. For example, a key with two groups of symbols for which + * groups wrap uses Group1 symbols if the global effective group is + * Group3 or Group2 symbols if the global effective group is Group4. + */ + default: + if (num_groups != 0) { + group %= num_groups; + } + break; + } + + XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group); + unsigned int active_mods = event_mask & key_type->mods.mask; + + int i, level = 0; + for (i = 0; i < key_type->map_count; i++) { + if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) { + level = key_type->map[i].level; + } + } + + keysym = XkbKeySymEntry(keyboard_map, keycode, level, group); + XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true); + } + + return keysym; +} + +//------------------------------------------------------------ +void ofAppEGLWindow::handleX11Event(const XEvent& event){ + ofMouseEventArgs mouseEvent; + ofKeyEventArgs keyEvent; + switch (event.type){ + case KeyPress: + case KeyRelease: + { + KeySym key = KeyCodeToKeySym(instance->x11Display,event.xkey.keycode,event.xkey.state); + keyEvent.key = key; + if (event.type == KeyPress) { + keyEvent.type = ofKeyEventArgs::Pressed; + if(key == 65307){ + keyEvent.key = OF_KEY_ESC; + } + } else if (event.type == KeyRelease){ + keyEvent.type = ofKeyEventArgs::Released; + } + + instance->coreEvents.notifyKeyEvent(keyEvent); + } + break; + case ButtonPress: + case ButtonRelease: + mouseEvent.x = static_cast(event.xbutton.x); + mouseEvent.y = static_cast(event.xbutton.y); + mouseEvent.button = event.xbutton.button; + if (event.type == ButtonPress){ + mouseEvent.type = ofMouseEventArgs::Pressed; + } else { + mouseEvent.type = ofMouseEventArgs::Released; + } + + instance->coreEvents.notifyMouseEvent(mouseEvent); + break; + case MotionNotify: + //cout << "motion notify" << endl; + mouseEvent.x = static_cast(event.xmotion.x); + mouseEvent.y = static_cast(event.xmotion.y); + mouseEvent.button = event.xbutton.button; + if(ofGetMousePressed()) { + mouseEvent.type = ofMouseEventArgs::Dragged; + } else { + mouseEvent.type = ofMouseEventArgs::Moved; + } + + instance->coreEvents.notifyMouseEvent(mouseEvent); + break; + case ConfigureNotify: + instance->currentWindowRect.x = event.xconfigure.x; + instance->currentWindowRect.y = event.xconfigure.y; + instance->currentWindowRect.width = event.xconfigure.width; + instance->currentWindowRect.height = event.xconfigure.height; + instance->nonFullscreenWindowRect = instance->currentWindowRect; + instance->coreEvents.notifyWindowResized(event.xconfigure.width,event.xconfigure.height); + break; + /*case ClientMessage:{ + if (event.xclient.message_type == wmProtocols_ && + event.xclient.format == 32 && + event.xclient.data.l[0] == (long) wmDeleteWindow_) + { + if (listener()) + { + if (listener()->onClose(wrapper() ? *wrapper() : *(WindowInterface*)this)) + isShuttingDown_ = true; + } + else + { + isShuttingDown_ = true; + } + } + break; + }*/ + } +} diff --git a/patches/ofAppEGLWindow.h b/patches/ofAppEGLWindow.h index 8a55a88..1830524 100644 --- a/patches/ofAppEGLWindow.h +++ b/patches/ofAppEGLWindow.h @@ -1,310 +1,310 @@ -#pragma once - -#include "ofBaseApp.h" - -#include "ofAppBaseWindow.h" -#include "ofThread.h" -#include "ofImage.h" -#include "ofBaseTypes.h" -#include "ofEvents.h" -#include "ofConstants.h" -#include "ofTypes.h" - -// include includes for both native and X11 possibilities -#include -#include -#include // sprintf -#include // malloc -#include -#include // open fcntl -#include // read close -#include - -#include "linux/kd.h" // keyboard stuff... -#include "termios.h" -#include "sys/ioctl.h" - -#include // scandir -#include // strlen - -// x11 -#include -#include - -#include -#include - -#include - -// TODO: this shold be passed in with the other window settings, like window alpha, etc. -enum ofAppEGLWindowType { - OF_APP_WINDOW_AUTO, - OF_APP_WINDOW_NATIVE, - OF_APP_WINDOW_X11 -}; - -struct ofAppEGLWindowMouseArgs { - string deviceName; - int fildes; // File Descriptor - int absXMin; - int absXMax; - int absYMin; - int absYMax; - float scaleX; - float scaleY; -}; - -typedef std::map ofEGLAttributeList; -typedef std::map::iterator ofEGLAttributeListIterator; - -class ofAppEGLWindow : public ofAppBaseGLESWindow, public ofThread { -public: - - struct Settings; - - ofAppEGLWindow(); - virtual ~ofAppEGLWindow(); - - static void loop(){}; - static bool doesLoop(){ return false; } - static bool allowsMultiWindow(){ return false; } - static bool needsPolling(){ return true; } - static void pollEvents(); - - using ofAppBaseGLESWindow::setup; - void setup(const Settings & settings); - void setup(const ofGLESWindowSettings & settings); - - void update(); - void draw(); - void close(); - void makeCurrent(); - void swapBuffers(); - void startRender(); - void finishRender(); - - ofCoreEvents & events(); - std::shared_ptr & renderer(); - - void setThreadTimeout(long timeOut){ threadTimeout = timeOut; } - - virtual void hideCursor(); - virtual void showCursor(); - - virtual void setWindowPosition(int x, int y); - virtual void setWindowShape(int w, int h); - - virtual glm::vec2 getWindowPosition(); - virtual glm::vec2 getWindowSize(); - virtual glm::vec2 getScreenSize(); - - virtual void setOrientation(ofOrientation orientation); - virtual ofOrientation getOrientation(); - virtual bool doesHWOrientation(); - - //this is used by ofGetWidth and now determines the window width based on orientation - virtual int getWidth(); - virtual int getHeight(); - - virtual void setWindowTitle(std::string title); // TODO const correct - - virtual ofWindowMode getWindowMode(); - - virtual void setFullscreen(bool fullscreen); - virtual void toggleFullscreen(); - - virtual void enableSetupScreen(); - virtual void disableSetupScreen(); - - virtual void setVerticalSync(bool enabled); - - struct Settings: public ofGLESWindowSettings { - public: - ofAppEGLWindowType eglWindowPreference; // what window type is preferred? - EGLint eglWindowOpacity; // 0-255 window alpha value - - ofEGLAttributeList frameBufferAttributes; - // surface creation - ofEGLAttributeList windowSurfaceAttributes; - - ofColor initialClearColor; - - int screenNum; - int layer; - - Settings(); - Settings(const ofGLESWindowSettings & settings); - }; - - EGLDisplay getEglDisplay() const; - EGLSurface getEglSurface() const; - EGLContext getEglContext() const; - -#ifndef TARGET_RASPBERRY_PI - Display* getX11Display(); - Window getX11Window(); -#endif - - EGLConfig getEglConfig() const; - - EGLint getEglVersionMajor () const; - EGLint getEglVersionMinor() const; - - -protected: - void setWindowRect(const ofRectangle& requestedWindowRect); - - -// bool create - - virtual void setupPeripherals(); - - virtual ofRectangle getScreenRect(); - - int getWindowWidth(); - int getWindowHeight(); - - ofWindowMode windowMode; - bool bNewScreenMode; ///< \brief This indicates if a (new) window rectangle has to be adjusted. - int buttonInUse; ///< \brief Mouse button currently in use. - bool bEnableSetupScreen; ///< \brief This indicates the need/intent to draw a setup screen. - bool bShowCursor; ///< \brief Indicate the visibility of the (mouse) cursor. - - std::string eglDisplayString; - int nFramesSinceWindowResized; ///< \brief The number of frames passed/shown since the window got resized. - ofOrientation orientation; - - - void threadedFunction(); - std::queue mouseEvents; - std::queue keyEvents; - void checkEvents(); - ofImage mouseCursor; - - // TODO: getters and setters? OR automatically set based on - // OS or screen size? Should be changed when screen is resized? - float mouseScaleX; ///< \brief Amount by which to mouse movements along the X axis. - float mouseScaleY; ///< \brief Amount by which to mouse movements along the Y axis. - - - // float getMouseScaleX() const; - // void setMouseScaleX(float x); - // float getMouseScaleY() const; - // void setMouseScaleY(float y); - - // For absolute input devices that send ABS_X and ABS_Y events, we want to store - // information about the min and max axis values. - int mouseAbsXMin; - int mouseAbsXMax; - int mouseAbsYMin; - int mouseAbsYMax; - - // TODO: a list of all valid and open mouse devices - // Store open mouse device file descriptors - vector mice; - - bool hasMouse() { return mouseDetected; } - bool hasKeyboard() { return keyboardDetected; } - - -//------------------------------------------------------------ -// EGL -//------------------------------------------------------------ - - bool createSurface(); - bool destroySurface(); - - // bool resizeSurface(); - - EGLDisplay eglDisplay; // EGL display connection - EGLSurface eglSurface; - EGLContext eglContext; - - EGLConfig eglConfig; - - EGLint eglVersionMajor; - EGLint eglVersionMinor; - -//------------------------------------------------------------ -// PLATFORM SPECIFIC WINDOWING -//------------------------------------------------------------ - -//------------------------------------------------------------ -// WINDOWING -//------------------------------------------------------------ - // EGL window - ofRectangle nonFullscreenWindowRect; // the rectangle describing the non-fullscreen window - ofRectangle currentWindowRect; // the rectangle describing the current device - - bool createWindow(const ofRectangle& requestedWindowRect); - bool destroyWindow(); - - bool isUsingX11; ///< \brief Indicate the use of the X Window System. - - bool isWindowInited; ///< \brief Indicate that the window is (properly) initialized. - bool isSurfaceInited; ///< \brief Indicate that the surface is (properly) initialized. - - void initNative(); - void exitNative(); - - EGLNativeWindowType getNativeWindow(); - EGLNativeDisplayType getNativeDisplay(); - -#ifdef TARGET_RASPBERRY_PI - void initRPiNative(); - void exitRPiNative(); - - EGL_DISPMANX_WINDOW_T dispman_native_window; // rpi - - DISPMANX_UPDATE_HANDLE_T dispman_update; - DISPMANX_ELEMENT_HANDLE_T dispman_element; - DISPMANX_DISPLAY_HANDLE_T dispman_display; - - DISPMANX_CLAMP_T dispman_clamp; - DISPMANX_TRANSFORM_T dispman_transform; - VC_DISPMANX_ALPHA_T dispman_alpha; - - bool createRPiNativeWindow(const ofRectangle& requestedWindowRect); - -#else - // if you are not raspberry pi, you will not be able to - // create a window without using x11. -#endif - - Display* x11Display; ///< \brief Indicate which X11 display is in use (currently). - Screen* x11Screen; ///< \brief Indicate which X11 screen is in use (currently). - Window x11Window; - long x11ScreenNum; ///< \brief The number of the X11 screen is in use (currently). - bool createX11NativeWindow(const ofRectangle& requestedWindowRect); - -//------------------------------------------------------------ -// EVENTS -//------------------------------------------------------------ - void setupNativeEvents(); - void destroyNativeEvents(); - - void setupNativeUDev(); - void destroyNativeUDev(); - - void setupNativeMouse(); - void setupNativeKeyboard(); - - void destroyNativeMouse(); - void destroyNativeKeyboard(); - - void readNativeMouseEvents(); - void readNativeKeyboardEvents(); - void readNativeUDevEvents(); - - static void handleX11Event(const XEvent& event); - -private: - Settings settings; - int glesVersion; ///< \brief Indicate the version of OpenGL for Embedded Systems. - bool keyboardDetected; - bool mouseDetected; - long threadTimeout; - ofCoreEvents coreEvents; - std::shared_ptr currentRenderer; - static ofAppEGLWindow * instance; -}; +#pragma once + +#include "ofBaseApp.h" + +#include "ofAppBaseWindow.h" +#include "ofThread.h" +#include "ofImage.h" +#include "ofBaseTypes.h" +#include "ofEvents.h" +#include "ofConstants.h" +#include "ofTypes.h" + +// include includes for both native and X11 possibilities +#include +#include +#include // sprintf +#include // malloc +#include +#include // open fcntl +#include // read close +#include + +#include "linux/kd.h" // keyboard stuff... +#include "termios.h" +#include "sys/ioctl.h" + +#include // scandir +#include // strlen + +// x11 +#include +#include + +#include +#include + +#include + +// TODO: this shold be passed in with the other window settings, like window alpha, etc. +enum ofAppEGLWindowType { + OF_APP_WINDOW_AUTO, + OF_APP_WINDOW_NATIVE, + OF_APP_WINDOW_X11 +}; + +struct ofAppEGLWindowMouseArgs { + string deviceName; + int fildes; // File Descriptor + int absXMin; + int absXMax; + int absYMin; + int absYMax; + float scaleX; + float scaleY; +}; + +typedef std::map ofEGLAttributeList; +typedef std::map::iterator ofEGLAttributeListIterator; + +class ofAppEGLWindow : public ofAppBaseGLESWindow, public ofThread { +public: + + struct Settings; + + ofAppEGLWindow(); + virtual ~ofAppEGLWindow(); + + static void loop(){}; + static bool doesLoop(){ return false; } + static bool allowsMultiWindow(){ return false; } + static bool needsPolling(){ return true; } + static void pollEvents(); + + using ofAppBaseGLESWindow::setup; + void setup(const Settings & settings); + void setup(const ofGLESWindowSettings & settings); + + void update(); + void draw(); + void close(); + void makeCurrent(); + void swapBuffers(); + void startRender(); + void finishRender(); + + ofCoreEvents & events(); + std::shared_ptr & renderer(); + + void setThreadTimeout(long timeOut){ threadTimeout = timeOut; } + + virtual void hideCursor(); + virtual void showCursor(); + + virtual void setWindowPosition(int x, int y); + virtual void setWindowShape(int w, int h); + + virtual glm::vec2 getWindowPosition(); + virtual glm::vec2 getWindowSize(); + virtual glm::vec2 getScreenSize(); + + virtual void setOrientation(ofOrientation orientation); + virtual ofOrientation getOrientation(); + virtual bool doesHWOrientation(); + + //this is used by ofGetWidth and now determines the window width based on orientation + virtual int getWidth(); + virtual int getHeight(); + + virtual void setWindowTitle(std::string title); // TODO const correct + + virtual ofWindowMode getWindowMode(); + + virtual void setFullscreen(bool fullscreen); + virtual void toggleFullscreen(); + + virtual void enableSetupScreen(); + virtual void disableSetupScreen(); + + virtual void setVerticalSync(bool enabled); + + struct Settings: public ofGLESWindowSettings { + public: + ofAppEGLWindowType eglWindowPreference; // what window type is preferred? + EGLint eglWindowOpacity; // 0-255 window alpha value + + ofEGLAttributeList frameBufferAttributes; + // surface creation + ofEGLAttributeList windowSurfaceAttributes; + + ofColor initialClearColor; + + int screenNum; + int layer; + + Settings(); + Settings(const ofGLESWindowSettings & settings); + }; + + EGLDisplay getEglDisplay() const; + EGLSurface getEglSurface() const; + EGLContext getEglContext() const; + +#ifndef TARGET_RASPBERRY_PI + Display* getX11Display(); + Window getX11Window(); +#endif + + EGLConfig getEglConfig() const; + + EGLint getEglVersionMajor () const; + EGLint getEglVersionMinor() const; + + +protected: + void setWindowRect(const ofRectangle& requestedWindowRect); + + +// bool create + + virtual void setupPeripherals(); + + virtual ofRectangle getScreenRect(); + + int getWindowWidth(); + int getWindowHeight(); + + ofWindowMode windowMode; + bool bNewScreenMode; ///< \brief This indicates if a (new) window rectangle has to be adjusted. + int buttonInUse; ///< \brief Mouse button currently in use. + bool bEnableSetupScreen; ///< \brief This indicates the need/intent to draw a setup screen. + bool bShowCursor; ///< \brief Indicate the visibility of the (mouse) cursor. + + std::string eglDisplayString; + int nFramesSinceWindowResized; ///< \brief The number of frames passed/shown since the window got resized. + ofOrientation orientation; + + + void threadedFunction(); + std::queue mouseEvents; + std::queue keyEvents; + void checkEvents(); + ofImage mouseCursor; + + // TODO: getters and setters? OR automatically set based on + // OS or screen size? Should be changed when screen is resized? + float mouseScaleX; ///< \brief Amount by which to mouse movements along the X axis. + float mouseScaleY; ///< \brief Amount by which to mouse movements along the Y axis. + + + // float getMouseScaleX() const; + // void setMouseScaleX(float x); + // float getMouseScaleY() const; + // void setMouseScaleY(float y); + + // For absolute input devices that send ABS_X and ABS_Y events, we want to store + // information about the min and max axis values. + int mouseAbsXMin; + int mouseAbsXMax; + int mouseAbsYMin; + int mouseAbsYMax; + + // TODO: a list of all valid and open mouse devices + // Store open mouse device file descriptors + vector mice; + + bool hasMouse() { return mouseDetected; } + bool hasKeyboard() { return keyboardDetected; } + + +//------------------------------------------------------------ +// EGL +//------------------------------------------------------------ + + bool createSurface(); + bool destroySurface(); + + // bool resizeSurface(); + + EGLDisplay eglDisplay; // EGL display connection + EGLSurface eglSurface; + EGLContext eglContext; + + EGLConfig eglConfig; + + EGLint eglVersionMajor; + EGLint eglVersionMinor; + +//------------------------------------------------------------ +// PLATFORM SPECIFIC WINDOWING +//------------------------------------------------------------ + +//------------------------------------------------------------ +// WINDOWING +//------------------------------------------------------------ + // EGL window + ofRectangle nonFullscreenWindowRect; // the rectangle describing the non-fullscreen window + ofRectangle currentWindowRect; // the rectangle describing the current device + + bool createWindow(const ofRectangle& requestedWindowRect); + bool destroyWindow(); + + bool isUsingX11; ///< \brief Indicate the use of the X Window System. + + bool isWindowInited; ///< \brief Indicate that the window is (properly) initialized. + bool isSurfaceInited; ///< \brief Indicate that the surface is (properly) initialized. + + void initNative(); + void exitNative(); + + EGLNativeWindowType getNativeWindow(); + EGLNativeDisplayType getNativeDisplay(); + +#ifdef TARGET_RASPBERRY_PI + void initRPiNative(); + void exitRPiNative(); + + EGL_DISPMANX_WINDOW_T dispman_native_window; // rpi + + DISPMANX_UPDATE_HANDLE_T dispman_update; + DISPMANX_ELEMENT_HANDLE_T dispman_element; + DISPMANX_DISPLAY_HANDLE_T dispman_display; + + DISPMANX_CLAMP_T dispman_clamp; + DISPMANX_TRANSFORM_T dispman_transform; + VC_DISPMANX_ALPHA_T dispman_alpha; + + bool createRPiNativeWindow(const ofRectangle& requestedWindowRect); + +#else + // if you are not raspberry pi, you will not be able to + // create a window without using x11. +#endif + + Display* x11Display; ///< \brief Indicate which X11 display is in use (currently). + Screen* x11Screen; ///< \brief Indicate which X11 screen is in use (currently). + Window x11Window; + long x11ScreenNum; ///< \brief The number of the X11 screen is in use (currently). + bool createX11NativeWindow(const ofRectangle& requestedWindowRect); + +//------------------------------------------------------------ +// EVENTS +//------------------------------------------------------------ + void setupNativeEvents(); + void destroyNativeEvents(); + + void setupNativeUDev(); + void destroyNativeUDev(); + + void setupNativeMouse(); + void setupNativeKeyboard(); + + void destroyNativeMouse(); + void destroyNativeKeyboard(); + + void readNativeMouseEvents(); + void readNativeKeyboardEvents(); + void readNativeUDevEvents(); + + static void handleX11Event(const XEvent& event); + +private: + Settings settings; + int glesVersion; ///< \brief Indicate the version of OpenGL for Embedded Systems. + bool keyboardDetected; + bool mouseDetected; + long threadTimeout; + ofCoreEvents coreEvents; + std::shared_ptr currentRenderer; + static ofAppEGLWindow * instance; +}; diff --git a/src/Application/Application.cpp b/src/Application/Application.cpp index 084b01b..54a7c92 100644 --- a/src/Application/Application.cpp +++ b/src/Application/Application.cpp @@ -1,668 +1,668 @@ -#include "Application.h" -#include "PresentationMode.h" - -namespace ofx { -namespace piMapper { - -Application::Application(){ - _keySequence = ""; - _surfaceManager.setMediaServer(&_mediaServer); - - // Set initial mode - setState(PresentationMode::instance()); - ofHideCursor(); - - ofAddListener(Gui::instance()->jointPressedEvent, this, &Application::onJointPressed); - ofAddListener(Gui::instance()->surfacePressedEvent, this, &Application::onSurfacePressed); - ofAddListener(Gui::instance()->backgroundPressedEvent, this, &Application::onBackgroundPressed); - ofAddListener(Gui::instance()->guiEvent, this, &Application::onGuiEvent); - - _lastSaveTime = 0.0f; - _autoSaveInterval = 60.0f; - _drawGui = true; -} - -void Application::setup(){ - // Setup components - _mediaServer.setup(); - - if(!loadXmlSettings(PIMAPPER_SETTINGS_FILE)){ - if(SettingsLoader::instance()->create(PIMAPPER_SETTINGS_FILE)){ - bool success = loadXmlSettings(PIMAPPER_SETTINGS_FILE); - if(!success){ - throw runtime_error("ofxPiMapper: Failed to load settings."); - } - }else{ - throw runtime_error("ofxPiMapper: Failed to create default settings file."); - } - } - - // Setup all states. - PresentationMode::instance()->setup(this); - TextureMappingMode::instance()->setup(this); - ProjectionMappingMode::instance()->setup(this); - SourceSelectionMode::instance()->setup(this); - - // TODO: Consider whether this is the right place for it - Gui::instance()->getScaleWidget().setSurfaceManager(&_surfaceManager); -} - -void Application::update(){ - _mediaServer.update(); - _state->update(this); - - // Autosave, do it only of the mode is not presentation mode - if(_state != PresentationMode::instance()){ - float timeNow = ofGetElapsedTimef(); - if(timeNow - _lastSaveTime > _autoSaveInterval){ - saveProject(); - _lastSaveTime = timeNow; - } - } -} - -ApplicationBaseMode * Application::getState(){ - return _state; -} - -void Application::draw(){ - _mediaServer.draw(); - - if(_drawGui){ - _state->draw(this); - }else{ - PresentationMode::instance()->draw(this); - } - - _info.draw(); -} - -// Here we handle application state changes only -void Application::onKeyPressed(ofKeyEventArgs & args){ - - // Key sequence based commands. Last three keys are taken into account. - _keySequence += args.key; - if(_keySequence.size() >= 3){ - _keySequence = _keySequence.substr(_keySequence.size() - 3, 3); - if(_keySequence == "new"){ - if(_surfaceManager.getActivePreset()->size()){ - _cmdManager.exec(new ClearSurfacesCmd(getSurfaceManager())); - } - return; - }else if(_keySequence == "rbt"){ - reboot(); - return; - }else if(_keySequence == "sdn"){ - shutdown(); - return; - }else if(_keySequence == "ext"){ - exit(0); - } - } - - // For now we set the state of the new system and also the old - // before it is completely ported to the state system. - - switch(args.key){ - case OF_KEY_SHIFT: - _shiftKeyDown = true; - break; - - case '/': - toggleShift(); - break; - - case '1': - setPresentationMode(); - break; - - case '2': - setTextureMode(); - break; - - case '3': - setProjectionMode(); - break; - - case '4': - setSourceMode(); - break; - - case 'i': - toggleInfo(); - break; - - case 's': - saveProject(); - break; - - case 'z': - undo(); - break; - - case 'f': - setNextPreset(); - break; - - case 'F': - setFullscreenSurface(); - break; - - default: - // All the other keypresses are handled by the application state onKeyPressed - _state->onKeyPressed(this, args); - break; - } -} - -void Application::onKeyReleased(ofKeyEventArgs & args){ - switch(args.key){ - case OF_KEY_SHIFT: - _shiftKeyDown = false; - break; - } -} - -void Application::onMousePressed(ofMouseEventArgs & args){ - _state->onMousePressed(this, args); -} - -void Application::onMouseReleased(ofMouseEventArgs & args){ - _state->onMouseReleased(this, args); -} - -void Application::onMouseDragged(ofMouseEventArgs &args){ - _state->onMouseDragged(this, args); -} - -void Application::onJointPressed(GuiJointEvent & e){ - _state->onJointPressed(this, e); -} - -void Application::onSurfacePressed(GuiSurfaceEvent & e){ - _state->onSurfacePressed(this, e); -} - -void Application::onBackgroundPressed(GuiBackgroundEvent & e){ - _state->onBackgroundPressed(this, e); -} - -void Application::onGuiEvent(GuiEvent & e){ - _state->onGuiEvent(this, e); -} - -void Application::addFboSource(FboSource & fboSource){ - _mediaServer.addFboSource(fboSource); -} - -void Application::addFboSource(FboSource * fboSource){ - _mediaServer.addFboSource(fboSource); -} - -void Application::createSurface(SurfaceType type){ - getCmdManager()->exec( - new AddSurfaceCmd(getSurfaceManager(), type)); -} - -void Application::eraseSurface(int i){ - if(i >= 0 && i < getSurfaceManager()->getActivePreset()->getSurfaces().size()){ - getCmdManager()->exec(new RmSurfaceCmd(getSurfaceManager(), i)); - } -} - -void Application::setInfoText(std::string text){ - _info.setText(text); -} - -void Application::toggleInfo(){ - _info.toggle(); -} - -void Application::togglePerspective(){ - if(getSurfaceManager()->getSelectedSurface() == 0){ - return; - } - - if(getSurfaceManager()->getSelectedSurface()->getType() == SurfaceType::QUAD_SURFACE){ - getCmdManager()->exec(new TogglePerspectiveCmd( - (QuadSurface *)getSurfaceManager()->getSelectedSurface())); - } -} - -void Application::saveProject(){ - ofLogNotice("Application::saveProject", "Saving project..."); - _surfaceManager.saveXmlSettings(SettingsLoader::instance()->getLastLoadedFilename()); -} - -void Application::setState(ApplicationBaseMode * st){ - _state = st; -} - -bool Application::isShiftKeyDown(){ - return _shiftKeyDown; -} - -bool Application::toggleShift(){ - _shiftKeyDown = !_shiftKeyDown; - return _shiftKeyDown; -} - -void Application::setPreset(unsigned int i){ - _cmdManager.exec(new SetPresetCmd(this, i)); -} - -void Application::setNextPreset(){ - unsigned int numPresets = _surfaceManager.getNumPresets(); - if(numPresets <= 1){ - return; - } - int activePreset = _surfaceManager.getActivePresetIndex(); - if(activePreset >= numPresets - 1){ - activePreset = 0; - }else{ - activePreset += 1; - } - setPreset(activePreset); -} - -void Application::reboot(){ - #ifdef TARGET_RASPBERRY_PI - system("sudo shutdown -r now"); - #else - ofLogNotice("Application::reboot()", "Supported only on Raspberry Pi"); - #endif -} - -void Application::shutdown(){ - #ifdef TARGET_RASPBERRY_PI - system("sudo shutdown -h now"); - #else - ofLogNotice("Application::shutdown()", "Supported only on Raspberry Pi"); - #endif -} - -bool Application::loadXmlSettings(std::string fileName){ - if(!ofFile::doesFileExist(fileName)){ - ofLogError("Application::loadXmlSettings()") << fileName << " does not exist"; - return false; - } - if(!_surfaceManager.loadXmlSettings(fileName)){ - ofLogError("Application::loadXmlSettings()") << "Failed to load " << fileName << std::endl; - return false; - } - return true; -} - -void Application::selectSurface(int i){ - if(getSurfaceManager()->size()){ - if(getSurfaceManager()->getSelectedSurfaceIndex() == i){ - return; - } - getCmdManager()->exec( - new SelSurfaceCmd( - getSurfaceManager(), - getSurfaceManager()->getSurface(i))); - } -} - -void Application::selectNextSurface(){ - if(getSurfaceManager()->size()){ - if(getSurfaceManager()->size() == 1 && - getSurfaceManager()->getSelectedSurface() == - getSurfaceManager()->getSurface(0)){ - return; - } - getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); - } -} - -void Application::selectPrevSurface(){ - if(getSurfaceManager()->size()){ - if(getSurfaceManager()->size() == 1 && - getSurfaceManager()->getSelectedSurface() == - getSurfaceManager()->getSurface(0)){ - return; - } - getCmdManager()->exec(new SelPrevSurfaceCmd(getSurfaceManager())); - } -} - -void Application::selectNextVertex(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec(new SelNextVertexCmd(getSurfaceManager())); - } -} - -void Application::selectPrevVertex(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec(new SelPrevVertexCmd(getSurfaceManager())); - } -} - -void Application::selectVertex(int surface, int vertex){ - if(getSurfaceManager()->size()){ - - // TODO: use one command instead of two - - getCmdManager()->exec( - new SelSurfaceCmd( - getSurfaceManager(), - getSurfaceManager()->getSurface(surface))); - - getCmdManager()->exec( - new SelVertexCmd( - getSurfaceManager(), - vertex)); - } -} - -void Application::selectNextTexCoord(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new SelNextTexCoordCmd( - &Gui::instance()->getTextureEditorWidget())); - } -} - -void Application::selectPrevTexCoord(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new SelPrevTexCoordCmd( - &Gui::instance()->getTextureEditorWidget())); - } -} - -void Application::moveSelection(Vec3 by){ - if(_state == ProjectionMappingMode::instance()){ - getCmdManager()->exec(new MvSelectionCmd(getSurfaceManager(), by)); - }else if(_state == TextureMappingMode::instance()){ - Vec2 tcBy(by.x, by.y); - int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); - if(selectedTexCoord >= 0){ - moveTexCoord(selectedTexCoord, tcBy); - } - } -} - -void Application::setPresentationMode(){ - _cmdManager.exec( - new ofx::piMapper::SetApplicationModeCmd( - this, PresentationMode::instance())); -} - -void Application::setTextureMode(){ - _cmdManager.exec( - new ofx::piMapper::SetApplicationModeCmd( - this, TextureMappingMode::instance())); -} - -void Application::setProjectionMode(){ - _cmdManager.exec( - new ofx::piMapper::SetApplicationModeCmd( - this, ProjectionMappingMode::instance())); -} - -void Application::setSourceMode(){ - _cmdManager.exec( - new ofx::piMapper::SetApplicationModeCmd( - this, SourceSelectionMode::instance())); -} - -void Application::moveLayerUp(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface() == - getSurfaceManager()->getActivePreset()->at( - getSurfaceManager()->getActivePreset()->size() - 1)){ - return; - } - - getCmdManager()->exec( - new MvLayerUpCmd( - getSurfaceManager()->getActivePreset(), - getSurfaceManager()->getSelectedSurface())); - } -} - -void Application::moveLayerDown(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface() == - getSurfaceManager()->getActivePreset()->at(0)){ - return; - } - - getCmdManager()->exec( - new MvLayerDnCmd( - getSurfaceManager()->getActivePreset(), - getSurfaceManager()->getSelectedSurface())); - } -} - -void Application::scaleUp(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new ScaleSurfaceFromToCmd( - getSurfaceManager()->getSelectedSurface(), - getSurfaceManager()->getSelectedSurface()->getScale(), - getSurfaceManager()->getSelectedSurface()->getScale() + 0.2f)); - } -} - -void Application::scaleDown(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface()->getScale() <= 0.21f){ - return; - } - getCmdManager()->exec( - new ScaleSurfaceFromToCmd( - getSurfaceManager()->getSelectedSurface(), - getSurfaceManager()->getSelectedSurface()->getScale(), - getSurfaceManager()->getSelectedSurface()->getScale() - 0.2f)); - } -} - -void Application::duplicateSurface(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new DuplicateSurfaceCmd( - getSurfaceManager()->getSelectedSurface(), - getSurfaceManager())); - } -} - -void Application::setFullscreenSurface(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new FullscreenSurfaceCmd(getSurfaceManager()->getSelectedSurface())); - } -} - -void Application::setNextSource(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new SetNextSourceCmd( - getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getSourcesEditorWidget())); - }else{ - getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); - } -} - -void Application::setFboSource(std::string sourceId){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec( - new SetSourceCmd( - SourceType::SOURCE_TYPE_FBO, - sourceId, - getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getSourcesEditorWidget())); - }else{ - getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); - } -} - -void Application::setVideoSource(std::string fileName, bool loop){ - vector loadedVideos = getMediaServer()->getVideoNames(); - for(auto i = 0; i < loadedVideos.size(); i++){ - if(ofIsStringInString(loadedVideos[i], fileName)){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - BaseSource * source = getSurfaceManager()->getSelectedSurface()->getSource(); - - if(source->getType() == SOURCE_TYPE_VIDEO){ - VideoSource * video = dynamic_cast(source); - video->stop(); - } - - getCmdManager()->exec( - new SetVideoSourceCmd( - getMediaServer()->getVideoPaths()[i], - loop, - getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getSourcesEditorWidget())); - }else{ - getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); - } - break; - } - } -} - -void Application::setImageSource(std::string fileName){ - vector loadedImages = getMediaServer()->getImageNames(); - for(auto i = 0; i < loadedImages.size(); i++){ - if(ofIsStringInString(loadedImages[i], fileName)){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - BaseSource * source = getSurfaceManager()->getSelectedSurface()->getSource(); - - if(source->getType() == SOURCE_TYPE_VIDEO){ - VideoSource * video = dynamic_cast(source); - video->stop(); - } - - getCmdManager()->exec( - new SetSourceCmd( - SourceType::SOURCE_TYPE_IMAGE, - getMediaServer()->getImagePaths()[i], - getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getSourcesEditorWidget())); - }else{ - getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); - } - break; - } - } -} - -void Application::setDrawGui(bool drawGui){ - _drawGui = drawGui; - if(!_drawGui){ - ofHideCursor(); - } -} - -void Application::addGridRow(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface()->getType() == - SurfaceType::GRID_WARP_SURFACE){ - // TODO: The command should not require projection editor pointer - getCmdManager()->exec( - new AddGridRowCmd( - (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); - } - } -} - -void Application::addGridColumn(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface()->getType() == - SurfaceType::GRID_WARP_SURFACE){ - // TODO: The command should not require projection editor pointer - getCmdManager()->exec( - new AddGridColCmd( - (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); - } - } -} - -void Application::removeGridRow(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface()->getType() == - SurfaceType::GRID_WARP_SURFACE){ - if(((GridWarpSurface *)getSurfaceManager()->getSelectedSurface())->getGridRows() > 1){ - // TODO: The command should not require projection editor pointer - getCmdManager()->exec( - new RmGridRowCmd( - (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); - } - } - } -} - -void Application::removeGridColumn(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - if(getSurfaceManager()->getSelectedSurface()->getType() == - SurfaceType::GRID_WARP_SURFACE){ - if(((GridWarpSurface *)getSurfaceManager()->getSelectedSurface())->getGridCols() > 1){ - // TODO: The command should not require projection editor pointer - getCmdManager()->exec( - new RmGridColCmd( - (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); - } - } - } -} - -void Application::togglePause(){ - if(getSurfaceManager()->getSelectedSurface() == 0){ - return; - } - - if(getSurfaceManager()->getSelectedSurface()->getSource()->getType() == - SourceType::SOURCE_TYPE_VIDEO){ - getCmdManager()->exec( - new ToggleAnimatedSourceCmd( - getSurfaceManager()->getSelectedSurface())); - } -} - -void Application::moveTexCoord(int texCoordIndex, Vec2 by){ - if(texCoordIndex >= 0){ - getCmdManager()->exec(new MvTexCoordCmd(texCoordIndex, by)); - }else{ - getCmdManager()->exec(new MvAllTexCoordsCmd( - getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getTextureEditorWidget())); - - Gui::instance()->getTextureEditorWidget().moveSelection(by); - } -} - -void Application::undo(){ - _cmdManager.undo(); -} - -void Application::deselect(){ - if(getSurfaceManager()->getSelectedSurface() != 0){ - getCmdManager()->exec(new DeselectSurfaceCmd(getSurfaceManager())); - } -} - -void Application::toggleLayerPanel(){ - if(getState() == ProjectionMappingMode::instance()){ - ProjectionMappingMode::instance()->toggleLayerPanel(); - } -} - -void Application::restart(){ - _mediaServer.restart(); -} - -void Application::pause(){ - _mediaServer.pause(); -} - -void Application::resume(){ - _mediaServer.resume(); -} - -} // namespace piMapper -} // namespace ofx +#include "Application.h" +#include "PresentationMode.h" + +namespace ofx { +namespace piMapper { + +Application::Application(){ + _keySequence = ""; + _surfaceManager.setMediaServer(&_mediaServer); + + // Set initial mode + setState(PresentationMode::instance()); + ofHideCursor(); + + ofAddListener(Gui::instance()->jointPressedEvent, this, &Application::onJointPressed); + ofAddListener(Gui::instance()->surfacePressedEvent, this, &Application::onSurfacePressed); + ofAddListener(Gui::instance()->backgroundPressedEvent, this, &Application::onBackgroundPressed); + ofAddListener(Gui::instance()->guiEvent, this, &Application::onGuiEvent); + + _lastSaveTime = 0.0f; + _autoSaveInterval = 60.0f; + _drawGui = true; +} + +void Application::setup(){ + // Setup components + _mediaServer.setup(); + + if(!loadXmlSettings(PIMAPPER_SETTINGS_FILE)){ + if(SettingsLoader::instance()->create(PIMAPPER_SETTINGS_FILE)){ + bool success = loadXmlSettings(PIMAPPER_SETTINGS_FILE); + if(!success){ + throw runtime_error("ofxPiMapper: Failed to load settings."); + } + }else{ + throw runtime_error("ofxPiMapper: Failed to create default settings file."); + } + } + + // Setup all states. + PresentationMode::instance()->setup(this); + TextureMappingMode::instance()->setup(this); + ProjectionMappingMode::instance()->setup(this); + SourceSelectionMode::instance()->setup(this); + + // TODO: Consider whether this is the right place for it + Gui::instance()->getScaleWidget().setSurfaceManager(&_surfaceManager); +} + +void Application::update(){ + _mediaServer.update(); + _state->update(this); + + // Autosave, do it only of the mode is not presentation mode + if(_state != PresentationMode::instance()){ + float timeNow = ofGetElapsedTimef(); + if(timeNow - _lastSaveTime > _autoSaveInterval){ + saveProject(); + _lastSaveTime = timeNow; + } + } +} + +ApplicationBaseMode * Application::getState(){ + return _state; +} + +void Application::draw(){ + _mediaServer.draw(); + + if(_drawGui){ + _state->draw(this); + }else{ + PresentationMode::instance()->draw(this); + } + + _info.draw(); +} + +// Here we handle application state changes only +void Application::onKeyPressed(ofKeyEventArgs & args){ + + // Key sequence based commands. Last three keys are taken into account. + _keySequence += args.key; + if(_keySequence.size() >= 3){ + _keySequence = _keySequence.substr(_keySequence.size() - 3, 3); + if(_keySequence == "new"){ + if(_surfaceManager.getActivePreset()->size()){ + _cmdManager.exec(new ClearSurfacesCmd(getSurfaceManager())); + } + return; + }else if(_keySequence == "rbt"){ + reboot(); + return; + }else if(_keySequence == "sdn"){ + shutdown(); + return; + }else if(_keySequence == "ext"){ + exit(0); + } + } + + // For now we set the state of the new system and also the old + // before it is completely ported to the state system. + + switch(args.key){ + case OF_KEY_SHIFT: + _shiftKeyDown = true; + break; + + case '/': + toggleShift(); + break; + + case '1': + setPresentationMode(); + break; + + case '2': + setTextureMode(); + break; + + case '3': + setProjectionMode(); + break; + + case '4': + setSourceMode(); + break; + + case 'i': + toggleInfo(); + break; + + case 's': + saveProject(); + break; + + case 'z': + undo(); + break; + + case 'f': + setNextPreset(); + break; + + case 'F': + setFullscreenSurface(); + break; + + default: + // All the other keypresses are handled by the application state onKeyPressed + _state->onKeyPressed(this, args); + break; + } +} + +void Application::onKeyReleased(ofKeyEventArgs & args){ + switch(args.key){ + case OF_KEY_SHIFT: + _shiftKeyDown = false; + break; + } +} + +void Application::onMousePressed(ofMouseEventArgs & args){ + _state->onMousePressed(this, args); +} + +void Application::onMouseReleased(ofMouseEventArgs & args){ + _state->onMouseReleased(this, args); +} + +void Application::onMouseDragged(ofMouseEventArgs &args){ + _state->onMouseDragged(this, args); +} + +void Application::onJointPressed(GuiJointEvent & e){ + _state->onJointPressed(this, e); +} + +void Application::onSurfacePressed(GuiSurfaceEvent & e){ + _state->onSurfacePressed(this, e); +} + +void Application::onBackgroundPressed(GuiBackgroundEvent & e){ + _state->onBackgroundPressed(this, e); +} + +void Application::onGuiEvent(GuiEvent & e){ + _state->onGuiEvent(this, e); +} + +void Application::addFboSource(FboSource & fboSource){ + _mediaServer.addFboSource(fboSource); +} + +void Application::addFboSource(FboSource * fboSource){ + _mediaServer.addFboSource(fboSource); +} + +void Application::createSurface(SurfaceType type){ + getCmdManager()->exec( + new AddSurfaceCmd(getSurfaceManager(), type)); +} + +void Application::eraseSurface(int i){ + if(i >= 0 && i < getSurfaceManager()->getActivePreset()->getSurfaces().size()){ + getCmdManager()->exec(new RmSurfaceCmd(getSurfaceManager(), i)); + } +} + +void Application::setInfoText(std::string text){ + _info.setText(text); +} + +void Application::toggleInfo(){ + _info.toggle(); +} + +void Application::togglePerspective(){ + if(getSurfaceManager()->getSelectedSurface() == 0){ + return; + } + + if(getSurfaceManager()->getSelectedSurface()->getType() == SurfaceType::QUAD_SURFACE){ + getCmdManager()->exec(new TogglePerspectiveCmd( + (QuadSurface *)getSurfaceManager()->getSelectedSurface())); + } +} + +void Application::saveProject(){ + ofLogNotice("Application::saveProject", "Saving project..."); + _surfaceManager.saveXmlSettings(SettingsLoader::instance()->getLastLoadedFilename()); +} + +void Application::setState(ApplicationBaseMode * st){ + _state = st; +} + +bool Application::isShiftKeyDown(){ + return _shiftKeyDown; +} + +bool Application::toggleShift(){ + _shiftKeyDown = !_shiftKeyDown; + return _shiftKeyDown; +} + +void Application::setPreset(unsigned int i){ + _cmdManager.exec(new SetPresetCmd(this, i)); +} + +void Application::setNextPreset(){ + unsigned int numPresets = _surfaceManager.getNumPresets(); + if(numPresets <= 1){ + return; + } + int activePreset = _surfaceManager.getActivePresetIndex(); + if(activePreset >= numPresets - 1){ + activePreset = 0; + }else{ + activePreset += 1; + } + setPreset(activePreset); +} + +void Application::reboot(){ + #ifdef TARGET_RASPBERRY_PI + system("sudo shutdown -r now"); + #else + ofLogNotice("Application::reboot()", "Supported only on Raspberry Pi"); + #endif +} + +void Application::shutdown(){ + #ifdef TARGET_RASPBERRY_PI + system("sudo shutdown -h now"); + #else + ofLogNotice("Application::shutdown()", "Supported only on Raspberry Pi"); + #endif +} + +bool Application::loadXmlSettings(std::string fileName){ + if(!ofFile::doesFileExist(fileName)){ + ofLogError("Application::loadXmlSettings()") << fileName << " does not exist"; + return false; + } + if(!_surfaceManager.loadXmlSettings(fileName)){ + ofLogError("Application::loadXmlSettings()") << "Failed to load " << fileName << std::endl; + return false; + } + return true; +} + +void Application::selectSurface(int i){ + if(getSurfaceManager()->size()){ + if(getSurfaceManager()->getSelectedSurfaceIndex() == i){ + return; + } + getCmdManager()->exec( + new SelSurfaceCmd( + getSurfaceManager(), + getSurfaceManager()->getSurface(i))); + } +} + +void Application::selectNextSurface(){ + if(getSurfaceManager()->size()){ + if(getSurfaceManager()->size() == 1 && + getSurfaceManager()->getSelectedSurface() == + getSurfaceManager()->getSurface(0)){ + return; + } + getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); + } +} + +void Application::selectPrevSurface(){ + if(getSurfaceManager()->size()){ + if(getSurfaceManager()->size() == 1 && + getSurfaceManager()->getSelectedSurface() == + getSurfaceManager()->getSurface(0)){ + return; + } + getCmdManager()->exec(new SelPrevSurfaceCmd(getSurfaceManager())); + } +} + +void Application::selectNextVertex(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec(new SelNextVertexCmd(getSurfaceManager())); + } +} + +void Application::selectPrevVertex(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec(new SelPrevVertexCmd(getSurfaceManager())); + } +} + +void Application::selectVertex(int surface, int vertex){ + if(getSurfaceManager()->size()){ + + // TODO: use one command instead of two + + getCmdManager()->exec( + new SelSurfaceCmd( + getSurfaceManager(), + getSurfaceManager()->getSurface(surface))); + + getCmdManager()->exec( + new SelVertexCmd( + getSurfaceManager(), + vertex)); + } +} + +void Application::selectNextTexCoord(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new SelNextTexCoordCmd( + &Gui::instance()->getTextureEditorWidget())); + } +} + +void Application::selectPrevTexCoord(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new SelPrevTexCoordCmd( + &Gui::instance()->getTextureEditorWidget())); + } +} + +void Application::moveSelection(Vec3 by){ + if(_state == ProjectionMappingMode::instance()){ + getCmdManager()->exec(new MvSelectionCmd(getSurfaceManager(), by)); + }else if(_state == TextureMappingMode::instance()){ + Vec2 tcBy(by.x, by.y); + int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); + if(selectedTexCoord >= 0){ + moveTexCoord(selectedTexCoord, tcBy); + } + } +} + +void Application::setPresentationMode(){ + _cmdManager.exec( + new ofx::piMapper::SetApplicationModeCmd( + this, PresentationMode::instance())); +} + +void Application::setTextureMode(){ + _cmdManager.exec( + new ofx::piMapper::SetApplicationModeCmd( + this, TextureMappingMode::instance())); +} + +void Application::setProjectionMode(){ + _cmdManager.exec( + new ofx::piMapper::SetApplicationModeCmd( + this, ProjectionMappingMode::instance())); +} + +void Application::setSourceMode(){ + _cmdManager.exec( + new ofx::piMapper::SetApplicationModeCmd( + this, SourceSelectionMode::instance())); +} + +void Application::moveLayerUp(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface() == + getSurfaceManager()->getActivePreset()->at( + getSurfaceManager()->getActivePreset()->size() - 1)){ + return; + } + + getCmdManager()->exec( + new MvLayerUpCmd( + getSurfaceManager()->getActivePreset(), + getSurfaceManager()->getSelectedSurface())); + } +} + +void Application::moveLayerDown(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface() == + getSurfaceManager()->getActivePreset()->at(0)){ + return; + } + + getCmdManager()->exec( + new MvLayerDnCmd( + getSurfaceManager()->getActivePreset(), + getSurfaceManager()->getSelectedSurface())); + } +} + +void Application::scaleUp(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new ScaleSurfaceFromToCmd( + getSurfaceManager()->getSelectedSurface(), + getSurfaceManager()->getSelectedSurface()->getScale(), + getSurfaceManager()->getSelectedSurface()->getScale() + 0.2f)); + } +} + +void Application::scaleDown(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface()->getScale() <= 0.21f){ + return; + } + getCmdManager()->exec( + new ScaleSurfaceFromToCmd( + getSurfaceManager()->getSelectedSurface(), + getSurfaceManager()->getSelectedSurface()->getScale(), + getSurfaceManager()->getSelectedSurface()->getScale() - 0.2f)); + } +} + +void Application::duplicateSurface(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new DuplicateSurfaceCmd( + getSurfaceManager()->getSelectedSurface(), + getSurfaceManager())); + } +} + +void Application::setFullscreenSurface(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new FullscreenSurfaceCmd(getSurfaceManager()->getSelectedSurface())); + } +} + +void Application::setNextSource(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new SetNextSourceCmd( + getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getSourcesEditorWidget())); + }else{ + getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); + } +} + +void Application::setFboSource(std::string sourceId){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec( + new SetSourceCmd( + SourceType::SOURCE_TYPE_FBO, + sourceId, + getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getSourcesEditorWidget())); + }else{ + getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); + } +} + +void Application::setVideoSource(std::string fileName, bool loop){ + vector loadedVideos = getMediaServer()->getVideoNames(); + for(auto i = 0; i < loadedVideos.size(); i++){ + if(ofIsStringInString(loadedVideos[i], fileName)){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + BaseSource * source = getSurfaceManager()->getSelectedSurface()->getSource(); + + if(source->getType() == SOURCE_TYPE_VIDEO){ + VideoSource * video = dynamic_cast(source); + video->stop(); + } + + getCmdManager()->exec( + new SetVideoSourceCmd( + getMediaServer()->getVideoPaths()[i], + loop, + getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getSourcesEditorWidget())); + }else{ + getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); + } + break; + } + } +} + +void Application::setImageSource(std::string fileName){ + vector loadedImages = getMediaServer()->getImageNames(); + for(auto i = 0; i < loadedImages.size(); i++){ + if(ofIsStringInString(loadedImages[i], fileName)){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + BaseSource * source = getSurfaceManager()->getSelectedSurface()->getSource(); + + if(source->getType() == SOURCE_TYPE_VIDEO){ + VideoSource * video = dynamic_cast(source); + video->stop(); + } + + getCmdManager()->exec( + new SetSourceCmd( + SourceType::SOURCE_TYPE_IMAGE, + getMediaServer()->getImagePaths()[i], + getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getSourcesEditorWidget())); + }else{ + getCmdManager()->exec(new SelNextSurfaceCmd(getSurfaceManager())); + } + break; + } + } +} + +void Application::setDrawGui(bool drawGui){ + _drawGui = drawGui; + if(!_drawGui){ + ofHideCursor(); + } +} + +void Application::addGridRow(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface()->getType() == + SurfaceType::GRID_WARP_SURFACE){ + // TODO: The command should not require projection editor pointer + getCmdManager()->exec( + new AddGridRowCmd( + (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); + } + } +} + +void Application::addGridColumn(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface()->getType() == + SurfaceType::GRID_WARP_SURFACE){ + // TODO: The command should not require projection editor pointer + getCmdManager()->exec( + new AddGridColCmd( + (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); + } + } +} + +void Application::removeGridRow(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface()->getType() == + SurfaceType::GRID_WARP_SURFACE){ + if(((GridWarpSurface *)getSurfaceManager()->getSelectedSurface())->getGridRows() > 1){ + // TODO: The command should not require projection editor pointer + getCmdManager()->exec( + new RmGridRowCmd( + (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); + } + } + } +} + +void Application::removeGridColumn(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + if(getSurfaceManager()->getSelectedSurface()->getType() == + SurfaceType::GRID_WARP_SURFACE){ + if(((GridWarpSurface *)getSurfaceManager()->getSelectedSurface())->getGridCols() > 1){ + // TODO: The command should not require projection editor pointer + getCmdManager()->exec( + new RmGridColCmd( + (GridWarpSurface *)getSurfaceManager()->getSelectedSurface() )); + } + } + } +} + +void Application::togglePause(){ + if(getSurfaceManager()->getSelectedSurface() == 0){ + return; + } + + if(getSurfaceManager()->getSelectedSurface()->getSource()->getType() == + SourceType::SOURCE_TYPE_VIDEO){ + getCmdManager()->exec( + new ToggleAnimatedSourceCmd( + getSurfaceManager()->getSelectedSurface())); + } +} + +void Application::moveTexCoord(int texCoordIndex, Vec2 by){ + if(texCoordIndex >= 0){ + getCmdManager()->exec(new MvTexCoordCmd(texCoordIndex, by)); + }else{ + getCmdManager()->exec(new MvAllTexCoordsCmd( + getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getTextureEditorWidget())); + + Gui::instance()->getTextureEditorWidget().moveSelection(by); + } +} + +void Application::undo(){ + _cmdManager.undo(); +} + +void Application::deselect(){ + if(getSurfaceManager()->getSelectedSurface() != 0){ + getCmdManager()->exec(new DeselectSurfaceCmd(getSurfaceManager())); + } +} + +void Application::toggleLayerPanel(){ + if(getState() == ProjectionMappingMode::instance()){ + ProjectionMappingMode::instance()->toggleLayerPanel(); + } +} + +void Application::restart(){ + _mediaServer.restart(); +} + +void Application::pause(){ + _mediaServer.pause(); +} + +void Application::resume(){ + _mediaServer.resume(); +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Application.h b/src/Application/Application.h index ff5e449..437d959 100644 --- a/src/Application/Application.h +++ b/src/Application/Application.h @@ -1,188 +1,188 @@ -#pragma once - -#include - -// OpenFrameworks components -#include "ofEvents.h" -#include "ofLog.h" - -// OfxPiMapper Components -#include "FboSource.h" -#include "Info.h" -#include "SurfaceStack.h" -#include "Gui.h" -#include "Vec2.h" - -// Commands -#include "SetApplicationModeCmd.h" -#include "ClearSurfacesCmd.h" -#include "SetPresetCmd.h" -#include "AddSurfaceCmd.h" -#include "RmSurfaceCmd.h" -#include "MvLayerUpCmd.h" -#include "MvLayerDnCmd.h" -#include "DuplicateSurfaceCmd.h" -#include "FullscreenSurfaceCmd.h" -#include "TogglePerspectiveCmd.h" -#include "SetNextSourceCmd.h" -#include "ScaleSurfaceFromToCmd.h" -#include "AddGridRowCmd.h" -#include "RmGridRowCmd.h" -#include "AddGridColCmd.h" -#include "RmGridColCmd.h" -#include "SelNextSurfaceCmd.h" -#include "SelPrevSurfaceCmd.h" -#include "SelNextVertexCmd.h" -#include "SelPrevVertexCmd.h" -#include "SelVertexCmd.h" -#include "SelSurfaceCmd.h" -#include "MvSelectionCmd.h" -#include "ToggleAnimatedSourceCmd.h" -#include "SelNextTexCoordCmd.h" -#include "SelPrevTexCoordCmd.h" -#include "DeselectSurfaceCmd.h" -#include "SetVideoSourceCmd.h" - -// Modes -#include "ApplicationBaseMode.h" -#include "PresentationMode.h" -#include "ProjectionMappingMode.h" -#include "TextureMappingMode.h" -#include "SourceSelectionMode.h" - -// TODO: Move all command executors to here (Application class) -// This would allow one not to repeat. Commands would be called in -// one place and includes of commands would not be duplicated. - -#define PIMAPPER_SETTINGS_FILE "ofxpimapper.xml" - -namespace ofx { -namespace piMapper { - -class ApplicationBaseMode; - -class Application { - - public: - Application(); - - ApplicationBaseMode * getState(); - - void setup(); - void update(); - void draw(); - - void onKeyPressed(ofKeyEventArgs & args); - void onKeyReleased(ofKeyEventArgs & args); - - // We use this to pass mouse events into the GUI layer - void onMousePressed(ofMouseEventArgs & args); - void onMouseReleased(ofMouseEventArgs & args); - void onMouseDragged(ofMouseEventArgs & args); - - // Then we catch GUI events with this one and create commands - void onJointPressed(GuiJointEvent & e); - void onSurfacePressed(GuiSurfaceEvent & e); - void onBackgroundPressed(GuiBackgroundEvent & e); - - void onGuiEvent(GuiEvent & e); - - void addFboSource(FboSource & fboSource); - void addFboSource(FboSource * fboSource); - void createSurface(SurfaceType type); - void eraseSurface(int i); - void setInfoText(std::string text); - void toggleInfo(); - void togglePerspective(); - void saveProject(); - bool loadXmlSettings(std::string fileName); - - bool isShiftKeyDown(); - bool toggleShift(); - - SurfaceManager * getSurfaceManager(){ return &_surfaceManager; } - CmdManager * getCmdManager(){ return &_cmdManager; } - MediaServer * getMediaServer(){ return &_mediaServer; } - - // Command executors - void selectSurface(int i); - void selectNextSurface(); - void selectPrevSurface(); - void selectNextVertex(); - void selectPrevVertex(); - void selectVertex(int surface, int vertex); - void selectNextTexCoord(); - void selectPrevTexCoord(); - - /* - Context sensitive move. - Moves vertex when in projection mapping mode. - Moves texture coordinate when in texture mapping mode. - */ - void moveSelection(Vec3 by); - - void setPresentationMode(); - void setTextureMode(); - void setProjectionMode(); - void setSourceMode(); - void moveLayerUp(); - void moveLayerDown(); - void scaleUp(); - void scaleDown(); - void duplicateSurface(); - void setFullscreenSurface(); - void setNextSource(); - void setFboSource(std::string sourceId); - void setVideoSource(std::string fileName, bool loop); - void setImageSource(std::string fileName); - void setDrawGui(bool drawGui); - void addGridRow(); - void addGridColumn(); - void removeGridRow(); - void removeGridColumn(); - void togglePause(); - void moveTexCoord(int texCoordIndex, Vec2 by); - // TODO: Add moveVertex. - // Make it so that other parts of the application react to the change. - void undo(); - void deselect(); - void toggleLayerPanel(); - - void setPreset(unsigned int i); - void setNextPreset(); - - // System commands - void reboot(); - void shutdown(); - - // video play control - void restart(); - void pause(); - void resume(); - - protected: - void setState(ApplicationBaseMode * st); - - private: - friend class ApplicationBaseMode; - friend class SetApplicationModeCmd; - - ApplicationBaseMode * _state; - - CmdManager _cmdManager; - MediaServer _mediaServer; - SurfaceManager _surfaceManager; - Info _info; - - bool _shiftKeyDown; - bool _drawGui; - - float _lastSaveTime; - float _autoSaveInterval; - - std::string _keySequence; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include + +// OpenFrameworks components +#include "ofEvents.h" +#include "ofLog.h" + +// OfxPiMapper Components +#include "FboSource.h" +#include "Info.h" +#include "SurfaceStack.h" +#include "Gui.h" +#include "Vec2.h" + +// Commands +#include "SetApplicationModeCmd.h" +#include "ClearSurfacesCmd.h" +#include "SetPresetCmd.h" +#include "AddSurfaceCmd.h" +#include "RmSurfaceCmd.h" +#include "MvLayerUpCmd.h" +#include "MvLayerDnCmd.h" +#include "DuplicateSurfaceCmd.h" +#include "FullscreenSurfaceCmd.h" +#include "TogglePerspectiveCmd.h" +#include "SetNextSourceCmd.h" +#include "ScaleSurfaceFromToCmd.h" +#include "AddGridRowCmd.h" +#include "RmGridRowCmd.h" +#include "AddGridColCmd.h" +#include "RmGridColCmd.h" +#include "SelNextSurfaceCmd.h" +#include "SelPrevSurfaceCmd.h" +#include "SelNextVertexCmd.h" +#include "SelPrevVertexCmd.h" +#include "SelVertexCmd.h" +#include "SelSurfaceCmd.h" +#include "MvSelectionCmd.h" +#include "ToggleAnimatedSourceCmd.h" +#include "SelNextTexCoordCmd.h" +#include "SelPrevTexCoordCmd.h" +#include "DeselectSurfaceCmd.h" +#include "SetVideoSourceCmd.h" + +// Modes +#include "ApplicationBaseMode.h" +#include "PresentationMode.h" +#include "ProjectionMappingMode.h" +#include "TextureMappingMode.h" +#include "SourceSelectionMode.h" + +// TODO: Move all command executors to here (Application class) +// This would allow one not to repeat. Commands would be called in +// one place and includes of commands would not be duplicated. + +#define PIMAPPER_SETTINGS_FILE "ofxpimapper.xml" + +namespace ofx { +namespace piMapper { + +class ApplicationBaseMode; + +class Application { + + public: + Application(); + + ApplicationBaseMode * getState(); + + void setup(); + void update(); + void draw(); + + void onKeyPressed(ofKeyEventArgs & args); + void onKeyReleased(ofKeyEventArgs & args); + + // We use this to pass mouse events into the GUI layer + void onMousePressed(ofMouseEventArgs & args); + void onMouseReleased(ofMouseEventArgs & args); + void onMouseDragged(ofMouseEventArgs & args); + + // Then we catch GUI events with this one and create commands + void onJointPressed(GuiJointEvent & e); + void onSurfacePressed(GuiSurfaceEvent & e); + void onBackgroundPressed(GuiBackgroundEvent & e); + + void onGuiEvent(GuiEvent & e); + + void addFboSource(FboSource & fboSource); + void addFboSource(FboSource * fboSource); + void createSurface(SurfaceType type); + void eraseSurface(int i); + void setInfoText(std::string text); + void toggleInfo(); + void togglePerspective(); + void saveProject(); + bool loadXmlSettings(std::string fileName); + + bool isShiftKeyDown(); + bool toggleShift(); + + SurfaceManager * getSurfaceManager(){ return &_surfaceManager; } + CmdManager * getCmdManager(){ return &_cmdManager; } + MediaServer * getMediaServer(){ return &_mediaServer; } + + // Command executors + void selectSurface(int i); + void selectNextSurface(); + void selectPrevSurface(); + void selectNextVertex(); + void selectPrevVertex(); + void selectVertex(int surface, int vertex); + void selectNextTexCoord(); + void selectPrevTexCoord(); + + /* + Context sensitive move. + Moves vertex when in projection mapping mode. + Moves texture coordinate when in texture mapping mode. + */ + void moveSelection(Vec3 by); + + void setPresentationMode(); + void setTextureMode(); + void setProjectionMode(); + void setSourceMode(); + void moveLayerUp(); + void moveLayerDown(); + void scaleUp(); + void scaleDown(); + void duplicateSurface(); + void setFullscreenSurface(); + void setNextSource(); + void setFboSource(std::string sourceId); + void setVideoSource(std::string fileName, bool loop); + void setImageSource(std::string fileName); + void setDrawGui(bool drawGui); + void addGridRow(); + void addGridColumn(); + void removeGridRow(); + void removeGridColumn(); + void togglePause(); + void moveTexCoord(int texCoordIndex, Vec2 by); + // TODO: Add moveVertex. + // Make it so that other parts of the application react to the change. + void undo(); + void deselect(); + void toggleLayerPanel(); + + void setPreset(unsigned int i); + void setNextPreset(); + + // System commands + void reboot(); + void shutdown(); + + // video play control + void restart(); + void pause(); + void resume(); + + protected: + void setState(ApplicationBaseMode * st); + + private: + friend class ApplicationBaseMode; + friend class SetApplicationModeCmd; + + ApplicationBaseMode * _state; + + CmdManager _cmdManager; + MediaServer _mediaServer; + SurfaceManager _surfaceManager; + Info _info; + + bool _shiftKeyDown; + bool _drawGui; + + float _lastSaveTime; + float _autoSaveInterval; + + std::string _keySequence; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/ApplicationBaseMode.cpp b/src/Application/Modes/ApplicationBaseMode.cpp index d0941b8..3f6ad8b 100644 --- a/src/Application/Modes/ApplicationBaseMode.cpp +++ b/src/Application/Modes/ApplicationBaseMode.cpp @@ -1,12 +1,12 @@ -#include "ApplicationBaseMode.h" -#include "PresentationMode.h" - -namespace ofx { -namespace piMapper { - -void ApplicationBaseMode::setState(Application * app, ApplicationBaseMode * st){ - app->setState(st); -} - -} // namespace piMapper -} // namespace ofx +#include "ApplicationBaseMode.h" +#include "PresentationMode.h" + +namespace ofx { +namespace piMapper { + +void ApplicationBaseMode::setState(Application * app, ApplicationBaseMode * st){ + app->setState(st); +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/ApplicationBaseMode.h b/src/Application/Modes/ApplicationBaseMode.h index c454e52..5b62adc 100644 --- a/src/Application/Modes/ApplicationBaseMode.h +++ b/src/Application/Modes/ApplicationBaseMode.h @@ -1,38 +1,38 @@ -#pragma once - -#include "ofEvents.h" -#include "ofLog.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class Application; - -class ApplicationBaseMode { - - public: - virtual void setup(Application * app){} - virtual void update(Application * app){} - virtual void draw(Application * app){} - virtual void setState(Application * app, ApplicationBaseMode * st); - - // Event handler virtual methods - virtual void onKeyPressed(Application * app, ofKeyEventArgs & args){} - virtual void onMousePressed(Application * app, ofMouseEventArgs & args){} - virtual void onMouseReleased(Application * app, ofMouseEventArgs & args){} - virtual void onMouseDragged(Application * app, ofMouseEventArgs & args){} - virtual void onJointPressed(Application * app, GuiJointEvent & e){} - virtual void onSurfacePressed(Application * app, GuiSurfaceEvent & e){} - virtual void onBackgroundPressed(Application * app, GuiBackgroundEvent & e){} - - virtual void onGuiEvent(Application * app, GuiEvent & e) = 0; - - // These are only used by TextureMappingMode for now. - virtual ofPoint getTranslation(){ return ofPoint(0, 0); } - virtual void setTranslation(ofPoint p){} - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofEvents.h" +#include "ofLog.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class Application; + +class ApplicationBaseMode { + + public: + virtual void setup(Application * app){} + virtual void update(Application * app){} + virtual void draw(Application * app){} + virtual void setState(Application * app, ApplicationBaseMode * st); + + // Event handler virtual methods + virtual void onKeyPressed(Application * app, ofKeyEventArgs & args){} + virtual void onMousePressed(Application * app, ofMouseEventArgs & args){} + virtual void onMouseReleased(Application * app, ofMouseEventArgs & args){} + virtual void onMouseDragged(Application * app, ofMouseEventArgs & args){} + virtual void onJointPressed(Application * app, GuiJointEvent & e){} + virtual void onSurfacePressed(Application * app, GuiSurfaceEvent & e){} + virtual void onBackgroundPressed(Application * app, GuiBackgroundEvent & e){} + + virtual void onGuiEvent(Application * app, GuiEvent & e) = 0; + + // These are only used by TextureMappingMode for now. + virtual ofPoint getTranslation(){ return ofPoint(0, 0); } + virtual void setTranslation(ofPoint p){} + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/PresentationMode.cpp b/src/Application/Modes/PresentationMode.cpp index f7c426f..20c3500 100644 --- a/src/Application/Modes/PresentationMode.cpp +++ b/src/Application/Modes/PresentationMode.cpp @@ -1,29 +1,29 @@ -#include "PresentationMode.h" - -namespace ofx { -namespace piMapper { - -PresentationMode * PresentationMode::_instance = 0; - -PresentationMode * PresentationMode::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::PresentationMode(); - } - return _instance; -} - -void PresentationMode::draw(Application * app){ - ofPushStyle(); - ofSetColor(255, 255, 255, 255); - app->getSurfaceManager()->draw(); - ofPopStyle(); -} - -void PresentationMode::onMousePressed(Application * app, ofMouseEventArgs & args){ - app->getCmdManager()->exec( - new ofx::piMapper::SetApplicationModeCmd( - app, ProjectionMappingMode::instance())); -} - -} // namespace piMapper +#include "PresentationMode.h" + +namespace ofx { +namespace piMapper { + +PresentationMode * PresentationMode::_instance = 0; + +PresentationMode * PresentationMode::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::PresentationMode(); + } + return _instance; +} + +void PresentationMode::draw(Application * app){ + ofPushStyle(); + ofSetColor(255, 255, 255, 255); + app->getSurfaceManager()->draw(); + ofPopStyle(); +} + +void PresentationMode::onMousePressed(Application * app, ofMouseEventArgs & args){ + app->getCmdManager()->exec( + new ofx::piMapper::SetApplicationModeCmd( + app, ProjectionMappingMode::instance())); +} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Application/Modes/PresentationMode.h b/src/Application/Modes/PresentationMode.h index ffb5de7..9e5f55c 100644 --- a/src/Application/Modes/PresentationMode.h +++ b/src/Application/Modes/PresentationMode.h @@ -1,29 +1,29 @@ -#pragma once - -#include "Application.h" -#include "ofEvents.h" -#include "ofLog.h" -#include "ofGraphics.h" -#include "SetApplicationModeCmd.h" -#include "ProjectionMappingMode.h" -#include "GuiMode.h" - -namespace ofx { -namespace piMapper { - -class PresentationMode : public ApplicationBaseMode { - - public: - static PresentationMode * instance(); - void draw(Application * app); - void onMousePressed(Application * app, ofMouseEventArgs & args); - - void onGuiEvent(Application * app, GuiEvent & e){} - - private: - static PresentationMode * _instance; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "Application.h" +#include "ofEvents.h" +#include "ofLog.h" +#include "ofGraphics.h" +#include "SetApplicationModeCmd.h" +#include "ProjectionMappingMode.h" +#include "GuiMode.h" + +namespace ofx { +namespace piMapper { + +class PresentationMode : public ApplicationBaseMode { + + public: + static PresentationMode * instance(); + void draw(Application * app); + void onMousePressed(Application * app, ofMouseEventArgs & args); + + void onGuiEvent(Application * app, GuiEvent & e){} + + private: + static PresentationMode * _instance; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/ProjectionMappingMode.cpp b/src/Application/Modes/ProjectionMappingMode.cpp index 8293471..14fe667 100644 --- a/src/Application/Modes/ProjectionMappingMode.cpp +++ b/src/Application/Modes/ProjectionMappingMode.cpp @@ -1,309 +1,309 @@ -#include "ProjectionMappingMode.h" - -namespace ofx { -namespace piMapper { - -ProjectionMappingMode::ProjectionMappingMode(){ - _surfaceScaleBeforeTransform = 1.0f; - _bDrawLayerPanel = true; -} - -ProjectionMappingMode * ProjectionMappingMode::_instance = 0; - -ProjectionMappingMode * ProjectionMappingMode::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::ProjectionMappingMode(); - } - return _instance; -} - -void ProjectionMappingMode::setup(Application *app){ - Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); - Gui::instance()->getLayerPanelWidget().setSurfaceManager(app->getSurfaceManager()); - Gui::instance()->getProjectionEditorWidget().setSurfaceManager(app->getSurfaceManager()); -} - -void ProjectionMappingMode::update(Application * app){ - Gui::instance()->getProjectionEditorWidget().update(); - Gui::instance()->getScaleWidget().update(); -} - -void ProjectionMappingMode::draw(Application * app){ - ofPushStyle(); - ofSetColor(255, 255, 255, 255); - app->getSurfaceManager()->draw(); - ofPopStyle(); - - Gui::instance()->getProjectionEditorWidget().draw(); - - // Draw scale widget. The size of the widget is being set on surface select. - BaseSurface * selectedSurface = app->getSurfaceManager()->getSelectedSurface(); - if(selectedSurface != 0){ - Gui::instance()->getScaleWidget().draw(); - } - - if(_bDrawLayerPanel){ - Gui::instance()->getLayerPanelWidget().draw(); - } - - Gui::instance()->getSurfaceHighlightWidget().draw(); -} - -void ProjectionMappingMode::toggleLayerPanel(){ - _bDrawLayerPanel = !_bDrawLayerPanel; -} - -void ProjectionMappingMode::onKeyPressed(Application * app, ofKeyEventArgs & args){ - switch(args.key){ - - case 't': - app->createSurface(SurfaceType::TRIANGLE_SURFACE); - break; - - case 'q': - app->createSurface(SurfaceType::QUAD_SURFACE); - break; - - case 'g': - app->createSurface(SurfaceType::GRID_WARP_SURFACE); - break; - - case 'h': - app->createSurface(SurfaceType::HEXAGON_SURFACE); - break; - - case 'c': - app->createSurface(SurfaceType::CIRCLE_SURFACE); - break; - - case OF_KEY_BACKSPACE: - app->eraseSurface(app->getSurfaceManager()->getSelectedSurfaceIndex()); - break; - - case 'p': - app->togglePerspective(); - break; - - case '}': - app->addGridRow(); - break; - - case '{': - app->removeGridRow(); - break; - - case ']': - app->addGridColumn(); - break; - - case '[': - app->removeGridColumn(); - break; - - case '.': - app->selectNextSurface(); - break; - - case ',': - app->selectPrevSurface(); - break; - - case '>': - app->selectNextVertex(); - break; - - case '<': - app->selectPrevVertex(); - break; - - case OF_KEY_UP: - if(app->isShiftKeyDown()){ - app->moveSelection(Vec3(0.0f, -10.0f, 0.0f)); - }else{ - app->moveSelection(Vec3(0.0f, -1.0f, 0.0f)); - } - break; - - case OF_KEY_DOWN: - if(app->isShiftKeyDown()){ - app->moveSelection(Vec3(0.0f, 10.0f, 0.0f)); - }else{ - app->moveSelection(Vec3(0.0f, 1.0f, 0.0f)); - } - break; - - case OF_KEY_LEFT: - if(app->isShiftKeyDown()){ - app->moveSelection(Vec3(-10.0f, 0.0f, 0.0f)); - }else{ - app->moveSelection(Vec3(-1.0f, 0.0f, 0.0f)); - } - break; - - case OF_KEY_RIGHT: - if(app->isShiftKeyDown()){ - app->moveSelection(Vec3(10.0f, 0.0f, 0.0f)); - }else{ - app->moveSelection(Vec3(1.0f, 0.0f, 0.0f)); - } - break; - - case ' ': - app->togglePause(); - break; - - case OF_KEY_TAB: - app->setNextSource(); - break; - - case 'd': - app->duplicateSurface(); - break; - - case '0': // Move selected surface up the layer stack - app->moveLayerUp(); - break; - - case '9': // Move selected surface down the layer stack - app->moveLayerDown(); - break; - - case '+': // Scale surface up - app->scaleUp(); - break; - - case '-': // Scale surface down - app->scaleDown(); - break; - - case 'l': - toggleLayerPanel(); - break; - - /* - case 'n': // Set next preset - app->getSurfaceManager()->setNextPreset(); - break; - */ - - default: - break; - } -} - -void ProjectionMappingMode::onMousePressed(Application * app, ofMouseEventArgs & args){ - Gui::instance()->onMousePressed(args); - - CircleJoint * hitJoint = 0; - int hitJointIndex = -1; - BaseSurface * hitSurface = 0; - - hitJoint = Gui::instance()->getProjectionEditorWidget().hitTestJoints(Vec2(args.x, args.y)); - - if(hitJoint){ - for(int i = Gui::instance()->getProjectionEditorWidget().getJoints()->size() - 1; i >= 0 ; --i){ - if((*Gui::instance()->getProjectionEditorWidget().getJoints())[i] == hitJoint){ - hitJointIndex = i; - break; - } - } - }else{ - for(int i = app->getSurfaceManager()->size() - 1; i >= 0; --i){ - if(app->getSurfaceManager()->getSurface(i)->hitTest(Vec2(args.x, args.y))){ - hitSurface = app->getSurfaceManager()->getSurface(i); - break; - } - } - } - - if(Gui::instance()->getScaleWidget().inside(args.x, args.y)){ - // - }else if(hitJoint){ - hitJoint->select(); - hitJoint->startDrag(); - Gui::instance()->notifyJointPressed(args, hitJointIndex); - }else if(hitSurface){ - _clickPosition = Vec2(args.x, args.y); // TODO: redesign this so we can use a kind of - // display stack. - _bSurfaceDrag = true; // TODO: Should be something like `hitSurface->startDrag()` - Gui::instance()->notifySurfacePressed(args, hitSurface); - }else{ - Gui::instance()->notifyBackgroundPressed(args); - } -} - -void ProjectionMappingMode::onMouseReleased(Application * app, ofMouseEventArgs & args){ - Gui::instance()->onMouseReleased(args); - _bSurfaceDrag = false; // TODO: handle this locally - Gui::instance()->getProjectionEditorWidget().stopDragJoints(); -} - -void ProjectionMappingMode::onMouseDragged(Application * app, ofMouseEventArgs & args){ - Gui::instance()->onMouseDragged(args); - Gui::instance()->getProjectionEditorWidget().mouseDragged(args); - - // TODO: Handle app->getGui()->clickPosition and app->getGui()->bDrag locally. - if(_bSurfaceDrag){ - Vec2 mousePosition = Vec2(args.x, args.y); - Vec2 distance = mousePosition - _clickPosition; - Gui::instance()->getProjectionEditorWidget().moveSelectedSurface(Vec3( - distance.x, - distance.y, - 0.0f)); - _clickPosition = mousePosition; - } -} - -void ProjectionMappingMode::onJointPressed(Application * app, GuiJointEvent & e){ - app->getCmdManager()->exec(new SelVertexCmd(app->getSurfaceManager(), e.jointIndex)); - app->getCmdManager()->exec(new MvSurfaceVertCmd( - e.jointIndex, - app->getSurfaceManager()->getSelectedSurface())); -} - -void ProjectionMappingMode::onSurfacePressed(Application * app, GuiSurfaceEvent & e){ - if(app->getSurfaceManager()->getSelectedSurface() != e.surface){ - app->getCmdManager()->exec(new SelSurfaceCmd(app->getSurfaceManager(), e.surface )); - } - - app->getCmdManager()->exec(new StartDragSurfaceCmd(e.surface)); -} - -void ProjectionMappingMode::onBackgroundPressed(Application * app, GuiBackgroundEvent & e){ - if(app->getSurfaceManager()->getSelectedSurface() != 0){ - app->getCmdManager()->exec(new DeselectSurfaceCmd(app->getSurfaceManager())); - } -} - -void ProjectionMappingMode::onGuiEvent(Application * app, GuiEvent & e){ - - // Scale widget now. More widgets later. - if(e.widget == &Gui::instance()->getScaleWidget()){ - if(e.args.type == e.args.Pressed){ - if(app->getSurfaceManager()->getSelectedSurface() == 0){ - return; - } - - _surfaceScaleBeforeTransform = - app->getSurfaceManager()->getSelectedSurface()->getScale(); - }else if(e.args.type == e.args.Released){ - if(app->getSurfaceManager()->getSelectedSurface() == 0){ - return; - } - - if(_surfaceScaleBeforeTransform != - app->getSurfaceManager()->getSelectedSurface()->getScale()){ - - app->getCmdManager()->exec(new ScaleSurfaceFromToCmd( - app->getSurfaceManager()->getSelectedSurface(), - _surfaceScaleBeforeTransform, - app->getSurfaceManager()->getSelectedSurface()->getScale())); - } - }else if(e.args.type == e.args.Dragged){ - app->getSurfaceManager()->getSelectedSurface()->scaleTo(e.widget->getScale()); - } - } -} - -} // namespace piMapper -} // namespace ofx +#include "ProjectionMappingMode.h" + +namespace ofx { +namespace piMapper { + +ProjectionMappingMode::ProjectionMappingMode(){ + _surfaceScaleBeforeTransform = 1.0f; + _bDrawLayerPanel = true; +} + +ProjectionMappingMode * ProjectionMappingMode::_instance = 0; + +ProjectionMappingMode * ProjectionMappingMode::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::ProjectionMappingMode(); + } + return _instance; +} + +void ProjectionMappingMode::setup(Application *app){ + Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); + Gui::instance()->getLayerPanelWidget().setSurfaceManager(app->getSurfaceManager()); + Gui::instance()->getProjectionEditorWidget().setSurfaceManager(app->getSurfaceManager()); +} + +void ProjectionMappingMode::update(Application * app){ + Gui::instance()->getProjectionEditorWidget().update(); + Gui::instance()->getScaleWidget().update(); +} + +void ProjectionMappingMode::draw(Application * app){ + ofPushStyle(); + ofSetColor(255, 255, 255, 255); + app->getSurfaceManager()->draw(); + ofPopStyle(); + + Gui::instance()->getProjectionEditorWidget().draw(); + + // Draw scale widget. The size of the widget is being set on surface select. + BaseSurface * selectedSurface = app->getSurfaceManager()->getSelectedSurface(); + if(selectedSurface != 0){ + Gui::instance()->getScaleWidget().draw(); + } + + if(_bDrawLayerPanel){ + Gui::instance()->getLayerPanelWidget().draw(); + } + + Gui::instance()->getSurfaceHighlightWidget().draw(); +} + +void ProjectionMappingMode::toggleLayerPanel(){ + _bDrawLayerPanel = !_bDrawLayerPanel; +} + +void ProjectionMappingMode::onKeyPressed(Application * app, ofKeyEventArgs & args){ + switch(args.key){ + + case 't': + app->createSurface(SurfaceType::TRIANGLE_SURFACE); + break; + + case 'q': + app->createSurface(SurfaceType::QUAD_SURFACE); + break; + + case 'g': + app->createSurface(SurfaceType::GRID_WARP_SURFACE); + break; + + case 'h': + app->createSurface(SurfaceType::HEXAGON_SURFACE); + break; + + case 'c': + app->createSurface(SurfaceType::CIRCLE_SURFACE); + break; + + case OF_KEY_BACKSPACE: + app->eraseSurface(app->getSurfaceManager()->getSelectedSurfaceIndex()); + break; + + case 'p': + app->togglePerspective(); + break; + + case '}': + app->addGridRow(); + break; + + case '{': + app->removeGridRow(); + break; + + case ']': + app->addGridColumn(); + break; + + case '[': + app->removeGridColumn(); + break; + + case '.': + app->selectNextSurface(); + break; + + case ',': + app->selectPrevSurface(); + break; + + case '>': + app->selectNextVertex(); + break; + + case '<': + app->selectPrevVertex(); + break; + + case OF_KEY_UP: + if(app->isShiftKeyDown()){ + app->moveSelection(Vec3(0.0f, -10.0f, 0.0f)); + }else{ + app->moveSelection(Vec3(0.0f, -1.0f, 0.0f)); + } + break; + + case OF_KEY_DOWN: + if(app->isShiftKeyDown()){ + app->moveSelection(Vec3(0.0f, 10.0f, 0.0f)); + }else{ + app->moveSelection(Vec3(0.0f, 1.0f, 0.0f)); + } + break; + + case OF_KEY_LEFT: + if(app->isShiftKeyDown()){ + app->moveSelection(Vec3(-10.0f, 0.0f, 0.0f)); + }else{ + app->moveSelection(Vec3(-1.0f, 0.0f, 0.0f)); + } + break; + + case OF_KEY_RIGHT: + if(app->isShiftKeyDown()){ + app->moveSelection(Vec3(10.0f, 0.0f, 0.0f)); + }else{ + app->moveSelection(Vec3(1.0f, 0.0f, 0.0f)); + } + break; + + case ' ': + app->togglePause(); + break; + + case OF_KEY_TAB: + app->setNextSource(); + break; + + case 'd': + app->duplicateSurface(); + break; + + case '0': // Move selected surface up the layer stack + app->moveLayerUp(); + break; + + case '9': // Move selected surface down the layer stack + app->moveLayerDown(); + break; + + case '+': // Scale surface up + app->scaleUp(); + break; + + case '-': // Scale surface down + app->scaleDown(); + break; + + case 'l': + toggleLayerPanel(); + break; + + /* + case 'n': // Set next preset + app->getSurfaceManager()->setNextPreset(); + break; + */ + + default: + break; + } +} + +void ProjectionMappingMode::onMousePressed(Application * app, ofMouseEventArgs & args){ + Gui::instance()->onMousePressed(args); + + CircleJoint * hitJoint = 0; + int hitJointIndex = -1; + BaseSurface * hitSurface = 0; + + hitJoint = Gui::instance()->getProjectionEditorWidget().hitTestJoints(Vec2(args.x, args.y)); + + if(hitJoint){ + for(int i = Gui::instance()->getProjectionEditorWidget().getJoints()->size() - 1; i >= 0 ; --i){ + if((*Gui::instance()->getProjectionEditorWidget().getJoints())[i] == hitJoint){ + hitJointIndex = i; + break; + } + } + }else{ + for(int i = app->getSurfaceManager()->size() - 1; i >= 0; --i){ + if(app->getSurfaceManager()->getSurface(i)->hitTest(Vec2(args.x, args.y))){ + hitSurface = app->getSurfaceManager()->getSurface(i); + break; + } + } + } + + if(Gui::instance()->getScaleWidget().inside(args.x, args.y)){ + // + }else if(hitJoint){ + hitJoint->select(); + hitJoint->startDrag(); + Gui::instance()->notifyJointPressed(args, hitJointIndex); + }else if(hitSurface){ + _clickPosition = Vec2(args.x, args.y); // TODO: redesign this so we can use a kind of + // display stack. + _bSurfaceDrag = true; // TODO: Should be something like `hitSurface->startDrag()` + Gui::instance()->notifySurfacePressed(args, hitSurface); + }else{ + Gui::instance()->notifyBackgroundPressed(args); + } +} + +void ProjectionMappingMode::onMouseReleased(Application * app, ofMouseEventArgs & args){ + Gui::instance()->onMouseReleased(args); + _bSurfaceDrag = false; // TODO: handle this locally + Gui::instance()->getProjectionEditorWidget().stopDragJoints(); +} + +void ProjectionMappingMode::onMouseDragged(Application * app, ofMouseEventArgs & args){ + Gui::instance()->onMouseDragged(args); + Gui::instance()->getProjectionEditorWidget().mouseDragged(args); + + // TODO: Handle app->getGui()->clickPosition and app->getGui()->bDrag locally. + if(_bSurfaceDrag){ + Vec2 mousePosition = Vec2(args.x, args.y); + Vec2 distance = mousePosition - _clickPosition; + Gui::instance()->getProjectionEditorWidget().moveSelectedSurface(Vec3( + distance.x, + distance.y, + 0.0f)); + _clickPosition = mousePosition; + } +} + +void ProjectionMappingMode::onJointPressed(Application * app, GuiJointEvent & e){ + app->getCmdManager()->exec(new SelVertexCmd(app->getSurfaceManager(), e.jointIndex)); + app->getCmdManager()->exec(new MvSurfaceVertCmd( + e.jointIndex, + app->getSurfaceManager()->getSelectedSurface())); +} + +void ProjectionMappingMode::onSurfacePressed(Application * app, GuiSurfaceEvent & e){ + if(app->getSurfaceManager()->getSelectedSurface() != e.surface){ + app->getCmdManager()->exec(new SelSurfaceCmd(app->getSurfaceManager(), e.surface )); + } + + app->getCmdManager()->exec(new StartDragSurfaceCmd(e.surface)); +} + +void ProjectionMappingMode::onBackgroundPressed(Application * app, GuiBackgroundEvent & e){ + if(app->getSurfaceManager()->getSelectedSurface() != 0){ + app->getCmdManager()->exec(new DeselectSurfaceCmd(app->getSurfaceManager())); + } +} + +void ProjectionMappingMode::onGuiEvent(Application * app, GuiEvent & e){ + + // Scale widget now. More widgets later. + if(e.widget == &Gui::instance()->getScaleWidget()){ + if(e.args.type == e.args.Pressed){ + if(app->getSurfaceManager()->getSelectedSurface() == 0){ + return; + } + + _surfaceScaleBeforeTransform = + app->getSurfaceManager()->getSelectedSurface()->getScale(); + }else if(e.args.type == e.args.Released){ + if(app->getSurfaceManager()->getSelectedSurface() == 0){ + return; + } + + if(_surfaceScaleBeforeTransform != + app->getSurfaceManager()->getSelectedSurface()->getScale()){ + + app->getCmdManager()->exec(new ScaleSurfaceFromToCmd( + app->getSurfaceManager()->getSelectedSurface(), + _surfaceScaleBeforeTransform, + app->getSurfaceManager()->getSelectedSurface()->getScale())); + } + }else if(e.args.type == e.args.Dragged){ + app->getSurfaceManager()->getSelectedSurface()->scaleTo(e.widget->getScale()); + } + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/ProjectionMappingMode.h b/src/Application/Modes/ProjectionMappingMode.h index eca83a1..4bb0172 100644 --- a/src/Application/Modes/ProjectionMappingMode.h +++ b/src/Application/Modes/ProjectionMappingMode.h @@ -1,54 +1,54 @@ -#pragma once - -#include "Application.h" -#include "ofLog.h" -#include "ofGraphics.h" -#include "StartDragSurfaceCmd.h" -#include "DeselectSurfaceCmd.h" -#include "MvSurfaceVertCmd.h" -#include "SurfaceType.h" -#include "Gui.h" -#include "ScaleWidget.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class ProjectionMappingMode : public ApplicationBaseMode { - - public: - static ProjectionMappingMode * instance(); - - void setup(Application * app); - void update(Application * app); - void draw(Application * app); - - void toggleLayerPanel(); - - void onKeyPressed(Application * app, ofKeyEventArgs & args); - void onMousePressed(Application * app, ofMouseEventArgs & args); - void onMouseReleased(Application * app, ofMouseEventArgs & args); - void onMouseDragged(Application * app, ofMouseEventArgs & args); - void onJointPressed(Application * app, GuiJointEvent & e); - void onSurfacePressed(Application * app, GuiSurfaceEvent & e); - void onBackgroundPressed(Application * app, GuiBackgroundEvent & e); - - void onGuiEvent(Application * app, GuiEvent & e); - - private: - ProjectionMappingMode(); - - static ProjectionMappingMode * _instance; - - float _surfaceScaleBeforeTransform; - - Vec2 _clickPosition; - - bool _bSurfaceDrag; - bool _bDrawLayerPanel; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "Application.h" +#include "ofLog.h" +#include "ofGraphics.h" +#include "StartDragSurfaceCmd.h" +#include "DeselectSurfaceCmd.h" +#include "MvSurfaceVertCmd.h" +#include "SurfaceType.h" +#include "Gui.h" +#include "ScaleWidget.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class ProjectionMappingMode : public ApplicationBaseMode { + + public: + static ProjectionMappingMode * instance(); + + void setup(Application * app); + void update(Application * app); + void draw(Application * app); + + void toggleLayerPanel(); + + void onKeyPressed(Application * app, ofKeyEventArgs & args); + void onMousePressed(Application * app, ofMouseEventArgs & args); + void onMouseReleased(Application * app, ofMouseEventArgs & args); + void onMouseDragged(Application * app, ofMouseEventArgs & args); + void onJointPressed(Application * app, GuiJointEvent & e); + void onSurfacePressed(Application * app, GuiSurfaceEvent & e); + void onBackgroundPressed(Application * app, GuiBackgroundEvent & e); + + void onGuiEvent(Application * app, GuiEvent & e); + + private: + ProjectionMappingMode(); + + static ProjectionMappingMode * _instance; + + float _surfaceScaleBeforeTransform; + + Vec2 _clickPosition; + + bool _bSurfaceDrag; + bool _bDrawLayerPanel; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/SourceSelectionMode.cpp b/src/Application/Modes/SourceSelectionMode.cpp index fb7d512..8e05a5d 100644 --- a/src/Application/Modes/SourceSelectionMode.cpp +++ b/src/Application/Modes/SourceSelectionMode.cpp @@ -1,37 +1,37 @@ -#include "SourceSelectionMode.h" - -namespace ofx { -namespace piMapper { - -SourceSelectionMode * SourceSelectionMode::_instance = 0; - -SourceSelectionMode * SourceSelectionMode::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::SourceSelectionMode(); - } - return _instance; -} - -void SourceSelectionMode::setup(Application * app){ - Gui::instance()->getSourcesEditorWidget().setSurfaceManager(app->getSurfaceManager()); - Gui::instance()->getSourcesEditorWidget().setMediaServer(app->getMediaServer()); - Gui::instance()->getSourcesEditorWidget().setCmdManager(app->getCmdManager()); - Gui::instance()->getSourcesEditorWidget().setup(); -} - -void SourceSelectionMode::draw(Application * app){ - ofPushStyle(); - ofSetColor(255, 255, 255, 255); - app->getSurfaceManager()->draw(); - ofPopStyle(); - - Gui::instance()->getSourcesEditorWidget().draw(); - - // TODO: Move the following line to setup() - Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); - Gui::instance()->getSurfaceHighlightWidget().draw(); -} - -} // namespace piMapper -} // namespace ofx - +#include "SourceSelectionMode.h" + +namespace ofx { +namespace piMapper { + +SourceSelectionMode * SourceSelectionMode::_instance = 0; + +SourceSelectionMode * SourceSelectionMode::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::SourceSelectionMode(); + } + return _instance; +} + +void SourceSelectionMode::setup(Application * app){ + Gui::instance()->getSourcesEditorWidget().setSurfaceManager(app->getSurfaceManager()); + Gui::instance()->getSourcesEditorWidget().setMediaServer(app->getMediaServer()); + Gui::instance()->getSourcesEditorWidget().setCmdManager(app->getCmdManager()); + Gui::instance()->getSourcesEditorWidget().setup(); +} + +void SourceSelectionMode::draw(Application * app){ + ofPushStyle(); + ofSetColor(255, 255, 255, 255); + app->getSurfaceManager()->draw(); + ofPopStyle(); + + Gui::instance()->getSourcesEditorWidget().draw(); + + // TODO: Move the following line to setup() + Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); + Gui::instance()->getSurfaceHighlightWidget().draw(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Application/Modes/SourceSelectionMode.h b/src/Application/Modes/SourceSelectionMode.h index 8c8a653..f679329 100644 --- a/src/Application/Modes/SourceSelectionMode.h +++ b/src/Application/Modes/SourceSelectionMode.h @@ -1,27 +1,27 @@ -#pragma once - -#include "Application.h" -#include "ofEvents.h" -#include "ofLog.h" -#include "ofGraphics.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class SourceSelectionMode : public ApplicationBaseMode { - - public: - static SourceSelectionMode * instance(); - void setup(Application * app); - void draw(Application * app); - - void onGuiEvent(Application * app, GuiEvent & e){} - - private: - static SourceSelectionMode * _instance; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "Application.h" +#include "ofEvents.h" +#include "ofLog.h" +#include "ofGraphics.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class SourceSelectionMode : public ApplicationBaseMode { + + public: + static SourceSelectionMode * instance(); + void setup(Application * app); + void draw(Application * app); + + void onGuiEvent(Application * app, GuiEvent & e){} + + private: + static SourceSelectionMode * _instance; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/TextureMappingMode.cpp b/src/Application/Modes/TextureMappingMode.cpp index 7a08a8d..dfdf9da 100644 --- a/src/Application/Modes/TextureMappingMode.cpp +++ b/src/Application/Modes/TextureMappingMode.cpp @@ -1,319 +1,319 @@ -#include "TextureMappingMode.h" - -namespace ofx { -namespace piMapper { - -TextureMappingMode * TextureMappingMode::_instance = 0; - -TextureMappingMode * TextureMappingMode::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::TextureMappingMode(); - } - return _instance; -} - -TextureMappingMode::TextureMappingMode(){ - _bTranslateCanvas = false; - _canvasTranslate = ofPoint(0, 0); - _clickCanvasTranslate = ofPoint(0, 0); - _drawMode = 0; -} - -void TextureMappingMode::setup(Application * app){ - Gui::instance()->getTextureHighlightWidget().setSurfaceManager(app->getSurfaceManager()); -} - -void TextureMappingMode::update(Application * app){ - Gui::instance()->getTextureEditorWidget().update(); -} - -void TextureMappingMode::draw(Application * app){ - - // TODO: Make state classes out of the following anti-code. - - if(_drawMode == 0){ // Semi-transparent surfaces on front - ofPushMatrix(); - ofTranslate(_canvasTranslate.x, _canvasTranslate.y); - drawTexture(app); - ofPopMatrix(); - - ofPushStyle(); - ofSetColor(255, 255, 255, 150); - app->getSurfaceManager()->draw(); - ofPopStyle(); - }else if(_drawMode == 1){ // Opaque surfaces on front - ofPushMatrix(); - ofTranslate(_canvasTranslate.x, _canvasTranslate.y); - drawTexture(app); - ofPopMatrix(); - - ofPushStyle(); - ofSetColor(255, 255, 255, 255); - app->getSurfaceManager()->draw(); - ofPopStyle(); - }else if(_drawMode == 2){ // Draw texture only - ofPushMatrix(); - ofTranslate(_canvasTranslate.x, _canvasTranslate.y); - drawTexture(app); - ofPopMatrix(); - }else{ - _drawMode = 0; - } - - if(_drawMode != 2){ - Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); - Gui::instance()->getSurfaceHighlightWidget().draw(); - } - - ofPushMatrix(); - ofTranslate(_canvasTranslate.x, _canvasTranslate.y); - Gui::instance()->getTextureHighlightWidget().draw(); - Gui::instance()->getTextureEditorWidget().draw(); - ofPopMatrix(); -} - -void TextureMappingMode::onKeyPressed(Application * app, ofKeyEventArgs & args){ - float moveStep; - - if(app->isShiftKeyDown()){ - moveStep = 10.0f; - }else{ - moveStep = 1.0f; - } - - switch(args.key){ - - case OF_KEY_LEFT: - moveSelectedTexCoord(app, Vec2(-moveStep, 0.0f)); - break; - - case OF_KEY_RIGHT: - moveSelectedTexCoord(app, Vec2(moveStep, 0.0f)); - break; - - case OF_KEY_UP: - moveSelectedTexCoord(app, Vec2(0.0f, -moveStep)); - break; - - case OF_KEY_DOWN: - moveSelectedTexCoord(app, Vec2(0.0f, moveStep)); - break; - - case '>': - app->selectNextTexCoord(); - break; - - case '<': - app->selectPrevTexCoord(); - break; - - case ' ': - app->togglePause(); - break; - - case OF_KEY_TAB: - app->setNextSource(); - break; - - case '0': // Next draw mode - app->getCmdManager()->exec(new SetTexMapDrawModeCmd( this, getNextDrawMode() )); - break; - - case '9': // Prew draw mode - app->getCmdManager()->exec(new SetTexMapDrawModeCmd( this, getPrevDrawMode() )); - break; - - } -} - -void TextureMappingMode::onBackgroundPressed(Application * app, GuiBackgroundEvent & e){ - // Exec the command only if a joint is selected. - bool selected = false; - for(unsigned int i = 0; i < Gui::instance()->getTextureEditorWidget().getJoints().size(); ++i){ - if(Gui::instance()->getTextureEditorWidget().getJoints()[i]->selected){ - selected = true; - break; - } - } - - if(selected){ - app->getCmdManager()->exec( - new DeselectTexCoordCmd(&Gui::instance()->getTextureEditorWidget())); - } - - _bTranslateCanvas = true; -} - -void TextureMappingMode::onMousePressed(Application * app, ofMouseEventArgs & args){ - if(app->getSurfaceManager()->getSelectedSurface() == 0){ - return; - } - - _clickPosition = ofPoint(args.x, args.y); - _prevCanvasTranslate = _canvasTranslate; - - // Alter mouse event args to match canvas translation - args.x -= _canvasTranslate.x; - args.y -= _canvasTranslate.y; - - CircleJoint * hitJoint = - Gui::instance()->getTextureEditorWidget().hitTestJoints( - Vec2(args.x, args.y)); - - if(hitJoint != 0){ - hitJoint->mousePressed(args); - int selectedTexCoord = -1; - for(int i = 0; i < Gui::instance()->getTextureEditorWidget().getJoints().size(); ++i){ - if(hitJoint == Gui::instance()->getTextureEditorWidget().getJoints()[i]){ - selectedTexCoord = i; - break; - } - } - - if(!hitJoint->isSelected()){ - app->getCmdManager()->exec( - new SelTexCoordCmd( - &Gui::instance()->getTextureEditorWidget(), - selectedTexCoord)); - } - - hitJoint->startDrag(); - - _texCoordOnClick = - app->getSurfaceManager()->getSelectedSurface()->getTexCoords()[selectedTexCoord]; - }else if(app->getSurfaceManager()->getSelectedSurface()->getTextureHitArea().inside(args.x, args.y)){ - - _clickPosition = ofPoint(args.x, args.y); - _bCropAreaDrag = true; - - int selectedTexCoordIndex = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); - if(selectedTexCoordIndex != -1){ - app->getCmdManager()->exec(new DeselectTexCoordCmd( - &Gui::instance()->getTextureEditorWidget())); - } - - // TODO: emit event through the gui singleton. - // TODO: create command only on mouse release. - app->getCmdManager()->exec(new MvAllTexCoordsCmd( - app->getSurfaceManager()->getSelectedSurface(), - &Gui::instance()->getTextureEditorWidget())); - - }else{ - Gui::instance()->notifyBackgroundPressed(args); - } -} - -void TextureMappingMode::onMouseReleased(Application * app, ofMouseEventArgs & args){ - _bTranslateCanvas = false; - - // If translation has happened, create an undoable command - if(_prevCanvasTranslate != _canvasTranslate){ - app->getCmdManager()->exec( - new TranslateCanvasCmd( - app, - _prevCanvasTranslate, - _canvasTranslate)); - } - - // If selected joint is being dragged and the mouse position has been changed - // create an undoable move tex coord command. - int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); - if(selectedTexCoord >= 0){ - Vec2 texCoordCurrent = - app->getSurfaceManager()->getSelectedSurface()->getTexCoords()[selectedTexCoord]; - - if(texCoordCurrent != _texCoordOnClick){ - app->getCmdManager()->exec(new SaveTexCoordPosCmd(selectedTexCoord, _texCoordOnClick)); - } - } - - _clickCanvasTranslate = _canvasTranslate; - - args.x -= _canvasTranslate.x; - args.y -= _canvasTranslate.y; - - _bCropAreaDrag = false; - Gui::instance()->getTextureEditorWidget().stopDragJoints(); -} - -// TODO: Handle app->getGui()->clickPosition and app->getGui()->bDrag locally. -void TextureMappingMode::onMouseDragged(Application * app, ofMouseEventArgs & args){ - if(!_bTranslateCanvas){ - args.x -= _canvasTranslate.x; - args.y -= _canvasTranslate.y; - Gui::instance()->getTextureEditorWidget().onMouseDragged(args); - - if(_bCropAreaDrag){ - ofPoint mousePosition = ofPoint(args.x, args.y); - ofPoint distance = mousePosition - _clickPosition; - Vec2 d = Vec2(distance.x, distance.y); - Gui::instance()->getTextureEditorWidget().moveTexCoords(d); - _clickPosition = mousePosition; - } - }else{ - ofPoint mousePosition = ofPoint(args.x, args.y); - ofPoint distance = mousePosition - _clickPosition; - _canvasTranslate = _clickCanvasTranslate + distance; - } -} - -void TextureMappingMode::drawTexture(Application * app){ - if(app->getSurfaceManager()->getSelectedSurface() != 0){ - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - ofSetColor(255, 255, 255, 255); - app->getSurfaceManager()->getSelectedSurface()->drawTexture(Vec3(0.0f, 0.0f, 0.0f)); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } - } -} - -void TextureMappingMode::moveSelectedTexCoord(Application * app, Vec2 by){ - if(app->getSurfaceManager()->getSelectedSurface() != 0){ - int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); - app->moveTexCoord(selectedTexCoord, by); - } -} - -ofPoint TextureMappingMode::getTranslation(){ - return _canvasTranslate; -} - -void TextureMappingMode::setTranslation(ofPoint p){ - _canvasTranslate = p; - _clickCanvasTranslate = p; -} - -void TextureMappingMode::setDrawMode(int m){ - _drawMode = m; -} - -int TextureMappingMode::getDrawMode(){ - return _drawMode; -} - -int TextureMappingMode::getNextDrawMode(){ - int nextDrawMode = _drawMode + 1; - - if(nextDrawMode > 2){ - nextDrawMode = 0; - } - - return nextDrawMode; -} - -int TextureMappingMode::getPrevDrawMode(){ - int prevDrawMode = _drawMode - 1; - - if(prevDrawMode < 0){ - prevDrawMode = 2; - } - - return prevDrawMode; -} - -} // namespace piMapper -} // namespace ofx +#include "TextureMappingMode.h" + +namespace ofx { +namespace piMapper { + +TextureMappingMode * TextureMappingMode::_instance = 0; + +TextureMappingMode * TextureMappingMode::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::TextureMappingMode(); + } + return _instance; +} + +TextureMappingMode::TextureMappingMode(){ + _bTranslateCanvas = false; + _canvasTranslate = ofPoint(0, 0); + _clickCanvasTranslate = ofPoint(0, 0); + _drawMode = 0; +} + +void TextureMappingMode::setup(Application * app){ + Gui::instance()->getTextureHighlightWidget().setSurfaceManager(app->getSurfaceManager()); +} + +void TextureMappingMode::update(Application * app){ + Gui::instance()->getTextureEditorWidget().update(); +} + +void TextureMappingMode::draw(Application * app){ + + // TODO: Make state classes out of the following anti-code. + + if(_drawMode == 0){ // Semi-transparent surfaces on front + ofPushMatrix(); + ofTranslate(_canvasTranslate.x, _canvasTranslate.y); + drawTexture(app); + ofPopMatrix(); + + ofPushStyle(); + ofSetColor(255, 255, 255, 150); + app->getSurfaceManager()->draw(); + ofPopStyle(); + }else if(_drawMode == 1){ // Opaque surfaces on front + ofPushMatrix(); + ofTranslate(_canvasTranslate.x, _canvasTranslate.y); + drawTexture(app); + ofPopMatrix(); + + ofPushStyle(); + ofSetColor(255, 255, 255, 255); + app->getSurfaceManager()->draw(); + ofPopStyle(); + }else if(_drawMode == 2){ // Draw texture only + ofPushMatrix(); + ofTranslate(_canvasTranslate.x, _canvasTranslate.y); + drawTexture(app); + ofPopMatrix(); + }else{ + _drawMode = 0; + } + + if(_drawMode != 2){ + Gui::instance()->getSurfaceHighlightWidget().setSurfaceManager(app->getSurfaceManager()); + Gui::instance()->getSurfaceHighlightWidget().draw(); + } + + ofPushMatrix(); + ofTranslate(_canvasTranslate.x, _canvasTranslate.y); + Gui::instance()->getTextureHighlightWidget().draw(); + Gui::instance()->getTextureEditorWidget().draw(); + ofPopMatrix(); +} + +void TextureMappingMode::onKeyPressed(Application * app, ofKeyEventArgs & args){ + float moveStep; + + if(app->isShiftKeyDown()){ + moveStep = 10.0f; + }else{ + moveStep = 1.0f; + } + + switch(args.key){ + + case OF_KEY_LEFT: + moveSelectedTexCoord(app, Vec2(-moveStep, 0.0f)); + break; + + case OF_KEY_RIGHT: + moveSelectedTexCoord(app, Vec2(moveStep, 0.0f)); + break; + + case OF_KEY_UP: + moveSelectedTexCoord(app, Vec2(0.0f, -moveStep)); + break; + + case OF_KEY_DOWN: + moveSelectedTexCoord(app, Vec2(0.0f, moveStep)); + break; + + case '>': + app->selectNextTexCoord(); + break; + + case '<': + app->selectPrevTexCoord(); + break; + + case ' ': + app->togglePause(); + break; + + case OF_KEY_TAB: + app->setNextSource(); + break; + + case '0': // Next draw mode + app->getCmdManager()->exec(new SetTexMapDrawModeCmd( this, getNextDrawMode() )); + break; + + case '9': // Prew draw mode + app->getCmdManager()->exec(new SetTexMapDrawModeCmd( this, getPrevDrawMode() )); + break; + + } +} + +void TextureMappingMode::onBackgroundPressed(Application * app, GuiBackgroundEvent & e){ + // Exec the command only if a joint is selected. + bool selected = false; + for(unsigned int i = 0; i < Gui::instance()->getTextureEditorWidget().getJoints().size(); ++i){ + if(Gui::instance()->getTextureEditorWidget().getJoints()[i]->selected){ + selected = true; + break; + } + } + + if(selected){ + app->getCmdManager()->exec( + new DeselectTexCoordCmd(&Gui::instance()->getTextureEditorWidget())); + } + + _bTranslateCanvas = true; +} + +void TextureMappingMode::onMousePressed(Application * app, ofMouseEventArgs & args){ + if(app->getSurfaceManager()->getSelectedSurface() == 0){ + return; + } + + _clickPosition = ofPoint(args.x, args.y); + _prevCanvasTranslate = _canvasTranslate; + + // Alter mouse event args to match canvas translation + args.x -= _canvasTranslate.x; + args.y -= _canvasTranslate.y; + + CircleJoint * hitJoint = + Gui::instance()->getTextureEditorWidget().hitTestJoints( + Vec2(args.x, args.y)); + + if(hitJoint != 0){ + hitJoint->mousePressed(args); + int selectedTexCoord = -1; + for(int i = 0; i < Gui::instance()->getTextureEditorWidget().getJoints().size(); ++i){ + if(hitJoint == Gui::instance()->getTextureEditorWidget().getJoints()[i]){ + selectedTexCoord = i; + break; + } + } + + if(!hitJoint->isSelected()){ + app->getCmdManager()->exec( + new SelTexCoordCmd( + &Gui::instance()->getTextureEditorWidget(), + selectedTexCoord)); + } + + hitJoint->startDrag(); + + _texCoordOnClick = + app->getSurfaceManager()->getSelectedSurface()->getTexCoords()[selectedTexCoord]; + }else if(app->getSurfaceManager()->getSelectedSurface()->getTextureHitArea().inside(args.x, args.y)){ + + _clickPosition = ofPoint(args.x, args.y); + _bCropAreaDrag = true; + + int selectedTexCoordIndex = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); + if(selectedTexCoordIndex != -1){ + app->getCmdManager()->exec(new DeselectTexCoordCmd( + &Gui::instance()->getTextureEditorWidget())); + } + + // TODO: emit event through the gui singleton. + // TODO: create command only on mouse release. + app->getCmdManager()->exec(new MvAllTexCoordsCmd( + app->getSurfaceManager()->getSelectedSurface(), + &Gui::instance()->getTextureEditorWidget())); + + }else{ + Gui::instance()->notifyBackgroundPressed(args); + } +} + +void TextureMappingMode::onMouseReleased(Application * app, ofMouseEventArgs & args){ + _bTranslateCanvas = false; + + // If translation has happened, create an undoable command + if(_prevCanvasTranslate != _canvasTranslate){ + app->getCmdManager()->exec( + new TranslateCanvasCmd( + app, + _prevCanvasTranslate, + _canvasTranslate)); + } + + // If selected joint is being dragged and the mouse position has been changed + // create an undoable move tex coord command. + int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); + if(selectedTexCoord >= 0){ + Vec2 texCoordCurrent = + app->getSurfaceManager()->getSelectedSurface()->getTexCoords()[selectedTexCoord]; + + if(texCoordCurrent != _texCoordOnClick){ + app->getCmdManager()->exec(new SaveTexCoordPosCmd(selectedTexCoord, _texCoordOnClick)); + } + } + + _clickCanvasTranslate = _canvasTranslate; + + args.x -= _canvasTranslate.x; + args.y -= _canvasTranslate.y; + + _bCropAreaDrag = false; + Gui::instance()->getTextureEditorWidget().stopDragJoints(); +} + +// TODO: Handle app->getGui()->clickPosition and app->getGui()->bDrag locally. +void TextureMappingMode::onMouseDragged(Application * app, ofMouseEventArgs & args){ + if(!_bTranslateCanvas){ + args.x -= _canvasTranslate.x; + args.y -= _canvasTranslate.y; + Gui::instance()->getTextureEditorWidget().onMouseDragged(args); + + if(_bCropAreaDrag){ + ofPoint mousePosition = ofPoint(args.x, args.y); + ofPoint distance = mousePosition - _clickPosition; + Vec2 d = Vec2(distance.x, distance.y); + Gui::instance()->getTextureEditorWidget().moveTexCoords(d); + _clickPosition = mousePosition; + } + }else{ + ofPoint mousePosition = ofPoint(args.x, args.y); + ofPoint distance = mousePosition - _clickPosition; + _canvasTranslate = _clickCanvasTranslate + distance; + } +} + +void TextureMappingMode::drawTexture(Application * app){ + if(app->getSurfaceManager()->getSelectedSurface() != 0){ + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + ofSetColor(255, 255, 255, 255); + app->getSurfaceManager()->getSelectedSurface()->drawTexture(Vec3(0.0f, 0.0f, 0.0f)); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } + } +} + +void TextureMappingMode::moveSelectedTexCoord(Application * app, Vec2 by){ + if(app->getSurfaceManager()->getSelectedSurface() != 0){ + int selectedTexCoord = Gui::instance()->getTextureEditorWidget().getSelectedTexCoord(); + app->moveTexCoord(selectedTexCoord, by); + } +} + +ofPoint TextureMappingMode::getTranslation(){ + return _canvasTranslate; +} + +void TextureMappingMode::setTranslation(ofPoint p){ + _canvasTranslate = p; + _clickCanvasTranslate = p; +} + +void TextureMappingMode::setDrawMode(int m){ + _drawMode = m; +} + +int TextureMappingMode::getDrawMode(){ + return _drawMode; +} + +int TextureMappingMode::getNextDrawMode(){ + int nextDrawMode = _drawMode + 1; + + if(nextDrawMode > 2){ + nextDrawMode = 0; + } + + return nextDrawMode; +} + +int TextureMappingMode::getPrevDrawMode(){ + int prevDrawMode = _drawMode - 1; + + if(prevDrawMode < 0){ + prevDrawMode = 2; + } + + return prevDrawMode; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/Modes/TextureMappingMode.h b/src/Application/Modes/TextureMappingMode.h index ae6eba1..a17861a 100644 --- a/src/Application/Modes/TextureMappingMode.h +++ b/src/Application/Modes/TextureMappingMode.h @@ -1,71 +1,71 @@ -#pragma once - -#include "Application.h" -#include "ofEvents.h" -#include "ofLog.h" -#include "ofGraphics.h" -#include "DeselectTexCoordCmd.h" -#include "SelNextSurfaceCmd.h" -#include "TranslateCanvasCmd.h" -#include "SetTexMapDrawModeCmd.h" -#include "MvTexCoordCmd.h" -#include "MvAllTexCoordsCmd.h" -#include "SaveTexCoordPosCmd.h" -#include "SelTexCoordCmd.h" -#include "Gui.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class TextureMappingMode : public ApplicationBaseMode { - - public: - static TextureMappingMode * instance(); - - void setup(Application * app); - void update(Application * app); - void draw(Application * app); - - void onKeyPressed(Application * app, ofKeyEventArgs & args); - void onBackgroundPressed(Application * app, GuiBackgroundEvent & e); - void onMousePressed(Application * app, ofMouseEventArgs & args); - void onMouseReleased(Application * app, ofMouseEventArgs & args); - void onMouseDragged(Application * app, ofMouseEventArgs & args); - void onGuiEvent(Application * app, GuiEvent & e){} - - void drawTexture(Application * app); - void moveSelectedTexCoord(Application * app, Vec2 by); - void selectNextVertex(Application * app); - void selectPrevVertex(Application * app); - - void setTranslation(ofPoint p); - void setDrawMode(int m); - - ofPoint getTranslation(); - - int getDrawMode(); - int getNextDrawMode(); - int getPrevDrawMode(); - - private: - static TextureMappingMode * _instance; - - TextureMappingMode(); - - bool _bTranslateCanvas; - bool _bCropAreaDrag; - - int _drawMode; - - ofPoint _clickPosition; - ofPoint _canvasTranslate; - ofPoint _prevCanvasTranslate; - ofPoint _clickCanvasTranslate; - - Vec2 _texCoordOnClick; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "Application.h" +#include "ofEvents.h" +#include "ofLog.h" +#include "ofGraphics.h" +#include "DeselectTexCoordCmd.h" +#include "SelNextSurfaceCmd.h" +#include "TranslateCanvasCmd.h" +#include "SetTexMapDrawModeCmd.h" +#include "MvTexCoordCmd.h" +#include "MvAllTexCoordsCmd.h" +#include "SaveTexCoordPosCmd.h" +#include "SelTexCoordCmd.h" +#include "Gui.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class TextureMappingMode : public ApplicationBaseMode { + + public: + static TextureMappingMode * instance(); + + void setup(Application * app); + void update(Application * app); + void draw(Application * app); + + void onKeyPressed(Application * app, ofKeyEventArgs & args); + void onBackgroundPressed(Application * app, GuiBackgroundEvent & e); + void onMousePressed(Application * app, ofMouseEventArgs & args); + void onMouseReleased(Application * app, ofMouseEventArgs & args); + void onMouseDragged(Application * app, ofMouseEventArgs & args); + void onGuiEvent(Application * app, GuiEvent & e){} + + void drawTexture(Application * app); + void moveSelectedTexCoord(Application * app, Vec2 by); + void selectNextVertex(Application * app); + void selectPrevVertex(Application * app); + + void setTranslation(ofPoint p); + void setDrawMode(int m); + + ofPoint getTranslation(); + + int getDrawMode(); + int getNextDrawMode(); + int getPrevDrawMode(); + + private: + static TextureMappingMode * _instance; + + TextureMappingMode(); + + bool _bTranslateCanvas; + bool _bCropAreaDrag; + + int _drawMode; + + ofPoint _clickPosition; + ofPoint _canvasTranslate; + ofPoint _prevCanvasTranslate; + ofPoint _clickCanvasTranslate; + + Vec2 _texCoordOnClick; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/SettingsLoader.cpp b/src/Application/SettingsLoader.cpp index 800d12f..4a6be54 100644 --- a/src/Application/SettingsLoader.cpp +++ b/src/Application/SettingsLoader.cpp @@ -1,567 +1,567 @@ -#include "SettingsLoader.h" - -namespace ofx { -namespace piMapper { - -SettingsLoader * SettingsLoader::_instance = 0; - -SettingsLoader * SettingsLoader::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::SettingsLoader(); - } - return _instance; -} - -SettingsLoader::SettingsLoader(){ - _lastLoadedFilename = "surfaces.xml"; -} - -bool SettingsLoader::load( - SurfaceManager & surfaceManager, - MediaServer & mediaServer, - std::string fileName){ - - ofxXmlSettings * xmlSettings = new ofxXmlSettings(); - std::string sourceType = ""; - std::string sourceName = ""; - - BaseSource * source = 0; - - if(!xmlSettings->loadFile(fileName)){ - ofLogWarning("SettingsLoader::load()") << "Could not load XML settings"; - return false; - } - - if(!xmlSettings->tagExists("surfaces")){ - xmlSettings->addTag("surfaces"); - } - - // Count tags. - unsigned int numPresets = xmlSettings->getNumTags("surfaces"); - std::cout << "numPresets: " << numPresets << std::endl; - - // Clear previous presets and surfaces first. - surfaceManager.clearPresets(); - - // Loop through tags in the XML. - for(unsigned int i = 0; i < numPresets; ++i){ - - xmlSettings->pushTag("surfaces", i); - - SurfaceStack * surfaces = surfaceManager.createPreset(); - - int numSurfaces = xmlSettings->getNumTags("surface"); - for(int i = 0; i < numSurfaces; i++){ - if(xmlSettings->tagExists("surface", i)){ - - SurfaceType type = SurfaceType::NONE; - if(xmlSettings->attributeExists("surface", "type")){ - type = static_cast( - xmlSettings->getAttribute("surface", "type", 0, i)); - } - - xmlSettings->pushTag("surface", i); - - // attempt to load surface source - if(xmlSettings->tagExists("source", 0)){ - xmlSettings->pushTag("source"); - sourceType = xmlSettings->getValue("source-type", ""); - sourceName = xmlSettings->getValue("source-name", ""); - - if(sourceName != "" && sourceName != "none" && sourceType != ""){ - - // Load source depending on type - SourceType typeEnum = SourceTypeHelper::GetSourceTypeHelperEnum(sourceType); - if(typeEnum == SourceType::SOURCE_TYPE_FBO){ - - // Load FBO source using sourceName - source = mediaServer.loadMedia(sourceName, typeEnum); - }else{ - - // relative pathss as default, absolute Paths for RASPI - bool absolutePathSwitch = false; - #ifdef TARGET_RASPBERRY_PI - absolutePathSwitch = true; - #endif - - // Construct full path - std::string dir = mediaServer.getDefaultMediaDir(typeEnum); - std::stringstream pathss; - pathss << ofToDataPath(dir, absolutePathSwitch) << sourceName; - std::string sourcePath = pathss.str(); - - // Check if file exists - // Continue for loop if not - if(!ofFile::doesFileExist(sourcePath)){ - continue; - } - - // Load media by using full path - source = mediaServer.loadMedia(sourcePath, typeEnum); - - if(typeEnum == SourceType::SOURCE_TYPE_VIDEO){ - // Attempt to set loop for this type of source - bool loop = xmlSettings->getValue("source-loop", true); - VideoSource * vid = dynamic_cast(source); - vid->setLoop(loop); - } - } - } - - xmlSettings->popTag(); // source - } - - int vertexCount = 0; - - if(xmlSettings->tagExists("vertices", 0)){ - xmlSettings->pushTag("vertices"); - vertexCount = xmlSettings->getNumTags("vertex"); - xmlSettings->popTag(); // vertices - } - - if(type == SurfaceType::NONE){ - if(vertexCount == 3){ - type = SurfaceType::TRIANGLE_SURFACE; - }else if(vertexCount == 4){ - type = SurfaceType::QUAD_SURFACE; - }else if(vertexCount > 4){ - type = SurfaceType::GRID_WARP_SURFACE; - } - } - - if(type == SurfaceType::TRIANGLE_SURFACE){ - BaseSurface * triangleSurface = getTriangleSurface(xmlSettings); - if(sourceName != "none" && source != 0){ - triangleSurface->setSource(source); - } - surfaces->push_back(triangleSurface); - }else if(type == SurfaceType::QUAD_SURFACE){ - BaseSurface * quadSurface = getQuadSurface(xmlSettings); - if(sourceName != "none" && source != 0){ - quadSurface->setSource(source); - } - surfaces->push_back(quadSurface); - }else if(type == SurfaceType::CIRCLE_SURFACE){ - QuadSurface * base = (QuadSurface*)getQuadSurface(xmlSettings); - CircleSurface * circleSurface = new CircleSurface(*base); - if(sourceName != "none" && source != 0){ - circleSurface->setSource(source); - } - surfaces->push_back(circleSurface); - }else if(type == SurfaceType::GRID_WARP_SURFACE){ - BaseSurface * gridWarpSurface = getGridWarpSurface(xmlSettings); - if(sourceName != "none" && source != 0){ - gridWarpSurface->setSource(source); - } - surfaces->push_back(gridWarpSurface); - }else if(type == SurfaceType::HEXAGON_SURFACE){ - BaseSurface * hexagonSurface = getHexagonSurface(xmlSettings); - if(sourceName != "none" && source != 0){ - hexagonSurface->setSource(source); - } - surfaces->push_back(hexagonSurface); - } - - xmlSettings->popTag(); // surface - } - } - - xmlSettings->popTag(); // surfaces - - } // for - - _lastLoadedFilename = fileName; - - return true; -} - -// TODO: Save all presets, not just the active one. -bool SettingsLoader::save(SurfaceManager & surfaceManager, std::string fileName){ - - ofxXmlSettings * xmlSettings = new ofxXmlSettings(); - - unsigned int numPresets = surfaceManager.getNumPresets(); - - for(unsigned int i = 0; i < numPresets; ++i){ - - SurfaceStack * surfaces = surfaceManager.getPresetAt(i); - - // Save surfaces - xmlSettings->addTag("surfaces"); - xmlSettings->pushTag("surfaces", i); - for(int i = 0; i < surfaces->size(); i++){ - BaseSurface * surface = surfaces->at(i); - - xmlSettings->addTag("surface"); - xmlSettings->addAttribute("surface", "type", surface->getType(), i); - xmlSettings->pushTag("surface", i); - xmlSettings->addTag("vertices"); - xmlSettings->pushTag("vertices"); - std::vector vertices = surface->getVertices(); - for(int j = 0; j < vertices.size(); j++){ - xmlSettings->addTag("vertex"); - xmlSettings->pushTag("vertex", j); - Vec3 * vertex = &vertices[j]; - xmlSettings->addValue("x", vertex->x); - xmlSettings->addValue("y", vertex->y); - - // we don't need z as it will be 0 anyways - - xmlSettings->popTag(); // vertex - } - xmlSettings->popTag(); // vertices - - xmlSettings->addTag("texCoords"); - xmlSettings->pushTag("texCoords"); - std::vector texCoords = surface->getTexCoords(); - for(int j = 0; j < texCoords.size(); j++){ - xmlSettings->addTag("texCoord"); - xmlSettings->pushTag("texCoord", j); - Vec2 * texCoord = &texCoords[j]; - xmlSettings->addValue("x", texCoord->x); - xmlSettings->addValue("y", texCoord->y); - xmlSettings->popTag(); // texCoord - } - xmlSettings->popTag(); // texCoords - xmlSettings->addTag("source"); - xmlSettings->pushTag("source"); - - std::string sourceTypeName = SourceTypeHelper::GetSourceTypeHelperName(surface->getSource()->getType()); - - xmlSettings->addValue("source-type", sourceTypeName); - std::string sourceName = surface->getSource()->getName(); - xmlSettings->addValue("source-name", (sourceName == "") ? "none" : sourceName); - - if(surface->getSource()->getType() == SOURCE_TYPE_VIDEO){ - VideoSource * vid = dynamic_cast(surface->getSource()); - xmlSettings->addValue("source-loop", vid->getLoop()); - } - - xmlSettings->popTag(); // source - - // Save surface options - // For now only if quad surface - if (surface->getType() == SurfaceType::QUAD_SURFACE || - surface->getType() == SurfaceType::CIRCLE_SURFACE) { - QuadSurface * qs = (QuadSurface *)surface; - if(!xmlSettings->tagExists("properties")){ - xmlSettings->addTag("properties"); - } - xmlSettings->pushTag("properties"); - xmlSettings->addValue("perspectiveWarping", qs->getPerspectiveWarping()); - xmlSettings->popTag(); // properties - }else if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ - GridWarpSurface * gws = (GridWarpSurface *)surface; - if(!xmlSettings->tagExists("properties")){ - xmlSettings->addTag("properties"); - } - xmlSettings->pushTag("properties"); - xmlSettings->addValue("gridCols", gws->getGridCols()); - xmlSettings->addValue("gridRows", gws->getGridRows()); - xmlSettings->popTag(); - } - - xmlSettings->popTag(); // surface - } - xmlSettings->popTag(); // surfaces - - } // for - - return xmlSettings->save(fileName); -} - -bool SettingsLoader::create(std::string fileName){ - ofxXmlSettings xml; - xml.addTag("surfaces"); - return xml.save(fileName); -} - -BaseSurface * SettingsLoader::getTriangleSurface(ofxXmlSettings * xmlSettings){ - std::vector vertices; - - if(xmlSettings->tagExists("vertices")){ - xmlSettings->pushTag("vertices"); - - if(xmlSettings->tagExists("vertex", 0)){ - xmlSettings->pushTag("vertex", 0); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("vertex", 1)){ - xmlSettings->pushTag("vertex", 1); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 100.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("vertex", 2)){ - xmlSettings->pushTag("vertex", 2); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 100.0f), - 0.0f)); - xmlSettings->popTag(); - } - - xmlSettings->popTag(); // vertices - } - - std::vector texCoords; - - if(xmlSettings->tagExists("texCoords")){ - xmlSettings->pushTag("texCoords"); - - if(xmlSettings->tagExists("texCoord", 0)){ - xmlSettings->pushTag("texCoord", 0); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("texCoord", 1)){ - xmlSettings->pushTag("texCoord", 1); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("texCoord", 2)){ - xmlSettings->pushTag("texCoord", 2); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 1.0f))); - xmlSettings->popTag(); - } - - xmlSettings->popTag(); // texCoords - } - - // Create and add a triangle surface - BaseSurface * triangleSurface = - SurfaceFactory::instance()->createSurface( - SurfaceType::TRIANGLE_SURFACE); - triangleSurface->setVertices(vertices); - triangleSurface->setTexCoords(texCoords); - - return triangleSurface; -} - -BaseSurface * SettingsLoader::getQuadSurface(ofxXmlSettings * xmlSettings){ - std::vector vertices; - - if(xmlSettings->tagExists("vertices")){ - xmlSettings->pushTag("vertices"); - - if(xmlSettings->tagExists("vertex", 0)){ - xmlSettings->pushTag("vertex", 0); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("vertex", 1)){ - xmlSettings->pushTag("vertex", 1); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 100.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("vertex", 2)){ - xmlSettings->pushTag("vertex", 2); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 100.0f), - xmlSettings->getValue("y", 100.0f), - 0.0f)); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("vertex", 3)){ - xmlSettings->pushTag("vertex", 3); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 100.0f), - 0.0f)); - xmlSettings->popTag(); - } - - xmlSettings->popTag(); // vertices - } - - std::vector texCoords; - - if(xmlSettings->tagExists("texCoords")){ - xmlSettings->pushTag("texCoords"); - - if(xmlSettings->tagExists("texCoord", 0)){ - xmlSettings->pushTag("texCoord", 0); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("texCoord", 1)){ - xmlSettings->pushTag("texCoord", 1); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("texCoord", 2)){ - xmlSettings->pushTag("texCoord", 2); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), - xmlSettings->getValue("y", 1.0f))); - xmlSettings->popTag(); - } - - if(xmlSettings->tagExists("texCoord", 3)){ - xmlSettings->pushTag("texCoord", 3); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 1.0f))); - xmlSettings->popTag(); - } - - xmlSettings->popTag(); // texCoords - } - - // Create and add quad surface - BaseSurface * quadSurface = - SurfaceFactory::instance()->createSurface( - SurfaceType::QUAD_SURFACE); - quadSurface->setVertices(vertices); - quadSurface->setTexCoords(texCoords); - - // Read properties - // Only perspective warping for now - bool perspectiveWarping = false; - if(xmlSettings->tagExists("properties")){ - xmlSettings->pushTag("properties"); - perspectiveWarping = xmlSettings->getValue("perspectiveWarping", false); - xmlSettings->popTag(); // properties - } - QuadSurface * qs = (QuadSurface *)quadSurface; - qs->setPerspectiveWarping(perspectiveWarping); - - return quadSurface; -} - -BaseSurface * SettingsLoader::getGridWarpSurface(ofxXmlSettings * xmlSettings){ - std::vector vertices; - - if(xmlSettings->tagExists("vertices")){ - xmlSettings->pushTag("vertices"); - - int iv = 0; - - while(xmlSettings->tagExists("vertex", iv)){ - xmlSettings->pushTag("vertex", iv); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); - ++iv; - } - - xmlSettings->popTag(); // vertices - } - - std::vector texCoords; - - if(xmlSettings->tagExists("texCoords")){ - xmlSettings->pushTag("texCoords"); - - int it = 0; - - while(xmlSettings->tagExists("texCoord", it)){ - xmlSettings->pushTag("texCoord", it); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); - ++it; - } - - xmlSettings->popTag(); // texCoords - } - - // Read properties - // Only perspective warping for now - int gridCols = 0; - int gridRows = 0; - if(xmlSettings->tagExists("properties")){ - xmlSettings->pushTag("properties"); - gridCols = xmlSettings->getValue("gridCols", 0); - gridRows = xmlSettings->getValue("gridRows", 0); - xmlSettings->popTag(); // properties - } - - // Create and add quad surface - BaseSurface * gridWarpSurface = - SurfaceFactory::instance()->createSurface( - SurfaceType::GRID_WARP_SURFACE); - ((GridWarpSurface *)gridWarpSurface)->setGridCols(gridCols); - ((GridWarpSurface *)gridWarpSurface)->setGridRows(gridRows); - ((GridWarpSurface *)gridWarpSurface)->createGridMesh(); - gridWarpSurface->setVertices(vertices); - gridWarpSurface->setTexCoords(texCoords); - - return gridWarpSurface; -} - -BaseSurface * SettingsLoader::getHexagonSurface(ofxXmlSettings * xmlSettings){ - std::vector vertices; - - if(xmlSettings->tagExists("vertices")){ - xmlSettings->pushTag("vertices"); - - unsigned int v = 0; - while(xmlSettings->tagExists("vertex", v)){ - xmlSettings->pushTag("vertex", v); - vertices.push_back(Vec3( - xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f), - 0.0f)); - xmlSettings->popTag(); // vertex - v += 1; - } - - xmlSettings->popTag(); // vertices - } - - std::vector texCoords; - - if(xmlSettings->tagExists("texCoords")){ - xmlSettings->pushTag("texCoords"); - - unsigned int t = 0; - while(xmlSettings->tagExists("texCoord", t)){ - xmlSettings->pushTag("texCoord", t); - texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), - xmlSettings->getValue("y", 0.0f))); - xmlSettings->popTag(); // texCoord - t += 1; - } - - xmlSettings->popTag(); // texCoords - } - - // Create and add a triangle surface - BaseSurface * hexagonSurface = - SurfaceFactory::instance()->createSurface( - SurfaceType::HEXAGON_SURFACE); - hexagonSurface->setVertices(vertices); - hexagonSurface->setTexCoords(texCoords); - - return hexagonSurface; -} - -} // namespace piMapper -} // namespace ofx +#include "SettingsLoader.h" + +namespace ofx { +namespace piMapper { + +SettingsLoader * SettingsLoader::_instance = 0; + +SettingsLoader * SettingsLoader::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::SettingsLoader(); + } + return _instance; +} + +SettingsLoader::SettingsLoader(){ + _lastLoadedFilename = "surfaces.xml"; +} + +bool SettingsLoader::load( + SurfaceManager & surfaceManager, + MediaServer & mediaServer, + std::string fileName){ + + ofxXmlSettings * xmlSettings = new ofxXmlSettings(); + std::string sourceType = ""; + std::string sourceName = ""; + + BaseSource * source = 0; + + if(!xmlSettings->loadFile(fileName)){ + ofLogWarning("SettingsLoader::load()") << "Could not load XML settings"; + return false; + } + + if(!xmlSettings->tagExists("surfaces")){ + xmlSettings->addTag("surfaces"); + } + + // Count tags. + unsigned int numPresets = xmlSettings->getNumTags("surfaces"); + std::cout << "numPresets: " << numPresets << std::endl; + + // Clear previous presets and surfaces first. + surfaceManager.clearPresets(); + + // Loop through tags in the XML. + for(unsigned int i = 0; i < numPresets; ++i){ + + xmlSettings->pushTag("surfaces", i); + + SurfaceStack * surfaces = surfaceManager.createPreset(); + + int numSurfaces = xmlSettings->getNumTags("surface"); + for(int i = 0; i < numSurfaces; i++){ + if(xmlSettings->tagExists("surface", i)){ + + SurfaceType type = SurfaceType::NONE; + if(xmlSettings->attributeExists("surface", "type")){ + type = static_cast( + xmlSettings->getAttribute("surface", "type", 0, i)); + } + + xmlSettings->pushTag("surface", i); + + // attempt to load surface source + if(xmlSettings->tagExists("source", 0)){ + xmlSettings->pushTag("source"); + sourceType = xmlSettings->getValue("source-type", ""); + sourceName = xmlSettings->getValue("source-name", ""); + + if(sourceName != "" && sourceName != "none" && sourceType != ""){ + + // Load source depending on type + SourceType typeEnum = SourceTypeHelper::GetSourceTypeHelperEnum(sourceType); + if(typeEnum == SourceType::SOURCE_TYPE_FBO){ + + // Load FBO source using sourceName + source = mediaServer.loadMedia(sourceName, typeEnum); + }else{ + + // relative pathss as default, absolute Paths for RASPI + bool absolutePathSwitch = false; + #ifdef TARGET_RASPBERRY_PI + absolutePathSwitch = true; + #endif + + // Construct full path + std::string dir = mediaServer.getDefaultMediaDir(typeEnum); + std::stringstream pathss; + pathss << ofToDataPath(dir, absolutePathSwitch) << sourceName; + std::string sourcePath = pathss.str(); + + // Check if file exists + // Continue for loop if not + if(!ofFile::doesFileExist(sourcePath)){ + continue; + } + + // Load media by using full path + source = mediaServer.loadMedia(sourcePath, typeEnum); + + if(typeEnum == SourceType::SOURCE_TYPE_VIDEO){ + // Attempt to set loop for this type of source + bool loop = xmlSettings->getValue("source-loop", true); + VideoSource * vid = dynamic_cast(source); + vid->setLoop(loop); + } + } + } + + xmlSettings->popTag(); // source + } + + int vertexCount = 0; + + if(xmlSettings->tagExists("vertices", 0)){ + xmlSettings->pushTag("vertices"); + vertexCount = xmlSettings->getNumTags("vertex"); + xmlSettings->popTag(); // vertices + } + + if(type == SurfaceType::NONE){ + if(vertexCount == 3){ + type = SurfaceType::TRIANGLE_SURFACE; + }else if(vertexCount == 4){ + type = SurfaceType::QUAD_SURFACE; + }else if(vertexCount > 4){ + type = SurfaceType::GRID_WARP_SURFACE; + } + } + + if(type == SurfaceType::TRIANGLE_SURFACE){ + BaseSurface * triangleSurface = getTriangleSurface(xmlSettings); + if(sourceName != "none" && source != 0){ + triangleSurface->setSource(source); + } + surfaces->push_back(triangleSurface); + }else if(type == SurfaceType::QUAD_SURFACE){ + BaseSurface * quadSurface = getQuadSurface(xmlSettings); + if(sourceName != "none" && source != 0){ + quadSurface->setSource(source); + } + surfaces->push_back(quadSurface); + }else if(type == SurfaceType::CIRCLE_SURFACE){ + QuadSurface * base = (QuadSurface*)getQuadSurface(xmlSettings); + CircleSurface * circleSurface = new CircleSurface(*base); + if(sourceName != "none" && source != 0){ + circleSurface->setSource(source); + } + surfaces->push_back(circleSurface); + }else if(type == SurfaceType::GRID_WARP_SURFACE){ + BaseSurface * gridWarpSurface = getGridWarpSurface(xmlSettings); + if(sourceName != "none" && source != 0){ + gridWarpSurface->setSource(source); + } + surfaces->push_back(gridWarpSurface); + }else if(type == SurfaceType::HEXAGON_SURFACE){ + BaseSurface * hexagonSurface = getHexagonSurface(xmlSettings); + if(sourceName != "none" && source != 0){ + hexagonSurface->setSource(source); + } + surfaces->push_back(hexagonSurface); + } + + xmlSettings->popTag(); // surface + } + } + + xmlSettings->popTag(); // surfaces + + } // for + + _lastLoadedFilename = fileName; + + return true; +} + +// TODO: Save all presets, not just the active one. +bool SettingsLoader::save(SurfaceManager & surfaceManager, std::string fileName){ + + ofxXmlSettings * xmlSettings = new ofxXmlSettings(); + + unsigned int numPresets = surfaceManager.getNumPresets(); + + for(unsigned int i = 0; i < numPresets; ++i){ + + SurfaceStack * surfaces = surfaceManager.getPresetAt(i); + + // Save surfaces + xmlSettings->addTag("surfaces"); + xmlSettings->pushTag("surfaces", i); + for(int i = 0; i < surfaces->size(); i++){ + BaseSurface * surface = surfaces->at(i); + + xmlSettings->addTag("surface"); + xmlSettings->addAttribute("surface", "type", surface->getType(), i); + xmlSettings->pushTag("surface", i); + xmlSettings->addTag("vertices"); + xmlSettings->pushTag("vertices"); + std::vector vertices = surface->getVertices(); + for(int j = 0; j < vertices.size(); j++){ + xmlSettings->addTag("vertex"); + xmlSettings->pushTag("vertex", j); + Vec3 * vertex = &vertices[j]; + xmlSettings->addValue("x", vertex->x); + xmlSettings->addValue("y", vertex->y); + + // we don't need z as it will be 0 anyways + + xmlSettings->popTag(); // vertex + } + xmlSettings->popTag(); // vertices + + xmlSettings->addTag("texCoords"); + xmlSettings->pushTag("texCoords"); + std::vector texCoords = surface->getTexCoords(); + for(int j = 0; j < texCoords.size(); j++){ + xmlSettings->addTag("texCoord"); + xmlSettings->pushTag("texCoord", j); + Vec2 * texCoord = &texCoords[j]; + xmlSettings->addValue("x", texCoord->x); + xmlSettings->addValue("y", texCoord->y); + xmlSettings->popTag(); // texCoord + } + xmlSettings->popTag(); // texCoords + xmlSettings->addTag("source"); + xmlSettings->pushTag("source"); + + std::string sourceTypeName = SourceTypeHelper::GetSourceTypeHelperName(surface->getSource()->getType()); + + xmlSettings->addValue("source-type", sourceTypeName); + std::string sourceName = surface->getSource()->getName(); + xmlSettings->addValue("source-name", (sourceName == "") ? "none" : sourceName); + + if(surface->getSource()->getType() == SOURCE_TYPE_VIDEO){ + VideoSource * vid = dynamic_cast(surface->getSource()); + xmlSettings->addValue("source-loop", vid->getLoop()); + } + + xmlSettings->popTag(); // source + + // Save surface options + // For now only if quad surface + if (surface->getType() == SurfaceType::QUAD_SURFACE || + surface->getType() == SurfaceType::CIRCLE_SURFACE) { + QuadSurface * qs = (QuadSurface *)surface; + if(!xmlSettings->tagExists("properties")){ + xmlSettings->addTag("properties"); + } + xmlSettings->pushTag("properties"); + xmlSettings->addValue("perspectiveWarping", qs->getPerspectiveWarping()); + xmlSettings->popTag(); // properties + }else if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ + GridWarpSurface * gws = (GridWarpSurface *)surface; + if(!xmlSettings->tagExists("properties")){ + xmlSettings->addTag("properties"); + } + xmlSettings->pushTag("properties"); + xmlSettings->addValue("gridCols", gws->getGridCols()); + xmlSettings->addValue("gridRows", gws->getGridRows()); + xmlSettings->popTag(); + } + + xmlSettings->popTag(); // surface + } + xmlSettings->popTag(); // surfaces + + } // for + + return xmlSettings->save(fileName); +} + +bool SettingsLoader::create(std::string fileName){ + ofxXmlSettings xml; + xml.addTag("surfaces"); + return xml.save(fileName); +} + +BaseSurface * SettingsLoader::getTriangleSurface(ofxXmlSettings * xmlSettings){ + std::vector vertices; + + if(xmlSettings->tagExists("vertices")){ + xmlSettings->pushTag("vertices"); + + if(xmlSettings->tagExists("vertex", 0)){ + xmlSettings->pushTag("vertex", 0); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("vertex", 1)){ + xmlSettings->pushTag("vertex", 1); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 100.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("vertex", 2)){ + xmlSettings->pushTag("vertex", 2); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 100.0f), + 0.0f)); + xmlSettings->popTag(); + } + + xmlSettings->popTag(); // vertices + } + + std::vector texCoords; + + if(xmlSettings->tagExists("texCoords")){ + xmlSettings->pushTag("texCoords"); + + if(xmlSettings->tagExists("texCoord", 0)){ + xmlSettings->pushTag("texCoord", 0); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("texCoord", 1)){ + xmlSettings->pushTag("texCoord", 1); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("texCoord", 2)){ + xmlSettings->pushTag("texCoord", 2); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 1.0f))); + xmlSettings->popTag(); + } + + xmlSettings->popTag(); // texCoords + } + + // Create and add a triangle surface + BaseSurface * triangleSurface = + SurfaceFactory::instance()->createSurface( + SurfaceType::TRIANGLE_SURFACE); + triangleSurface->setVertices(vertices); + triangleSurface->setTexCoords(texCoords); + + return triangleSurface; +} + +BaseSurface * SettingsLoader::getQuadSurface(ofxXmlSettings * xmlSettings){ + std::vector vertices; + + if(xmlSettings->tagExists("vertices")){ + xmlSettings->pushTag("vertices"); + + if(xmlSettings->tagExists("vertex", 0)){ + xmlSettings->pushTag("vertex", 0); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("vertex", 1)){ + xmlSettings->pushTag("vertex", 1); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 100.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("vertex", 2)){ + xmlSettings->pushTag("vertex", 2); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 100.0f), + xmlSettings->getValue("y", 100.0f), + 0.0f)); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("vertex", 3)){ + xmlSettings->pushTag("vertex", 3); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 100.0f), + 0.0f)); + xmlSettings->popTag(); + } + + xmlSettings->popTag(); // vertices + } + + std::vector texCoords; + + if(xmlSettings->tagExists("texCoords")){ + xmlSettings->pushTag("texCoords"); + + if(xmlSettings->tagExists("texCoord", 0)){ + xmlSettings->pushTag("texCoord", 0); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("texCoord", 1)){ + xmlSettings->pushTag("texCoord", 1); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("texCoord", 2)){ + xmlSettings->pushTag("texCoord", 2); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 1.0f), + xmlSettings->getValue("y", 1.0f))); + xmlSettings->popTag(); + } + + if(xmlSettings->tagExists("texCoord", 3)){ + xmlSettings->pushTag("texCoord", 3); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 1.0f))); + xmlSettings->popTag(); + } + + xmlSettings->popTag(); // texCoords + } + + // Create and add quad surface + BaseSurface * quadSurface = + SurfaceFactory::instance()->createSurface( + SurfaceType::QUAD_SURFACE); + quadSurface->setVertices(vertices); + quadSurface->setTexCoords(texCoords); + + // Read properties + // Only perspective warping for now + bool perspectiveWarping = false; + if(xmlSettings->tagExists("properties")){ + xmlSettings->pushTag("properties"); + perspectiveWarping = xmlSettings->getValue("perspectiveWarping", false); + xmlSettings->popTag(); // properties + } + QuadSurface * qs = (QuadSurface *)quadSurface; + qs->setPerspectiveWarping(perspectiveWarping); + + return quadSurface; +} + +BaseSurface * SettingsLoader::getGridWarpSurface(ofxXmlSettings * xmlSettings){ + std::vector vertices; + + if(xmlSettings->tagExists("vertices")){ + xmlSettings->pushTag("vertices"); + + int iv = 0; + + while(xmlSettings->tagExists("vertex", iv)){ + xmlSettings->pushTag("vertex", iv); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); + ++iv; + } + + xmlSettings->popTag(); // vertices + } + + std::vector texCoords; + + if(xmlSettings->tagExists("texCoords")){ + xmlSettings->pushTag("texCoords"); + + int it = 0; + + while(xmlSettings->tagExists("texCoord", it)){ + xmlSettings->pushTag("texCoord", it); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); + ++it; + } + + xmlSettings->popTag(); // texCoords + } + + // Read properties + // Only perspective warping for now + int gridCols = 0; + int gridRows = 0; + if(xmlSettings->tagExists("properties")){ + xmlSettings->pushTag("properties"); + gridCols = xmlSettings->getValue("gridCols", 0); + gridRows = xmlSettings->getValue("gridRows", 0); + xmlSettings->popTag(); // properties + } + + // Create and add quad surface + BaseSurface * gridWarpSurface = + SurfaceFactory::instance()->createSurface( + SurfaceType::GRID_WARP_SURFACE); + ((GridWarpSurface *)gridWarpSurface)->setGridCols(gridCols); + ((GridWarpSurface *)gridWarpSurface)->setGridRows(gridRows); + ((GridWarpSurface *)gridWarpSurface)->createGridMesh(); + gridWarpSurface->setVertices(vertices); + gridWarpSurface->setTexCoords(texCoords); + + return gridWarpSurface; +} + +BaseSurface * SettingsLoader::getHexagonSurface(ofxXmlSettings * xmlSettings){ + std::vector vertices; + + if(xmlSettings->tagExists("vertices")){ + xmlSettings->pushTag("vertices"); + + unsigned int v = 0; + while(xmlSettings->tagExists("vertex", v)){ + xmlSettings->pushTag("vertex", v); + vertices.push_back(Vec3( + xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f), + 0.0f)); + xmlSettings->popTag(); // vertex + v += 1; + } + + xmlSettings->popTag(); // vertices + } + + std::vector texCoords; + + if(xmlSettings->tagExists("texCoords")){ + xmlSettings->pushTag("texCoords"); + + unsigned int t = 0; + while(xmlSettings->tagExists("texCoord", t)){ + xmlSettings->pushTag("texCoord", t); + texCoords.push_back(Vec2(xmlSettings->getValue("x", 0.0f), + xmlSettings->getValue("y", 0.0f))); + xmlSettings->popTag(); // texCoord + t += 1; + } + + xmlSettings->popTag(); // texCoords + } + + // Create and add a triangle surface + BaseSurface * hexagonSurface = + SurfaceFactory::instance()->createSurface( + SurfaceType::HEXAGON_SURFACE); + hexagonSurface->setVertices(vertices); + hexagonSurface->setTexCoords(texCoords); + + return hexagonSurface; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Application/SettingsLoader.h b/src/Application/SettingsLoader.h index 3e1f2e6..6cfac62 100644 --- a/src/Application/SettingsLoader.h +++ b/src/Application/SettingsLoader.h @@ -1,43 +1,43 @@ -#pragma once - -#include "ofMain.h" -#include "ofxXmlSettings.h" -#include "SurfaceStack.h" -#include "SurfaceManager.h" -#include "MediaServer.h" -#include "SurfaceFactory.h" -#include "SurfaceType.h" -#include "SourceTypeHelper.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class SurfaceManager; - -class SettingsLoader { - public: - static SettingsLoader * instance(); - - bool load(SurfaceManager & surfaceManager, MediaServer & mediaServer, std::string fileName); - bool save(SurfaceManager & surfaceManager, std::string fileName); - bool create(std::string fileName); - - std::string getLastLoadedFilename(){ return _lastLoadedFilename; }; - - private: - static SettingsLoader * _instance; - - SettingsLoader(); - - BaseSurface * getTriangleSurface(ofxXmlSettings * xmlSettings); - BaseSurface * getQuadSurface(ofxXmlSettings * xmlSettings); - BaseSurface * getGridWarpSurface(ofxXmlSettings * xmlSettings); - BaseSurface * getHexagonSurface(ofxXmlSettings * xmlSettings); - - std::string _lastLoadedFilename; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "ofxXmlSettings.h" +#include "SurfaceStack.h" +#include "SurfaceManager.h" +#include "MediaServer.h" +#include "SurfaceFactory.h" +#include "SurfaceType.h" +#include "SourceTypeHelper.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class SurfaceManager; + +class SettingsLoader { + public: + static SettingsLoader * instance(); + + bool load(SurfaceManager & surfaceManager, MediaServer & mediaServer, std::string fileName); + bool save(SurfaceManager & surfaceManager, std::string fileName); + bool create(std::string fileName); + + std::string getLastLoadedFilename(){ return _lastLoadedFilename; }; + + private: + static SettingsLoader * _instance; + + SettingsLoader(); + + BaseSurface * getTriangleSurface(ofxXmlSettings * xmlSettings); + BaseSurface * getQuadSurface(ofxXmlSettings * xmlSettings); + BaseSurface * getGridWarpSurface(ofxXmlSettings * xmlSettings); + BaseSurface * getHexagonSurface(ofxXmlSettings * xmlSettings); + + std::string _lastLoadedFilename; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Commands/AddGridColCmd.cpp b/src/Commands/AddGridColCmd.cpp index f6931d6..365a754 100644 --- a/src/Commands/AddGridColCmd.cpp +++ b/src/Commands/AddGridColCmd.cpp @@ -1,27 +1,27 @@ -#include "AddGridColCmd.h" - -namespace ofx { -namespace piMapper { - -AddGridColCmd::AddGridColCmd(GridWarpSurface * s){ - _surface = s; -} - -void AddGridColCmd::exec(){ - - // TODO: Figure out nice math to not loose existing vertex positions - _vertices = _surface->getVertices(); - _texCoords = _surface->getTexCoords(); - _surface->setGridCols(_surface->getGridCols() + 1); -} - -void AddGridColCmd::undo(){ - ofLogNotice("AddGridColCmd", "undo"); - _surface->setGridCols(_surface->getGridCols() - 1); - _surface->setVertices(_vertices); - _surface->setTexCoords(_texCoords); -} - -} // namespace piMapper -} // namespace ofx - +#include "AddGridColCmd.h" + +namespace ofx { +namespace piMapper { + +AddGridColCmd::AddGridColCmd(GridWarpSurface * s){ + _surface = s; +} + +void AddGridColCmd::exec(){ + + // TODO: Figure out nice math to not loose existing vertex positions + _vertices = _surface->getVertices(); + _texCoords = _surface->getTexCoords(); + _surface->setGridCols(_surface->getGridCols() + 1); +} + +void AddGridColCmd::undo(){ + ofLogNotice("AddGridColCmd", "undo"); + _surface->setGridCols(_surface->getGridCols() - 1); + _surface->setVertices(_vertices); + _surface->setTexCoords(_texCoords); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/AddGridColCmd.h b/src/Commands/AddGridColCmd.h index f8a6b84..714879c 100644 --- a/src/Commands/AddGridColCmd.h +++ b/src/Commands/AddGridColCmd.h @@ -1,31 +1,31 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "GridWarpSurface.h" -#include "ProjectionEditorWidget.h" -#include "Vec2.h" -#include "Vec3.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class AddGridColCmd : public BaseUndoCmd { - - public: - AddGridColCmd(GridWarpSurface * s); - void exec(); - void undo(); - - private: - std::vector _vertices; - std::vector _texCoords; - GridWarpSurface * _surface; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "GridWarpSurface.h" +#include "ProjectionEditorWidget.h" +#include "Vec2.h" +#include "Vec3.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class AddGridColCmd : public BaseUndoCmd { + + public: + AddGridColCmd(GridWarpSurface * s); + void exec(); + void undo(); + + private: + std::vector _vertices; + std::vector _texCoords; + GridWarpSurface * _surface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/AddGridRowCmd.cpp b/src/Commands/AddGridRowCmd.cpp index a54817a..e85444d 100644 --- a/src/Commands/AddGridRowCmd.cpp +++ b/src/Commands/AddGridRowCmd.cpp @@ -1,27 +1,27 @@ -#include "AddGridRowCmd.h" - -namespace ofx { -namespace piMapper { - -AddGridRowCmd::AddGridRowCmd(GridWarpSurface * s){ - _surface = s; -} - -void AddGridRowCmd::exec(){ - - // TODO: Figure out nice math to not loose existing vertex positions - _vertices = _surface->getVertices(); - _texCoords = _surface->getTexCoords(); - _surface->setGridRows(_surface->getGridRows() + 1); -} - -void AddGridRowCmd::undo(){ - ofLogNotice("AddGridRowCmd", "undo"); - _surface->setGridRows(_surface->getGridRows() - 1); - _surface->setVertices(_vertices); - _surface->setTexCoords(_texCoords); -} - -} // namespace piMapper -} // namespace ofx - +#include "AddGridRowCmd.h" + +namespace ofx { +namespace piMapper { + +AddGridRowCmd::AddGridRowCmd(GridWarpSurface * s){ + _surface = s; +} + +void AddGridRowCmd::exec(){ + + // TODO: Figure out nice math to not loose existing vertex positions + _vertices = _surface->getVertices(); + _texCoords = _surface->getTexCoords(); + _surface->setGridRows(_surface->getGridRows() + 1); +} + +void AddGridRowCmd::undo(){ + ofLogNotice("AddGridRowCmd", "undo"); + _surface->setGridRows(_surface->getGridRows() - 1); + _surface->setVertices(_vertices); + _surface->setTexCoords(_texCoords); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/AddGridRowCmd.h b/src/Commands/AddGridRowCmd.h index 0cc3c10..c18cb24 100644 --- a/src/Commands/AddGridRowCmd.h +++ b/src/Commands/AddGridRowCmd.h @@ -1,31 +1,31 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "GridWarpSurface.h" -#include "ProjectionEditorWidget.h" -#include "Vec2.h" -#include "Vec3.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class AddGridRowCmd : public BaseUndoCmd { - - public: - AddGridRowCmd(GridWarpSurface * s); - void exec(); - void undo(); - - private: - std::vector _vertices; - std::vector _texCoords; - GridWarpSurface * _surface; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "GridWarpSurface.h" +#include "ProjectionEditorWidget.h" +#include "Vec2.h" +#include "Vec3.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class AddGridRowCmd : public BaseUndoCmd { + + public: + AddGridRowCmd(GridWarpSurface * s); + void exec(); + void undo(); + + private: + std::vector _vertices; + std::vector _texCoords; + GridWarpSurface * _surface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/AddSurfaceCmd.cpp b/src/Commands/AddSurfaceCmd.cpp index c81d19c..122044d 100644 --- a/src/Commands/AddSurfaceCmd.cpp +++ b/src/Commands/AddSurfaceCmd.cpp @@ -1,27 +1,27 @@ -#include "AddSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -AddSurfaceCmd::AddSurfaceCmd(SurfaceManager * sm, SurfaceType surfaceType){ - _surfaceManager = sm; - _surfaceType = surfaceType; - _selectedSurface = 0; -} - -void AddSurfaceCmd::exec(){ - _selectedSurface = _surfaceManager->getSelectedSurface(); - BaseSurface * surface = SurfaceFactory::instance()->createSurface(_surfaceType); - _surfaceManager->addSurface(surface); - _surfaceManager->selectSurface(surface); -} - -void AddSurfaceCmd::undo(){ - ofLogNotice("AddSurfaceCmd", "undo"); - _surfaceManager->removeSurface(); - _surfaceManager->selectSurface(_selectedSurface); -} - -} // namespace piMapper -} // namespace ofx - +#include "AddSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +AddSurfaceCmd::AddSurfaceCmd(SurfaceManager * sm, SurfaceType surfaceType){ + _surfaceManager = sm; + _surfaceType = surfaceType; + _selectedSurface = 0; +} + +void AddSurfaceCmd::exec(){ + _selectedSurface = _surfaceManager->getSelectedSurface(); + BaseSurface * surface = SurfaceFactory::instance()->createSurface(_surfaceType); + _surfaceManager->addSurface(surface); + _surfaceManager->selectSurface(surface); +} + +void AddSurfaceCmd::undo(){ + ofLogNotice("AddSurfaceCmd", "undo"); + _surfaceManager->removeSurface(); + _surfaceManager->selectSurface(_selectedSurface); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/AddSurfaceCmd.h b/src/Commands/AddSurfaceCmd.h index 83d2c6f..fd6e2fd 100644 --- a/src/Commands/AddSurfaceCmd.h +++ b/src/Commands/AddSurfaceCmd.h @@ -1,30 +1,30 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "SurfaceType.h" -#include "BaseSurface.h" -#include "SurfaceFactory.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class AddSurfaceCmd : public BaseUndoCmd { - - public: - AddSurfaceCmd(SurfaceManager * sm, SurfaceType surfaceType); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - SurfaceType _surfaceType; - BaseSurface * _selectedSurface; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "SurfaceType.h" +#include "BaseSurface.h" +#include "SurfaceFactory.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class AddSurfaceCmd : public BaseUndoCmd { + + public: + AddSurfaceCmd(SurfaceManager * sm, SurfaceType surfaceType); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + SurfaceType _surfaceType; + BaseSurface * _selectedSurface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/BaseCmd.h b/src/Commands/BaseCmd.h index e4aa219..d54784f 100644 --- a/src/Commands/BaseCmd.h +++ b/src/Commands/BaseCmd.h @@ -1,49 +1,49 @@ -// Command base class for separating ofxPiMapper available commands from the core. -// Created by Krisjanis Rijnieks 2015-03-23 - -// Good example -// http://gameprogrammingpatterns.com/command.html -// This file contains declarations of both: -// - non-undoable command base class -// - undoable command base class - -#pragma once - -namespace ofx { -namespace piMapper { - -// Base class for all commands -class BaseCmd { - - public: - virtual ~BaseCmd(){} - virtual void exec() = 0; - - // By default a command is not undo - virtual bool isUndoable(){ - return false; - } - - protected: - // In order to avoid using this class directly, - // we make the constructor protected. - BaseCmd(){} - -}; - -// Base class for all undoable commands -class BaseUndoCmd : public BaseCmd { - - public: - virtual void undo() = 0; - virtual bool isUndoable(){ - return true; - } - - protected: - BaseUndoCmd(){} - -}; - -} // namespace piMapper -} // namespace ofx +// Command base class for separating ofxPiMapper available commands from the core. +// Created by Krisjanis Rijnieks 2015-03-23 + +// Good example +// http://gameprogrammingpatterns.com/command.html +// This file contains declarations of both: +// - non-undoable command base class +// - undoable command base class + +#pragma once + +namespace ofx { +namespace piMapper { + +// Base class for all commands +class BaseCmd { + + public: + virtual ~BaseCmd(){} + virtual void exec() = 0; + + // By default a command is not undo + virtual bool isUndoable(){ + return false; + } + + protected: + // In order to avoid using this class directly, + // we make the constructor protected. + BaseCmd(){} + +}; + +// Base class for all undoable commands +class BaseUndoCmd : public BaseCmd { + + public: + virtual void undo() = 0; + virtual bool isUndoable(){ + return true; + } + + protected: + BaseUndoCmd(){} + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Commands/ClearSurfacesCmd.cpp b/src/Commands/ClearSurfacesCmd.cpp index a8753b8..1fa8095 100644 --- a/src/Commands/ClearSurfacesCmd.cpp +++ b/src/Commands/ClearSurfacesCmd.cpp @@ -1,27 +1,27 @@ -#include "ClearSurfacesCmd.h" - -namespace ofx { -namespace piMapper { - -ClearSurfacesCmd::ClearSurfacesCmd(SurfaceManager * sm){ - _surfaceManager = sm; - _selectedSurface = _surfaceManager->getSelectedSurface(); - _surfaces = sm->getActivePreset()->getSurfaces(); -} - -void ClearSurfacesCmd::exec(){ - _surfaceManager->deselectSurface(); - _surfaceManager->getActivePreset()->clear(); -} - -void ClearSurfacesCmd::undo(){ - ofLogNotice("ClearSurfacesCmd", "undo"); - for(unsigned int i = 0; i < _surfaces.size(); ++i){ - _surfaceManager->getActivePreset()->push_back(_surfaces[i]); - } - _surfaceManager->selectSurface(_selectedSurface); -} - -} // namespace piMapper -} // namespace ofx - +#include "ClearSurfacesCmd.h" + +namespace ofx { +namespace piMapper { + +ClearSurfacesCmd::ClearSurfacesCmd(SurfaceManager * sm){ + _surfaceManager = sm; + _selectedSurface = _surfaceManager->getSelectedSurface(); + _surfaces = sm->getActivePreset()->getSurfaces(); +} + +void ClearSurfacesCmd::exec(){ + _surfaceManager->deselectSurface(); + _surfaceManager->getActivePreset()->clear(); +} + +void ClearSurfacesCmd::undo(){ + ofLogNotice("ClearSurfacesCmd", "undo"); + for(unsigned int i = 0; i < _surfaces.size(); ++i){ + _surfaceManager->getActivePreset()->push_back(_surfaces[i]); + } + _surfaceManager->selectSurface(_selectedSurface); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/ClearSurfacesCmd.h b/src/Commands/ClearSurfacesCmd.h index a29b119..2f3870a 100644 --- a/src/Commands/ClearSurfacesCmd.h +++ b/src/Commands/ClearSurfacesCmd.h @@ -1,33 +1,33 @@ -// SelSurfaceCmd -// Provides with option to undo select surface operation. -// Created by Krisjanis Rijnieks 2015-05-14 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceStack.h" -#include "SurfaceManager.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class ClearSurfacesCmd : public BaseUndoCmd { - - public: - ClearSurfacesCmd(SurfaceManager * sm); - void exec(); - void undo(); - - private: - // Here it would make sense to have another instance of SurfaceStack - std::vector _surfaces; - SurfaceManager * _surfaceManager; - BaseSurface * _selectedSurface; - -}; - -} // namespace piMapper -} // namespace ofx - +// SelSurfaceCmd +// Provides with option to undo select surface operation. +// Created by Krisjanis Rijnieks 2015-05-14 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceStack.h" +#include "SurfaceManager.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class ClearSurfacesCmd : public BaseUndoCmd { + + public: + ClearSurfacesCmd(SurfaceManager * sm); + void exec(); + void undo(); + + private: + // Here it would make sense to have another instance of SurfaceStack + std::vector _surfaces; + SurfaceManager * _surfaceManager; + BaseSurface * _selectedSurface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/CmdManager.cpp b/src/Commands/CmdManager.cpp index 67b8c0f..9933b06 100644 --- a/src/Commands/CmdManager.cpp +++ b/src/Commands/CmdManager.cpp @@ -1,28 +1,28 @@ -#include "CmdManager.h" - -namespace ofx { -namespace piMapper { - -void CmdManager::exec(BaseCmd * cmd){ - cmd->exec(); - if(cmd->isUndoable()){ - cmdStack.push_back(static_cast (cmd)); - } -} - -void CmdManager::undo(){ - ofLogNotice("CmdManager", "undo"); - if(cmdStack.size() > 0){ - BaseUndoCmd * cmd = cmdStack.back(); - cmd->undo(); - - // Delete last command now, change this when implementing redo. - delete cmdStack.back(); - cmdStack.pop_back(); - }else{ - ofLogNotice("CmdManager", "Nothing to undo"); - } -} - -} // namespace piMapper +#include "CmdManager.h" + +namespace ofx { +namespace piMapper { + +void CmdManager::exec(BaseCmd * cmd){ + cmd->exec(); + if(cmd->isUndoable()){ + cmdStack.push_back(static_cast (cmd)); + } +} + +void CmdManager::undo(){ + ofLogNotice("CmdManager", "undo"); + if(cmdStack.size() > 0){ + BaseUndoCmd * cmd = cmdStack.back(); + cmd->undo(); + + // Delete last command now, change this when implementing redo. + delete cmdStack.back(); + cmdStack.pop_back(); + }else{ + ofLogNotice("CmdManager", "Nothing to undo"); + } +} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Commands/CmdManager.h b/src/Commands/CmdManager.h index 9628c33..f33376a 100644 --- a/src/Commands/CmdManager.h +++ b/src/Commands/CmdManager.h @@ -1,22 +1,22 @@ -#pragma once - -#include -#include "BaseCmd.h" -#include "ofLog.h" - -namespace ofx { -namespace piMapper { - -class CmdManager { - - public: - void exec(BaseCmd * cmd); - void undo(); - - private: - std::vector cmdStack; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include +#include "BaseCmd.h" +#include "ofLog.h" + +namespace ofx { +namespace piMapper { + +class CmdManager { + + public: + void exec(BaseCmd * cmd); + void undo(); + + private: + std::vector cmdStack; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Commands/DeselectSurfaceCmd.cpp b/src/Commands/DeselectSurfaceCmd.cpp index fdd6293..cebfb54 100644 --- a/src/Commands/DeselectSurfaceCmd.cpp +++ b/src/Commands/DeselectSurfaceCmd.cpp @@ -1,26 +1,26 @@ -#include "DeselectSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -DeselectSurfaceCmd::DeselectSurfaceCmd(SurfaceManager * sm){ - _surfaceManager = sm; - _surface = 0; -} - -void DeselectSurfaceCmd::exec(){ - ofLogNotice("DeselectSurfaceCmd", "exec"); - _surface = _surfaceManager->getSelectedSurface(); - _selectedVertexIndex = _surfaceManager->getSelectedVertexIndex(); - _surfaceManager->deselectSurface(); -} - -void DeselectSurfaceCmd::undo(){ - ofLogNotice("DeselectSurfaceCmd", "undo"); - _surfaceManager->selectSurface(_surface); - _surfaceManager->selectVertex(_selectedVertexIndex); -} - -} // namespace piMapper -} // namespace ofx - +#include "DeselectSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +DeselectSurfaceCmd::DeselectSurfaceCmd(SurfaceManager * sm){ + _surfaceManager = sm; + _surface = 0; +} + +void DeselectSurfaceCmd::exec(){ + ofLogNotice("DeselectSurfaceCmd", "exec"); + _surface = _surfaceManager->getSelectedSurface(); + _selectedVertexIndex = _surfaceManager->getSelectedVertexIndex(); + _surfaceManager->deselectSurface(); +} + +void DeselectSurfaceCmd::undo(){ + ofLogNotice("DeselectSurfaceCmd", "undo"); + _surfaceManager->selectSurface(_surface); + _surfaceManager->selectVertex(_selectedVertexIndex); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/DeselectSurfaceCmd.h b/src/Commands/DeselectSurfaceCmd.h index 60cf6e4..22b2666 100644 --- a/src/Commands/DeselectSurfaceCmd.h +++ b/src/Commands/DeselectSurfaceCmd.h @@ -1,28 +1,28 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "BaseSurface.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class DeselectSurfaceCmd : public BaseUndoCmd { - - public: - DeselectSurfaceCmd(SurfaceManager * sm); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - BaseSurface * _surface; - int _selectedVertexIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "BaseSurface.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class DeselectSurfaceCmd : public BaseUndoCmd { + + public: + DeselectSurfaceCmd(SurfaceManager * sm); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + BaseSurface * _surface; + int _selectedVertexIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/DeselectTexCoordCmd.cpp b/src/Commands/DeselectTexCoordCmd.cpp index 6a12984..76dbc9d 100644 --- a/src/Commands/DeselectTexCoordCmd.cpp +++ b/src/Commands/DeselectTexCoordCmd.cpp @@ -1,35 +1,35 @@ -#include "DeselectTexCoordCmd.h" - -namespace ofx { -namespace piMapper { - -DeselectTexCoordCmd::DeselectTexCoordCmd(TextureEditorWidget * te){ - _textureEditor = te; -} - -void DeselectTexCoordCmd::exec(){ - ofLogNotice("DeselectTexCoordCmd", "exec"); - - _selectedTexCoord = -1; - std::vector joints = _textureEditor->getJoints(); - for(unsigned int i = 0; i < joints.size(); ++i){ - if(joints[i]->isSelected()){ - _selectedTexCoord = i; - } - } - - _textureEditor->unselectAllJoints(); -} - -void DeselectTexCoordCmd::undo(){ - ofLogNotice("DeselectTexCoordCmd", "undo"); - if(_selectedTexCoord == -1){ - return; - } - - _textureEditor->getJoints()[_selectedTexCoord]->select(); -} - -} // namespace piMapper -} // namespace ofx - +#include "DeselectTexCoordCmd.h" + +namespace ofx { +namespace piMapper { + +DeselectTexCoordCmd::DeselectTexCoordCmd(TextureEditorWidget * te){ + _textureEditor = te; +} + +void DeselectTexCoordCmd::exec(){ + ofLogNotice("DeselectTexCoordCmd", "exec"); + + _selectedTexCoord = -1; + std::vector joints = _textureEditor->getJoints(); + for(unsigned int i = 0; i < joints.size(); ++i){ + if(joints[i]->isSelected()){ + _selectedTexCoord = i; + } + } + + _textureEditor->unselectAllJoints(); +} + +void DeselectTexCoordCmd::undo(){ + ofLogNotice("DeselectTexCoordCmd", "undo"); + if(_selectedTexCoord == -1){ + return; + } + + _textureEditor->getJoints()[_selectedTexCoord]->select(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/DeselectTexCoordCmd.h b/src/Commands/DeselectTexCoordCmd.h index 8c0f308..c41de0d 100644 --- a/src/Commands/DeselectTexCoordCmd.h +++ b/src/Commands/DeselectTexCoordCmd.h @@ -1,27 +1,27 @@ -#pragma once - -#include "BaseCmd.h" -#include "TextureEditorWidget.h" -#include "CircleJoint.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class DeselectTexCoordCmd : public BaseUndoCmd { - - public: - DeselectTexCoordCmd(TextureEditorWidget * te); - void exec(); - void undo(); - - private: - TextureEditorWidget * _textureEditor; - int _selectedTexCoord; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "TextureEditorWidget.h" +#include "CircleJoint.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class DeselectTexCoordCmd : public BaseUndoCmd { + + public: + DeselectTexCoordCmd(TextureEditorWidget * te); + void exec(); + void undo(); + + private: + TextureEditorWidget * _textureEditor; + int _selectedTexCoord; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/DuplicateSurfaceCmd.cpp b/src/Commands/DuplicateSurfaceCmd.cpp index 5e050c7..d234024 100644 --- a/src/Commands/DuplicateSurfaceCmd.cpp +++ b/src/Commands/DuplicateSurfaceCmd.cpp @@ -1,27 +1,27 @@ -#include "DuplicateSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -DuplicateSurfaceCmd::DuplicateSurfaceCmd(BaseSurface * surface, SurfaceManager * surfaceManager){ - _surface = surface; - _surfaceManager = surfaceManager; -} - -void DuplicateSurfaceCmd::exec(){ - ofLogNotice("DuplicateSurfaceCmd", "exec"); - _duplicate = _surface->clone(); - _surfaceManager->addSurface(_duplicate); - _duplicate->moveBy(Vec3(10.0f, 10.0f, 0.0f)); - _surfaceManager->selectSurface(_duplicate); -} - -void DuplicateSurfaceCmd::undo(){ - ofLogNotice("DuplicateSurfaceCmd", "undo"); - _surfaceManager->selectSurface(_surface); - _surfaceManager->deleteSurface(_duplicate); -} - -} // namespace piMapper -} // namespace ofx - +#include "DuplicateSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +DuplicateSurfaceCmd::DuplicateSurfaceCmd(BaseSurface * surface, SurfaceManager * surfaceManager){ + _surface = surface; + _surfaceManager = surfaceManager; +} + +void DuplicateSurfaceCmd::exec(){ + ofLogNotice("DuplicateSurfaceCmd", "exec"); + _duplicate = _surface->clone(); + _surfaceManager->addSurface(_duplicate); + _duplicate->moveBy(Vec3(10.0f, 10.0f, 0.0f)); + _surfaceManager->selectSurface(_duplicate); +} + +void DuplicateSurfaceCmd::undo(){ + ofLogNotice("DuplicateSurfaceCmd", "undo"); + _surfaceManager->selectSurface(_surface); + _surfaceManager->deleteSurface(_duplicate); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/DuplicateSurfaceCmd.h b/src/Commands/DuplicateSurfaceCmd.h index 801a1e1..d804518 100644 --- a/src/Commands/DuplicateSurfaceCmd.h +++ b/src/Commands/DuplicateSurfaceCmd.h @@ -1,31 +1,31 @@ -// DuplicateSurfaceCmd -// Duplicates selected surface -// Created by Krisjanis Rijnieks 2016-03-04 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class DuplicateSurfaceCmd : public BaseUndoCmd { - - public: - DuplicateSurfaceCmd(BaseSurface * surface, SurfaceManager * surfaceManager); - void exec(); - void undo(); - - private: - BaseSurface * _surface; - BaseSurface * _duplicate; - SurfaceManager * _surfaceManager; - -}; - -} // namespace piMapper -} // namespace ofx - +// DuplicateSurfaceCmd +// Duplicates selected surface +// Created by Krisjanis Rijnieks 2016-03-04 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class DuplicateSurfaceCmd : public BaseUndoCmd { + + public: + DuplicateSurfaceCmd(BaseSurface * surface, SurfaceManager * surfaceManager); + void exec(); + void undo(); + + private: + BaseSurface * _surface; + BaseSurface * _duplicate; + SurfaceManager * _surfaceManager; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/FullscreenSurfaceCmd.cpp b/src/Commands/FullscreenSurfaceCmd.cpp index 87739aa..e161931 100644 --- a/src/Commands/FullscreenSurfaceCmd.cpp +++ b/src/Commands/FullscreenSurfaceCmd.cpp @@ -1,25 +1,25 @@ -#include "FullscreenSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -FullscreenSurfaceCmd::FullscreenSurfaceCmd(BaseSurface * surface){ - _surface = surface; -} - -void FullscreenSurfaceCmd::exec(){ - ofLogNotice("FullscreenSurfaceCmd", "exec"); - _previousVertices = _surface->getVertices(); - _surface->fullScreen(); -} - -void FullscreenSurfaceCmd::undo(){ - ofLogNotice("FullscreenSurfaceCmd", "undo"); - for(int i = 0; i < _surface->getVertices().size(); i++){ - _surface->setVertex(i,_previousVertices[i]); - } -} - -} // namespace piMapper -} // namespace ofx - +#include "FullscreenSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +FullscreenSurfaceCmd::FullscreenSurfaceCmd(BaseSurface * surface){ + _surface = surface; +} + +void FullscreenSurfaceCmd::exec(){ + ofLogNotice("FullscreenSurfaceCmd", "exec"); + _previousVertices = _surface->getVertices(); + _surface->fullScreen(); +} + +void FullscreenSurfaceCmd::undo(){ + ofLogNotice("FullscreenSurfaceCmd", "undo"); + for(int i = 0; i < _surface->getVertices().size(); i++){ + _surface->setVertex(i,_previousVertices[i]); + } +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/FullscreenSurfaceCmd.h b/src/Commands/FullscreenSurfaceCmd.h index 9b3c918..144da23 100644 --- a/src/Commands/FullscreenSurfaceCmd.h +++ b/src/Commands/FullscreenSurfaceCmd.h @@ -1,29 +1,29 @@ -// FullscreenSurfaceCmd -// Makes selected surface resize to fit the screen -// Created by Pierre Proske 25-03-2020 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class FullscreenSurfaceCmd : public BaseUndoCmd { - - public: - FullscreenSurfaceCmd(BaseSurface * surface); - void exec(); - void undo(); - - private: - BaseSurface * _surface; - std::vector _previousVertices; -}; - -} // namespace piMapper -} // namespace ofx - +// FullscreenSurfaceCmd +// Makes selected surface resize to fit the screen +// Created by Pierre Proske 25-03-2020 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class FullscreenSurfaceCmd : public BaseUndoCmd { + + public: + FullscreenSurfaceCmd(BaseSurface * surface); + void exec(); + void undo(); + + private: + BaseSurface * _surface; + std::vector _previousVertices; +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvAllTexCoordsCmd.cpp b/src/Commands/MvAllTexCoordsCmd.cpp index 121dbdb..339eab0 100644 --- a/src/Commands/MvAllTexCoordsCmd.cpp +++ b/src/Commands/MvAllTexCoordsCmd.cpp @@ -1,27 +1,27 @@ -#include "MvAllTexCoordsCmd.h" - -namespace ofx { -namespace piMapper { - -MvAllTexCoordsCmd::MvAllTexCoordsCmd(BaseSurface * surface, TextureEditorWidget * texEditor){ - _surface = surface; - _texEditor = texEditor; -} - -void MvAllTexCoordsCmd::exec(){ - ofLogNotice("MvAllTexCoordsCmd", "exec"); - _texCoords = _surface->getTexCoords(); -} - -void MvAllTexCoordsCmd::undo(){ - ofLogNotice("MvAllTexCoordsCmd", "undo"); - Vec2 dist = _texCoords[0] - _surface->getTexCoords()[0]; - dist.x = _surface->getSource()->getTexture()->getWidth() * dist.x; - dist.y = _surface->getSource()->getTexture()->getHeight() * dist.y; - _texEditor->moveTexCoords(dist); - _surface = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "MvAllTexCoordsCmd.h" + +namespace ofx { +namespace piMapper { + +MvAllTexCoordsCmd::MvAllTexCoordsCmd(BaseSurface * surface, TextureEditorWidget * texEditor){ + _surface = surface; + _texEditor = texEditor; +} + +void MvAllTexCoordsCmd::exec(){ + ofLogNotice("MvAllTexCoordsCmd", "exec"); + _texCoords = _surface->getTexCoords(); +} + +void MvAllTexCoordsCmd::undo(){ + ofLogNotice("MvAllTexCoordsCmd", "undo"); + Vec2 dist = _texCoords[0] - _surface->getTexCoords()[0]; + dist.x = _surface->getSource()->getTexture()->getWidth() * dist.x; + dist.y = _surface->getSource()->getTexture()->getHeight() * dist.y; + _texEditor->moveTexCoords(dist); + _surface = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvAllTexCoordsCmd.h b/src/Commands/MvAllTexCoordsCmd.h index b6601e5..1ddff2c 100644 --- a/src/Commands/MvAllTexCoordsCmd.h +++ b/src/Commands/MvAllTexCoordsCmd.h @@ -1,31 +1,31 @@ -// MvAllTexCoordsCmd -// Move all texture coordinates of a selected surface undoable command -// Created by Krisjanis Rijnieks 2015-05-18 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "TextureEditorWidget.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class MvAllTexCoordsCmd : public BaseUndoCmd { - - public: - MvAllTexCoordsCmd(BaseSurface * surface, TextureEditorWidget * texEditor); - void exec(); - void undo(); - - private: - std::vector _texCoords; - BaseSurface * _surface; - TextureEditorWidget * _texEditor; - -}; - -} // namespace piMapper -} // namespace ofx - +// MvAllTexCoordsCmd +// Move all texture coordinates of a selected surface undoable command +// Created by Krisjanis Rijnieks 2015-05-18 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "TextureEditorWidget.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class MvAllTexCoordsCmd : public BaseUndoCmd { + + public: + MvAllTexCoordsCmd(BaseSurface * surface, TextureEditorWidget * texEditor); + void exec(); + void undo(); + + private: + std::vector _texCoords; + BaseSurface * _surface; + TextureEditorWidget * _texEditor; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvLayerDnCmd.cpp b/src/Commands/MvLayerDnCmd.cpp index 4360fdc..ea2f22a 100644 --- a/src/Commands/MvLayerDnCmd.cpp +++ b/src/Commands/MvLayerDnCmd.cpp @@ -1,46 +1,46 @@ -#include "MvLayerDnCmd.h" - -namespace ofx { -namespace piMapper { - -MvLayerDnCmd::MvLayerDnCmd(SurfaceStack * stack, BaseSurface * selectedSurface){ - _stack = stack; - _selectedSurface = selectedSurface; - _selectedSurfaceIndex = -1; -} - -void MvLayerDnCmd::exec(){ - ofLogNotice("MvLayerDnCmd", "exec"); - - // Find selected surface index in SurfaceStack. - for(int i = 0; i < _stack->size(); ++i){ - if(_selectedSurface == _stack->at(i)){ - _selectedSurfaceIndex = i; - break; - } - } - - if(_selectedSurfaceIndex == -1){ - throw runtime_error("MvLayerUpCmd used with no surface selected"); - } - - if(_selectedSurfaceIndex == 0){ - throw runtime_error("Check if selected surface is not bottom before using MvLayerUpCmd"); - } - - if(_stack->size() <= 1){ - throw runtime_error("Check if there is more than one surface before using MvLayerUpCmd"); - } - - // Swap it with the previous surface - _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex - 1); -} - -void MvLayerDnCmd::undo(){ - ofLogNotice("MvLayerDnCmd", "undo"); - _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex - 1); -} - -} // namespace piMapper -} // namespace ofx - +#include "MvLayerDnCmd.h" + +namespace ofx { +namespace piMapper { + +MvLayerDnCmd::MvLayerDnCmd(SurfaceStack * stack, BaseSurface * selectedSurface){ + _stack = stack; + _selectedSurface = selectedSurface; + _selectedSurfaceIndex = -1; +} + +void MvLayerDnCmd::exec(){ + ofLogNotice("MvLayerDnCmd", "exec"); + + // Find selected surface index in SurfaceStack. + for(int i = 0; i < _stack->size(); ++i){ + if(_selectedSurface == _stack->at(i)){ + _selectedSurfaceIndex = i; + break; + } + } + + if(_selectedSurfaceIndex == -1){ + throw runtime_error("MvLayerUpCmd used with no surface selected"); + } + + if(_selectedSurfaceIndex == 0){ + throw runtime_error("Check if selected surface is not bottom before using MvLayerUpCmd"); + } + + if(_stack->size() <= 1){ + throw runtime_error("Check if there is more than one surface before using MvLayerUpCmd"); + } + + // Swap it with the previous surface + _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex - 1); +} + +void MvLayerDnCmd::undo(){ + ofLogNotice("MvLayerDnCmd", "undo"); + _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex - 1); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvLayerDnCmd.h b/src/Commands/MvLayerDnCmd.h index 9280da6..39334a1 100644 --- a/src/Commands/MvLayerDnCmd.h +++ b/src/Commands/MvLayerDnCmd.h @@ -1,28 +1,28 @@ -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceStack.h" - -namespace ofx { -namespace piMapper { - -class MvLayerDnCmd : public BaseUndoCmd { - - public: - MvLayerDnCmd(SurfaceStack * stack, BaseSurface * selectedSurface); - void exec(); - void undo(); - - private: - SurfaceStack * _stack; - - BaseSurface * _selectedSurface; - - int _selectedSurfaceIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceStack.h" + +namespace ofx { +namespace piMapper { + +class MvLayerDnCmd : public BaseUndoCmd { + + public: + MvLayerDnCmd(SurfaceStack * stack, BaseSurface * selectedSurface); + void exec(); + void undo(); + + private: + SurfaceStack * _stack; + + BaseSurface * _selectedSurface; + + int _selectedSurfaceIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvLayerUpCmd.cpp b/src/Commands/MvLayerUpCmd.cpp index ef0e31d..dcfabd2 100644 --- a/src/Commands/MvLayerUpCmd.cpp +++ b/src/Commands/MvLayerUpCmd.cpp @@ -1,46 +1,46 @@ -#include "MvLayerUpCmd.h" - -namespace ofx { -namespace piMapper { - -MvLayerUpCmd::MvLayerUpCmd(SurfaceStack * stack, BaseSurface * selectedSurface){ - _stack = stack; - _selectedSurface = selectedSurface; - _selectedSurfaceIndex = -1; -} - -void MvLayerUpCmd::exec(){ - ofLogNotice("MvLayerUpCmd", "exec"); - - // Find selected surface index in SurfaceStack. - for(int i = 0; i < _stack->size(); ++i){ - if(_selectedSurface == _stack->at(i)){ - _selectedSurfaceIndex = i; - break; - } - } - - if(_selectedSurfaceIndex == -1){ - throw runtime_error("MvLayerUpCmd used with no surface selected"); - } - - if(_selectedSurfaceIndex == _stack->size() - 1){ - throw runtime_error("Check if selected surface is not top before using MvLayerUpCmd"); - } - - if(_stack->size() <= 1){ - throw runtime_error("Check if there is more than one surface before using MvLayerUpCmd"); - } - - // Swap it with the next surface - _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex + 1); -} - -void MvLayerUpCmd::undo(){ - ofLogNotice("MvLayerUoCmd", "undo"); - _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex + 1); -} - -} // namespace piMapper -} // namespace ofx - +#include "MvLayerUpCmd.h" + +namespace ofx { +namespace piMapper { + +MvLayerUpCmd::MvLayerUpCmd(SurfaceStack * stack, BaseSurface * selectedSurface){ + _stack = stack; + _selectedSurface = selectedSurface; + _selectedSurfaceIndex = -1; +} + +void MvLayerUpCmd::exec(){ + ofLogNotice("MvLayerUpCmd", "exec"); + + // Find selected surface index in SurfaceStack. + for(int i = 0; i < _stack->size(); ++i){ + if(_selectedSurface == _stack->at(i)){ + _selectedSurfaceIndex = i; + break; + } + } + + if(_selectedSurfaceIndex == -1){ + throw runtime_error("MvLayerUpCmd used with no surface selected"); + } + + if(_selectedSurfaceIndex == _stack->size() - 1){ + throw runtime_error("Check if selected surface is not top before using MvLayerUpCmd"); + } + + if(_stack->size() <= 1){ + throw runtime_error("Check if there is more than one surface before using MvLayerUpCmd"); + } + + // Swap it with the next surface + _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex + 1); +} + +void MvLayerUpCmd::undo(){ + ofLogNotice("MvLayerUoCmd", "undo"); + _stack->swap(_selectedSurfaceIndex, _selectedSurfaceIndex + 1); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvLayerUpCmd.h b/src/Commands/MvLayerUpCmd.h index 5f15608..cfa4e4c 100644 --- a/src/Commands/MvLayerUpCmd.h +++ b/src/Commands/MvLayerUpCmd.h @@ -1,27 +1,27 @@ -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceStack.h" - -namespace ofx { -namespace piMapper { - -class MvLayerUpCmd : public BaseUndoCmd { - - public: - MvLayerUpCmd(SurfaceStack * stack, BaseSurface * selectedSurface); - void exec(); - void undo(); - - private: - SurfaceStack * _stack; - BaseSurface * _selectedSurface; - - int _selectedSurfaceIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceStack.h" + +namespace ofx { +namespace piMapper { + +class MvLayerUpCmd : public BaseUndoCmd { + + public: + MvLayerUpCmd(SurfaceStack * stack, BaseSurface * selectedSurface); + void exec(); + void undo(); + + private: + SurfaceStack * _stack; + BaseSurface * _selectedSurface; + + int _selectedSurfaceIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvSelectionCmd.cpp b/src/Commands/MvSelectionCmd.cpp index ff346c8..73c0082 100644 --- a/src/Commands/MvSelectionCmd.cpp +++ b/src/Commands/MvSelectionCmd.cpp @@ -1,23 +1,23 @@ -#include "MvSelectionCmd.h" - -namespace ofx { -namespace piMapper { - -MvSelectionCmd::MvSelectionCmd(SurfaceManager * sm, Vec3 moveBy){ - _surfaceManager = sm; - _movedBy = moveBy; -} - -void MvSelectionCmd::exec(){ - ofLogNotice("MvSelectionCmd", "exec"); - _surfaceManager->moveSelectionBy(_movedBy); -} - -void MvSelectionCmd::undo(){ - ofLogNotice("MvSelectionCmd", "undo"); - _surfaceManager->moveSelectionBy(-_movedBy); -} - -} // namespace piMapper -} // namespace ofx - +#include "MvSelectionCmd.h" + +namespace ofx { +namespace piMapper { + +MvSelectionCmd::MvSelectionCmd(SurfaceManager * sm, Vec3 moveBy){ + _surfaceManager = sm; + _movedBy = moveBy; +} + +void MvSelectionCmd::exec(){ + ofLogNotice("MvSelectionCmd", "exec"); + _surfaceManager->moveSelectionBy(_movedBy); +} + +void MvSelectionCmd::undo(){ + ofLogNotice("MvSelectionCmd", "undo"); + _surfaceManager->moveSelectionBy(-_movedBy); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvSelectionCmd.h b/src/Commands/MvSelectionCmd.h index 0881429..1ebefb5 100644 --- a/src/Commands/MvSelectionCmd.h +++ b/src/Commands/MvSelectionCmd.h @@ -1,25 +1,25 @@ -#pragma once - -#include "BaseCmd.h" -#include "SurfaceManager.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class MvSelectionCmd : public BaseUndoCmd { - - public: - MvSelectionCmd(SurfaceManager * sm, Vec3 moveBy); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - Vec3 _movedBy; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "SurfaceManager.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class MvSelectionCmd : public BaseUndoCmd { + + public: + MvSelectionCmd(SurfaceManager * sm, Vec3 moveBy); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + Vec3 _movedBy; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvSurfaceVertCmd.cpp b/src/Commands/MvSurfaceVertCmd.cpp index 8feb78c..35653fc 100644 --- a/src/Commands/MvSurfaceVertCmd.cpp +++ b/src/Commands/MvSurfaceVertCmd.cpp @@ -1,23 +1,23 @@ -#include "MvSurfaceVertCmd.h" - -namespace ofx { -namespace piMapper { - -MvSurfaceVertCmd::MvSurfaceVertCmd(int vertIndex, BaseSurface * surface){ - _vertIndex = vertIndex; - _surface = surface; -} - -void MvSurfaceVertCmd::exec(){ - ofLogNotice("MvSurfaceVertCommand", "exec"); - _prevVertPos = _surface->getVertices()[_vertIndex]; -} - -void MvSurfaceVertCmd::undo(){ - ofLogNotice("MvSurfaceVertCommand", "undo"); - _surface->setVertex(_vertIndex, _prevVertPos); -} - -} // namespace piMapper -} // namespace ofx - +#include "MvSurfaceVertCmd.h" + +namespace ofx { +namespace piMapper { + +MvSurfaceVertCmd::MvSurfaceVertCmd(int vertIndex, BaseSurface * surface){ + _vertIndex = vertIndex; + _surface = surface; +} + +void MvSurfaceVertCmd::exec(){ + ofLogNotice("MvSurfaceVertCommand", "exec"); + _prevVertPos = _surface->getVertices()[_vertIndex]; +} + +void MvSurfaceVertCmd::undo(){ + ofLogNotice("MvSurfaceVertCommand", "undo"); + _surface->setVertex(_vertIndex, _prevVertPos); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvSurfaceVertCmd.h b/src/Commands/MvSurfaceVertCmd.h index c3abd9f..b331eeb 100644 --- a/src/Commands/MvSurfaceVertCmd.h +++ b/src/Commands/MvSurfaceVertCmd.h @@ -1,32 +1,32 @@ -// MvSurfaceVertCmd -// Provides with option to undo move surface vertex operation. -// Created by Krisjanis Rijnieks 2015-05-15 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "ProjectionEditorWidget.h" -#include "BaseJoint.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class MvSurfaceVertCmd : public BaseUndoCmd { - - public: - MvSurfaceVertCmd(int vertIndex, BaseSurface * surface); - void exec(); - void undo(); - - private: - int _vertIndex; - Vec3 _prevVertPos; - BaseSurface * _surface; - -}; - -} // namespace piMapper -} // namespace ofx - +// MvSurfaceVertCmd +// Provides with option to undo move surface vertex operation. +// Created by Krisjanis Rijnieks 2015-05-15 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "ProjectionEditorWidget.h" +#include "BaseJoint.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class MvSurfaceVertCmd : public BaseUndoCmd { + + public: + MvSurfaceVertCmd(int vertIndex, BaseSurface * surface); + void exec(); + void undo(); + + private: + int _vertIndex; + Vec3 _prevVertPos; + BaseSurface * _surface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvTexCoordCmd.cpp b/src/Commands/MvTexCoordCmd.cpp index 53b9450..e85f444 100644 --- a/src/Commands/MvTexCoordCmd.cpp +++ b/src/Commands/MvTexCoordCmd.cpp @@ -1,31 +1,31 @@ -#include "MvTexCoordCmd.h" - -namespace ofx { -namespace piMapper { - -MvTexCoordCmd::MvTexCoordCmd(int texCoordIndex, Vec2 by){ - _texCoordIndex = texCoordIndex; - _moveBy = by; -} - -void MvTexCoordCmd::exec(){ - ofLogNotice("MvTexCoordCmd", "exec"); - _positionBefore = - Gui::instance()->getTextureEditorWidget().getJoints()[_texCoordIndex]->position; - Gui::instance()->getTextureEditorWidget().moveSelection(_moveBy); -} - -void MvTexCoordCmd::undo(){ - ofLogNotice("MvTexCoordCmd", "undo"); - // TODO: Set position exactly to the one stored in _positionBefore - Gui::instance()->getTextureEditorWidget().moveSelection(-_moveBy); - - //_texEditor->unselectAllJoints(); - //_texEditor->getJoints()[_jointIndex]->select(); - //_texEditor->getJoints()[_jointIndex]->position = _jointPosition; - //_texEditor = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "MvTexCoordCmd.h" + +namespace ofx { +namespace piMapper { + +MvTexCoordCmd::MvTexCoordCmd(int texCoordIndex, Vec2 by){ + _texCoordIndex = texCoordIndex; + _moveBy = by; +} + +void MvTexCoordCmd::exec(){ + ofLogNotice("MvTexCoordCmd", "exec"); + _positionBefore = + Gui::instance()->getTextureEditorWidget().getJoints()[_texCoordIndex]->position; + Gui::instance()->getTextureEditorWidget().moveSelection(_moveBy); +} + +void MvTexCoordCmd::undo(){ + ofLogNotice("MvTexCoordCmd", "undo"); + // TODO: Set position exactly to the one stored in _positionBefore + Gui::instance()->getTextureEditorWidget().moveSelection(-_moveBy); + + //_texEditor->unselectAllJoints(); + //_texEditor->getJoints()[_jointIndex]->select(); + //_texEditor->getJoints()[_jointIndex]->position = _jointPosition; + //_texEditor = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/MvTexCoordCmd.h b/src/Commands/MvTexCoordCmd.h index 950ebf0..c3190bb 100644 --- a/src/Commands/MvTexCoordCmd.h +++ b/src/Commands/MvTexCoordCmd.h @@ -1,31 +1,31 @@ -// MvTexCoordCmd -// Move texture coordinate of a selected surface and be able to undo it -// Created by Krisjanis Rijnieks 2015-05-19 - -#pragma once - -#include "BaseCmd.h" -#include "CircleJoint.h" -#include "Gui.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class MvTexCoordCmd : public BaseUndoCmd { - - public: - MvTexCoordCmd(int texCoordIndex, Vec2 by); - void exec(); - void undo(); - - private: - int _texCoordIndex; - Vec2 _moveBy; - Vec2 _positionBefore; - -}; - -} // namespace piMapper -} // namespace ofx - +// MvTexCoordCmd +// Move texture coordinate of a selected surface and be able to undo it +// Created by Krisjanis Rijnieks 2015-05-19 + +#pragma once + +#include "BaseCmd.h" +#include "CircleJoint.h" +#include "Gui.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class MvTexCoordCmd : public BaseUndoCmd { + + public: + MvTexCoordCmd(int texCoordIndex, Vec2 by); + void exec(); + void undo(); + + private: + int _texCoordIndex; + Vec2 _moveBy; + Vec2 _positionBefore; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmGridColCmd.cpp b/src/Commands/RmGridColCmd.cpp index 6f2e567..71da8b6 100644 --- a/src/Commands/RmGridColCmd.cpp +++ b/src/Commands/RmGridColCmd.cpp @@ -1,39 +1,39 @@ -#include "RmGridColCmd.h" - -namespace ofx { -namespace piMapper { - -RmGridColCmd::RmGridColCmd(GridWarpSurface * s){ - _surface = s; - _doNotUndo = false; -} - -void RmGridColCmd::exec(){ - - // TODO: Figure out nice math to not loose existing vertex positions - - if(_surface->getGridCols() > 1){ - _vertices = _surface->getVertices(); - _texCoords = _surface->getTexCoords(); - _surface->setGridCols(_surface->getGridCols() - 1); - }else{ - _doNotUndo = true; - } - -} - -void RmGridColCmd::undo(){ - ofLogNotice("RmGridColCmd", "undo"); - - if(_doNotUndo){ - return; - } - - _surface->setGridCols(_surface->getGridCols() + 1); - _surface->setVertices(_vertices); - _surface->setTexCoords(_texCoords); -} - -} // namespace piMapper -} // namespace ofx - +#include "RmGridColCmd.h" + +namespace ofx { +namespace piMapper { + +RmGridColCmd::RmGridColCmd(GridWarpSurface * s){ + _surface = s; + _doNotUndo = false; +} + +void RmGridColCmd::exec(){ + + // TODO: Figure out nice math to not loose existing vertex positions + + if(_surface->getGridCols() > 1){ + _vertices = _surface->getVertices(); + _texCoords = _surface->getTexCoords(); + _surface->setGridCols(_surface->getGridCols() - 1); + }else{ + _doNotUndo = true; + } + +} + +void RmGridColCmd::undo(){ + ofLogNotice("RmGridColCmd", "undo"); + + if(_doNotUndo){ + return; + } + + _surface->setGridCols(_surface->getGridCols() + 1); + _surface->setVertices(_vertices); + _surface->setTexCoords(_texCoords); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmGridColCmd.h b/src/Commands/RmGridColCmd.h index ced88d6..1e6fcfd 100644 --- a/src/Commands/RmGridColCmd.h +++ b/src/Commands/RmGridColCmd.h @@ -1,32 +1,32 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "GridWarpSurface.h" -#include "ProjectionEditorWidget.h" -#include "Vec2.h" -#include "Vec3.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class RmGridColCmd : public BaseUndoCmd { - - public: - RmGridColCmd(GridWarpSurface * s); - void exec(); - void undo(); - - private: - std::vector _vertices; - std::vector _texCoords; - GridWarpSurface * _surface; - bool _doNotUndo; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "GridWarpSurface.h" +#include "ProjectionEditorWidget.h" +#include "Vec2.h" +#include "Vec3.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class RmGridColCmd : public BaseUndoCmd { + + public: + RmGridColCmd(GridWarpSurface * s); + void exec(); + void undo(); + + private: + std::vector _vertices; + std::vector _texCoords; + GridWarpSurface * _surface; + bool _doNotUndo; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmGridRowCmd.cpp b/src/Commands/RmGridRowCmd.cpp index 36de4ee..005efd3 100644 --- a/src/Commands/RmGridRowCmd.cpp +++ b/src/Commands/RmGridRowCmd.cpp @@ -1,39 +1,39 @@ -#include "RmGridRowCmd.h" - -namespace ofx { -namespace piMapper { - -RmGridRowCmd::RmGridRowCmd(GridWarpSurface * s){ - _surface = s; - _doNotUndo = false; -} - -void RmGridRowCmd::exec(){ - - // TODO: Figure out nice math to not loose existing vertex positions - - if(_surface->getGridRows() > 1){ - _vertices = _surface->getVertices(); - _texCoords = _surface->getTexCoords(); - _surface->setGridRows(_surface->getGridRows() - 1); - }else{ - _doNotUndo = true; - } - -} - -void RmGridRowCmd::undo(){ - ofLogNotice("RmGridRowCmd", "undo"); - - if(_doNotUndo){ - return; - } - - _surface->setGridRows(_surface->getGridRows() + 1); - _surface->setVertices(_vertices); - _surface->setTexCoords(_texCoords); -} - -} // namespace piMapper -} // namespace ofx - +#include "RmGridRowCmd.h" + +namespace ofx { +namespace piMapper { + +RmGridRowCmd::RmGridRowCmd(GridWarpSurface * s){ + _surface = s; + _doNotUndo = false; +} + +void RmGridRowCmd::exec(){ + + // TODO: Figure out nice math to not loose existing vertex positions + + if(_surface->getGridRows() > 1){ + _vertices = _surface->getVertices(); + _texCoords = _surface->getTexCoords(); + _surface->setGridRows(_surface->getGridRows() - 1); + }else{ + _doNotUndo = true; + } + +} + +void RmGridRowCmd::undo(){ + ofLogNotice("RmGridRowCmd", "undo"); + + if(_doNotUndo){ + return; + } + + _surface->setGridRows(_surface->getGridRows() + 1); + _surface->setVertices(_vertices); + _surface->setTexCoords(_texCoords); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmGridRowCmd.h b/src/Commands/RmGridRowCmd.h index 32d2c3e..40bfd33 100644 --- a/src/Commands/RmGridRowCmd.h +++ b/src/Commands/RmGridRowCmd.h @@ -1,32 +1,32 @@ -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "GridWarpSurface.h" -#include "ProjectionEditorWidget.h" -#include "Vec2.h" -#include "Vec3.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class RmGridRowCmd : public BaseUndoCmd { - - public: - RmGridRowCmd(GridWarpSurface * s); - void exec(); - void undo(); - - private: - std::vector _vertices; - std::vector _texCoords; - GridWarpSurface * _surface; - bool _doNotUndo; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "GridWarpSurface.h" +#include "ProjectionEditorWidget.h" +#include "Vec2.h" +#include "Vec3.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class RmGridRowCmd : public BaseUndoCmd { + + public: + RmGridRowCmd(GridWarpSurface * s); + void exec(); + void undo(); + + private: + std::vector _vertices; + std::vector _texCoords; + GridWarpSurface * _surface; + bool _doNotUndo; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmSurfaceCmd.cpp b/src/Commands/RmSurfaceCmd.cpp index 2183615..5032093 100644 --- a/src/Commands/RmSurfaceCmd.cpp +++ b/src/Commands/RmSurfaceCmd.cpp @@ -1,32 +1,32 @@ -#include "RmSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -RmSurfaceCmd::RmSurfaceCmd(SurfaceManager * sm, int i){ - _surfaceManager = sm; - _surface = 0; - _surfaceIndex = i; -} - -void RmSurfaceCmd::exec(){ - // Store the surface, this implies that the surfaceManager's - // removeSelectedSurface does not destroy the surface. - // The owner is being changed. - _surface = _surfaceManager->getSurface(_surfaceIndex); - _surfaceManager->removeSurface(_surfaceIndex); -} - -void RmSurfaceCmd::undo(){ - ofLogNotice("RmSurfaceCmd", "undo"); - if(_surface == 0){ - ofLogError("RmSurfaceCmd", "No surface stored"); - } - _surfaceManager->addSurface(_surface); - _surfaceManager->selectSurface(_surface); - _surface = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "RmSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +RmSurfaceCmd::RmSurfaceCmd(SurfaceManager * sm, int i){ + _surfaceManager = sm; + _surface = 0; + _surfaceIndex = i; +} + +void RmSurfaceCmd::exec(){ + // Store the surface, this implies that the surfaceManager's + // removeSelectedSurface does not destroy the surface. + // The owner is being changed. + _surface = _surfaceManager->getSurface(_surfaceIndex); + _surfaceManager->removeSurface(_surfaceIndex); +} + +void RmSurfaceCmd::undo(){ + ofLogNotice("RmSurfaceCmd", "undo"); + if(_surface == 0){ + ofLogError("RmSurfaceCmd", "No surface stored"); + } + _surfaceManager->addSurface(_surface); + _surfaceManager->selectSurface(_surface); + _surface = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/RmSurfaceCmd.h b/src/Commands/RmSurfaceCmd.h index d75805a..774c901 100644 --- a/src/Commands/RmSurfaceCmd.h +++ b/src/Commands/RmSurfaceCmd.h @@ -1,32 +1,32 @@ -// RmSurfaceCmd -// Provides with option to undo remove surface operation. -// Created by Krisjanis Rijnieks 2015-05-14 - -#pragma once - -#include "SurfaceManager.h" -#include "BaseCmd.h" -#include "BaseSurface.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class RmSurfaceCmd : public BaseUndoCmd { - - public: - RmSurfaceCmd(SurfaceManager * sm, int i); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - BaseSurface * _surface; - int _surfaceIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +// RmSurfaceCmd +// Provides with option to undo remove surface operation. +// Created by Krisjanis Rijnieks 2015-05-14 + +#pragma once + +#include "SurfaceManager.h" +#include "BaseCmd.h" +#include "BaseSurface.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class RmSurfaceCmd : public BaseUndoCmd { + + public: + RmSurfaceCmd(SurfaceManager * sm, int i); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + BaseSurface * _surface; + int _surfaceIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SaveTexCoordPosCmd.cpp b/src/Commands/SaveTexCoordPosCmd.cpp index 323cc2e..75693f1 100644 --- a/src/Commands/SaveTexCoordPosCmd.cpp +++ b/src/Commands/SaveTexCoordPosCmd.cpp @@ -1,22 +1,22 @@ -#include "SaveTexCoordPosCmd.h" - -namespace ofx { -namespace piMapper { - -SaveTexCoordPosCmd::SaveTexCoordPosCmd(int texCoordIndex, Vec2 position){ - _texCoordIndex = texCoordIndex; - _position = position; -} - -void SaveTexCoordPosCmd::exec(){ - ofLogNotice("SaveTexCoordPosCmd", "exec"); -} - -void SaveTexCoordPosCmd::undo(){ - ofLogNotice("SaveTexCoordPosCmd", "undo"); - Gui::instance()->getTextureEditorWidget().moveTexCoordTo(_texCoordIndex, _position); -} - -} // namespace piMapper -} // namespace ofx - +#include "SaveTexCoordPosCmd.h" + +namespace ofx { +namespace piMapper { + +SaveTexCoordPosCmd::SaveTexCoordPosCmd(int texCoordIndex, Vec2 position){ + _texCoordIndex = texCoordIndex; + _position = position; +} + +void SaveTexCoordPosCmd::exec(){ + ofLogNotice("SaveTexCoordPosCmd", "exec"); +} + +void SaveTexCoordPosCmd::undo(){ + ofLogNotice("SaveTexCoordPosCmd", "undo"); + Gui::instance()->getTextureEditorWidget().moveTexCoordTo(_texCoordIndex, _position); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SaveTexCoordPosCmd.h b/src/Commands/SaveTexCoordPosCmd.h index aec4af8..93b0ebf 100644 --- a/src/Commands/SaveTexCoordPosCmd.h +++ b/src/Commands/SaveTexCoordPosCmd.h @@ -1,30 +1,30 @@ -// SaveTexCoordPosCmd -// Saves current position of the texture coordinate and resets it. -// Created by Krisjanis Rijnieks 2016-10-30 - -#pragma once - -#include "BaseCmd.h" -#include "CircleJoint.h" -#include "Gui.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class SaveTexCoordPosCmd : public BaseUndoCmd { - - public: - SaveTexCoordPosCmd(int texCoordIndex, Vec2 position); - void exec(); - void undo(); - - private: - int _texCoordIndex; - Vec2 _position; - -}; - -} // namespace piMapper -} // namespace ofx - +// SaveTexCoordPosCmd +// Saves current position of the texture coordinate and resets it. +// Created by Krisjanis Rijnieks 2016-10-30 + +#pragma once + +#include "BaseCmd.h" +#include "CircleJoint.h" +#include "Gui.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class SaveTexCoordPosCmd : public BaseUndoCmd { + + public: + SaveTexCoordPosCmd(int texCoordIndex, Vec2 position); + void exec(); + void undo(); + + private: + int _texCoordIndex; + Vec2 _position; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/ScaleSurfaceFromToCmd.cpp b/src/Commands/ScaleSurfaceFromToCmd.cpp index 03f909a..1d620cd 100644 --- a/src/Commands/ScaleSurfaceFromToCmd.cpp +++ b/src/Commands/ScaleSurfaceFromToCmd.cpp @@ -1,24 +1,24 @@ -#include "ScaleSurfaceFromToCmd.h" - -namespace ofx { -namespace piMapper { - -ScaleSurfaceFromToCmd::ScaleSurfaceFromToCmd(BaseSurface * selectedSurface, float from, float to){ - _selectedSurface = selectedSurface; - _scaleFrom = from; - _scaleTo = to; -} - -void ScaleSurfaceFromToCmd::exec(){ - ofLogNotice("ScaleSurfaceFromToCmd", "exec"); - _selectedSurface->scaleTo(_scaleTo); -} - -void ScaleSurfaceFromToCmd::undo(){ - ofLogNotice("ScaleSurfaceFromToCmd", "undo"); - _selectedSurface->scaleTo(_scaleFrom); -} - -} // namespace piMapper -} // namespace ofx - +#include "ScaleSurfaceFromToCmd.h" + +namespace ofx { +namespace piMapper { + +ScaleSurfaceFromToCmd::ScaleSurfaceFromToCmd(BaseSurface * selectedSurface, float from, float to){ + _selectedSurface = selectedSurface; + _scaleFrom = from; + _scaleTo = to; +} + +void ScaleSurfaceFromToCmd::exec(){ + ofLogNotice("ScaleSurfaceFromToCmd", "exec"); + _selectedSurface->scaleTo(_scaleTo); +} + +void ScaleSurfaceFromToCmd::undo(){ + ofLogNotice("ScaleSurfaceFromToCmd", "undo"); + _selectedSurface->scaleTo(_scaleFrom); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/ScaleSurfaceFromToCmd.h b/src/Commands/ScaleSurfaceFromToCmd.h index 20ac959..0c17a2e 100644 --- a/src/Commands/ScaleSurfaceFromToCmd.h +++ b/src/Commands/ScaleSurfaceFromToCmd.h @@ -1,26 +1,26 @@ -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" - -namespace ofx { -namespace piMapper { - -class ScaleSurfaceFromToCmd : public BaseUndoCmd { - - public: - ScaleSurfaceFromToCmd(BaseSurface * selectedSurface, float from, float to); - void exec(); - void undo(); - - private: - BaseSurface * _selectedSurface; - - float _scaleFrom; - float _scaleTo; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" + +namespace ofx { +namespace piMapper { + +class ScaleSurfaceFromToCmd : public BaseUndoCmd { + + public: + ScaleSurfaceFromToCmd(BaseSurface * selectedSurface, float from, float to); + void exec(); + void undo(); + + private: + BaseSurface * _selectedSurface; + + float _scaleFrom; + float _scaleTo; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextSurfaceCmd.cpp b/src/Commands/SelNextSurfaceCmd.cpp index 72ea110..dd38617 100644 --- a/src/Commands/SelNextSurfaceCmd.cpp +++ b/src/Commands/SelNextSurfaceCmd.cpp @@ -1,26 +1,26 @@ -#include "SelNextSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -SelNextSurfaceCmd::SelNextSurfaceCmd(SurfaceManager * surfaceManager){ - _surfaceManager = surfaceManager; -} - -void SelNextSurfaceCmd::exec(){ - ofLogNotice("SelNextSurfaceCmd", "exec"); - _prevSelectedSurface = _surfaceManager->getSelectedSurface(); - _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); - _surfaceManager->selectNextSurface(); -} - -void SelNextSurfaceCmd::undo(){ - ofLogNotice("SelNextSurfaceCmd", "undo"); - _surfaceManager->selectSurface(_prevSelectedSurface); - _surfaceManager->selectVertex(_prevSelectedVertex); - _prevSelectedSurface = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "SelNextSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +SelNextSurfaceCmd::SelNextSurfaceCmd(SurfaceManager * surfaceManager){ + _surfaceManager = surfaceManager; +} + +void SelNextSurfaceCmd::exec(){ + ofLogNotice("SelNextSurfaceCmd", "exec"); + _prevSelectedSurface = _surfaceManager->getSelectedSurface(); + _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); + _surfaceManager->selectNextSurface(); +} + +void SelNextSurfaceCmd::undo(){ + ofLogNotice("SelNextSurfaceCmd", "undo"); + _surfaceManager->selectSurface(_prevSelectedSurface); + _surfaceManager->selectVertex(_prevSelectedVertex); + _prevSelectedSurface = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextSurfaceCmd.h b/src/Commands/SelNextSurfaceCmd.h index 3cbf7ff..52b37ac 100644 --- a/src/Commands/SelNextSurfaceCmd.h +++ b/src/Commands/SelNextSurfaceCmd.h @@ -1,31 +1,31 @@ -// SelNextSurfaceCmd -// Selects next surface in the projection mapping mode -// Created by Krisjanis Rijnieks 2016-02-03 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class SelNextSurfaceCmd : public BaseUndoCmd { - - public: - SelNextSurfaceCmd(SurfaceManager * surfaceManager); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - BaseSurface * _prevSelectedSurface; - int _prevSelectedVertex; - -}; - -} // namespace piMapper -} // namespace ofx - +// SelNextSurfaceCmd +// Selects next surface in the projection mapping mode +// Created by Krisjanis Rijnieks 2016-02-03 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class SelNextSurfaceCmd : public BaseUndoCmd { + + public: + SelNextSurfaceCmd(SurfaceManager * surfaceManager); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + BaseSurface * _prevSelectedSurface; + int _prevSelectedVertex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextTexCoordCmd.cpp b/src/Commands/SelNextTexCoordCmd.cpp index 4d007fd..b2c6635 100644 --- a/src/Commands/SelNextTexCoordCmd.cpp +++ b/src/Commands/SelNextTexCoordCmd.cpp @@ -1,24 +1,24 @@ -#include "SelNextTexCoordCmd.h" - -namespace ofx { -namespace piMapper { - -SelNextTexCoordCmd::SelNextTexCoordCmd(TextureEditorWidget * te){ - _textureEditor = te; -} - -void SelNextTexCoordCmd::exec(){ - ofLogNotice("SelNextTexCoordCmd", "exec"); - _prevSelection = _textureEditor->getSelectedTexCoord(); - _textureEditor->selectNextTexCoord(); -} - -void SelNextTexCoordCmd::undo(){ - ofLogNotice("SelNextTexCoordCmd", "undo"); - //_textureEditor->selectPrevTexCoord(); - _textureEditor->selectTexCoord(_prevSelection); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelNextTexCoordCmd.h" + +namespace ofx { +namespace piMapper { + +SelNextTexCoordCmd::SelNextTexCoordCmd(TextureEditorWidget * te){ + _textureEditor = te; +} + +void SelNextTexCoordCmd::exec(){ + ofLogNotice("SelNextTexCoordCmd", "exec"); + _prevSelection = _textureEditor->getSelectedTexCoord(); + _textureEditor->selectNextTexCoord(); +} + +void SelNextTexCoordCmd::undo(){ + ofLogNotice("SelNextTexCoordCmd", "undo"); + //_textureEditor->selectPrevTexCoord(); + _textureEditor->selectTexCoord(_prevSelection); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextTexCoordCmd.h b/src/Commands/SelNextTexCoordCmd.h index b638f87..9640a62 100644 --- a/src/Commands/SelNextTexCoordCmd.h +++ b/src/Commands/SelNextTexCoordCmd.h @@ -1,26 +1,26 @@ -#pragma once - -#include "BaseCmd.h" -#include "TextureEditorWidget.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelNextTexCoordCmd : public BaseUndoCmd { - - public: - SelNextTexCoordCmd(TextureEditorWidget * te); - void exec(); - void undo(); - - private: - TextureEditorWidget * _textureEditor; - int _prevSelection; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "TextureEditorWidget.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelNextTexCoordCmd : public BaseUndoCmd { + + public: + SelNextTexCoordCmd(TextureEditorWidget * te); + void exec(); + void undo(); + + private: + TextureEditorWidget * _textureEditor; + int _prevSelection; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextVertexCmd.cpp b/src/Commands/SelNextVertexCmd.cpp index 8d89dbd..c466e25 100644 --- a/src/Commands/SelNextVertexCmd.cpp +++ b/src/Commands/SelNextVertexCmd.cpp @@ -1,21 +1,21 @@ -#include "SelNextVertexCmd.h" - -namespace ofx { -namespace piMapper { - -SelNextVertexCmd::SelNextVertexCmd(SurfaceManager * sm){ - _surfaceManager = sm; -} - -void SelNextVertexCmd::exec(){ - _surfaceManager->selectNextVertex(); -} - -void SelNextVertexCmd::undo(){ - ofLogNotice("SelNextVertexCmd", "undo"); - _surfaceManager->selectPrevVertex(); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelNextVertexCmd.h" + +namespace ofx { +namespace piMapper { + +SelNextVertexCmd::SelNextVertexCmd(SurfaceManager * sm){ + _surfaceManager = sm; +} + +void SelNextVertexCmd::exec(){ + _surfaceManager->selectNextVertex(); +} + +void SelNextVertexCmd::undo(){ + ofLogNotice("SelNextVertexCmd", "undo"); + _surfaceManager->selectPrevVertex(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelNextVertexCmd.h b/src/Commands/SelNextVertexCmd.h index f8c636b..b9ebf6a 100644 --- a/src/Commands/SelNextVertexCmd.h +++ b/src/Commands/SelNextVertexCmd.h @@ -1,25 +1,25 @@ -#pragma once - -#include "BaseCmd.h" -#include "SurfaceManager.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelNextVertexCmd : public BaseUndoCmd { - - public: - SelNextVertexCmd(SurfaceManager * sm); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "SurfaceManager.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelNextVertexCmd : public BaseUndoCmd { + + public: + SelNextVertexCmd(SurfaceManager * sm); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevSurfaceCmd.cpp b/src/Commands/SelPrevSurfaceCmd.cpp index 6c0d442..1db76f9 100644 --- a/src/Commands/SelPrevSurfaceCmd.cpp +++ b/src/Commands/SelPrevSurfaceCmd.cpp @@ -1,25 +1,25 @@ -#include "SelPrevSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -SelPrevSurfaceCmd::SelPrevSurfaceCmd(SurfaceManager * surfaceManager){ - _surfaceManager = surfaceManager; -} - -void SelPrevSurfaceCmd::exec(){ - _prevSelectedSurface = _surfaceManager->getSelectedSurface(); - _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); - _surfaceManager->selectPrevSurface(); -} - -void SelPrevSurfaceCmd::undo(){ - ofLogNotice("SelPrevSurfaceCmd", "undo"); - _surfaceManager->selectSurface(_prevSelectedSurface); - _surfaceManager->selectVertex(_prevSelectedVertex); - _prevSelectedSurface = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "SelPrevSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +SelPrevSurfaceCmd::SelPrevSurfaceCmd(SurfaceManager * surfaceManager){ + _surfaceManager = surfaceManager; +} + +void SelPrevSurfaceCmd::exec(){ + _prevSelectedSurface = _surfaceManager->getSelectedSurface(); + _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); + _surfaceManager->selectPrevSurface(); +} + +void SelPrevSurfaceCmd::undo(){ + ofLogNotice("SelPrevSurfaceCmd", "undo"); + _surfaceManager->selectSurface(_prevSelectedSurface); + _surfaceManager->selectVertex(_prevSelectedVertex); + _prevSelectedSurface = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevSurfaceCmd.h b/src/Commands/SelPrevSurfaceCmd.h index 5a46009..bf18968 100644 --- a/src/Commands/SelPrevSurfaceCmd.h +++ b/src/Commands/SelPrevSurfaceCmd.h @@ -1,31 +1,31 @@ -// SelPrevSurfaceCmd -// Selects previous surface in the projection mapping mode -// Created by Krisjanis Rijnieks 2016-02-03 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class SelPrevSurfaceCmd : public BaseUndoCmd { - - public: - SelPrevSurfaceCmd(SurfaceManager * surfaceManager); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - BaseSurface * _prevSelectedSurface; - int _prevSelectedVertex; - -}; - -} // namespace piMapper -} // namespace ofx - +// SelPrevSurfaceCmd +// Selects previous surface in the projection mapping mode +// Created by Krisjanis Rijnieks 2016-02-03 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class SelPrevSurfaceCmd : public BaseUndoCmd { + + public: + SelPrevSurfaceCmd(SurfaceManager * surfaceManager); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + BaseSurface * _prevSelectedSurface; + int _prevSelectedVertex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevTexCoordCmd.cpp b/src/Commands/SelPrevTexCoordCmd.cpp index 7a2af26..8bd75b5 100644 --- a/src/Commands/SelPrevTexCoordCmd.cpp +++ b/src/Commands/SelPrevTexCoordCmd.cpp @@ -1,24 +1,24 @@ -#include "SelPrevTexCoordCmd.h" - -namespace ofx { -namespace piMapper { - -SelPrevTexCoordCmd::SelPrevTexCoordCmd(TextureEditorWidget * te){ - _textureEditor = te; -} - -void SelPrevTexCoordCmd::exec(){ - ofLogNotice("SelPrevTexCoordCmd", "exec"); - _prevSelection = _textureEditor->getSelectedTexCoord(); - _textureEditor->selectPrevTexCoord(); -} - -void SelPrevTexCoordCmd::undo(){ - ofLogNotice("SelPrevTexCoordCmd", "undo"); - //_textureEditor->selectNextTexCoord(); - _textureEditor->selectTexCoord(_prevSelection); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelPrevTexCoordCmd.h" + +namespace ofx { +namespace piMapper { + +SelPrevTexCoordCmd::SelPrevTexCoordCmd(TextureEditorWidget * te){ + _textureEditor = te; +} + +void SelPrevTexCoordCmd::exec(){ + ofLogNotice("SelPrevTexCoordCmd", "exec"); + _prevSelection = _textureEditor->getSelectedTexCoord(); + _textureEditor->selectPrevTexCoord(); +} + +void SelPrevTexCoordCmd::undo(){ + ofLogNotice("SelPrevTexCoordCmd", "undo"); + //_textureEditor->selectNextTexCoord(); + _textureEditor->selectTexCoord(_prevSelection); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevTexCoordCmd.h b/src/Commands/SelPrevTexCoordCmd.h index 74d48c5..466c2d0 100644 --- a/src/Commands/SelPrevTexCoordCmd.h +++ b/src/Commands/SelPrevTexCoordCmd.h @@ -1,26 +1,26 @@ -#pragma once - -#include "BaseCmd.h" -#include "TextureEditorWidget.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelPrevTexCoordCmd : public BaseUndoCmd { - - public: - SelPrevTexCoordCmd(TextureEditorWidget * te); - void exec(); - void undo(); - - private: - TextureEditorWidget * _textureEditor; - int _prevSelection; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "TextureEditorWidget.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelPrevTexCoordCmd : public BaseUndoCmd { + + public: + SelPrevTexCoordCmd(TextureEditorWidget * te); + void exec(); + void undo(); + + private: + TextureEditorWidget * _textureEditor; + int _prevSelection; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevVertexCmd.cpp b/src/Commands/SelPrevVertexCmd.cpp index e5b92c2..73a1290 100644 --- a/src/Commands/SelPrevVertexCmd.cpp +++ b/src/Commands/SelPrevVertexCmd.cpp @@ -1,21 +1,21 @@ -#include "SelPrevVertexCmd.h" - -namespace ofx { -namespace piMapper { - -SelPrevVertexCmd::SelPrevVertexCmd(SurfaceManager * sm){ - _surfaceManager = sm; -} - -void SelPrevVertexCmd::exec(){ - _surfaceManager->selectPrevVertex(); -} - -void SelPrevVertexCmd::undo(){ - ofLogNotice("SelPrevVertexCmd", "undo"); - _surfaceManager->selectNextVertex(); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelPrevVertexCmd.h" + +namespace ofx { +namespace piMapper { + +SelPrevVertexCmd::SelPrevVertexCmd(SurfaceManager * sm){ + _surfaceManager = sm; +} + +void SelPrevVertexCmd::exec(){ + _surfaceManager->selectPrevVertex(); +} + +void SelPrevVertexCmd::undo(){ + ofLogNotice("SelPrevVertexCmd", "undo"); + _surfaceManager->selectNextVertex(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelPrevVertexCmd.h b/src/Commands/SelPrevVertexCmd.h index f81748b..744cd09 100644 --- a/src/Commands/SelPrevVertexCmd.h +++ b/src/Commands/SelPrevVertexCmd.h @@ -1,25 +1,25 @@ -#pragma once - -#include "BaseCmd.h" -#include "SurfaceManager.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelPrevVertexCmd : public BaseUndoCmd { - - public: - SelPrevVertexCmd(SurfaceManager * sm); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "SurfaceManager.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelPrevVertexCmd : public BaseUndoCmd { + + public: + SelPrevVertexCmd(SurfaceManager * sm); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelSurfaceCmd.cpp b/src/Commands/SelSurfaceCmd.cpp index aa7a9a0..57b2d8a 100644 --- a/src/Commands/SelSurfaceCmd.cpp +++ b/src/Commands/SelSurfaceCmd.cpp @@ -1,25 +1,25 @@ -#include "SelSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -SelSurfaceCmd::SelSurfaceCmd(SurfaceManager * surfaceManager, BaseSurface * surfaceToSelect){ - _surfaceManager = surfaceManager; - _surfaceToSelect = surfaceToSelect; -} - -void SelSurfaceCmd::exec(){ - _prevSelectedSurface = _surfaceManager->getSelectedSurface(); - _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); - _surfaceManager->selectSurface(_surfaceToSelect); -} - -void SelSurfaceCmd::undo(){ - ofLogNotice("SelSurfaceCmd", "undo"); - _surfaceManager->selectSurface(_prevSelectedSurface); - _surfaceManager->selectVertex(_prevSelectedVertex); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +SelSurfaceCmd::SelSurfaceCmd(SurfaceManager * surfaceManager, BaseSurface * surfaceToSelect){ + _surfaceManager = surfaceManager; + _surfaceToSelect = surfaceToSelect; +} + +void SelSurfaceCmd::exec(){ + _prevSelectedSurface = _surfaceManager->getSelectedSurface(); + _prevSelectedVertex = _surfaceManager->getSelectedVertexIndex(); + _surfaceManager->selectSurface(_surfaceToSelect); +} + +void SelSurfaceCmd::undo(){ + ofLogNotice("SelSurfaceCmd", "undo"); + _surfaceManager->selectSurface(_prevSelectedSurface); + _surfaceManager->selectVertex(_prevSelectedVertex); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelSurfaceCmd.h b/src/Commands/SelSurfaceCmd.h index d00522f..7e5e667 100644 --- a/src/Commands/SelSurfaceCmd.h +++ b/src/Commands/SelSurfaceCmd.h @@ -1,32 +1,32 @@ -// SelSurfaceCmd -// Provides with option to undo select surface operation. -// Created by Krisjanis Rijnieks 2015-05-14 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -class SelSurfaceCmd : public BaseUndoCmd { - - public: - SelSurfaceCmd(SurfaceManager * surfaceManager, BaseSurface * surfaceToSelect); - void exec(); - void undo(); - - private: - BaseSurface * _surfaceToSelect; - SurfaceManager * _surfaceManager; - BaseSurface * _prevSelectedSurface; - int _prevSelectedVertex; - -}; - -} // namespace piMapper -} // namespace ofx - +// SelSurfaceCmd +// Provides with option to undo select surface operation. +// Created by Krisjanis Rijnieks 2015-05-14 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +class SelSurfaceCmd : public BaseUndoCmd { + + public: + SelSurfaceCmd(SurfaceManager * surfaceManager, BaseSurface * surfaceToSelect); + void exec(); + void undo(); + + private: + BaseSurface * _surfaceToSelect; + SurfaceManager * _surfaceManager; + BaseSurface * _prevSelectedSurface; + int _prevSelectedVertex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelTexCoordCmd.cpp b/src/Commands/SelTexCoordCmd.cpp index f414e63..4a60345 100644 --- a/src/Commands/SelTexCoordCmd.cpp +++ b/src/Commands/SelTexCoordCmd.cpp @@ -1,24 +1,24 @@ -#include "SelTexCoordCmd.h" - -namespace ofx { -namespace piMapper { - -SelTexCoordCmd::SelTexCoordCmd(TextureEditorWidget * te, int texCoordIndex){ - _textureEditor = te; - _texCoordIndex = texCoordIndex; -} - -void SelTexCoordCmd::exec(){ - ofLogNotice("SelTexCoordCmd", "exec"); - _prevSelectionIndex = _textureEditor->getSelectedTexCoord(); - _textureEditor->selectTexCoord(_texCoordIndex); -} - -void SelTexCoordCmd::undo(){ - ofLogNotice("SelTexCoordCmd", "undo"); - _textureEditor->selectTexCoord(_prevSelectionIndex); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelTexCoordCmd.h" + +namespace ofx { +namespace piMapper { + +SelTexCoordCmd::SelTexCoordCmd(TextureEditorWidget * te, int texCoordIndex){ + _textureEditor = te; + _texCoordIndex = texCoordIndex; +} + +void SelTexCoordCmd::exec(){ + ofLogNotice("SelTexCoordCmd", "exec"); + _prevSelectionIndex = _textureEditor->getSelectedTexCoord(); + _textureEditor->selectTexCoord(_texCoordIndex); +} + +void SelTexCoordCmd::undo(){ + ofLogNotice("SelTexCoordCmd", "undo"); + _textureEditor->selectTexCoord(_prevSelectionIndex); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelTexCoordCmd.h b/src/Commands/SelTexCoordCmd.h index a297de3..bbf24a6 100644 --- a/src/Commands/SelTexCoordCmd.h +++ b/src/Commands/SelTexCoordCmd.h @@ -1,27 +1,27 @@ -#pragma once - -#include "BaseCmd.h" -#include "TextureEditorWidget.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelTexCoordCmd : public BaseUndoCmd { - - public: - SelTexCoordCmd(TextureEditorWidget * te, int texCoordIndex); - void exec(); - void undo(); - - private: - TextureEditorWidget * _textureEditor; - int _texCoordIndex; - int _prevSelectionIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "TextureEditorWidget.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelTexCoordCmd : public BaseUndoCmd { + + public: + SelTexCoordCmd(TextureEditorWidget * te, int texCoordIndex); + void exec(); + void undo(); + + private: + TextureEditorWidget * _textureEditor; + int _texCoordIndex; + int _prevSelectionIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelVertexCmd.cpp b/src/Commands/SelVertexCmd.cpp index d5d2b11..5455bee 100644 --- a/src/Commands/SelVertexCmd.cpp +++ b/src/Commands/SelVertexCmd.cpp @@ -1,23 +1,23 @@ -#include "SelVertexCmd.h" - -namespace ofx { -namespace piMapper { - -SelVertexCmd::SelVertexCmd(SurfaceManager * sm, int i){ - _surfaceManager = sm; - _newVertexIndex = i; -} - -void SelVertexCmd::exec(){ - _prevVertexIndex = _surfaceManager->getSelectedVertexIndex(); - _surfaceManager->selectVertex(_newVertexIndex); -} - -void SelVertexCmd::undo(){ - ofLogNotice("SelVertexCmd", "undo"); - _surfaceManager->selectVertex(_prevVertexIndex); -} - -} // namespace piMapper -} // namespace ofx - +#include "SelVertexCmd.h" + +namespace ofx { +namespace piMapper { + +SelVertexCmd::SelVertexCmd(SurfaceManager * sm, int i){ + _surfaceManager = sm; + _newVertexIndex = i; +} + +void SelVertexCmd::exec(){ + _prevVertexIndex = _surfaceManager->getSelectedVertexIndex(); + _surfaceManager->selectVertex(_newVertexIndex); +} + +void SelVertexCmd::undo(){ + ofLogNotice("SelVertexCmd", "undo"); + _surfaceManager->selectVertex(_prevVertexIndex); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SelVertexCmd.h b/src/Commands/SelVertexCmd.h index 1c6acd3..ae22939 100644 --- a/src/Commands/SelVertexCmd.h +++ b/src/Commands/SelVertexCmd.h @@ -1,27 +1,27 @@ -#pragma once - -#include "BaseCmd.h" -#include "SurfaceManager.h" - -class ofxPiMapper; - -namespace ofx { -namespace piMapper { - -class SelVertexCmd : public BaseUndoCmd { - - public: - SelVertexCmd(SurfaceManager * sm, int i); - void exec(); - void undo(); - - private: - SurfaceManager * _surfaceManager; - int _newVertexIndex; - int _prevVertexIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "SurfaceManager.h" + +class ofxPiMapper; + +namespace ofx { +namespace piMapper { + +class SelVertexCmd : public BaseUndoCmd { + + public: + SelVertexCmd(SurfaceManager * sm, int i); + void exec(); + void undo(); + + private: + SurfaceManager * _surfaceManager; + int _newVertexIndex; + int _prevVertexIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetApplicationModeCmd.cpp b/src/Commands/SetApplicationModeCmd.cpp index 69f8686..fb34524 100644 --- a/src/Commands/SetApplicationModeCmd.cpp +++ b/src/Commands/SetApplicationModeCmd.cpp @@ -1,61 +1,61 @@ -#include "SetApplicationModeCmd.h" - -namespace ofx { -namespace piMapper { - -SetApplicationModeCmd::SetApplicationModeCmd( - Application * app, - ApplicationBaseMode * st){ - - _application = app; - _prevApplicationState = 0; - _applicationState = st; -} - -void SetApplicationModeCmd::exec(){ - _prevApplicationState = _application->getState(); - _application->setState(_applicationState); - _applicationState->setTranslation(ofPoint(0, 0)); - _translation = _prevApplicationState->getTranslation(); - - Gui::instance()->getTextureEditorWidget().setSurface( - _application->getSurfaceManager()->getSelectedSurface()); - Gui::instance()->getTextureHighlightWidget().findConsumerSurfaces(); - - if(_applicationState != PresentationMode::instance()){ - ofShowCursor(); - }else{ - ofHideCursor(); - } - - if(_applicationState == SourceSelectionMode::instance()){ - Gui::instance()->getSourcesEditorWidget().enable(); - }else{ - Gui::instance()->getSourcesEditorWidget().disable(); - } -} - -void SetApplicationModeCmd::undo(){ - ofLogNotice("SetApplicationModeCmd", "undo"); - _application->setState(_prevApplicationState); - _application->getState()->setTranslation(_translation); - - Gui::instance()->getTextureEditorWidget().setSurface( - _application->getSurfaceManager()->getSelectedSurface()); - - if(_prevApplicationState != PresentationMode::instance()){ - ofShowCursor(); - }else{ - ofHideCursor(); - } - - if(_prevApplicationState == SourceSelectionMode::instance()){ - Gui::instance()->getSourcesEditorWidget().enable(); - }else{ - Gui::instance()->getSourcesEditorWidget().disable(); - } -} - -} // namespace piMapper -} // namespace ofx - +#include "SetApplicationModeCmd.h" + +namespace ofx { +namespace piMapper { + +SetApplicationModeCmd::SetApplicationModeCmd( + Application * app, + ApplicationBaseMode * st){ + + _application = app; + _prevApplicationState = 0; + _applicationState = st; +} + +void SetApplicationModeCmd::exec(){ + _prevApplicationState = _application->getState(); + _application->setState(_applicationState); + _applicationState->setTranslation(ofPoint(0, 0)); + _translation = _prevApplicationState->getTranslation(); + + Gui::instance()->getTextureEditorWidget().setSurface( + _application->getSurfaceManager()->getSelectedSurface()); + Gui::instance()->getTextureHighlightWidget().findConsumerSurfaces(); + + if(_applicationState != PresentationMode::instance()){ + ofShowCursor(); + }else{ + ofHideCursor(); + } + + if(_applicationState == SourceSelectionMode::instance()){ + Gui::instance()->getSourcesEditorWidget().enable(); + }else{ + Gui::instance()->getSourcesEditorWidget().disable(); + } +} + +void SetApplicationModeCmd::undo(){ + ofLogNotice("SetApplicationModeCmd", "undo"); + _application->setState(_prevApplicationState); + _application->getState()->setTranslation(_translation); + + Gui::instance()->getTextureEditorWidget().setSurface( + _application->getSurfaceManager()->getSelectedSurface()); + + if(_prevApplicationState != PresentationMode::instance()){ + ofShowCursor(); + }else{ + ofHideCursor(); + } + + if(_prevApplicationState == SourceSelectionMode::instance()){ + Gui::instance()->getSourcesEditorWidget().enable(); + }else{ + Gui::instance()->getSourcesEditorWidget().disable(); + } +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetApplicationModeCmd.h b/src/Commands/SetApplicationModeCmd.h index 115d6e7..7d05052 100644 --- a/src/Commands/SetApplicationModeCmd.h +++ b/src/Commands/SetApplicationModeCmd.h @@ -1,33 +1,33 @@ -#pragma once - -#include "BaseCmd.h" -#include "Application.h" - -namespace ofx { -namespace piMapper { - -class Application; -class ApplicationBaseMode; - -class SetApplicationModeCmd : public BaseUndoCmd { - - public: - SetApplicationModeCmd( - Application * app, - ApplicationBaseMode * st); - - void exec(); - void undo(); - - private: - Application * _application; - ApplicationBaseMode * _prevApplicationState; - ApplicationBaseMode * _applicationState; - - ofPoint _translation; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "Application.h" + +namespace ofx { +namespace piMapper { + +class Application; +class ApplicationBaseMode; + +class SetApplicationModeCmd : public BaseUndoCmd { + + public: + SetApplicationModeCmd( + Application * app, + ApplicationBaseMode * st); + + void exec(); + void undo(); + + private: + Application * _application; + ApplicationBaseMode * _prevApplicationState; + ApplicationBaseMode * _applicationState; + + ofPoint _translation; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetNextSourceCmd.cpp b/src/Commands/SetNextSourceCmd.cpp index 775bcc3..0f71f43 100644 --- a/src/Commands/SetNextSourceCmd.cpp +++ b/src/Commands/SetNextSourceCmd.cpp @@ -1,106 +1,106 @@ -#include "SetNextSourceCmd.h" - -namespace ofx { -namespace piMapper { - -SetNextSourceCmd::SetNextSourceCmd(BaseSurface * surface, SourcesEditorWidget * sourcesEditor){ - _surface = surface; - _sourcesEditor = sourcesEditor; -} - -void SetNextSourceCmd::exec(){ - ofLogNotice("SetNextSourceCmd", "exec"); - - // Get current source - BaseSource * source = _surface->getSource(); - int sourceType = source->getType(); - - std::string sourceId; - if(source->isLoadable()){ - sourceId = source->getPath(); - }else{ - sourceId = source->getName(); - } - - // MediaServer shortcut - MediaServer * mediaServer = _sourcesEditor->getMediaServer(); - - // Read sources into a single vector - for(unsigned int i = 0; i < mediaServer->getImagePaths().size(); ++i){ - SourceData data; - data.type = SourceType::SOURCE_TYPE_IMAGE; - data.id = mediaServer->getImagePaths()[i]; - _sources.push_back(data); - } - for(unsigned int i = 0; i < mediaServer->getVideoPaths().size(); ++i){ - SourceData data; - data.type = SourceType::SOURCE_TYPE_VIDEO; - data.id = mediaServer->getVideoPaths()[i]; - _sources.push_back(data); - } - for(unsigned int i = 0; i < mediaServer->getFboSourceNames().size(); ++i){ - SourceData data; - data.type = SourceType::SOURCE_TYPE_FBO; - data.id = mediaServer->getFboSourceNames()[i]; - _sources.push_back(data); - } - - if(_sources.size() <= 0){ - return; - } - - _sourceIndex = -1; - - // Search for current source among all - for(unsigned int i = 0; i < _sources.size(); ++i){ - if(sourceType == _sources[i].type && sourceId == _sources[i].id){ - _sourceIndex = i; - break; - } - } - - if(_sourceIndex == -1){ - if(_sources.size()){ - _nextSourceIndex = 0; - }else{ - return; - } - } - - _nextSourceIndex = _sourceIndex + 1; - if(_nextSourceIndex >= _sources.size()){ - _nextSourceIndex = 0; - } - - if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_IMAGE){ - _sourcesEditor->setImageSource(_sources[_nextSourceIndex].id); - }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_VIDEO){ - _sourcesEditor->setVideoSource(_sources[_nextSourceIndex].id); - }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_FBO){ - _sourcesEditor->setFboSource(_sources[_nextSourceIndex].id); - }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_NONE){ - _sourcesEditor->clearSource(); - } - - Gui::instance()->getTextureEditorWidget().createJoints(); -} - -void SetNextSourceCmd::undo(){ - ofLogNotice("SetNextSourceCmd", "undo"); - - if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_IMAGE){ - _sourcesEditor->setImageSource(_sources[_sourceIndex].id); - }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_VIDEO){ - _sourcesEditor->setVideoSource(_sources[_sourceIndex].id); - }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_FBO){ - _sourcesEditor->setFboSource(_sources[_sourceIndex].id); - }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_NONE){ - _sourcesEditor->clearSource(); - } - - Gui::instance()->getTextureEditorWidget().createJoints(); -} - -} // namespace piMapper -} // namespace ofx - +#include "SetNextSourceCmd.h" + +namespace ofx { +namespace piMapper { + +SetNextSourceCmd::SetNextSourceCmd(BaseSurface * surface, SourcesEditorWidget * sourcesEditor){ + _surface = surface; + _sourcesEditor = sourcesEditor; +} + +void SetNextSourceCmd::exec(){ + ofLogNotice("SetNextSourceCmd", "exec"); + + // Get current source + BaseSource * source = _surface->getSource(); + int sourceType = source->getType(); + + std::string sourceId; + if(source->isLoadable()){ + sourceId = source->getPath(); + }else{ + sourceId = source->getName(); + } + + // MediaServer shortcut + MediaServer * mediaServer = _sourcesEditor->getMediaServer(); + + // Read sources into a single vector + for(unsigned int i = 0; i < mediaServer->getImagePaths().size(); ++i){ + SourceData data; + data.type = SourceType::SOURCE_TYPE_IMAGE; + data.id = mediaServer->getImagePaths()[i]; + _sources.push_back(data); + } + for(unsigned int i = 0; i < mediaServer->getVideoPaths().size(); ++i){ + SourceData data; + data.type = SourceType::SOURCE_TYPE_VIDEO; + data.id = mediaServer->getVideoPaths()[i]; + _sources.push_back(data); + } + for(unsigned int i = 0; i < mediaServer->getFboSourceNames().size(); ++i){ + SourceData data; + data.type = SourceType::SOURCE_TYPE_FBO; + data.id = mediaServer->getFboSourceNames()[i]; + _sources.push_back(data); + } + + if(_sources.size() <= 0){ + return; + } + + _sourceIndex = -1; + + // Search for current source among all + for(unsigned int i = 0; i < _sources.size(); ++i){ + if(sourceType == _sources[i].type && sourceId == _sources[i].id){ + _sourceIndex = i; + break; + } + } + + if(_sourceIndex == -1){ + if(_sources.size()){ + _nextSourceIndex = 0; + }else{ + return; + } + } + + _nextSourceIndex = _sourceIndex + 1; + if(_nextSourceIndex >= _sources.size()){ + _nextSourceIndex = 0; + } + + if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_IMAGE){ + _sourcesEditor->setImageSource(_sources[_nextSourceIndex].id); + }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_VIDEO){ + _sourcesEditor->setVideoSource(_sources[_nextSourceIndex].id); + }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_FBO){ + _sourcesEditor->setFboSource(_sources[_nextSourceIndex].id); + }else if(_sources[_nextSourceIndex].type == SourceType::SOURCE_TYPE_NONE){ + _sourcesEditor->clearSource(); + } + + Gui::instance()->getTextureEditorWidget().createJoints(); +} + +void SetNextSourceCmd::undo(){ + ofLogNotice("SetNextSourceCmd", "undo"); + + if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_IMAGE){ + _sourcesEditor->setImageSource(_sources[_sourceIndex].id); + }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_VIDEO){ + _sourcesEditor->setVideoSource(_sources[_sourceIndex].id); + }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_FBO){ + _sourcesEditor->setFboSource(_sources[_sourceIndex].id); + }else if(_sources[_sourceIndex].type == SourceType::SOURCE_TYPE_NONE){ + _sourcesEditor->clearSource(); + } + + Gui::instance()->getTextureEditorWidget().createJoints(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetNextSourceCmd.h b/src/Commands/SetNextSourceCmd.h index b0dada9..823fb76 100644 --- a/src/Commands/SetNextSourceCmd.h +++ b/src/Commands/SetNextSourceCmd.h @@ -1,37 +1,37 @@ -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SourcesEditorWidget.h" -#include "MediaServer.h" -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -struct SourceData { - int type; - std::string id; -}; - -class SourcesEditorWidget; - -class SetNextSourceCmd : public BaseUndoCmd { - - public: - SetNextSourceCmd(BaseSurface * surface, SourcesEditorWidget * sourcesEditor); - void exec(); - void undo(); - - private: - BaseSurface * _surface; - SourcesEditorWidget * _sourcesEditor; - std::vector _sources; - int _sourceIndex; // Previous source index - int _nextSourceIndex; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SourcesEditorWidget.h" +#include "MediaServer.h" +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +struct SourceData { + int type; + std::string id; +}; + +class SourcesEditorWidget; + +class SetNextSourceCmd : public BaseUndoCmd { + + public: + SetNextSourceCmd(BaseSurface * surface, SourcesEditorWidget * sourcesEditor); + void exec(); + void undo(); + + private: + BaseSurface * _surface; + SourcesEditorWidget * _sourcesEditor; + std::vector _sources; + int _sourceIndex; // Previous source index + int _nextSourceIndex; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetPresetCmd.cpp b/src/Commands/SetPresetCmd.cpp index c379e9b..c7da7e8 100644 --- a/src/Commands/SetPresetCmd.cpp +++ b/src/Commands/SetPresetCmd.cpp @@ -1,27 +1,27 @@ -#include "SetPresetCmd.h" - -namespace ofx { -namespace piMapper { - -SetPresetCmd::SetPresetCmd(Application * app, unsigned int pi){ - _app = app; - _newPresetIndex = pi; -} - -void SetPresetCmd::exec(){ - ofLogNotice("SetPresetCmd", "exec"); - _prevPresetIndex = _app->getSurfaceManager()->getActivePresetIndex(); - _app->getSurfaceManager()->deselectSurface(); - _selectedSurfaceIndex = _app->getSurfaceManager()->getSelectedSurfaceIndex(); - _app->getSurfaceManager()->setPreset(_newPresetIndex); -} - -void SetPresetCmd::undo(){ - ofLogNotice("SetPresetCmd", "undo"); - _app->getSurfaceManager()->setPreset(_prevPresetIndex); - _app->getSurfaceManager()->selectSurface(_selectedSurfaceIndex); -} - -} // namespace piMapper -} // namespace ofx - +#include "SetPresetCmd.h" + +namespace ofx { +namespace piMapper { + +SetPresetCmd::SetPresetCmd(Application * app, unsigned int pi){ + _app = app; + _newPresetIndex = pi; +} + +void SetPresetCmd::exec(){ + ofLogNotice("SetPresetCmd", "exec"); + _prevPresetIndex = _app->getSurfaceManager()->getActivePresetIndex(); + _app->getSurfaceManager()->deselectSurface(); + _selectedSurfaceIndex = _app->getSurfaceManager()->getSelectedSurfaceIndex(); + _app->getSurfaceManager()->setPreset(_newPresetIndex); +} + +void SetPresetCmd::undo(){ + ofLogNotice("SetPresetCmd", "undo"); + _app->getSurfaceManager()->setPreset(_prevPresetIndex); + _app->getSurfaceManager()->selectSurface(_selectedSurfaceIndex); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetPresetCmd.h b/src/Commands/SetPresetCmd.h index ebfe9f2..075ccef 100644 --- a/src/Commands/SetPresetCmd.h +++ b/src/Commands/SetPresetCmd.h @@ -1,33 +1,33 @@ -// SetPresetCmd -// Sets active preset, stores previous preset index and restores it on undo. -// Created by Krisjanis Rijnieks 2016-10-07 -// At the ORA bar in Berlin. Waiting for Park to celebrate his birthday. - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "Application.h" - -namespace ofx { -namespace piMapper { - -class Application; - -class SetPresetCmd : public BaseUndoCmd { - - public: - SetPresetCmd(Application * app, unsigned int pi); - void exec(); - void undo(); - - private: - Application * _app; - unsigned int _newPresetIndex; - unsigned int _prevPresetIndex; - int _selectedSurfaceIndex; -}; - -} // namespace piMapper -} // namespace ofx - +// SetPresetCmd +// Sets active preset, stores previous preset index and restores it on undo. +// Created by Krisjanis Rijnieks 2016-10-07 +// At the ORA bar in Berlin. Waiting for Park to celebrate his birthday. + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "Application.h" + +namespace ofx { +namespace piMapper { + +class Application; + +class SetPresetCmd : public BaseUndoCmd { + + public: + SetPresetCmd(Application * app, unsigned int pi); + void exec(); + void undo(); + + private: + Application * _app; + unsigned int _newPresetIndex; + unsigned int _prevPresetIndex; + int _selectedSurfaceIndex; +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetSourceCmd.cpp b/src/Commands/SetSourceCmd.cpp index 9871a31..7941634 100644 --- a/src/Commands/SetSourceCmd.cpp +++ b/src/Commands/SetSourceCmd.cpp @@ -1,57 +1,57 @@ -#include "SetSourceCmd.h" - -namespace ofx { -namespace piMapper { - -SetSourceCmd::SetSourceCmd(int sourceType, - std::string sourceId, - BaseSurface * surface, - SourcesEditorWidget * sourcesEditor){ - - _sourceType = sourceType; - _sourceId = sourceId; - _surface = surface; - _sourcesEditor = sourcesEditor; -} - -void SetSourceCmd::exec(){ - ofLogNotice("SetSourceCmd", "exec"); - - _oldSourceTypeHelper = _surface->getSource()->getType(); - if(_surface->getSource()->isLoadable()){ - _oldSourceId = _surface->getSource()->getPath(); - }else{ - _oldSourceId = _surface->getSource()->getName(); - } - - if(_sourceType == SourceType::SOURCE_TYPE_IMAGE){ - _sourcesEditor->setImageSource(_sourceId); - }else if(_sourceType == SourceType::SOURCE_TYPE_VIDEO){ - _sourcesEditor->setVideoSource(_sourceId); - }else if(_sourceType == SourceType::SOURCE_TYPE_FBO){ - _sourcesEditor->setFboSource(_sourceId); - }else if(_sourceType == SourceType::SOURCE_TYPE_NONE){ - _sourcesEditor->clearSource(); - } -} - -void SetSourceCmd::undo(){ - ofLogNotice("SetSourceCmd", "undo"); - - if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_IMAGE){ - _sourcesEditor->setImageSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_VIDEO){ - _sourcesEditor->setVideoSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_FBO){ - _sourcesEditor->setFboSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_NONE){ - _sourcesEditor->clearSource(); - } - - _surface = 0; - _sourcesEditor = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "SetSourceCmd.h" + +namespace ofx { +namespace piMapper { + +SetSourceCmd::SetSourceCmd(int sourceType, + std::string sourceId, + BaseSurface * surface, + SourcesEditorWidget * sourcesEditor){ + + _sourceType = sourceType; + _sourceId = sourceId; + _surface = surface; + _sourcesEditor = sourcesEditor; +} + +void SetSourceCmd::exec(){ + ofLogNotice("SetSourceCmd", "exec"); + + _oldSourceTypeHelper = _surface->getSource()->getType(); + if(_surface->getSource()->isLoadable()){ + _oldSourceId = _surface->getSource()->getPath(); + }else{ + _oldSourceId = _surface->getSource()->getName(); + } + + if(_sourceType == SourceType::SOURCE_TYPE_IMAGE){ + _sourcesEditor->setImageSource(_sourceId); + }else if(_sourceType == SourceType::SOURCE_TYPE_VIDEO){ + _sourcesEditor->setVideoSource(_sourceId); + }else if(_sourceType == SourceType::SOURCE_TYPE_FBO){ + _sourcesEditor->setFboSource(_sourceId); + }else if(_sourceType == SourceType::SOURCE_TYPE_NONE){ + _sourcesEditor->clearSource(); + } +} + +void SetSourceCmd::undo(){ + ofLogNotice("SetSourceCmd", "undo"); + + if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_IMAGE){ + _sourcesEditor->setImageSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_VIDEO){ + _sourcesEditor->setVideoSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_FBO){ + _sourcesEditor->setFboSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_NONE){ + _sourcesEditor->clearSource(); + } + + _surface = 0; + _sourcesEditor = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetSourceCmd.h b/src/Commands/SetSourceCmd.h index fb818fe..79f7f83 100644 --- a/src/Commands/SetSourceCmd.h +++ b/src/Commands/SetSourceCmd.h @@ -1,39 +1,39 @@ -// SetSourceCmd -// Set selected surface source undoable command -// Created by Krisjanis Rijnieks 2015-05-20 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SourcesEditorWidget.h" - -namespace ofx { -namespace piMapper { - -class SourcesEditorWidget; - -class SetSourceCmd : public BaseUndoCmd { - - public: - SetSourceCmd(int sourceType, - std::string sourceId, - BaseSurface * surface, - SourcesEditorWidget * sourcesEditor); - void exec(); - void undo(); - - private: - int _sourceType; - std::string _sourceId; - BaseSurface * _surface; - SourcesEditorWidget * _sourcesEditor; - - int _oldSourceTypeHelper; - std::string _oldSourceId; - -}; - -} // namespace piMapper -} // namespace ofx - +// SetSourceCmd +// Set selected surface source undoable command +// Created by Krisjanis Rijnieks 2015-05-20 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SourcesEditorWidget.h" + +namespace ofx { +namespace piMapper { + +class SourcesEditorWidget; + +class SetSourceCmd : public BaseUndoCmd { + + public: + SetSourceCmd(int sourceType, + std::string sourceId, + BaseSurface * surface, + SourcesEditorWidget * sourcesEditor); + void exec(); + void undo(); + + private: + int _sourceType; + std::string _sourceId; + BaseSurface * _surface; + SourcesEditorWidget * _sourcesEditor; + + int _oldSourceTypeHelper; + std::string _oldSourceId; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetTexMapDrawModeCmd.cpp b/src/Commands/SetTexMapDrawModeCmd.cpp index d80730c..ee54054 100644 --- a/src/Commands/SetTexMapDrawModeCmd.cpp +++ b/src/Commands/SetTexMapDrawModeCmd.cpp @@ -1,24 +1,24 @@ -#include "SetTexMapDrawModeCmd.h" - -namespace ofx { -namespace piMapper { - -SetTexMapDrawModeCmd::SetTexMapDrawModeCmd(TextureMappingMode * s, int m){ - _state = s; - _newMode = m; -} - -void SetTexMapDrawModeCmd::exec(){ - ofLogNotice("SetTexMapDrawModeCmd", "exec"); - _oldMode = _state->getDrawMode(); - _state->setDrawMode(_newMode); -} - -void SetTexMapDrawModeCmd::undo(){ - ofLogNotice("SetTexMapDrawModeCmd", "undo"); - _state->setDrawMode(_oldMode); -} - -} // namespace piMapper -} // namespace ofx - +#include "SetTexMapDrawModeCmd.h" + +namespace ofx { +namespace piMapper { + +SetTexMapDrawModeCmd::SetTexMapDrawModeCmd(TextureMappingMode * s, int m){ + _state = s; + _newMode = m; +} + +void SetTexMapDrawModeCmd::exec(){ + ofLogNotice("SetTexMapDrawModeCmd", "exec"); + _oldMode = _state->getDrawMode(); + _state->setDrawMode(_newMode); +} + +void SetTexMapDrawModeCmd::undo(){ + ofLogNotice("SetTexMapDrawModeCmd", "undo"); + _state->setDrawMode(_oldMode); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetTexMapDrawModeCmd.h b/src/Commands/SetTexMapDrawModeCmd.h index 9a40889..bb993b6 100644 --- a/src/Commands/SetTexMapDrawModeCmd.h +++ b/src/Commands/SetTexMapDrawModeCmd.h @@ -1,31 +1,31 @@ -// SetTexMapDrawMode -// Sets draw mode of the texture mapping state -// Created by Krisjanis Rijnieks 2016-09-16 - -#pragma once - -#include "BaseCmd.h" -#include "TextureMappingMode.h" - -namespace ofx { -namespace piMapper { - -class TextureMappingMode; - -class SetTexMapDrawModeCmd : public BaseUndoCmd { - - public: - SetTexMapDrawModeCmd(TextureMappingMode * s, int m); - void exec(); - void undo(); - - private: - TextureMappingMode * _state; - int _oldMode; - int _newMode; - -}; - -} // namespace piMapper -} // namespace ofx - +// SetTexMapDrawMode +// Sets draw mode of the texture mapping state +// Created by Krisjanis Rijnieks 2016-09-16 + +#pragma once + +#include "BaseCmd.h" +#include "TextureMappingMode.h" + +namespace ofx { +namespace piMapper { + +class TextureMappingMode; + +class SetTexMapDrawModeCmd : public BaseUndoCmd { + + public: + SetTexMapDrawModeCmd(TextureMappingMode * s, int m); + void exec(); + void undo(); + + private: + TextureMappingMode * _state; + int _oldMode; + int _newMode; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetVideoSourceCmd.cpp b/src/Commands/SetVideoSourceCmd.cpp index 4a82112..30edb17 100644 --- a/src/Commands/SetVideoSourceCmd.cpp +++ b/src/Commands/SetVideoSourceCmd.cpp @@ -1,51 +1,51 @@ -#include "SetVideoSourceCmd.h" - -namespace ofx { -namespace piMapper { - -SetVideoSourceCmd::SetVideoSourceCmd(std::string sourceId, - bool loop, - BaseSurface * surface, - SourcesEditorWidget * sourcesEditor){ - _sourceId = sourceId; - _loop = loop; - _surface = surface; - _sourcesEditor = sourcesEditor; -} - -void SetVideoSourceCmd::exec(){ - ofLogNotice("SetVideoSourceCmd", "exec"); - - _oldSourceTypeHelper = _surface->getSource()->getType(); - if(_surface->getSource()->isLoadable()){ - _oldSourceId = _surface->getSource()->getPath(); - }else{ - _oldSourceId = _surface->getSource()->getName(); - } - - _sourcesEditor->setVideoSource(_sourceId); - BaseSource * src = _surface->getSource(); - VideoSource * vid = dynamic_cast(src); - vid->setLoop(_loop); -} - -void SetVideoSourceCmd::undo(){ - ofLogNotice("SetVideoSourceCmd", "undo"); - - if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_IMAGE){ - _sourcesEditor->setImageSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_VIDEO){ - _sourcesEditor->setVideoSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_FBO){ - _sourcesEditor->setFboSource(_oldSourceId); - }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_NONE){ - _sourcesEditor->clearSource(); - } - - _surface = 0; - _sourcesEditor = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "SetVideoSourceCmd.h" + +namespace ofx { +namespace piMapper { + +SetVideoSourceCmd::SetVideoSourceCmd(std::string sourceId, + bool loop, + BaseSurface * surface, + SourcesEditorWidget * sourcesEditor){ + _sourceId = sourceId; + _loop = loop; + _surface = surface; + _sourcesEditor = sourcesEditor; +} + +void SetVideoSourceCmd::exec(){ + ofLogNotice("SetVideoSourceCmd", "exec"); + + _oldSourceTypeHelper = _surface->getSource()->getType(); + if(_surface->getSource()->isLoadable()){ + _oldSourceId = _surface->getSource()->getPath(); + }else{ + _oldSourceId = _surface->getSource()->getName(); + } + + _sourcesEditor->setVideoSource(_sourceId); + BaseSource * src = _surface->getSource(); + VideoSource * vid = dynamic_cast(src); + vid->setLoop(_loop); +} + +void SetVideoSourceCmd::undo(){ + ofLogNotice("SetVideoSourceCmd", "undo"); + + if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_IMAGE){ + _sourcesEditor->setImageSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_VIDEO){ + _sourcesEditor->setVideoSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_FBO){ + _sourcesEditor->setFboSource(_oldSourceId); + }else if(_oldSourceTypeHelper == SourceType::SOURCE_TYPE_NONE){ + _sourcesEditor->clearSource(); + } + + _surface = 0; + _sourcesEditor = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/SetVideoSourceCmd.h b/src/Commands/SetVideoSourceCmd.h index 10778d0..1d965b0 100644 --- a/src/Commands/SetVideoSourceCmd.h +++ b/src/Commands/SetVideoSourceCmd.h @@ -1,39 +1,39 @@ -// SetVideoSourceCmd -// Set selected surface video source undoable command -// Created by Krisjanis Rijnieks 2018-08-10 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SourcesEditorWidget.h" - -namespace ofx { -namespace piMapper { - -class SourcesEditorWidget; - -class SetVideoSourceCmd : public BaseUndoCmd { - - public: - SetVideoSourceCmd(std::string sourceId, - bool loop, - BaseSurface * surface, - SourcesEditorWidget * sourcesEditor); - void exec(); - void undo(); - - private: - std::string _sourceId; - bool _loop; - BaseSurface * _surface; - SourcesEditorWidget * _sourcesEditor; - - int _oldSourceTypeHelper; - std::string _oldSourceId; - -}; - -} // namespace piMapper -} // namespace ofx - +// SetVideoSourceCmd +// Set selected surface video source undoable command +// Created by Krisjanis Rijnieks 2018-08-10 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SourcesEditorWidget.h" + +namespace ofx { +namespace piMapper { + +class SourcesEditorWidget; + +class SetVideoSourceCmd : public BaseUndoCmd { + + public: + SetVideoSourceCmd(std::string sourceId, + bool loop, + BaseSurface * surface, + SourcesEditorWidget * sourcesEditor); + void exec(); + void undo(); + + private: + std::string _sourceId; + bool _loop; + BaseSurface * _surface; + SourcesEditorWidget * _sourcesEditor; + + int _oldSourceTypeHelper; + std::string _oldSourceId; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/StartDragSurfaceCmd.cpp b/src/Commands/StartDragSurfaceCmd.cpp index 2f133eb..e33ce89 100644 --- a/src/Commands/StartDragSurfaceCmd.cpp +++ b/src/Commands/StartDragSurfaceCmd.cpp @@ -1,24 +1,24 @@ -#include "StartDragSurfaceCmd.h" - -namespace ofx { -namespace piMapper { - -StartDragSurfaceCmd::StartDragSurfaceCmd(BaseSurface * surface){ - _surface = surface; -} - -void StartDragSurfaceCmd::exec(){ - ofLogNotice("StartDragSurfaceCmd", "exec"); - _previousVertices = _surface->getVertices(); - _surface->setMoved(false); -} - -void StartDragSurfaceCmd::undo(){ - ofLogNotice("StartDragSurfaceCmd", "undo"); - Vec3 step = _previousVertices[0] - _surface->getVertices()[0]; - _surface->moveBy(step); -} - -} // namespace piMapper -} // namespace ofx - +#include "StartDragSurfaceCmd.h" + +namespace ofx { +namespace piMapper { + +StartDragSurfaceCmd::StartDragSurfaceCmd(BaseSurface * surface){ + _surface = surface; +} + +void StartDragSurfaceCmd::exec(){ + ofLogNotice("StartDragSurfaceCmd", "exec"); + _previousVertices = _surface->getVertices(); + _surface->setMoved(false); +} + +void StartDragSurfaceCmd::undo(){ + ofLogNotice("StartDragSurfaceCmd", "undo"); + Vec3 step = _previousVertices[0] - _surface->getVertices()[0]; + _surface->moveBy(step); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/StartDragSurfaceCmd.h b/src/Commands/StartDragSurfaceCmd.h index e46ddda..7cd8a41 100644 --- a/src/Commands/StartDragSurfaceCmd.h +++ b/src/Commands/StartDragSurfaceCmd.h @@ -1,25 +1,25 @@ -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class StartDragSurfaceCmd : public BaseUndoCmd { - - public: - StartDragSurfaceCmd(BaseSurface * surface); - void exec(); - void undo(); - - private: - BaseSurface * _surface; - std::vector _previousVertices; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class StartDragSurfaceCmd : public BaseUndoCmd { + + public: + StartDragSurfaceCmd(BaseSurface * surface); + void exec(); + void undo(); + + private: + BaseSurface * _surface; + std::vector _previousVertices; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/ToggleAnimatedSourceCmd.cpp b/src/Commands/ToggleAnimatedSourceCmd.cpp index b096a3e..445c51b 100644 --- a/src/Commands/ToggleAnimatedSourceCmd.cpp +++ b/src/Commands/ToggleAnimatedSourceCmd.cpp @@ -1,22 +1,22 @@ -#include "ToggleAnimatedSourceCmd.h" - -namespace ofx { -namespace piMapper { - -ToggleAnimatedSourceCmd::ToggleAnimatedSourceCmd(BaseSurface * surface){ - _surface = surface; -} - -void ToggleAnimatedSourceCmd::exec(){ - ofLogNotice("ToggleAnimatedSourceCmd", "exec"); - _surface->getSource()->togglePause(); -} - -void ToggleAnimatedSourceCmd::undo(){ - ofLogNotice("ToggleAnimatedSourceCmd", "undo"); - _surface->getSource()->togglePause(); -} - -} // namespace piMapper -} // namespace ofx - +#include "ToggleAnimatedSourceCmd.h" + +namespace ofx { +namespace piMapper { + +ToggleAnimatedSourceCmd::ToggleAnimatedSourceCmd(BaseSurface * surface){ + _surface = surface; +} + +void ToggleAnimatedSourceCmd::exec(){ + ofLogNotice("ToggleAnimatedSourceCmd", "exec"); + _surface->getSource()->togglePause(); +} + +void ToggleAnimatedSourceCmd::undo(){ + ofLogNotice("ToggleAnimatedSourceCmd", "undo"); + _surface->getSource()->togglePause(); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/ToggleAnimatedSourceCmd.h b/src/Commands/ToggleAnimatedSourceCmd.h index 09d35e9..4e72a70 100644 --- a/src/Commands/ToggleAnimatedSourceCmd.h +++ b/src/Commands/ToggleAnimatedSourceCmd.h @@ -1,29 +1,29 @@ -// ToggleAnimatedSourceCmd -// Toggles playing of animated (video, gif) sources -// Created by Krisjanis Rijnieks 2016-06-10 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "SourceType.h" -#include "VideoSource.h" - -namespace ofx { -namespace piMapper { - -class ToggleAnimatedSourceCmd : public BaseUndoCmd { - - public: - ToggleAnimatedSourceCmd(BaseSurface * surface); - void exec(); - void undo(); - - private: - BaseSurface * _surface; - -}; - -} // namespace piMapper -} // namespace ofx - +// ToggleAnimatedSourceCmd +// Toggles playing of animated (video, gif) sources +// Created by Krisjanis Rijnieks 2016-06-10 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "SourceType.h" +#include "VideoSource.h" + +namespace ofx { +namespace piMapper { + +class ToggleAnimatedSourceCmd : public BaseUndoCmd { + + public: + ToggleAnimatedSourceCmd(BaseSurface * surface); + void exec(); + void undo(); + + private: + BaseSurface * _surface; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/TogglePerspectiveCmd.cpp b/src/Commands/TogglePerspectiveCmd.cpp index 0756c87..5b633dc 100644 --- a/src/Commands/TogglePerspectiveCmd.cpp +++ b/src/Commands/TogglePerspectiveCmd.cpp @@ -1,24 +1,24 @@ -#include "TogglePerspectiveCmd.h" - -namespace ofx { -namespace piMapper { - -TogglePerspectiveCmd::TogglePerspectiveCmd(QuadSurface * surface){ - _surface = surface; -} - -void TogglePerspectiveCmd::exec(){ - ofLogNotice("TogglePerspectiveCmd", "exec"); - _perspectiveBeforeExec = _surface->getPerspectiveWarping(); - _surface->setPerspectiveWarping(!_perspectiveBeforeExec); -} - -void TogglePerspectiveCmd::undo(){ - ofLogNotice("TogglePerspectiveCmd", "undo"); - _surface->setPerspectiveWarping(_perspectiveBeforeExec); - _surface = 0; -} - -} // namespace piMapper -} // namespace ofx - +#include "TogglePerspectiveCmd.h" + +namespace ofx { +namespace piMapper { + +TogglePerspectiveCmd::TogglePerspectiveCmd(QuadSurface * surface){ + _surface = surface; +} + +void TogglePerspectiveCmd::exec(){ + ofLogNotice("TogglePerspectiveCmd", "exec"); + _perspectiveBeforeExec = _surface->getPerspectiveWarping(); + _surface->setPerspectiveWarping(!_perspectiveBeforeExec); +} + +void TogglePerspectiveCmd::undo(){ + ofLogNotice("TogglePerspectiveCmd", "undo"); + _surface->setPerspectiveWarping(_perspectiveBeforeExec); + _surface = 0; +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/TogglePerspectiveCmd.h b/src/Commands/TogglePerspectiveCmd.h index ccfb204..90421be 100644 --- a/src/Commands/TogglePerspectiveCmd.h +++ b/src/Commands/TogglePerspectiveCmd.h @@ -1,27 +1,27 @@ -#pragma once - -#include "BaseCmd.h" -#include "QuadSurface.h" -#include "SourcesEditorWidget.h" - -namespace ofx { -namespace piMapper { - -class SourcesEditorWidget; - -class TogglePerspectiveCmd : public BaseUndoCmd { - - public: - TogglePerspectiveCmd(QuadSurface * surface); - void exec(); - void undo(); - - private: - QuadSurface * _surface; - bool _perspectiveBeforeExec; - -}; - -} // namespace piMapper -} // namespace ofx - +#pragma once + +#include "BaseCmd.h" +#include "QuadSurface.h" +#include "SourcesEditorWidget.h" + +namespace ofx { +namespace piMapper { + +class SourcesEditorWidget; + +class TogglePerspectiveCmd : public BaseUndoCmd { + + public: + TogglePerspectiveCmd(QuadSurface * surface); + void exec(); + void undo(); + + private: + QuadSurface * _surface; + bool _perspectiveBeforeExec; + +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/TranslateCanvasCmd.cpp b/src/Commands/TranslateCanvasCmd.cpp index 67fdf6a..76b1be9 100644 --- a/src/Commands/TranslateCanvasCmd.cpp +++ b/src/Commands/TranslateCanvasCmd.cpp @@ -1,24 +1,24 @@ -#include "TranslateCanvasCmd.h" - -namespace ofx { -namespace piMapper { - -TranslateCanvasCmd::TranslateCanvasCmd(Application * app, ofPoint from, ofPoint to){ - _app = app; - _from = from; - _to = to; -} - -void TranslateCanvasCmd::exec(){ - ofLogNotice("TranslateCanvasCmd", "exec"); - _app->getState()->setTranslation(_to); -} - -void TranslateCanvasCmd::undo(){ - ofLogNotice("TranslateCanvasCmd", "undo"); - _app->getState()->setTranslation(_from); -} - -} // namespace piMapper -} // namespace ofx - +#include "TranslateCanvasCmd.h" + +namespace ofx { +namespace piMapper { + +TranslateCanvasCmd::TranslateCanvasCmd(Application * app, ofPoint from, ofPoint to){ + _app = app; + _from = from; + _to = to; +} + +void TranslateCanvasCmd::exec(){ + ofLogNotice("TranslateCanvasCmd", "exec"); + _app->getState()->setTranslation(_to); +} + +void TranslateCanvasCmd::undo(){ + ofLogNotice("TranslateCanvasCmd", "undo"); + _app->getState()->setTranslation(_from); +} + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Commands/TranslateCanvasCmd.h b/src/Commands/TranslateCanvasCmd.h index 0ddb408..97416e6 100644 --- a/src/Commands/TranslateCanvasCmd.h +++ b/src/Commands/TranslateCanvasCmd.h @@ -1,29 +1,29 @@ -// TranslateCanvasCmd -// Stores and restores the canvas of a mode/state. -// Created by Krisjanis Rijnieks 2016-09-13 - -#pragma once - -#include "BaseCmd.h" -#include "BaseSurface.h" -#include "Application.h" - -namespace ofx { -namespace piMapper { - -class TranslateCanvasCmd : public BaseUndoCmd { - - public: - TranslateCanvasCmd(Application * app, ofPoint from, ofPoint to); - void exec(); - void undo(); - - private: - Application * _app; - ofPoint _from; - ofPoint _to; -}; - -} // namespace piMapper -} // namespace ofx - +// TranslateCanvasCmd +// Stores and restores the canvas of a mode/state. +// Created by Krisjanis Rijnieks 2016-09-13 + +#pragma once + +#include "BaseCmd.h" +#include "BaseSurface.h" +#include "Application.h" + +namespace ofx { +namespace piMapper { + +class TranslateCanvasCmd : public BaseUndoCmd { + + public: + TranslateCanvasCmd(Application * app, ofPoint from, ofPoint to); + void exec(); + void undo(); + + private: + Application * _app; + ofPoint _from; + ofPoint _to; +}; + +} // namespace piMapper +} // namespace ofx + diff --git a/src/Gui/Gui.cpp b/src/Gui/Gui.cpp index da147f1..bcf43e3 100644 --- a/src/Gui/Gui.cpp +++ b/src/Gui/Gui.cpp @@ -1,119 +1,119 @@ -#include "Gui.h" - -namespace ofx { -namespace piMapper { - -Gui * Gui::_instance = 0; - -Gui * Gui::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::Gui(); - } - return _instance; -} - -Gui::Gui(){ - ofAddListener(_scaleWidget.guiWidgetEvent, this, &Gui::onScaleWidgetEvent); -} - -Gui::~Gui(){ - ofRemoveListener(_scaleWidget.guiWidgetEvent, this, &Gui::onScaleWidgetEvent); -} - -void Gui::notifyJointPressed(ofMouseEventArgs & args, int jointIndex){ - GuiJointEvent e; - e.args = args; - e.jointIndex = jointIndex; - ofNotifyEvent(jointPressedEvent, e, this); -} - -void Gui::notifyJointReleased(ofMouseEventArgs & args, int jointIndex){ - GuiJointEvent e; - e.args = args; - e.jointIndex = jointIndex; - ofNotifyEvent(jointReleasedEvent, e, this); -} - -void Gui::notifyJointDragged(ofMouseEventArgs & args, int jointIndex){ - GuiJointEvent e; - e.args = args; - e.jointIndex = jointIndex; - ofNotifyEvent(jointDraggedEvent, e, this); -} - -void Gui::notifySurfacePressed(ofMouseEventArgs & args, BaseSurface * surface){ - GuiSurfaceEvent e; - e.args = args; - e.surface = surface; - ofNotifyEvent(surfacePressedEvent, e, this); -} - -void Gui::notifySurfaceReleased(ofMouseEventArgs & args, BaseSurface * surface){ - GuiSurfaceEvent e; - e.args = args; - e.surface = surface; - ofNotifyEvent(surfaceReleasedEvent, e, this); -} - -void Gui::notifySurfaceDragged(ofMouseEventArgs & args, BaseSurface * surface){ - GuiSurfaceEvent e; - e.args = args; - e.surface = surface; - ofNotifyEvent(surfaceDraggedEvent, e, this); -} - -void Gui::notifyBackgroundPressed(ofMouseEventArgs & args){ - GuiBackgroundEvent e; - e.args = args; - ofNotifyEvent(backgroundPressedEvent, e, this); -} - -void Gui::onMousePressed(ofMouseEventArgs & args){ - _scaleWidget.onMousePressed(args); -} - -void Gui::onMouseReleased(ofMouseEventArgs & args){ - _scaleWidget.onMouseReleased(args); -} - -void Gui::onMouseDragged(ofMouseEventArgs & args){ - _scaleWidget.onMouseDragged(args); -} - -ScaleWidget & Gui::getScaleWidget(){ - return _scaleWidget; -} - -LayerPanelWidget & Gui::getLayerPanelWidget(){ - return _layerPanelWidget; -} - -SurfaceHighlightWidget & Gui::getSurfaceHighlightWidget(){ - return _surfaceHighlightWidget; -} - -TextureHighlightWidget & Gui::getTextureHighlightWidget(){ - return _textureHighlightWidget; -} - -TextureEditorWidget & Gui::getTextureEditorWidget(){ - return _textureEditorWidget; -} - -ProjectionEditorWidget & Gui::getProjectionEditorWidget(){ - return _projectionEditorWidget; -} - -SourcesEditorWidget & Gui::getSourcesEditorWidget(){ - return _sourcesEditorWidget; -} - -void Gui::onScaleWidgetEvent(GuiWidgetEvent & event){ - GuiEvent e; - e.args = event.args; - e.widget = &_scaleWidget; - ofNotifyEvent(guiEvent, e, this); -} - -} // piMapper +#include "Gui.h" + +namespace ofx { +namespace piMapper { + +Gui * Gui::_instance = 0; + +Gui * Gui::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::Gui(); + } + return _instance; +} + +Gui::Gui(){ + ofAddListener(_scaleWidget.guiWidgetEvent, this, &Gui::onScaleWidgetEvent); +} + +Gui::~Gui(){ + ofRemoveListener(_scaleWidget.guiWidgetEvent, this, &Gui::onScaleWidgetEvent); +} + +void Gui::notifyJointPressed(ofMouseEventArgs & args, int jointIndex){ + GuiJointEvent e; + e.args = args; + e.jointIndex = jointIndex; + ofNotifyEvent(jointPressedEvent, e, this); +} + +void Gui::notifyJointReleased(ofMouseEventArgs & args, int jointIndex){ + GuiJointEvent e; + e.args = args; + e.jointIndex = jointIndex; + ofNotifyEvent(jointReleasedEvent, e, this); +} + +void Gui::notifyJointDragged(ofMouseEventArgs & args, int jointIndex){ + GuiJointEvent e; + e.args = args; + e.jointIndex = jointIndex; + ofNotifyEvent(jointDraggedEvent, e, this); +} + +void Gui::notifySurfacePressed(ofMouseEventArgs & args, BaseSurface * surface){ + GuiSurfaceEvent e; + e.args = args; + e.surface = surface; + ofNotifyEvent(surfacePressedEvent, e, this); +} + +void Gui::notifySurfaceReleased(ofMouseEventArgs & args, BaseSurface * surface){ + GuiSurfaceEvent e; + e.args = args; + e.surface = surface; + ofNotifyEvent(surfaceReleasedEvent, e, this); +} + +void Gui::notifySurfaceDragged(ofMouseEventArgs & args, BaseSurface * surface){ + GuiSurfaceEvent e; + e.args = args; + e.surface = surface; + ofNotifyEvent(surfaceDraggedEvent, e, this); +} + +void Gui::notifyBackgroundPressed(ofMouseEventArgs & args){ + GuiBackgroundEvent e; + e.args = args; + ofNotifyEvent(backgroundPressedEvent, e, this); +} + +void Gui::onMousePressed(ofMouseEventArgs & args){ + _scaleWidget.onMousePressed(args); +} + +void Gui::onMouseReleased(ofMouseEventArgs & args){ + _scaleWidget.onMouseReleased(args); +} + +void Gui::onMouseDragged(ofMouseEventArgs & args){ + _scaleWidget.onMouseDragged(args); +} + +ScaleWidget & Gui::getScaleWidget(){ + return _scaleWidget; +} + +LayerPanelWidget & Gui::getLayerPanelWidget(){ + return _layerPanelWidget; +} + +SurfaceHighlightWidget & Gui::getSurfaceHighlightWidget(){ + return _surfaceHighlightWidget; +} + +TextureHighlightWidget & Gui::getTextureHighlightWidget(){ + return _textureHighlightWidget; +} + +TextureEditorWidget & Gui::getTextureEditorWidget(){ + return _textureEditorWidget; +} + +ProjectionEditorWidget & Gui::getProjectionEditorWidget(){ + return _projectionEditorWidget; +} + +SourcesEditorWidget & Gui::getSourcesEditorWidget(){ + return _sourcesEditorWidget; +} + +void Gui::onScaleWidgetEvent(GuiWidgetEvent & event){ + GuiEvent e; + e.args = event.args; + e.widget = &_scaleWidget; + ofNotifyEvent(guiEvent, e, this); +} + +} // piMapper } // ofx \ No newline at end of file diff --git a/src/Gui/Gui.h b/src/Gui/Gui.h index 2b04367..86e051b 100644 --- a/src/Gui/Gui.h +++ b/src/Gui/Gui.h @@ -1,102 +1,102 @@ -#pragma once - -#include "ofEvents.h" -#include "BaseSurface.h" - -#include "GuiBaseWidget.h" -#include "ScaleWidget.h" -#include "LayerPanelWidget.h" -#include "SurfaceHighlightWidget.h" -#include "TextureHighlightWidget.h" -#include "TextureEditorWidget.h" -#include "ProjectionEditorWidget.h" -#include "SourcesEditorWidget.h" - -namespace ofx { -namespace piMapper { - -struct GuiEvent{ - ofMouseEventArgs args; - GuiBaseWidget * widget; -}; - -// TODO: compress the following structs into something like: -// struct GuiEvent{ -// ofMouseEventArgs args; -// GuiObject obj; -// }; -// It could be then possible to check the object in question -// to decide what to do next. -struct GuiJointEvent{ - ofMouseEventArgs args; - int jointIndex; -}; - -struct GuiSurfaceEvent{ - ofMouseEventArgs args; - BaseSurface * surface; -}; - -struct GuiBackgroundEvent{ - ofMouseEventArgs args; -}; - -class Gui { - public: - static Gui * instance(); - - // TODO: combine the following events into one - ofEvent jointPressedEvent; - ofEvent jointReleasedEvent; - ofEvent jointDraggedEvent; - - void notifyJointPressed(ofMouseEventArgs & args, int jointIndex); - void notifyJointReleased(ofMouseEventArgs & args, int jointIndex); - void notifyJointDragged(ofMouseEventArgs & args, int jointIndex); - - ofEvent surfacePressedEvent; - ofEvent surfaceReleasedEvent; - ofEvent surfaceDraggedEvent; - - void notifySurfacePressed(ofMouseEventArgs & args, BaseSurface * surface); - void notifySurfaceReleased(ofMouseEventArgs & args, BaseSurface * surface); - void notifySurfaceDragged(ofMouseEventArgs & args, BaseSurface * surface); - - ofEvent backgroundPressedEvent; - - void notifyBackgroundPressed(ofMouseEventArgs & args); - - ScaleWidget & getScaleWidget(); - LayerPanelWidget & getLayerPanelWidget(); - SurfaceHighlightWidget & getSurfaceHighlightWidget(); - TextureHighlightWidget & getTextureHighlightWidget(); - TextureEditorWidget & getTextureEditorWidget(); - ProjectionEditorWidget & getProjectionEditorWidget(); - SourcesEditorWidget & getSourcesEditorWidget(); - - // Consider these as a part of the application states/modes. - void onMousePressed(ofMouseEventArgs & args); - void onMouseReleased(ofMouseEventArgs & args); - void onMouseDragged(ofMouseEventArgs & args); - - void onScaleWidgetEvent(GuiWidgetEvent & event); - - ofEvent guiEvent; - - private: - Gui(); - ~Gui(); - - static Gui * _instance; - - ScaleWidget _scaleWidget; - LayerPanelWidget _layerPanelWidget; - SurfaceHighlightWidget _surfaceHighlightWidget; - TextureHighlightWidget _textureHighlightWidget; - TextureEditorWidget _textureEditorWidget; - ProjectionEditorWidget _projectionEditorWidget; - SourcesEditorWidget _sourcesEditorWidget; -}; - -} // piMapper +#pragma once + +#include "ofEvents.h" +#include "BaseSurface.h" + +#include "GuiBaseWidget.h" +#include "ScaleWidget.h" +#include "LayerPanelWidget.h" +#include "SurfaceHighlightWidget.h" +#include "TextureHighlightWidget.h" +#include "TextureEditorWidget.h" +#include "ProjectionEditorWidget.h" +#include "SourcesEditorWidget.h" + +namespace ofx { +namespace piMapper { + +struct GuiEvent{ + ofMouseEventArgs args; + GuiBaseWidget * widget; +}; + +// TODO: compress the following structs into something like: +// struct GuiEvent{ +// ofMouseEventArgs args; +// GuiObject obj; +// }; +// It could be then possible to check the object in question +// to decide what to do next. +struct GuiJointEvent{ + ofMouseEventArgs args; + int jointIndex; +}; + +struct GuiSurfaceEvent{ + ofMouseEventArgs args; + BaseSurface * surface; +}; + +struct GuiBackgroundEvent{ + ofMouseEventArgs args; +}; + +class Gui { + public: + static Gui * instance(); + + // TODO: combine the following events into one + ofEvent jointPressedEvent; + ofEvent jointReleasedEvent; + ofEvent jointDraggedEvent; + + void notifyJointPressed(ofMouseEventArgs & args, int jointIndex); + void notifyJointReleased(ofMouseEventArgs & args, int jointIndex); + void notifyJointDragged(ofMouseEventArgs & args, int jointIndex); + + ofEvent surfacePressedEvent; + ofEvent surfaceReleasedEvent; + ofEvent surfaceDraggedEvent; + + void notifySurfacePressed(ofMouseEventArgs & args, BaseSurface * surface); + void notifySurfaceReleased(ofMouseEventArgs & args, BaseSurface * surface); + void notifySurfaceDragged(ofMouseEventArgs & args, BaseSurface * surface); + + ofEvent backgroundPressedEvent; + + void notifyBackgroundPressed(ofMouseEventArgs & args); + + ScaleWidget & getScaleWidget(); + LayerPanelWidget & getLayerPanelWidget(); + SurfaceHighlightWidget & getSurfaceHighlightWidget(); + TextureHighlightWidget & getTextureHighlightWidget(); + TextureEditorWidget & getTextureEditorWidget(); + ProjectionEditorWidget & getProjectionEditorWidget(); + SourcesEditorWidget & getSourcesEditorWidget(); + + // Consider these as a part of the application states/modes. + void onMousePressed(ofMouseEventArgs & args); + void onMouseReleased(ofMouseEventArgs & args); + void onMouseDragged(ofMouseEventArgs & args); + + void onScaleWidgetEvent(GuiWidgetEvent & event); + + ofEvent guiEvent; + + private: + Gui(); + ~Gui(); + + static Gui * _instance; + + ScaleWidget _scaleWidget; + LayerPanelWidget _layerPanelWidget; + SurfaceHighlightWidget _surfaceHighlightWidget; + TextureHighlightWidget _textureHighlightWidget; + TextureEditorWidget _textureEditorWidget; + ProjectionEditorWidget _projectionEditorWidget; + SourcesEditorWidget _sourcesEditorWidget; +}; + +} // piMapper } // ofx \ No newline at end of file diff --git a/src/Gui/Widgets/GuiBaseWidget.h b/src/Gui/Widgets/GuiBaseWidget.h index 5bc0dfd..cfef990 100644 --- a/src/Gui/Widgets/GuiBaseWidget.h +++ b/src/Gui/Widgets/GuiBaseWidget.h @@ -1,30 +1,30 @@ -#pragma once - -#include "ofEvents.h" - -namespace ofx { -namespace piMapper { - -struct GuiWidgetEvent{ - ofMouseEventArgs args; -}; - -class GuiBaseWidget { - public: - virtual void setup() = 0; - virtual void update() = 0; - virtual void draw() = 0; - - virtual void onMousePressed(ofMouseEventArgs & e) = 0; - virtual void onMouseReleased(ofMouseEventArgs & e) = 0; - virtual void onMouseDragged(ofMouseEventArgs & e) = 0; - - virtual bool inside(float x, float y) = 0; - - virtual float getScale(){ return 0.0f; } - - ofEvent guiWidgetEvent; -}; - -} // namespace piMapper +#pragma once + +#include "ofEvents.h" + +namespace ofx { +namespace piMapper { + +struct GuiWidgetEvent{ + ofMouseEventArgs args; +}; + +class GuiBaseWidget { + public: + virtual void setup() = 0; + virtual void update() = 0; + virtual void draw() = 0; + + virtual void onMousePressed(ofMouseEventArgs & e) = 0; + virtual void onMouseReleased(ofMouseEventArgs & e) = 0; + virtual void onMouseDragged(ofMouseEventArgs & e) = 0; + + virtual bool inside(float x, float y) = 0; + + virtual float getScale(){ return 0.0f; } + + ofEvent guiWidgetEvent; +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/LayerPanelWidget.cpp b/src/Gui/Widgets/LayerPanelWidget.cpp index bb59b78..c5005f3 100644 --- a/src/Gui/Widgets/LayerPanelWidget.cpp +++ b/src/Gui/Widgets/LayerPanelWidget.cpp @@ -1,54 +1,54 @@ -#include "LayerPanelWidget.h" - -namespace ofx{ -namespace piMapper{ - -LayerPanelWidget::LayerPanelWidget(){ - _sm = 0; -} - -void LayerPanelWidget::draw(){ - if(_sm == 0){ - return; - } - - int numSurfaces = _sm->size(); - - for(int i = 0; i < numSurfaces; ++i){ - BaseSurface * surface = _sm->getSurface(i); - BaseSurface * surfaceSelected = _sm->getSelectedSurface(); - - ofPushStyle(); - ofSetColor(255, 255, 255); - - if(surface == surfaceSelected){ - ofFill(); - }else{ - ofNoFill(); - } - - int layerIconWidth = 45; - int layerIconHeight = 20; - int offsetRight = 20; - int offsetTop = 40; - int verticalSpacing = 10; - int layerIconX = ofGetWidth() - offsetRight - layerIconWidth; - int layerIconY = offsetTop + ((layerIconHeight + verticalSpacing) * (numSurfaces - i - 1)); - - std::string label = "Layers"; - ofDrawBitmapString(label, ofGetWidth() - 66, 30); - - ofRectangle layerIcon = ofRectangle( - layerIconX, - layerIconY, - layerIconWidth, - layerIconHeight); - - ofDrawRectangle(layerIcon); - - ofPopStyle(); - } -} - -} // namespace piMapper +#include "LayerPanelWidget.h" + +namespace ofx{ +namespace piMapper{ + +LayerPanelWidget::LayerPanelWidget(){ + _sm = 0; +} + +void LayerPanelWidget::draw(){ + if(_sm == 0){ + return; + } + + int numSurfaces = _sm->size(); + + for(int i = 0; i < numSurfaces; ++i){ + BaseSurface * surface = _sm->getSurface(i); + BaseSurface * surfaceSelected = _sm->getSelectedSurface(); + + ofPushStyle(); + ofSetColor(255, 255, 255); + + if(surface == surfaceSelected){ + ofFill(); + }else{ + ofNoFill(); + } + + int layerIconWidth = 45; + int layerIconHeight = 20; + int offsetRight = 20; + int offsetTop = 40; + int verticalSpacing = 10; + int layerIconX = ofGetWidth() - offsetRight - layerIconWidth; + int layerIconY = offsetTop + ((layerIconHeight + verticalSpacing) * (numSurfaces - i - 1)); + + std::string label = "Layers"; + ofDrawBitmapString(label, ofGetWidth() - 66, 30); + + ofRectangle layerIcon = ofRectangle( + layerIconX, + layerIconY, + layerIconWidth, + layerIconHeight); + + ofDrawRectangle(layerIcon); + + ofPopStyle(); + } +} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/LayerPanelWidget.h b/src/Gui/Widgets/LayerPanelWidget.h index 22ed526..0691215 100644 --- a/src/Gui/Widgets/LayerPanelWidget.h +++ b/src/Gui/Widgets/LayerPanelWidget.h @@ -1,31 +1,31 @@ -#pragma once - -#include "GuiBaseWidget.h" -#include "SurfaceManager.h" - -namespace ofx { -namespace piMapper { - -class LayerPanelWidget : public GuiBaseWidget { - public: - LayerPanelWidget(); - - void setup(){} - void update(){} - void draw(); - - void onMousePressed(ofMouseEventArgs & args){} - void onMouseReleased(ofMouseEventArgs & args){} - void onMouseDragged(ofMouseEventArgs & args){} - - bool inside(float x, float y){ return false; } - - void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } - - private: - SurfaceManager * _sm; - -}; - -} // namespace piMapper +#pragma once + +#include "GuiBaseWidget.h" +#include "SurfaceManager.h" + +namespace ofx { +namespace piMapper { + +class LayerPanelWidget : public GuiBaseWidget { + public: + LayerPanelWidget(); + + void setup(){} + void update(){} + void draw(); + + void onMousePressed(ofMouseEventArgs & args){} + void onMouseReleased(ofMouseEventArgs & args){} + void onMouseDragged(ofMouseEventArgs & args){} + + bool inside(float x, float y){ return false; } + + void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } + + private: + SurfaceManager * _sm; + +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/ProjectionEditorWidget.cpp b/src/Gui/Widgets/ProjectionEditorWidget.cpp index 5693a9a..9d6da94 100644 --- a/src/Gui/Widgets/ProjectionEditorWidget.cpp +++ b/src/Gui/Widgets/ProjectionEditorWidget.cpp @@ -1,247 +1,247 @@ -#include "ProjectionEditorWidget.h" - -namespace ofx { -namespace piMapper { - -ProjectionEditorWidget::ProjectionEditorWidget(){ - surfaceManager = 0; - bShiftKeyDown = false; - fSnapDistance = 10.0f; -} - -void ProjectionEditorWidget::update(){ - // update surface if one of the joints is being dragged - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->isDragged() || joints[i]->isSelected()){ - if(surfaceManager->getSelectedSurface() != 0){ - // update vertex to new location - surfaceManager->getSelectedSurface()->setVertex(i, Vec3( - joints[i]->position.x, - joints[i]->position.y, - 0.0f)); - }else{ - // clear joints if there is no surface selected - // as the remove selected surface in the surface manager - // is not supposed to access joints here - joints.clear(); - } - break; - } - } -} - -void ProjectionEditorWidget::draw(){ - if(surfaceManager == 0){ - return; - } - if(surfaceManager->getSelectedSurface() == 0){ - return; - } - if(joints.size() <= 0){ - createJoints(); - } - drawJoints(); -} - -void ProjectionEditorWidget::mouseDragged(ofMouseEventArgs & args){ - - // Pass args to joint mouse events - for(unsigned int i = 0; i < joints.size(); ++i){ - joints[i]->mouseDragged(args); - } - - Vec2 mousePosition = Vec2(args.x, args.y); - - // Collect all vertices of the projection surfaces - std::vector allVertices; - for(int i = 0; i < surfaceManager->size(); i++){ - BaseSurface * surface = surfaceManager->getSurface(i); - - if(surface == surfaceManager->getSelectedSurface()){ - continue; // Don't add vertices of the selected surface - } - - for(int j = 0; j < surface->getVertices().size(); j++){ - allVertices.push_back(surface->getVertices()[j]); - } - } - - // Snap currently dragged joint to nearest vertex - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->isDragged()){ - for(int j = 0; j < allVertices.size(); j++){ - Vec2 v(allVertices[j].x, allVertices[j].y); - float distance = mousePosition.distance(v); - - if(distance < fSnapDistance){ - joints[i]->position = v; - Vec2 clickDistance = joints[i]->position - Vec2(args.x, args.y); - joints[i]->setClickDistance(clickDistance); - break; - } - } - } - } -} - -void ProjectionEditorWidget::gotMessage(ofMessage & msg){ - if(msg.message == "surfaceSelected"){ - clearJoints(); - createJoints(); - } -} - -void ProjectionEditorWidget::setSurfaceManager(SurfaceManager * newSurfaceManager){ - if(surfaceManager != 0){ - ofRemoveListener(surfaceManager->vertexChangedEvent, this, - &ProjectionEditorWidget::onVertexChanged); - ofRemoveListener(surfaceManager->verticesChangedEvent, this, - &ProjectionEditorWidget::onVerticesChanged); - ofRemoveListener(surfaceManager->surfaceSelectedEvent, this, - &ProjectionEditorWidget::onSurfaceSelected); - ofRemoveListener(surfaceManager->vertexSelectedEvent, this, - &ProjectionEditorWidget::onVertexSelected); - ofRemoveListener(surfaceManager->vertexUnselectedEvent, this, - &ProjectionEditorWidget::onVertexUnselected); - } - - surfaceManager = newSurfaceManager; - - ofAddListener(surfaceManager->vertexChangedEvent, this, - &ProjectionEditorWidget::onVertexChanged); - ofAddListener(surfaceManager->verticesChangedEvent, this, - &ProjectionEditorWidget::onVerticesChanged); - ofAddListener(surfaceManager->surfaceSelectedEvent, this, - &ProjectionEditorWidget::onSurfaceSelected); - ofAddListener(surfaceManager->vertexSelectedEvent, this, - &ProjectionEditorWidget::onVertexSelected); - ofAddListener(surfaceManager->vertexUnselectedEvent, this, - &ProjectionEditorWidget::onVertexUnselected); -} - -void ProjectionEditorWidget::clearJoints(){ - while(joints.size()){ - delete joints.back(); - joints.pop_back(); - } -} - -void ProjectionEditorWidget::createJoints(){ - if(surfaceManager == 0){ - return; - } - clearJoints(); - - if(surfaceManager->getSelectedSurface() == 0){ - ofLog(OF_LOG_WARNING, "Trying to create joints while no surface selected."); - return; - } - - std::vector vertices = surfaceManager->getSelectedSurface()->getVertices(); - - for(int i = 0; i < vertices.size(); i++){ - joints.push_back(new CircleJoint()); - joints.back()->position = Vec2(vertices[i].x, vertices[i].y); - } -} - -void ProjectionEditorWidget::updateJoints(){ - if(surfaceManager->getSelectedSurface()){ - std::vector vertices = surfaceManager->getSelectedSurface()->getVertices(); - - for(int i = 0; i < vertices.size(); i++){ - joints[i]->position = Vec2(vertices[i].x, vertices[i].y); - } - } - -} - -void ProjectionEditorWidget::unselectAllJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->unselect(); - } -} - -void ProjectionEditorWidget::moveSelectedSurface(Vec3 by){ - if(surfaceManager == 0){ - return; - } - - if(surfaceManager->getSelectedSurface() == 0){ - return; - } - - surfaceManager->getSelectedSurface()->moveBy(by); - updateJoints(); -} - -void ProjectionEditorWidget::stopDragJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->stopDrag(); - } -} - -void ProjectionEditorWidget::setSnapDistance(float newSnapDistance){ - fSnapDistance = newSnapDistance; -} - -CircleJoint * ProjectionEditorWidget::hitTestJoints(Vec2 pos){ - if(surfaceManager->getSelectedSurface() == 0){ - return 0; - } - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->hitTest(pos)){ - return joints[i]; - } - } - return 0; -} - -std::vector * ProjectionEditorWidget::getJoints(){ - return &joints; -} - -void ProjectionEditorWidget::onVertexChanged(int & i){ - bool isDragged = getJoints()->at(i)->isDragged(); - createJoints(); - getJoints()->at(i)->select(); - if(isDragged){ - getJoints()->at(i)->startDrag(); - }else{ - getJoints()->at(i)->stopDrag(); - } -} - -void ProjectionEditorWidget::onVerticesChanged(std::vector & vertices){ - createJoints(); -} - -void ProjectionEditorWidget::onSurfaceSelected(int & surfaceIndex){ - createJoints(); -} - -void ProjectionEditorWidget::onVertexSelected(int & vertexIndex){ - if(getJoints()->size() == 0){ - return; - } - - unselectAllJoints(); - getJoints()->at(vertexIndex)->select(); -} - -void ProjectionEditorWidget::onVertexUnselected(int & vertexIndex){ - if(getJoints()->size() == 0){ - return; - } - - unselectAllJoints(); -} - -void ProjectionEditorWidget::drawJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->draw(); - } -} - -} // namespace piMapper -} // namespace ofx +#include "ProjectionEditorWidget.h" + +namespace ofx { +namespace piMapper { + +ProjectionEditorWidget::ProjectionEditorWidget(){ + surfaceManager = 0; + bShiftKeyDown = false; + fSnapDistance = 10.0f; +} + +void ProjectionEditorWidget::update(){ + // update surface if one of the joints is being dragged + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->isDragged() || joints[i]->isSelected()){ + if(surfaceManager->getSelectedSurface() != 0){ + // update vertex to new location + surfaceManager->getSelectedSurface()->setVertex(i, Vec3( + joints[i]->position.x, + joints[i]->position.y, + 0.0f)); + }else{ + // clear joints if there is no surface selected + // as the remove selected surface in the surface manager + // is not supposed to access joints here + joints.clear(); + } + break; + } + } +} + +void ProjectionEditorWidget::draw(){ + if(surfaceManager == 0){ + return; + } + if(surfaceManager->getSelectedSurface() == 0){ + return; + } + if(joints.size() <= 0){ + createJoints(); + } + drawJoints(); +} + +void ProjectionEditorWidget::mouseDragged(ofMouseEventArgs & args){ + + // Pass args to joint mouse events + for(unsigned int i = 0; i < joints.size(); ++i){ + joints[i]->mouseDragged(args); + } + + Vec2 mousePosition = Vec2(args.x, args.y); + + // Collect all vertices of the projection surfaces + std::vector allVertices; + for(int i = 0; i < surfaceManager->size(); i++){ + BaseSurface * surface = surfaceManager->getSurface(i); + + if(surface == surfaceManager->getSelectedSurface()){ + continue; // Don't add vertices of the selected surface + } + + for(int j = 0; j < surface->getVertices().size(); j++){ + allVertices.push_back(surface->getVertices()[j]); + } + } + + // Snap currently dragged joint to nearest vertex + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->isDragged()){ + for(int j = 0; j < allVertices.size(); j++){ + Vec2 v(allVertices[j].x, allVertices[j].y); + float distance = mousePosition.distance(v); + + if(distance < fSnapDistance){ + joints[i]->position = v; + Vec2 clickDistance = joints[i]->position - Vec2(args.x, args.y); + joints[i]->setClickDistance(clickDistance); + break; + } + } + } + } +} + +void ProjectionEditorWidget::gotMessage(ofMessage & msg){ + if(msg.message == "surfaceSelected"){ + clearJoints(); + createJoints(); + } +} + +void ProjectionEditorWidget::setSurfaceManager(SurfaceManager * newSurfaceManager){ + if(surfaceManager != 0){ + ofRemoveListener(surfaceManager->vertexChangedEvent, this, + &ProjectionEditorWidget::onVertexChanged); + ofRemoveListener(surfaceManager->verticesChangedEvent, this, + &ProjectionEditorWidget::onVerticesChanged); + ofRemoveListener(surfaceManager->surfaceSelectedEvent, this, + &ProjectionEditorWidget::onSurfaceSelected); + ofRemoveListener(surfaceManager->vertexSelectedEvent, this, + &ProjectionEditorWidget::onVertexSelected); + ofRemoveListener(surfaceManager->vertexUnselectedEvent, this, + &ProjectionEditorWidget::onVertexUnselected); + } + + surfaceManager = newSurfaceManager; + + ofAddListener(surfaceManager->vertexChangedEvent, this, + &ProjectionEditorWidget::onVertexChanged); + ofAddListener(surfaceManager->verticesChangedEvent, this, + &ProjectionEditorWidget::onVerticesChanged); + ofAddListener(surfaceManager->surfaceSelectedEvent, this, + &ProjectionEditorWidget::onSurfaceSelected); + ofAddListener(surfaceManager->vertexSelectedEvent, this, + &ProjectionEditorWidget::onVertexSelected); + ofAddListener(surfaceManager->vertexUnselectedEvent, this, + &ProjectionEditorWidget::onVertexUnselected); +} + +void ProjectionEditorWidget::clearJoints(){ + while(joints.size()){ + delete joints.back(); + joints.pop_back(); + } +} + +void ProjectionEditorWidget::createJoints(){ + if(surfaceManager == 0){ + return; + } + clearJoints(); + + if(surfaceManager->getSelectedSurface() == 0){ + ofLog(OF_LOG_WARNING, "Trying to create joints while no surface selected."); + return; + } + + std::vector vertices = surfaceManager->getSelectedSurface()->getVertices(); + + for(int i = 0; i < vertices.size(); i++){ + joints.push_back(new CircleJoint()); + joints.back()->position = Vec2(vertices[i].x, vertices[i].y); + } +} + +void ProjectionEditorWidget::updateJoints(){ + if(surfaceManager->getSelectedSurface()){ + std::vector vertices = surfaceManager->getSelectedSurface()->getVertices(); + + for(int i = 0; i < vertices.size(); i++){ + joints[i]->position = Vec2(vertices[i].x, vertices[i].y); + } + } + +} + +void ProjectionEditorWidget::unselectAllJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->unselect(); + } +} + +void ProjectionEditorWidget::moveSelectedSurface(Vec3 by){ + if(surfaceManager == 0){ + return; + } + + if(surfaceManager->getSelectedSurface() == 0){ + return; + } + + surfaceManager->getSelectedSurface()->moveBy(by); + updateJoints(); +} + +void ProjectionEditorWidget::stopDragJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->stopDrag(); + } +} + +void ProjectionEditorWidget::setSnapDistance(float newSnapDistance){ + fSnapDistance = newSnapDistance; +} + +CircleJoint * ProjectionEditorWidget::hitTestJoints(Vec2 pos){ + if(surfaceManager->getSelectedSurface() == 0){ + return 0; + } + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->hitTest(pos)){ + return joints[i]; + } + } + return 0; +} + +std::vector * ProjectionEditorWidget::getJoints(){ + return &joints; +} + +void ProjectionEditorWidget::onVertexChanged(int & i){ + bool isDragged = getJoints()->at(i)->isDragged(); + createJoints(); + getJoints()->at(i)->select(); + if(isDragged){ + getJoints()->at(i)->startDrag(); + }else{ + getJoints()->at(i)->stopDrag(); + } +} + +void ProjectionEditorWidget::onVerticesChanged(std::vector & vertices){ + createJoints(); +} + +void ProjectionEditorWidget::onSurfaceSelected(int & surfaceIndex){ + createJoints(); +} + +void ProjectionEditorWidget::onVertexSelected(int & vertexIndex){ + if(getJoints()->size() == 0){ + return; + } + + unselectAllJoints(); + getJoints()->at(vertexIndex)->select(); +} + +void ProjectionEditorWidget::onVertexUnselected(int & vertexIndex){ + if(getJoints()->size() == 0){ + return; + } + + unselectAllJoints(); +} + +void ProjectionEditorWidget::drawJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->draw(); + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/ProjectionEditorWidget.h b/src/Gui/Widgets/ProjectionEditorWidget.h index 58037e9..8633294 100644 --- a/src/Gui/Widgets/ProjectionEditorWidget.h +++ b/src/Gui/Widgets/ProjectionEditorWidget.h @@ -1,51 +1,51 @@ -#pragma once - -#include "SurfaceManager.h" -#include "CircleJoint.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class ProjectionEditorWidget { - - public: - ProjectionEditorWidget(); - - void update(); - void draw(); - - void mouseDragged(ofMouseEventArgs & args); - void gotMessage(ofMessage & msg); - - void setSurfaceManager(SurfaceManager * newSurfaceManager); - void clearJoints(); - void createJoints(); - void updateJoints(); - void unselectAllJoints(); - void moveSelectedSurface(Vec3 by); - void stopDragJoints(); - void updateVertices(); - void setSnapDistance(float newSnapDistance); - CircleJoint * hitTestJoints(Vec2 pos); - std::vector * getJoints(); - - void onVertexChanged(int & i); - void onVerticesChanged(std::vector & vertices); - void onSurfaceSelected(int & surfaceIndex); - void onVertexSelected(int & vertexIndex); - void onVertexUnselected(int & vertexIndex); - - private: - SurfaceManager * surfaceManager; - std::vector joints; - bool bShiftKeyDown; - float fSnapDistance; - - void drawJoints(); - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "SurfaceManager.h" +#include "CircleJoint.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class ProjectionEditorWidget { + + public: + ProjectionEditorWidget(); + + void update(); + void draw(); + + void mouseDragged(ofMouseEventArgs & args); + void gotMessage(ofMessage & msg); + + void setSurfaceManager(SurfaceManager * newSurfaceManager); + void clearJoints(); + void createJoints(); + void updateJoints(); + void unselectAllJoints(); + void moveSelectedSurface(Vec3 by); + void stopDragJoints(); + void updateVertices(); + void setSnapDistance(float newSnapDistance); + CircleJoint * hitTestJoints(Vec2 pos); + std::vector * getJoints(); + + void onVertexChanged(int & i); + void onVerticesChanged(std::vector & vertices); + void onSurfaceSelected(int & surfaceIndex); + void onVertexSelected(int & vertexIndex); + void onVertexUnselected(int & vertexIndex); + + private: + SurfaceManager * surfaceManager; + std::vector joints; + bool bShiftKeyDown; + float fSnapDistance; + + void drawJoints(); + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/ScaleWidget.cpp b/src/Gui/Widgets/ScaleWidget.cpp index 57e0577..e7889b3 100644 --- a/src/Gui/Widgets/ScaleWidget.cpp +++ b/src/Gui/Widgets/ScaleWidget.cpp @@ -1,191 +1,191 @@ -#include "ScaleWidget.h" - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR > 9 - #include "glm/geometric.hpp" -#endif - -namespace ofx { -namespace piMapper { - -ScaleWidget::ScaleWidget(){ - _line.addVertex(ofPoint(0, 0)); - _line.addVertex(ofPoint(0, 0)); - - _handle.width = 20; - _handle.height = 20; - - _scale = 1.0f; - _surfaceManager = 0; - _selectedSurface = 0; -} - -void ScaleWidget::setup(){ - -} - -void ScaleWidget::update(){ - if(_surfaceManager == 0){ - return; - } - - if(_surfaceManager->getSelectedSurface() == 0){ - return; - } - - if(_selectedSurface != _surfaceManager->getSelectedSurface()){ - _selectedSurface = _surfaceManager->getSelectedSurface(); - setRect(_surfaceManager->getSelectedSurface()->getBoundingBox()); - } -} - -void ScaleWidget::draw(){ - if(_surfaceManager == 0){ - return; - } - - if(_surfaceManager->getSelectedSurface() != 0){ - ofPoint centroid = _surfaceManager->getSelectedSurface()->getBoundingBox().getCenter(); - float lineLength = centroid.distance( - ofPoint( - _surfaceManager->getSelectedSurface()->getBoundingBox().x + - _surfaceManager->getSelectedSurface()->getBoundingBox().width, - _surfaceManager->getSelectedSurface()->getBoundingBox().y)); - - // Handle surface move - float dx = _line[0].x - centroid.x; - float dy = _line[0].y - centroid.y; - - _line[0].x -= dx; - _line[0].y -= dy; - _line[1].x -= dx; - _line[1].y -= dy; - - // Continue - #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - float scale = lineLength / _line[0].distance(_line[1]); - #else - float scale = lineLength / glm::distance(_line[0], _line[1]); - #endif - - _line[1].x = _line[0].x + (_line[1].x - _line[0].x) * scale; - _line[1].y = _line[0].y + (_line[1].y - _line[0].y) * scale; - - _handle.x = _line[1].x - (_handle.width / 2.0f); - _handle.y = _line[1].y - (_handle.height / 2.0f); - } - - ofPushStyle(); - - ofSetColor(255, 255, 255); - ofNoFill(); - - ofSetLineWidth(1); - _line.draw(); - - ofFill(); - ofDrawRectangle( - _line.getVertices()[0].x - 5, - _line.getVertices()[0].y - 5, - 10, 10); - - ofNoFill(); - ofSetLineWidth(2); - ofDrawRectangle(_handle); - - ofPopStyle(); -} - -void ScaleWidget::onMousePressed(ofMouseEventArgs & args){ - if(_surfaceManager->getSelectedSurface() == 0){ - return; - } - - if(_handle.inside(args.x, args.y)){ - _dragging = true; - - GuiWidgetEvent e; - e.args = args; - ofNotifyEvent(guiWidgetEvent, e, this); - } -} - -void ScaleWidget::onMouseReleased(ofMouseEventArgs & args){ - if(_dragging){ - GuiWidgetEvent e; - e.args = args; - ofNotifyEvent(guiWidgetEvent, e, this); - } - - _dragging = false; -} - -void ScaleWidget::onMouseDragged(ofMouseEventArgs & args){ - if(_dragging){ - if(_surfaceManager == 0){ - return; - } - - if(_surfaceManager->getSelectedSurface() == 0){ - return; - } - - ofRectangle box = _surfaceManager->getSelectedSurface()->getBoundingBox(); - ofPolyline newLine = _line; - newLine[1].x = args.x; - newLine[1].y = args.y; - - #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - _scale = _surfaceManager->getSelectedSurface()->getScale() / - _line[0].distance(_line[1]) * - newLine[0].distance(newLine[1]); - #else - _scale = _surfaceManager->getSelectedSurface()->getScale() / - glm::distance(_line[0], _line[1]) * - glm::distance(newLine[0], newLine[1]); - #endif - - _line = newLine; - - _handle.x = _line[1].x - (_handle.width / 2.0f); - _handle.y = _line[1].y - (_handle.height / 2.0f); - - GuiWidgetEvent e; - e.args = args; - ofNotifyEvent(guiWidgetEvent, e, this); - } -} - -bool ScaleWidget::inside(float x, float y){ - ofPoint p = ofPoint(x, y); - return _handle.inside(p); -} - -void ScaleWidget::setRect(ofRectangle rect){ - if(_dragging){ - return; - } - - ofPoint center = rect.getCenter(); - - _line.getVertices()[0].x = center.x; - _line.getVertices()[0].y = center.y; - - _line.getVertices()[1].x = rect.x + rect.width; - _line.getVertices()[1].y = rect.y; - - _handle.x = rect.x + rect.width - (_handle.width / 2.0f); - _handle.y = rect.y - (_handle.height / 2.0f); -} - -void ScaleWidget::setSurfaceManager(SurfaceManager * sm){ - _surfaceManager = sm; - - if(_surfaceManager->getSelectedSurface() == 0){ - return; - } - - setRect(_surfaceManager->getSelectedSurface()->getBoundingBox()); -} - -} // namespace piMapper -} // namespace ofx +#include "ScaleWidget.h" + +#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR > 9 + #include "glm/geometric.hpp" +#endif + +namespace ofx { +namespace piMapper { + +ScaleWidget::ScaleWidget(){ + _line.addVertex(ofPoint(0, 0)); + _line.addVertex(ofPoint(0, 0)); + + _handle.width = 20; + _handle.height = 20; + + _scale = 1.0f; + _surfaceManager = 0; + _selectedSurface = 0; +} + +void ScaleWidget::setup(){ + +} + +void ScaleWidget::update(){ + if(_surfaceManager == 0){ + return; + } + + if(_surfaceManager->getSelectedSurface() == 0){ + return; + } + + if(_selectedSurface != _surfaceManager->getSelectedSurface()){ + _selectedSurface = _surfaceManager->getSelectedSurface(); + setRect(_surfaceManager->getSelectedSurface()->getBoundingBox()); + } +} + +void ScaleWidget::draw(){ + if(_surfaceManager == 0){ + return; + } + + if(_surfaceManager->getSelectedSurface() != 0){ + ofPoint centroid = _surfaceManager->getSelectedSurface()->getBoundingBox().getCenter(); + float lineLength = centroid.distance( + ofPoint( + _surfaceManager->getSelectedSurface()->getBoundingBox().x + + _surfaceManager->getSelectedSurface()->getBoundingBox().width, + _surfaceManager->getSelectedSurface()->getBoundingBox().y)); + + // Handle surface move + float dx = _line[0].x - centroid.x; + float dy = _line[0].y - centroid.y; + + _line[0].x -= dx; + _line[0].y -= dy; + _line[1].x -= dx; + _line[1].y -= dy; + + // Continue + #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 + float scale = lineLength / _line[0].distance(_line[1]); + #else + float scale = lineLength / glm::distance(_line[0], _line[1]); + #endif + + _line[1].x = _line[0].x + (_line[1].x - _line[0].x) * scale; + _line[1].y = _line[0].y + (_line[1].y - _line[0].y) * scale; + + _handle.x = _line[1].x - (_handle.width / 2.0f); + _handle.y = _line[1].y - (_handle.height / 2.0f); + } + + ofPushStyle(); + + ofSetColor(255, 255, 255); + ofNoFill(); + + ofSetLineWidth(1); + _line.draw(); + + ofFill(); + ofDrawRectangle( + _line.getVertices()[0].x - 5, + _line.getVertices()[0].y - 5, + 10, 10); + + ofNoFill(); + ofSetLineWidth(2); + ofDrawRectangle(_handle); + + ofPopStyle(); +} + +void ScaleWidget::onMousePressed(ofMouseEventArgs & args){ + if(_surfaceManager->getSelectedSurface() == 0){ + return; + } + + if(_handle.inside(args.x, args.y)){ + _dragging = true; + + GuiWidgetEvent e; + e.args = args; + ofNotifyEvent(guiWidgetEvent, e, this); + } +} + +void ScaleWidget::onMouseReleased(ofMouseEventArgs & args){ + if(_dragging){ + GuiWidgetEvent e; + e.args = args; + ofNotifyEvent(guiWidgetEvent, e, this); + } + + _dragging = false; +} + +void ScaleWidget::onMouseDragged(ofMouseEventArgs & args){ + if(_dragging){ + if(_surfaceManager == 0){ + return; + } + + if(_surfaceManager->getSelectedSurface() == 0){ + return; + } + + ofRectangle box = _surfaceManager->getSelectedSurface()->getBoundingBox(); + ofPolyline newLine = _line; + newLine[1].x = args.x; + newLine[1].y = args.y; + + #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 + _scale = _surfaceManager->getSelectedSurface()->getScale() / + _line[0].distance(_line[1]) * + newLine[0].distance(newLine[1]); + #else + _scale = _surfaceManager->getSelectedSurface()->getScale() / + glm::distance(_line[0], _line[1]) * + glm::distance(newLine[0], newLine[1]); + #endif + + _line = newLine; + + _handle.x = _line[1].x - (_handle.width / 2.0f); + _handle.y = _line[1].y - (_handle.height / 2.0f); + + GuiWidgetEvent e; + e.args = args; + ofNotifyEvent(guiWidgetEvent, e, this); + } +} + +bool ScaleWidget::inside(float x, float y){ + ofPoint p = ofPoint(x, y); + return _handle.inside(p); +} + +void ScaleWidget::setRect(ofRectangle rect){ + if(_dragging){ + return; + } + + ofPoint center = rect.getCenter(); + + _line.getVertices()[0].x = center.x; + _line.getVertices()[0].y = center.y; + + _line.getVertices()[1].x = rect.x + rect.width; + _line.getVertices()[1].y = rect.y; + + _handle.x = rect.x + rect.width - (_handle.width / 2.0f); + _handle.y = rect.y - (_handle.height / 2.0f); +} + +void ScaleWidget::setSurfaceManager(SurfaceManager * sm){ + _surfaceManager = sm; + + if(_surfaceManager->getSelectedSurface() == 0){ + return; + } + + setRect(_surfaceManager->getSelectedSurface()->getBoundingBox()); +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/ScaleWidget.h b/src/Gui/Widgets/ScaleWidget.h index b95e5e7..2cda6ee 100644 --- a/src/Gui/Widgets/ScaleWidget.h +++ b/src/Gui/Widgets/ScaleWidget.h @@ -1,50 +1,50 @@ -#pragma once - -#include "ofRectangle.h" -#include "ofPolyline.h" -#include "GuiBaseWidget.h" -#include "ofGraphics.h" -#include "BaseSurface.h" -#include "SurfaceManager.h" - -namespace ofx { -namespace piMapper { - -class ScaleWidget : public GuiBaseWidget { - public: - ScaleWidget(); - - void setup(); - void update(); - void draw(); - - void onMousePressed(ofMouseEventArgs & args); - void onMouseReleased(ofMouseEventArgs & args); - void onMouseDragged(ofMouseEventArgs & args); - - bool inside(float x, float y); - - // This should be the size of the objet's bounding box - void setSurfaceManager(SurfaceManager * sm); - - float getScale(){ - return _scale; - } - - private: - ofRectangle _handle; - - ofPolyline _line; - - float _scale; - - bool _dragging; - - BaseSurface * _selectedSurface; - SurfaceManager * _surfaceManager; - - void setRect(ofRectangle rect); -}; - -} // namespace piMapper +#pragma once + +#include "ofRectangle.h" +#include "ofPolyline.h" +#include "GuiBaseWidget.h" +#include "ofGraphics.h" +#include "BaseSurface.h" +#include "SurfaceManager.h" + +namespace ofx { +namespace piMapper { + +class ScaleWidget : public GuiBaseWidget { + public: + ScaleWidget(); + + void setup(); + void update(); + void draw(); + + void onMousePressed(ofMouseEventArgs & args); + void onMouseReleased(ofMouseEventArgs & args); + void onMouseDragged(ofMouseEventArgs & args); + + bool inside(float x, float y); + + // This should be the size of the objet's bounding box + void setSurfaceManager(SurfaceManager * sm); + + float getScale(){ + return _scale; + } + + private: + ofRectangle _handle; + + ofPolyline _line; + + float _scale; + + bool _dragging; + + BaseSurface * _selectedSurface; + SurfaceManager * _surfaceManager; + + void setRect(ofRectangle rect); +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/SourcesEditorWidget.cpp b/src/Gui/Widgets/SourcesEditorWidget.cpp index 7af2134..7dc145b 100644 --- a/src/Gui/Widgets/SourcesEditorWidget.cpp +++ b/src/Gui/Widgets/SourcesEditorWidget.cpp @@ -1,345 +1,345 @@ -#include "SourcesEditorWidget.h" - -namespace ofx { -namespace piMapper { - -SourcesEditorWidget::SourcesEditorWidget(){ - mediaServer = 0; -} - -void SourcesEditorWidget::setup(){ - createSelectors(); -} - -void SourcesEditorWidget::createSelectors(){ - imageSelector = new RadioList(); - videoSelector = new RadioList(); - fboSelector = new RadioList(); - - int numImages = mediaServer->getNumImages(); - int numVideos = mediaServer->getNumVideos(); - int numFbos = mediaServer->getNumFboSources(); - - // Depending on media count, decide what to load and initialize - if(numImages){ - // Get image names from media server - std::vector imageNames = mediaServer->getImageNames(); - imageSelector->setup("Images", imageNames, mediaServer->getImagePaths()); - ofAddListener(imageSelector->onRadioSelected, this, &SourcesEditorWidget::handleImageSelected); - } - if(numVideos){ - std::vector videoNames = mediaServer->getVideoNames(); - videoSelector->setup("Videos", videoNames, mediaServer->getVideoPaths()); - ofAddListener(videoSelector->onRadioSelected, this, &SourcesEditorWidget::handleVideoSelected); - } - if(numFbos){ - std::vector fboNames = mediaServer->getFboSourceNames(); - fboSelector->setup("FBOs", fboNames, fboNames); - ofAddListener(fboSelector->onRadioSelected, this, &SourcesEditorWidget::handleFboSelected); - } - - // Align menus - int menuPosX = 20; - int distX = 230; - if(numImages){ - imageSelector->setPosition(menuPosX, 20); - menuPosX += distX; - } - if(numVideos){ - videoSelector->setPosition(menuPosX, 20); - menuPosX += distX; - } - if(numFbos){ - fboSelector->setPosition(menuPosX, 20); - } -} - -void SourcesEditorWidget::draw(){ - // Don't draw if there is no source selected - if(surfaceManager->getSelectedSurface() == 0){ - return; - } - if(imageSelector->size()){ - imageSelector->draw(); - } - if(videoSelector->size()){ - videoSelector->draw(); - } - if(fboSelector->size()){ - fboSelector->draw(); - } -} - -// TODO: Redesign the selectors completely so they do not need enable and disable. -void SourcesEditorWidget::disable(){ - if(imageSelector->size()){ - imageSelector->disable(); - } - if(videoSelector->size()){ - videoSelector->disable(); - } - if(fboSelector->size()){ - fboSelector->disable(); - } -} - -void SourcesEditorWidget::enable(){ - // Don't enable if there is no surface selected - if(surfaceManager->getSelectedSurface() == 0){ - ofLogNotice("SourcesEditorWidget") << "No surface selected. Not enabling and not showing source list."; - return; - } - if(imageSelector->size()){ - imageSelector->enable(); - } - if(videoSelector->size()){ - videoSelector->enable(); - } - if(fboSelector->size()){ - fboSelector->enable(); - } - BaseSource * source = surfaceManager->getSelectedSurface()->getSource(); - - // TODO: getPath should be replaced with something like getId() as now we - // use paths for loadable sources and names for FBOs - if(source->getType() == SourceType::SOURCE_TYPE_FBO){ - selectSourceRadioButton(source->getName()); - }else{ - selectSourceRadioButton(source->getPath()); - } -} - -void SourcesEditorWidget::setSurfaceManager(SurfaceManager * newSurfaceManager){ - surfaceManager = newSurfaceManager; -} - -void SourcesEditorWidget::setCmdManager(CmdManager * cmdManager){ - _cmdManager = cmdManager; -} - -void SourcesEditorWidget::setMediaServer(MediaServer * newMediaServer){ - if(newMediaServer == 0){ - ofLogFatalError("SourcesEditorWidget") << "New media server is 0"; - exit(EXIT_FAILURE); - } - - if(mediaServer != 0){ - removeMediaServerListeners(); - } - clearMediaServer(); - mediaServer = newMediaServer; - addMediaServerListeners(); -} - -MediaServer * SourcesEditorWidget::getMediaServer(){ - return mediaServer; -} - -void SourcesEditorWidget::selectSourceRadioButton(std::string & sourcePath){ - if(sourcePath == ""){ - ofLogNotice("SourcesEditorWidget") << "Path is empty"; - if(imageSelector->size()){ - imageSelector->unselectAll(); - } - if(videoSelector->size()){ - videoSelector->unselectAll(); - } - if(fboSelector->size()){ - fboSelector->unselectAll(); - } - return; - }else{ - // Check image selector first - bool imageRadioSelected = false; - bool videoRadioSelected = false; - bool fboRadioSelected = false; - if(imageSelector->size()){ - imageRadioSelected = imageSelector->selectItemByValue(sourcePath); - } - if(videoSelector->size()){ - videoRadioSelected = videoSelector->selectItemByValue(sourcePath); - } - if(fboSelector->size()){ - fboRadioSelected = fboSelector->selectItemByValue(sourcePath); - } - if(imageRadioSelected || videoRadioSelected || fboRadioSelected){ - return; - } - // Log warning if we are still here - ofLogWarning("SourcesEditorWidget") << "Could not find option in any of the source lists"; - } -} - -void SourcesEditorWidget::addMediaServerListeners(){ - // Check if the media server is valid - if(mediaServer == 0){ - ofLogError("SourcesEditorWidget::addMediaServerListeners", "Media server not set"); - return; - } - // Add listeners to custom events of the media server - ofAddListener(mediaServer->onImageAdded, this, &SourcesEditorWidget::handleImageAdded); - ofAddListener(mediaServer->onImageRemoved, this, &SourcesEditorWidget::handleImageRemoved); - ofAddListener(mediaServer->onVideoAdded, this, &SourcesEditorWidget::handleVideoAdded); - ofAddListener(mediaServer->onVideoRemoved, this, &SourcesEditorWidget::handleVideoRemoved); - ofAddListener(mediaServer->onImageLoaded, this, &SourcesEditorWidget::handleImageLoaded); - ofAddListener(mediaServer->onImageUnloaded, this, &SourcesEditorWidget::handleImageUnloaded); - - ofAddListener(mediaServer->onFboSourceAdded, this, &SourcesEditorWidget::handleFboSourceAdded); - ofAddListener(mediaServer->onFboSourceRemoved, this, &SourcesEditorWidget::handleFboSourceRemoved); - ofAddListener(mediaServer->onFboSourceLoaded, this, &SourcesEditorWidget::handleFboSourceLoaded); - ofAddListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditorWidget::handleFboSourceUnloaded); - -} - -void SourcesEditorWidget::removeMediaServerListeners(){ - // Check if the media server is valid - if(mediaServer == 0){ - ofLogError("SourcesEditorWidget::addMediaServerListeners", "Media server not set"); - return; - } - // Remove listeners to custom events of the media server - ofRemoveListener(mediaServer->onImageAdded, this, &SourcesEditorWidget::handleImageAdded); - ofRemoveListener(mediaServer->onImageRemoved, this, &SourcesEditorWidget::handleImageRemoved); - ofRemoveListener(mediaServer->onVideoAdded, this, &SourcesEditorWidget::handleVideoAdded); - ofRemoveListener(mediaServer->onVideoRemoved, this, &SourcesEditorWidget::handleVideoRemoved); - ofRemoveListener(mediaServer->onImageLoaded, this, &SourcesEditorWidget::handleImageLoaded); - ofRemoveListener(mediaServer->onImageUnloaded, this, &SourcesEditorWidget::handleImageUnloaded); - ofRemoveListener(mediaServer->onFboSourceAdded, this, &SourcesEditorWidget::handleFboSourceAdded); - ofRemoveListener(mediaServer->onFboSourceRemoved, this, &SourcesEditorWidget::handleFboSourceRemoved); - ofRemoveListener(mediaServer->onFboSourceLoaded, this, &SourcesEditorWidget::handleFboSourceLoaded); - ofRemoveListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditorWidget::handleFboSourceUnloaded); -} - -void SourcesEditorWidget::handleImageSelected(std::string & imagePath){ - _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_IMAGE, - imagePath, - surfaceManager->getSelectedSurface(), - (SourcesEditorWidget *)this)); -} - -void SourcesEditorWidget::setImageSource(std::string & imagePath){ - // Unselect selected items - videoSelector->unselectAll(); - fboSelector->unselectAll(); - - BaseSurface * surface = surfaceManager->getSelectedSurface(); - if(surface == 0){ - ofLogWarning("SourcesEditorWidget") << "No surface selected"; - return; - } - - // Unload old media - BaseSource * source = surface->getSource(); - if(source->isLoadable()){ - mediaServer->unloadMedia(source->getPath()); - }else{ - mediaServer->unloadMedia(source->getName()); - } - - // Load new image - surface->setSource(mediaServer->loadImage(imagePath)); -} - -void SourcesEditorWidget::handleVideoSelected(std::string & videoPath){ - _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_VIDEO, - videoPath, - surfaceManager->getSelectedSurface(), - (SourcesEditorWidget *)this)); -} - -void SourcesEditorWidget::setVideoSource(std::string & videoPath){ - // Unselect any selected items - fboSelector->unselectAll(); - imageSelector->unselectAll(); - - BaseSurface * surface = surfaceManager->getSelectedSurface(); - if(surface == 0){ - ofLogWarning("SourcesEditorWidget") << "No surface selected"; - return; - } - - // Unload old media - BaseSource * source = surface->getSource(); - if(source->isLoadable()){ - mediaServer->unloadMedia(source->getPath()); - }else{ - mediaServer->unloadMedia(source->getName()); - } - - // Load new video - surface->setSource(mediaServer->loadVideo(videoPath)); -} - -void SourcesEditorWidget::handleFboSelected(std::string & fboName){ - _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_FBO, - fboName, - surfaceManager->getSelectedSurface(), - (SourcesEditorWidget *)this)); -} - -void SourcesEditorWidget::setFboSource(std::string & fboName){ - videoSelector->unselectAll(); - imageSelector->unselectAll(); - - // Get selected surface - BaseSurface * surface = surfaceManager->getSelectedSurface(); - if(surface == 0){ - ofLogWarning("SourcesEditorWidget") << "No surface selected"; - return; - } - - // Unload old media - BaseSource * source = surface->getSource(); - if(source->isLoadable()){ - mediaServer->unloadMedia(source->getPath()); - }else{ - mediaServer->unloadMedia(source->getName()); - } - - // Load new FBO - surface->setSource(mediaServer->loadFboSource(fboName)); -} - -void SourcesEditorWidget::clearSource(){ - BaseSurface * surface = surfaceManager->getSelectedSurface(); - - // Unload old media - BaseSource * source = surface->getSource(); - if(source->isLoadable()){ - mediaServer->unloadMedia(source->getPath()); - }else{ - mediaServer->unloadMedia(source->getName()); - } - - // Reset default source - surface->setSource(surface->getDefaultSource()); -} - -void SourcesEditorWidget::clearMediaServer(){ - if(mediaServer == 0){ - return; - } - mediaServer->clear(); - delete mediaServer; - mediaServer = 0; -} - -// TODO: There is no need for those at the moment. They add too much overhead. -void SourcesEditorWidget::handleImageAdded(std::string & path){ - ofLogNotice("SourcesEditorWidget::handleImageAdded") - << "Image path: " - << path; -} - -void SourcesEditorWidget::handleImageRemoved(std::string & path){} -void SourcesEditorWidget::handleVideoAdded(std::string & path){} -void SourcesEditorWidget::handleVideoRemoved(std::string & path){} -void SourcesEditorWidget::handleImageLoaded(std::string & path){} -void SourcesEditorWidget::handleImageUnloaded(std::string & path){} -void SourcesEditorWidget::handleFboSourceAdded(std::string & name){} -void SourcesEditorWidget::handleFboSourceRemoved(std::string & name){} -void SourcesEditorWidget::handleFboSourceLoaded(std::string & name){} -void SourcesEditorWidget::handleFboSourceUnloaded(std::string & name){} - -} // namespace piMapper +#include "SourcesEditorWidget.h" + +namespace ofx { +namespace piMapper { + +SourcesEditorWidget::SourcesEditorWidget(){ + mediaServer = 0; +} + +void SourcesEditorWidget::setup(){ + createSelectors(); +} + +void SourcesEditorWidget::createSelectors(){ + imageSelector = new RadioList(); + videoSelector = new RadioList(); + fboSelector = new RadioList(); + + int numImages = mediaServer->getNumImages(); + int numVideos = mediaServer->getNumVideos(); + int numFbos = mediaServer->getNumFboSources(); + + // Depending on media count, decide what to load and initialize + if(numImages){ + // Get image names from media server + std::vector imageNames = mediaServer->getImageNames(); + imageSelector->setup("Images", imageNames, mediaServer->getImagePaths()); + ofAddListener(imageSelector->onRadioSelected, this, &SourcesEditorWidget::handleImageSelected); + } + if(numVideos){ + std::vector videoNames = mediaServer->getVideoNames(); + videoSelector->setup("Videos", videoNames, mediaServer->getVideoPaths()); + ofAddListener(videoSelector->onRadioSelected, this, &SourcesEditorWidget::handleVideoSelected); + } + if(numFbos){ + std::vector fboNames = mediaServer->getFboSourceNames(); + fboSelector->setup("FBOs", fboNames, fboNames); + ofAddListener(fboSelector->onRadioSelected, this, &SourcesEditorWidget::handleFboSelected); + } + + // Align menus + int menuPosX = 20; + int distX = 230; + if(numImages){ + imageSelector->setPosition(menuPosX, 20); + menuPosX += distX; + } + if(numVideos){ + videoSelector->setPosition(menuPosX, 20); + menuPosX += distX; + } + if(numFbos){ + fboSelector->setPosition(menuPosX, 20); + } +} + +void SourcesEditorWidget::draw(){ + // Don't draw if there is no source selected + if(surfaceManager->getSelectedSurface() == 0){ + return; + } + if(imageSelector->size()){ + imageSelector->draw(); + } + if(videoSelector->size()){ + videoSelector->draw(); + } + if(fboSelector->size()){ + fboSelector->draw(); + } +} + +// TODO: Redesign the selectors completely so they do not need enable and disable. +void SourcesEditorWidget::disable(){ + if(imageSelector->size()){ + imageSelector->disable(); + } + if(videoSelector->size()){ + videoSelector->disable(); + } + if(fboSelector->size()){ + fboSelector->disable(); + } +} + +void SourcesEditorWidget::enable(){ + // Don't enable if there is no surface selected + if(surfaceManager->getSelectedSurface() == 0){ + ofLogNotice("SourcesEditorWidget") << "No surface selected. Not enabling and not showing source list."; + return; + } + if(imageSelector->size()){ + imageSelector->enable(); + } + if(videoSelector->size()){ + videoSelector->enable(); + } + if(fboSelector->size()){ + fboSelector->enable(); + } + BaseSource * source = surfaceManager->getSelectedSurface()->getSource(); + + // TODO: getPath should be replaced with something like getId() as now we + // use paths for loadable sources and names for FBOs + if(source->getType() == SourceType::SOURCE_TYPE_FBO){ + selectSourceRadioButton(source->getName()); + }else{ + selectSourceRadioButton(source->getPath()); + } +} + +void SourcesEditorWidget::setSurfaceManager(SurfaceManager * newSurfaceManager){ + surfaceManager = newSurfaceManager; +} + +void SourcesEditorWidget::setCmdManager(CmdManager * cmdManager){ + _cmdManager = cmdManager; +} + +void SourcesEditorWidget::setMediaServer(MediaServer * newMediaServer){ + if(newMediaServer == 0){ + ofLogFatalError("SourcesEditorWidget") << "New media server is 0"; + exit(EXIT_FAILURE); + } + + if(mediaServer != 0){ + removeMediaServerListeners(); + } + clearMediaServer(); + mediaServer = newMediaServer; + addMediaServerListeners(); +} + +MediaServer * SourcesEditorWidget::getMediaServer(){ + return mediaServer; +} + +void SourcesEditorWidget::selectSourceRadioButton(std::string & sourcePath){ + if(sourcePath == ""){ + ofLogNotice("SourcesEditorWidget") << "Path is empty"; + if(imageSelector->size()){ + imageSelector->unselectAll(); + } + if(videoSelector->size()){ + videoSelector->unselectAll(); + } + if(fboSelector->size()){ + fboSelector->unselectAll(); + } + return; + }else{ + // Check image selector first + bool imageRadioSelected = false; + bool videoRadioSelected = false; + bool fboRadioSelected = false; + if(imageSelector->size()){ + imageRadioSelected = imageSelector->selectItemByValue(sourcePath); + } + if(videoSelector->size()){ + videoRadioSelected = videoSelector->selectItemByValue(sourcePath); + } + if(fboSelector->size()){ + fboRadioSelected = fboSelector->selectItemByValue(sourcePath); + } + if(imageRadioSelected || videoRadioSelected || fboRadioSelected){ + return; + } + // Log warning if we are still here + ofLogWarning("SourcesEditorWidget") << "Could not find option in any of the source lists"; + } +} + +void SourcesEditorWidget::addMediaServerListeners(){ + // Check if the media server is valid + if(mediaServer == 0){ + ofLogError("SourcesEditorWidget::addMediaServerListeners", "Media server not set"); + return; + } + // Add listeners to custom events of the media server + ofAddListener(mediaServer->onImageAdded, this, &SourcesEditorWidget::handleImageAdded); + ofAddListener(mediaServer->onImageRemoved, this, &SourcesEditorWidget::handleImageRemoved); + ofAddListener(mediaServer->onVideoAdded, this, &SourcesEditorWidget::handleVideoAdded); + ofAddListener(mediaServer->onVideoRemoved, this, &SourcesEditorWidget::handleVideoRemoved); + ofAddListener(mediaServer->onImageLoaded, this, &SourcesEditorWidget::handleImageLoaded); + ofAddListener(mediaServer->onImageUnloaded, this, &SourcesEditorWidget::handleImageUnloaded); + + ofAddListener(mediaServer->onFboSourceAdded, this, &SourcesEditorWidget::handleFboSourceAdded); + ofAddListener(mediaServer->onFboSourceRemoved, this, &SourcesEditorWidget::handleFboSourceRemoved); + ofAddListener(mediaServer->onFboSourceLoaded, this, &SourcesEditorWidget::handleFboSourceLoaded); + ofAddListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditorWidget::handleFboSourceUnloaded); + +} + +void SourcesEditorWidget::removeMediaServerListeners(){ + // Check if the media server is valid + if(mediaServer == 0){ + ofLogError("SourcesEditorWidget::addMediaServerListeners", "Media server not set"); + return; + } + // Remove listeners to custom events of the media server + ofRemoveListener(mediaServer->onImageAdded, this, &SourcesEditorWidget::handleImageAdded); + ofRemoveListener(mediaServer->onImageRemoved, this, &SourcesEditorWidget::handleImageRemoved); + ofRemoveListener(mediaServer->onVideoAdded, this, &SourcesEditorWidget::handleVideoAdded); + ofRemoveListener(mediaServer->onVideoRemoved, this, &SourcesEditorWidget::handleVideoRemoved); + ofRemoveListener(mediaServer->onImageLoaded, this, &SourcesEditorWidget::handleImageLoaded); + ofRemoveListener(mediaServer->onImageUnloaded, this, &SourcesEditorWidget::handleImageUnloaded); + ofRemoveListener(mediaServer->onFboSourceAdded, this, &SourcesEditorWidget::handleFboSourceAdded); + ofRemoveListener(mediaServer->onFboSourceRemoved, this, &SourcesEditorWidget::handleFboSourceRemoved); + ofRemoveListener(mediaServer->onFboSourceLoaded, this, &SourcesEditorWidget::handleFboSourceLoaded); + ofRemoveListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditorWidget::handleFboSourceUnloaded); +} + +void SourcesEditorWidget::handleImageSelected(std::string & imagePath){ + _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_IMAGE, + imagePath, + surfaceManager->getSelectedSurface(), + (SourcesEditorWidget *)this)); +} + +void SourcesEditorWidget::setImageSource(std::string & imagePath){ + // Unselect selected items + videoSelector->unselectAll(); + fboSelector->unselectAll(); + + BaseSurface * surface = surfaceManager->getSelectedSurface(); + if(surface == 0){ + ofLogWarning("SourcesEditorWidget") << "No surface selected"; + return; + } + + // Unload old media + BaseSource * source = surface->getSource(); + if(source->isLoadable()){ + mediaServer->unloadMedia(source->getPath()); + }else{ + mediaServer->unloadMedia(source->getName()); + } + + // Load new image + surface->setSource(mediaServer->loadImage(imagePath)); +} + +void SourcesEditorWidget::handleVideoSelected(std::string & videoPath){ + _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_VIDEO, + videoPath, + surfaceManager->getSelectedSurface(), + (SourcesEditorWidget *)this)); +} + +void SourcesEditorWidget::setVideoSource(std::string & videoPath){ + // Unselect any selected items + fboSelector->unselectAll(); + imageSelector->unselectAll(); + + BaseSurface * surface = surfaceManager->getSelectedSurface(); + if(surface == 0){ + ofLogWarning("SourcesEditorWidget") << "No surface selected"; + return; + } + + // Unload old media + BaseSource * source = surface->getSource(); + if(source->isLoadable()){ + mediaServer->unloadMedia(source->getPath()); + }else{ + mediaServer->unloadMedia(source->getName()); + } + + // Load new video + surface->setSource(mediaServer->loadVideo(videoPath)); +} + +void SourcesEditorWidget::handleFboSelected(std::string & fboName){ + _cmdManager->exec(new SetSourceCmd(SourceType::SOURCE_TYPE_FBO, + fboName, + surfaceManager->getSelectedSurface(), + (SourcesEditorWidget *)this)); +} + +void SourcesEditorWidget::setFboSource(std::string & fboName){ + videoSelector->unselectAll(); + imageSelector->unselectAll(); + + // Get selected surface + BaseSurface * surface = surfaceManager->getSelectedSurface(); + if(surface == 0){ + ofLogWarning("SourcesEditorWidget") << "No surface selected"; + return; + } + + // Unload old media + BaseSource * source = surface->getSource(); + if(source->isLoadable()){ + mediaServer->unloadMedia(source->getPath()); + }else{ + mediaServer->unloadMedia(source->getName()); + } + + // Load new FBO + surface->setSource(mediaServer->loadFboSource(fboName)); +} + +void SourcesEditorWidget::clearSource(){ + BaseSurface * surface = surfaceManager->getSelectedSurface(); + + // Unload old media + BaseSource * source = surface->getSource(); + if(source->isLoadable()){ + mediaServer->unloadMedia(source->getPath()); + }else{ + mediaServer->unloadMedia(source->getName()); + } + + // Reset default source + surface->setSource(surface->getDefaultSource()); +} + +void SourcesEditorWidget::clearMediaServer(){ + if(mediaServer == 0){ + return; + } + mediaServer->clear(); + delete mediaServer; + mediaServer = 0; +} + +// TODO: There is no need for those at the moment. They add too much overhead. +void SourcesEditorWidget::handleImageAdded(std::string & path){ + ofLogNotice("SourcesEditorWidget::handleImageAdded") + << "Image path: " + << path; +} + +void SourcesEditorWidget::handleImageRemoved(std::string & path){} +void SourcesEditorWidget::handleVideoAdded(std::string & path){} +void SourcesEditorWidget::handleVideoRemoved(std::string & path){} +void SourcesEditorWidget::handleImageLoaded(std::string & path){} +void SourcesEditorWidget::handleImageUnloaded(std::string & path){} +void SourcesEditorWidget::handleFboSourceAdded(std::string & name){} +void SourcesEditorWidget::handleFboSourceRemoved(std::string & name){} +void SourcesEditorWidget::handleFboSourceLoaded(std::string & name){} +void SourcesEditorWidget::handleFboSourceUnloaded(std::string & name){} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/SourcesEditorWidget.h b/src/Gui/Widgets/SourcesEditorWidget.h index 59c6278..5a0baea 100644 --- a/src/Gui/Widgets/SourcesEditorWidget.h +++ b/src/Gui/Widgets/SourcesEditorWidget.h @@ -1,79 +1,79 @@ -#pragma once - -#include "ofGraphics.h" -#include "ofEvents.h" -#include "SurfaceManager.h" -#include "RadioList.h" -#include "MediaServer.h" -#include "CmdManager.h" -#include "SetSourceCmd.h" - -namespace ofx { -namespace piMapper { - -class SourcesEditorWidget { - public: - SourcesEditorWidget(); - - void setup(); - void draw(); - void loadImage(std::string name, std::string path); - void disable(); - void enable(); - void setSurfaceManager(SurfaceManager * newSurfaceManager); - void setCmdManager(CmdManager * cmdManager); - - // Sets external MediaServer - void setMediaServer(MediaServer * newMediaServer); - MediaServer * getMediaServer(); - //void selectImageSourceRadioButton(std::string name); - void selectSourceRadioButton(std::string & sourcePath); - - int getLoadedTexCount(); - ofTexture * getTexture(int index); - - void setImageSource(std::string & imagePath); - void setVideoSource(std::string & videoPath); - void setFboSource(std::string & fboName); - void clearSource(); - - private: - MediaServer * mediaServer; - SurfaceManager * surfaceManager; - RadioList * imageSelector; - RadioList * videoSelector; - RadioList * fboSelector; - CmdManager * _cmdManager; - - // Methods for creating and destroying the source selectors - void createSelectors(); - - // Methods for adding and removing listeners to the media server - void addMediaServerListeners(); - void removeMediaServerListeners(); - - // Handles GUI event, whenever someone has clicked on a radio button - void handleImageSelected(std::string & imagePath); - void handleVideoSelected(std::string & videoPath); - void handleFboSelected(std::string & fboName); - - // Careful clearing of the media server, - // clears only if the media server has been initialized locally - void clearMediaServer(); - - // MediaServer event handlers - void handleImageAdded(std::string & path); - void handleImageRemoved(std::string & path); - void handleVideoAdded(std::string & path); - void handleVideoRemoved(std::string & path); - void handleImageLoaded(std::string & path); - void handleImageUnloaded(std::string & path); - void handleFboSourceAdded(std::string & name); - void handleFboSourceRemoved(std::string & name); - void handleFboSourceLoaded(std::string & name); - void handleFboSourceUnloaded(std::string & name); - -}; - -} // namespace piMapper +#pragma once + +#include "ofGraphics.h" +#include "ofEvents.h" +#include "SurfaceManager.h" +#include "RadioList.h" +#include "MediaServer.h" +#include "CmdManager.h" +#include "SetSourceCmd.h" + +namespace ofx { +namespace piMapper { + +class SourcesEditorWidget { + public: + SourcesEditorWidget(); + + void setup(); + void draw(); + void loadImage(std::string name, std::string path); + void disable(); + void enable(); + void setSurfaceManager(SurfaceManager * newSurfaceManager); + void setCmdManager(CmdManager * cmdManager); + + // Sets external MediaServer + void setMediaServer(MediaServer * newMediaServer); + MediaServer * getMediaServer(); + //void selectImageSourceRadioButton(std::string name); + void selectSourceRadioButton(std::string & sourcePath); + + int getLoadedTexCount(); + ofTexture * getTexture(int index); + + void setImageSource(std::string & imagePath); + void setVideoSource(std::string & videoPath); + void setFboSource(std::string & fboName); + void clearSource(); + + private: + MediaServer * mediaServer; + SurfaceManager * surfaceManager; + RadioList * imageSelector; + RadioList * videoSelector; + RadioList * fboSelector; + CmdManager * _cmdManager; + + // Methods for creating and destroying the source selectors + void createSelectors(); + + // Methods for adding and removing listeners to the media server + void addMediaServerListeners(); + void removeMediaServerListeners(); + + // Handles GUI event, whenever someone has clicked on a radio button + void handleImageSelected(std::string & imagePath); + void handleVideoSelected(std::string & videoPath); + void handleFboSelected(std::string & fboName); + + // Careful clearing of the media server, + // clears only if the media server has been initialized locally + void clearMediaServer(); + + // MediaServer event handlers + void handleImageAdded(std::string & path); + void handleImageRemoved(std::string & path); + void handleVideoAdded(std::string & path); + void handleVideoRemoved(std::string & path); + void handleImageLoaded(std::string & path); + void handleImageUnloaded(std::string & path); + void handleFboSourceAdded(std::string & name); + void handleFboSourceRemoved(std::string & name); + void handleFboSourceLoaded(std::string & name); + void handleFboSourceUnloaded(std::string & name); + +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/SurfaceHighlightWidget.cpp b/src/Gui/Widgets/SurfaceHighlightWidget.cpp index ccaec16..2f99d8a 100644 --- a/src/Gui/Widgets/SurfaceHighlightWidget.cpp +++ b/src/Gui/Widgets/SurfaceHighlightWidget.cpp @@ -1,71 +1,71 @@ -#include "SurfaceHighlightWidget.h" - -namespace ofx { -namespace piMapper { - -SurfaceHighlightWidget::SurfaceHighlightWidget(){ - _sm = 0; -} - -void SurfaceHighlightWidget::draw(){ - if(_sm == 0){ - return; - } - - drawAllSurfaceOutlines(); - - if(_sm->getSelectedSurface() == 0){ - return; - } - - ofPushStyle(); - ofSetLineWidth(2); - ofSetColor(255); - - drawSurfaceOutlines(_sm->getSelectedSurface()); - - ofPopStyle(); -} - -void SurfaceHighlightWidget::drawAllSurfaceOutlines(){ - if(_sm == 0){ - return; - } - - ofPushStyle(); - ofSetColor(255, 255, 255, 150); - ofSetLineWidth(2); - for(unsigned int i = 0; i < _sm->size(); ++i){ - if(_sm->getSurface(i) != _sm->getSelectedSurface()){ - drawSurfaceOutlines(_sm->getSurface(i)); - } - } - ofPopStyle(); -} - -void SurfaceHighlightWidget::drawSurfaceOutlines(BaseSurface * s){ - // TODO: Use Surface::drawOutline here - if(s->getType() == SurfaceType::QUAD_SURFACE && - ((QuadSurface *)s)->getPerspectiveWarping()){ - ofPolyline line = s->getHitArea(); - line.draw(); - }else if(s->getType() == SurfaceType::GRID_WARP_SURFACE){ - s->getMesh().drawWireframe(); - }else if(s->getType() == SurfaceType::HEXAGON_SURFACE){ - s->getMesh().drawWireframe(); - }else{ - ofPolyline p; - for(unsigned int i = 0; - i < s->getMesh().getVertices().size(); - ++i){ - - p.addVertex(ofPoint( - s->getMesh().getVertices()[i])); - } - p.close(); - p.draw(); - } -} - -} // namespace piMapper -} // namespace ofx +#include "SurfaceHighlightWidget.h" + +namespace ofx { +namespace piMapper { + +SurfaceHighlightWidget::SurfaceHighlightWidget(){ + _sm = 0; +} + +void SurfaceHighlightWidget::draw(){ + if(_sm == 0){ + return; + } + + drawAllSurfaceOutlines(); + + if(_sm->getSelectedSurface() == 0){ + return; + } + + ofPushStyle(); + ofSetLineWidth(2); + ofSetColor(255); + + drawSurfaceOutlines(_sm->getSelectedSurface()); + + ofPopStyle(); +} + +void SurfaceHighlightWidget::drawAllSurfaceOutlines(){ + if(_sm == 0){ + return; + } + + ofPushStyle(); + ofSetColor(255, 255, 255, 150); + ofSetLineWidth(2); + for(unsigned int i = 0; i < _sm->size(); ++i){ + if(_sm->getSurface(i) != _sm->getSelectedSurface()){ + drawSurfaceOutlines(_sm->getSurface(i)); + } + } + ofPopStyle(); +} + +void SurfaceHighlightWidget::drawSurfaceOutlines(BaseSurface * s){ + // TODO: Use Surface::drawOutline here + if(s->getType() == SurfaceType::QUAD_SURFACE && + ((QuadSurface *)s)->getPerspectiveWarping()){ + ofPolyline line = s->getHitArea(); + line.draw(); + }else if(s->getType() == SurfaceType::GRID_WARP_SURFACE){ + s->getMesh().drawWireframe(); + }else if(s->getType() == SurfaceType::HEXAGON_SURFACE){ + s->getMesh().drawWireframe(); + }else{ + ofPolyline p; + for(unsigned int i = 0; + i < s->getMesh().getVertices().size(); + ++i){ + + p.addVertex(ofPoint( + s->getMesh().getVertices()[i])); + } + p.close(); + p.draw(); + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/SurfaceHighlightWidget.h b/src/Gui/Widgets/SurfaceHighlightWidget.h index 00c8c6b..e5b6ee9 100644 --- a/src/Gui/Widgets/SurfaceHighlightWidget.h +++ b/src/Gui/Widgets/SurfaceHighlightWidget.h @@ -1,32 +1,32 @@ -#pragma once - -#include "GuiBaseWidget.h" -#include "SurfaceManager.h" - -namespace ofx { -namespace piMapper { - -class SurfaceHighlightWidget : public GuiBaseWidget { - public: - SurfaceHighlightWidget(); - - void setup(){} - void update(){} - void draw(); - - void onMousePressed(ofMouseEventArgs & args){} - void onMouseReleased(ofMouseEventArgs & args){} - void onMouseDragged(ofMouseEventArgs & args){} - - bool inside(float x, float y){ return false; } - - void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } - void drawAllSurfaceOutlines(); - void drawSurfaceOutlines(BaseSurface * s); - - private: - SurfaceManager * _sm; -}; - -} // namespace piMappe +#pragma once + +#include "GuiBaseWidget.h" +#include "SurfaceManager.h" + +namespace ofx { +namespace piMapper { + +class SurfaceHighlightWidget : public GuiBaseWidget { + public: + SurfaceHighlightWidget(); + + void setup(){} + void update(){} + void draw(); + + void onMousePressed(ofMouseEventArgs & args){} + void onMouseReleased(ofMouseEventArgs & args){} + void onMouseDragged(ofMouseEventArgs & args){} + + bool inside(float x, float y){ return false; } + + void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } + void drawAllSurfaceOutlines(); + void drawSurfaceOutlines(BaseSurface * s); + + private: + SurfaceManager * _sm; +}; + +} // namespace piMappe } // namespace ofx \ No newline at end of file diff --git a/src/Gui/Widgets/TextureEditorWidget.cpp b/src/Gui/Widgets/TextureEditorWidget.cpp index f94599a..9af649e 100644 --- a/src/Gui/Widgets/TextureEditorWidget.cpp +++ b/src/Gui/Widgets/TextureEditorWidget.cpp @@ -1,408 +1,408 @@ -#include "TextureEditorWidget.h" - -namespace ofx { -namespace piMapper { - -TextureEditorWidget::TextureEditorWidget(){ - _pollCreateJoints = false; - - clear(); -} - -void TextureEditorWidget::setup(){ - // Nothing here yet. -} - -void TextureEditorWidget::update(){ - if(surface == 0){ - return; - } - - if(_pollCreateJoints){ - createJoints(); - } - - // update surface if one of the joints is being dragged - Vec2 textureSize = Vec2(surface->getSource()->getTexture()->getWidth(), - surface->getSource()->getTexture()->getHeight()); - - // Get selected joint index - int selectedJointIndex = 0; - bool bJointSelected = false; - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->isDragged() || joints[i]->isSelected()){ - selectedJointIndex = i; - bJointSelected = true; - break; - } - } // for - - // Constrain quad texture selection - if(joints.size() == 4){ - if(bJointSelected){ - constrainJointsToQuad(selectedJointIndex); - - if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ - GridWarpSurface * s = (GridWarpSurface *)surface; - std::vector texCoords = surface->getTexCoords(); - Vec2 textureSize = Vec2( - surface->getSource()->getTexture()->getWidth(), - surface->getSource()->getTexture()->getHeight()); - - int rows = s->getGridRows(); - int cols = s->getGridCols(); - int vertsPerRow = cols + 1; - - // Distance between horizontal tex coords - float sx = joints[0]->position.x / textureSize.x; - float ex = joints[1]->position.x / textureSize.x; - float dx = (ex - sx) / (float)cols; - - // Distance between vertical tex coords - float sy = joints[0]->position.y / textureSize.y; - float ey = joints[2]->position.y / textureSize.y; - float dy = (ey - sy) / (float)rows; - - int i = 0; - for(int iy = 0; iy <= rows; ++iy){ - for(int ix = 0; ix <= cols; ++ix){ - Vec2 t; - t.x = sx + dx * ix; - t.y = sy + dy * iy; - surface->setTexCoord(i, t); - ++i; - } - } - }else{ - for(int i = 0; i < joints.size(); i++){ - surface->setTexCoord(i, joints[i]->position / textureSize); - } - } - } // if - }else{ - if(bJointSelected){ - surface->setTexCoord(selectedJointIndex, joints[selectedJointIndex]->position / textureSize); - } - } // else -} - -void TextureEditorWidget::onMousePressed(ofMouseEventArgs & args){ - for(unsigned int i = 0; i < joints.size(); ++i){ - joints[i]->mousePressed(args); - } -} - -void TextureEditorWidget::onMouseReleased(ofMouseEventArgs & args){ - // Nothing -} - -void TextureEditorWidget::onMouseDragged(ofMouseEventArgs & args){ - for(unsigned int i = 0; i < joints.size(); ++i){ - joints[i]->mouseDragged(args); - } -} - -void TextureEditorWidget::draw(){ - if(surface == 0){ - return; - } - - // Reset default color to white - ofSetColor(255, 255, 255, 255); - drawJoints(); -} - -void TextureEditorWidget::drawJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->draw(); - } -} - -void TextureEditorWidget::setSurface(BaseSurface * newSurface){ - surface = newSurface; - createJoints(); -} - -void TextureEditorWidget::clear(){ - surface = 0; - clearJoints(); -} - -void TextureEditorWidget::createJoints(){ - if(surface == 0){ - return; - } - - clearJoints(); - std::vector texCoords = surface->getTexCoords(); - - if(surface->getSource()->getTexture()->isAllocated()){ - _pollCreateJoints = false; - }else{ - _pollCreateJoints = true; - return; - } - - Vec2 textureSize = Vec2( - surface->getSource()->getTexture()->getWidth(), - surface->getSource()->getTexture()->getHeight()); - - // Select joints depending on the surface type - std::vector tc; - - if(surface->getType() == SurfaceType::TRIANGLE_SURFACE){ - tc = texCoords; - }else if(surface->getType() == SurfaceType::QUAD_SURFACE || - surface->getType() == SurfaceType::CIRCLE_SURFACE){ - tc = texCoords; - }else if(surface->getType() == SurfaceType::HEXAGON_SURFACE){ - tc = texCoords; - }else if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ - GridWarpSurface * s = (GridWarpSurface *)surface; - - int rows = s->getGridRows(); - int cols = s->getGridCols(); - int vertsPerRow = cols + 1; - int vertsPerCol = rows + 1; - - int a = 0; - int b = cols; - int c = (rows * vertsPerRow) + (vertsPerRow - 1); - int d = (rows * vertsPerRow); - - tc.push_back(texCoords[a]); - tc.push_back(texCoords[b]); - tc.push_back(texCoords[c]); - tc.push_back(texCoords[d]); - } - - for(int i = 0; i < tc.size(); i++){ - joints.push_back(new CircleJoint()); - joints.back()->position = tc[i] * textureSize; - } -} - -void TextureEditorWidget::clearJoints(){ - while(joints.size()){ - delete joints.back(); - joints.pop_back(); - } -} - -void TextureEditorWidget::unselectAllJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->unselect(); - } -} - -void TextureEditorWidget::selectTexCoord(int i){ - if(joints.size() <= 0){ - return; - } - - if(i >= (int)joints.size()){ - ofLogError("TextureEditorWidget::selectTexCoord", - "Attempt to select non existent tex coord"); - return; - } - - unselectAllJoints(); - - if(i >= 0){ - joints[i]->select(); - } -} - -int TextureEditorWidget::getSelectedTexCoord(){ - if(joints.size() <= 0){ - return -1; - } - - for(unsigned int i = 0; i < joints.size(); ++i){ - if(joints[i]->isSelected()){ - return i; - } - } - - return -1; -} - -void TextureEditorWidget::selectNextTexCoord(){ - if(joints.size() <= 0){ - return; - } - - // Search for current selected joint - for(unsigned int i = 0; i < joints.size(); ++i){ - if(joints[i]->isSelected()){ - unsigned int next = i + 1; - if(next >= joints.size()){ - next = 0; - } - unselectAllJoints(); - //joints[next]->select(); - selectTexCoord(next); - return; - } - } - - // If none found, select 0th - //joints[0]->select(); - selectTexCoord(0); -} - -void TextureEditorWidget::selectPrevTexCoord(){ - if(joints.size() <= 0){ - return; - } - - // Search for current selected joint - for(unsigned int i = 0; i < joints.size(); ++i){ - if(joints[i]->isSelected()){ - unsigned int prev; - if(i == 0){ - prev = joints.size() - 1; - }else{ - prev = i - 1; - } - unselectAllJoints(); - //joints[prev]->select(); - selectTexCoord(prev); - return; - } - } - - // Select last if none selected - //joints[joints.size() - 1]->select(); - selectTexCoord(joints.size() - 1); -} - -void TextureEditorWidget::moveTexCoords(Vec2 by){ - if(surface == 0){ - return; - } - - std::vector texCoords = surface->getTexCoords(); - Vec2 textureSize = Vec2( - surface->getSource()->getTexture()->getWidth(), - surface->getSource()->getTexture()->getHeight()); - - for(int i = 0; i < joints.size(); i++){ - joints[i]->position += by; - } - - if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ - GridWarpSurface * s = (GridWarpSurface *)surface; - - int rows = s->getGridRows(); - int cols = s->getGridCols(); - - // Distance between horizontal tex coords - float sx = joints[0]->position.x / textureSize.x; - float ex = joints[1]->position.x / textureSize.x; - float dx = (ex - sx) / (float)cols; - - // Distance between vertical tex coords - float sy = joints[0]->position.y / textureSize.y; - float ey = joints[2]->position.y / textureSize.y; - float dy = (ey - sy) / (float)rows; - - int i = 0; - for(int iy = 0; iy <= rows; ++iy){ - for(int ix = 0; ix <= cols; ++ix){ - Vec2 t; - t.x = sx + dx * ix; - t.y = sy + dy * iy; - surface->setTexCoord(i, t); - ++i; - } - } - }else{ - for(int i = 0; i < texCoords.size(); i++){ - surface->setTexCoord(i, joints[i]->position / textureSize); - } - } -} - -void TextureEditorWidget::moveTexCoordTo(int texCoordIndex, Vec2 position){ - if(surface == 0){ - return; - } - - ofLogNotice("TextureEditorWidget::moveTexCoordTo") << texCoordIndex << ", " << position.x << ", " << position.y; - surface->setTexCoord(texCoordIndex, position); - - Vec2 textureSize = Vec2( - surface->getSource()->getTexture()->getWidth(), - surface->getSource()->getTexture()->getHeight()); - joints[texCoordIndex]->position = position * textureSize; -} - -void TextureEditorWidget::stopDragJoints(){ - for(int i = 0; i < joints.size(); i++){ - joints[i]->stopDrag(); - } -} - -void TextureEditorWidget::moveSelection(Vec2 by){ - // check if joints selected - bool bJointSelected = false; - BaseJoint * selectedJoint; - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->isSelected()){ - bJointSelected = true; - selectedJoint = joints[i]; - break; - } - } - - if(bJointSelected){ - selectedJoint->position += by; - }else{ - moveTexCoords(by); - } -} - -void TextureEditorWidget::constrainJointsToQuad(int selectedJointIndex){ - switch(selectedJointIndex){ - case 0: - joints[1]->position = Vec2(joints[1]->position.x, joints[0]->position.y); - joints[2]->position = Vec2(joints[1]->position.x, joints[3]->position.y); - joints[3]->position = Vec2(joints[0]->position.x, joints[3]->position.y); - break; - - case 1: - joints[0]->position = Vec2(joints[0]->position.x, joints[1]->position.y); - joints[2]->position = Vec2(joints[1]->position.x, joints[2]->position.y); - joints[3]->position = Vec2(joints[0]->position.x, joints[2]->position.y); - break; - - case 2: - joints[1]->position = Vec2(joints[2]->position.x, joints[1]->position.y); - joints[3]->position = Vec2(joints[3]->position.x, joints[2]->position.y); - joints[0]->position = Vec2(joints[3]->position.x, joints[1]->position.y); - break; - - case 3: - joints[0]->position = Vec2(joints[3]->position.x, joints[0]->position.y); - joints[2]->position = Vec2(joints[2]->position.x, joints[3]->position.y); - joints[1]->position = Vec2(joints[2]->position.x, joints[0]->position.y); - break; - } // switch -} - -CircleJoint * TextureEditorWidget::hitTestJoints(Vec2 pos){ - for(int i = 0; i < joints.size(); i++){ - if(joints[i]->hitTest(pos)){ - return joints[i]; - } - } - return 0; -} - -std::vector & TextureEditorWidget::getJoints(){ - return joints; -} - -} // namespace piMapper -} // namespace ofx +#include "TextureEditorWidget.h" + +namespace ofx { +namespace piMapper { + +TextureEditorWidget::TextureEditorWidget(){ + _pollCreateJoints = false; + + clear(); +} + +void TextureEditorWidget::setup(){ + // Nothing here yet. +} + +void TextureEditorWidget::update(){ + if(surface == 0){ + return; + } + + if(_pollCreateJoints){ + createJoints(); + } + + // update surface if one of the joints is being dragged + Vec2 textureSize = Vec2(surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + + // Get selected joint index + int selectedJointIndex = 0; + bool bJointSelected = false; + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->isDragged() || joints[i]->isSelected()){ + selectedJointIndex = i; + bJointSelected = true; + break; + } + } // for + + // Constrain quad texture selection + if(joints.size() == 4){ + if(bJointSelected){ + constrainJointsToQuad(selectedJointIndex); + + if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ + GridWarpSurface * s = (GridWarpSurface *)surface; + std::vector texCoords = surface->getTexCoords(); + Vec2 textureSize = Vec2( + surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + + int rows = s->getGridRows(); + int cols = s->getGridCols(); + int vertsPerRow = cols + 1; + + // Distance between horizontal tex coords + float sx = joints[0]->position.x / textureSize.x; + float ex = joints[1]->position.x / textureSize.x; + float dx = (ex - sx) / (float)cols; + + // Distance between vertical tex coords + float sy = joints[0]->position.y / textureSize.y; + float ey = joints[2]->position.y / textureSize.y; + float dy = (ey - sy) / (float)rows; + + int i = 0; + for(int iy = 0; iy <= rows; ++iy){ + for(int ix = 0; ix <= cols; ++ix){ + Vec2 t; + t.x = sx + dx * ix; + t.y = sy + dy * iy; + surface->setTexCoord(i, t); + ++i; + } + } + }else{ + for(int i = 0; i < joints.size(); i++){ + surface->setTexCoord(i, joints[i]->position / textureSize); + } + } + } // if + }else{ + if(bJointSelected){ + surface->setTexCoord(selectedJointIndex, joints[selectedJointIndex]->position / textureSize); + } + } // else +} + +void TextureEditorWidget::onMousePressed(ofMouseEventArgs & args){ + for(unsigned int i = 0; i < joints.size(); ++i){ + joints[i]->mousePressed(args); + } +} + +void TextureEditorWidget::onMouseReleased(ofMouseEventArgs & args){ + // Nothing +} + +void TextureEditorWidget::onMouseDragged(ofMouseEventArgs & args){ + for(unsigned int i = 0; i < joints.size(); ++i){ + joints[i]->mouseDragged(args); + } +} + +void TextureEditorWidget::draw(){ + if(surface == 0){ + return; + } + + // Reset default color to white + ofSetColor(255, 255, 255, 255); + drawJoints(); +} + +void TextureEditorWidget::drawJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->draw(); + } +} + +void TextureEditorWidget::setSurface(BaseSurface * newSurface){ + surface = newSurface; + createJoints(); +} + +void TextureEditorWidget::clear(){ + surface = 0; + clearJoints(); +} + +void TextureEditorWidget::createJoints(){ + if(surface == 0){ + return; + } + + clearJoints(); + std::vector texCoords = surface->getTexCoords(); + + if(surface->getSource()->getTexture()->isAllocated()){ + _pollCreateJoints = false; + }else{ + _pollCreateJoints = true; + return; + } + + Vec2 textureSize = Vec2( + surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + + // Select joints depending on the surface type + std::vector tc; + + if(surface->getType() == SurfaceType::TRIANGLE_SURFACE){ + tc = texCoords; + }else if(surface->getType() == SurfaceType::QUAD_SURFACE || + surface->getType() == SurfaceType::CIRCLE_SURFACE){ + tc = texCoords; + }else if(surface->getType() == SurfaceType::HEXAGON_SURFACE){ + tc = texCoords; + }else if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ + GridWarpSurface * s = (GridWarpSurface *)surface; + + int rows = s->getGridRows(); + int cols = s->getGridCols(); + int vertsPerRow = cols + 1; + int vertsPerCol = rows + 1; + + int a = 0; + int b = cols; + int c = (rows * vertsPerRow) + (vertsPerRow - 1); + int d = (rows * vertsPerRow); + + tc.push_back(texCoords[a]); + tc.push_back(texCoords[b]); + tc.push_back(texCoords[c]); + tc.push_back(texCoords[d]); + } + + for(int i = 0; i < tc.size(); i++){ + joints.push_back(new CircleJoint()); + joints.back()->position = tc[i] * textureSize; + } +} + +void TextureEditorWidget::clearJoints(){ + while(joints.size()){ + delete joints.back(); + joints.pop_back(); + } +} + +void TextureEditorWidget::unselectAllJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->unselect(); + } +} + +void TextureEditorWidget::selectTexCoord(int i){ + if(joints.size() <= 0){ + return; + } + + if(i >= (int)joints.size()){ + ofLogError("TextureEditorWidget::selectTexCoord", + "Attempt to select non existent tex coord"); + return; + } + + unselectAllJoints(); + + if(i >= 0){ + joints[i]->select(); + } +} + +int TextureEditorWidget::getSelectedTexCoord(){ + if(joints.size() <= 0){ + return -1; + } + + for(unsigned int i = 0; i < joints.size(); ++i){ + if(joints[i]->isSelected()){ + return i; + } + } + + return -1; +} + +void TextureEditorWidget::selectNextTexCoord(){ + if(joints.size() <= 0){ + return; + } + + // Search for current selected joint + for(unsigned int i = 0; i < joints.size(); ++i){ + if(joints[i]->isSelected()){ + unsigned int next = i + 1; + if(next >= joints.size()){ + next = 0; + } + unselectAllJoints(); + //joints[next]->select(); + selectTexCoord(next); + return; + } + } + + // If none found, select 0th + //joints[0]->select(); + selectTexCoord(0); +} + +void TextureEditorWidget::selectPrevTexCoord(){ + if(joints.size() <= 0){ + return; + } + + // Search for current selected joint + for(unsigned int i = 0; i < joints.size(); ++i){ + if(joints[i]->isSelected()){ + unsigned int prev; + if(i == 0){ + prev = joints.size() - 1; + }else{ + prev = i - 1; + } + unselectAllJoints(); + //joints[prev]->select(); + selectTexCoord(prev); + return; + } + } + + // Select last if none selected + //joints[joints.size() - 1]->select(); + selectTexCoord(joints.size() - 1); +} + +void TextureEditorWidget::moveTexCoords(Vec2 by){ + if(surface == 0){ + return; + } + + std::vector texCoords = surface->getTexCoords(); + Vec2 textureSize = Vec2( + surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + + for(int i = 0; i < joints.size(); i++){ + joints[i]->position += by; + } + + if(surface->getType() == SurfaceType::GRID_WARP_SURFACE){ + GridWarpSurface * s = (GridWarpSurface *)surface; + + int rows = s->getGridRows(); + int cols = s->getGridCols(); + + // Distance between horizontal tex coords + float sx = joints[0]->position.x / textureSize.x; + float ex = joints[1]->position.x / textureSize.x; + float dx = (ex - sx) / (float)cols; + + // Distance between vertical tex coords + float sy = joints[0]->position.y / textureSize.y; + float ey = joints[2]->position.y / textureSize.y; + float dy = (ey - sy) / (float)rows; + + int i = 0; + for(int iy = 0; iy <= rows; ++iy){ + for(int ix = 0; ix <= cols; ++ix){ + Vec2 t; + t.x = sx + dx * ix; + t.y = sy + dy * iy; + surface->setTexCoord(i, t); + ++i; + } + } + }else{ + for(int i = 0; i < texCoords.size(); i++){ + surface->setTexCoord(i, joints[i]->position / textureSize); + } + } +} + +void TextureEditorWidget::moveTexCoordTo(int texCoordIndex, Vec2 position){ + if(surface == 0){ + return; + } + + ofLogNotice("TextureEditorWidget::moveTexCoordTo") << texCoordIndex << ", " << position.x << ", " << position.y; + surface->setTexCoord(texCoordIndex, position); + + Vec2 textureSize = Vec2( + surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + joints[texCoordIndex]->position = position * textureSize; +} + +void TextureEditorWidget::stopDragJoints(){ + for(int i = 0; i < joints.size(); i++){ + joints[i]->stopDrag(); + } +} + +void TextureEditorWidget::moveSelection(Vec2 by){ + // check if joints selected + bool bJointSelected = false; + BaseJoint * selectedJoint; + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->isSelected()){ + bJointSelected = true; + selectedJoint = joints[i]; + break; + } + } + + if(bJointSelected){ + selectedJoint->position += by; + }else{ + moveTexCoords(by); + } +} + +void TextureEditorWidget::constrainJointsToQuad(int selectedJointIndex){ + switch(selectedJointIndex){ + case 0: + joints[1]->position = Vec2(joints[1]->position.x, joints[0]->position.y); + joints[2]->position = Vec2(joints[1]->position.x, joints[3]->position.y); + joints[3]->position = Vec2(joints[0]->position.x, joints[3]->position.y); + break; + + case 1: + joints[0]->position = Vec2(joints[0]->position.x, joints[1]->position.y); + joints[2]->position = Vec2(joints[1]->position.x, joints[2]->position.y); + joints[3]->position = Vec2(joints[0]->position.x, joints[2]->position.y); + break; + + case 2: + joints[1]->position = Vec2(joints[2]->position.x, joints[1]->position.y); + joints[3]->position = Vec2(joints[3]->position.x, joints[2]->position.y); + joints[0]->position = Vec2(joints[3]->position.x, joints[1]->position.y); + break; + + case 3: + joints[0]->position = Vec2(joints[3]->position.x, joints[0]->position.y); + joints[2]->position = Vec2(joints[2]->position.x, joints[3]->position.y); + joints[1]->position = Vec2(joints[2]->position.x, joints[0]->position.y); + break; + } // switch +} + +CircleJoint * TextureEditorWidget::hitTestJoints(Vec2 pos){ + for(int i = 0; i < joints.size(); i++){ + if(joints[i]->hitTest(pos)){ + return joints[i]; + } + } + return 0; +} + +std::vector & TextureEditorWidget::getJoints(){ + return joints; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/TextureEditorWidget.h b/src/Gui/Widgets/TextureEditorWidget.h index 6bd3ee5..bb8509c 100644 --- a/src/Gui/Widgets/TextureEditorWidget.h +++ b/src/Gui/Widgets/TextureEditorWidget.h @@ -1,61 +1,61 @@ -#pragma once - -#include "ofEvents.h" - -#include "BaseSurface.h" -#include "GridWarpSurface.h" -#include "CircleJoint.h" -#include "SurfaceType.h" -#include "GuiBaseWidget.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class TextureEditorWidget : public GuiBaseWidget { - - public: - TextureEditorWidget(); - - void setup(); - void update(); // Maybe the Application pointer would make sense there. Not sure yet. - void draw(); - - void onMousePressed(ofMouseEventArgs & e); - void onMouseReleased(ofMouseEventArgs & e); - void onMouseDragged(ofMouseEventArgs & e); - - bool inside(float x, float y){ return false; } - - void drawJoints(); - void setSurface(BaseSurface * newSurface); - void clear(); - void createJoints(); - void clearJoints(); - void unselectAllJoints(); - - void selectTexCoord(int i); - int getSelectedTexCoord(); - void selectNextTexCoord(); - void selectPrevTexCoord(); - - void moveTexCoords(Vec2 by); - void moveTexCoordTo(int texCoordIndex, Vec2 position); - - void stopDragJoints(); - void moveSelection(Vec2 by); - void constrainJointsToQuad(int selectedJointIndex); - CircleJoint * hitTestJoints(Vec2 pos); - std::vector & getJoints(); - - private: - BaseSurface * surface; - std::vector joints; - - bool bShiftKeyDown; - bool _pollCreateJoints; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofEvents.h" + +#include "BaseSurface.h" +#include "GridWarpSurface.h" +#include "CircleJoint.h" +#include "SurfaceType.h" +#include "GuiBaseWidget.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class TextureEditorWidget : public GuiBaseWidget { + + public: + TextureEditorWidget(); + + void setup(); + void update(); // Maybe the Application pointer would make sense there. Not sure yet. + void draw(); + + void onMousePressed(ofMouseEventArgs & e); + void onMouseReleased(ofMouseEventArgs & e); + void onMouseDragged(ofMouseEventArgs & e); + + bool inside(float x, float y){ return false; } + + void drawJoints(); + void setSurface(BaseSurface * newSurface); + void clear(); + void createJoints(); + void clearJoints(); + void unselectAllJoints(); + + void selectTexCoord(int i); + int getSelectedTexCoord(); + void selectNextTexCoord(); + void selectPrevTexCoord(); + + void moveTexCoords(Vec2 by); + void moveTexCoordTo(int texCoordIndex, Vec2 position); + + void stopDragJoints(); + void moveSelection(Vec2 by); + void constrainJointsToQuad(int selectedJointIndex); + CircleJoint * hitTestJoints(Vec2 pos); + std::vector & getJoints(); + + private: + BaseSurface * surface; + std::vector joints; + + bool bShiftKeyDown; + bool _pollCreateJoints; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/TextureHighlightWidget.cpp b/src/Gui/Widgets/TextureHighlightWidget.cpp index 062787e..24cfbdc 100644 --- a/src/Gui/Widgets/TextureHighlightWidget.cpp +++ b/src/Gui/Widgets/TextureHighlightWidget.cpp @@ -1,56 +1,56 @@ -#include "TextureHighlightWidget.h" - -namespace ofx { -namespace piMapper { - -TextureHighlightWidget::TextureHighlightWidget(){ - _sm = 0; -} - -void TextureHighlightWidget::draw(){ - if(_sm == 0){ - return; - } - - if(_sm->getSelectedSurface() == 0){ - return; - } - - // Draw texture coordinates of the surfaces consuming this source - ofPushStyle(); - ofSetLineWidth(2); - ofSetColor(0, 255, 255, 150); - for(unsigned int i = 0; i < _consumerSurfaces.size(); ++i){ - _consumerSurfaces[i]->getTextureHitArea().draw(); - } - - // Draw the texture coordinates of the selected surface - ofPolyline line = _sm->getSelectedSurface()->getTextureHitArea(); - ofSetLineWidth(2); - ofSetColor(0, 255, 255); - line.draw(); - ofPopStyle(); -} - -void TextureHighlightWidget::findConsumerSurfaces(){ - if(_sm == 0){ - return; - } - - if(_sm->getSelectedSurface() == 0){ - return; - } - - BaseSource * activeSource = _sm->getSelectedSurface()->getSource(); - - _consumerSurfaces.clear(); - for(unsigned int i = 0; i < _sm->getActivePreset()->size(); ++i){ - if( activeSource == _sm->getActivePreset()->at(i)->getSource() && - _sm->getSelectedSurface() != _sm->getActivePreset()->at(i)){ - _consumerSurfaces.push_back(_sm->getActivePreset()->at(i)); - } - } -} - -} // namespace piMapper -} // namespace ofx +#include "TextureHighlightWidget.h" + +namespace ofx { +namespace piMapper { + +TextureHighlightWidget::TextureHighlightWidget(){ + _sm = 0; +} + +void TextureHighlightWidget::draw(){ + if(_sm == 0){ + return; + } + + if(_sm->getSelectedSurface() == 0){ + return; + } + + // Draw texture coordinates of the surfaces consuming this source + ofPushStyle(); + ofSetLineWidth(2); + ofSetColor(0, 255, 255, 150); + for(unsigned int i = 0; i < _consumerSurfaces.size(); ++i){ + _consumerSurfaces[i]->getTextureHitArea().draw(); + } + + // Draw the texture coordinates of the selected surface + ofPolyline line = _sm->getSelectedSurface()->getTextureHitArea(); + ofSetLineWidth(2); + ofSetColor(0, 255, 255); + line.draw(); + ofPopStyle(); +} + +void TextureHighlightWidget::findConsumerSurfaces(){ + if(_sm == 0){ + return; + } + + if(_sm->getSelectedSurface() == 0){ + return; + } + + BaseSource * activeSource = _sm->getSelectedSurface()->getSource(); + + _consumerSurfaces.clear(); + for(unsigned int i = 0; i < _sm->getActivePreset()->size(); ++i){ + if( activeSource == _sm->getActivePreset()->at(i)->getSource() && + _sm->getSelectedSurface() != _sm->getActivePreset()->at(i)){ + _consumerSurfaces.push_back(_sm->getActivePreset()->at(i)); + } + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Gui/Widgets/TextureHighlightWidget.h b/src/Gui/Widgets/TextureHighlightWidget.h index 27353d9..cc7a601 100644 --- a/src/Gui/Widgets/TextureHighlightWidget.h +++ b/src/Gui/Widgets/TextureHighlightWidget.h @@ -1,34 +1,34 @@ -#pragma once - -#include "GuiBaseWidget.h" -#include "SurfaceManager.h" -#include "BaseSurface.h" - -namespace ofx { -namespace piMapper { - -class TextureHighlightWidget : public GuiBaseWidget { - public: - TextureHighlightWidget(); - - void setup(){} - void update(){} - void draw(); - - void onMousePressed(ofMouseEventArgs & args){} - void onMouseReleased(ofMouseEventArgs & args){} - void onMouseDragged(ofMouseEventArgs & args){} - - bool inside(float x, float y){ return false; } - - void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } - void findConsumerSurfaces(); - - private: - SurfaceManager * _sm; - - std::vector _consumerSurfaces; -}; - -} // namespace piMapper +#pragma once + +#include "GuiBaseWidget.h" +#include "SurfaceManager.h" +#include "BaseSurface.h" + +namespace ofx { +namespace piMapper { + +class TextureHighlightWidget : public GuiBaseWidget { + public: + TextureHighlightWidget(); + + void setup(){} + void update(){} + void draw(); + + void onMousePressed(ofMouseEventArgs & args){} + void onMouseReleased(ofMouseEventArgs & args){} + void onMouseDragged(ofMouseEventArgs & args){} + + bool inside(float x, float y){ return false; } + + void setSurfaceManager(SurfaceManager * sm){ _sm = sm; } + void findConsumerSurfaces(); + + private: + SurfaceManager * _sm; + + std::vector _consumerSurfaces; +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Info/Info.cpp b/src/Info/Info.cpp index c723ad2..b22f346 100644 --- a/src/Info/Info.cpp +++ b/src/Info/Info.cpp @@ -1,60 +1,60 @@ -#include "Info.h" - -namespace ofx { -namespace piMapper { - -Info::Info(){ - _visible = false; - _text = "There are 4 modes:\n\n" - " 1. Presentation mode\n" - " 2. Texture mapping mode\n" - " - Press \"<\" and \">\" to select previous or next vertex\n" - " - Press to play/pause the video\n" - " 3. Projection mapping mode\n" - " - Press <,> and <.> to select previous or next surface\n" - " - Press \"<\" and \">\" to select previous or next vertex\n" - " - Press to add new Triangle surface\n" - " - Press to add new Quad surface\n" - " - Press to add a new ciRcle surface\n" - " - Press

to toggle Perspective warping while quad surface selected\n" - " - Press to expand selected quad surface to fill screen\n" - " - Press to add new Grid surface\n" - " - Press <[> and <]> to remove or add columns to selected grid surface\n" - " - Press <{> and <}> to remove or add rows to selected grid surface\n" - " - Press <+> and <-> to scale surface up and down\n" - " - Press <9> and <0> to move selected surface one layer up or down\n" - " - Press to hide/show Layer panel\n" - " - Press to delete selection\n" - " - Press to play/pause the video\n" - " - Type to clear composition\n" - " - Type to exit to command line interface\n" - " - Type to reboot\n" - " - Type to shutdown\n" - " 4. Source selection mode\n\n" - - "You can switch between the modes by using <1>, <2>, <3> and <4> " - "keys on the keyboard.\n\n" - - "Press to save the composition\n" - "Press to undo\n" - "Press to hide this message"; -} - -void Info::draw(){ - if(_visible){ - ofDrawBitmapStringHighlight(_text, 10, 20, - ofColor(0, 0, 0, 100), - ofColor(255, 255, 255, 200)); - } -} - -void Info::toggle(){ - _visible = !_visible; -} - -void Info::setText(std::string text){ - _text = text; -} - -} // namespace piMapper -} // namespace ofx +#include "Info.h" + +namespace ofx { +namespace piMapper { + +Info::Info(){ + _visible = false; + _text = "There are 4 modes:\n\n" + " 1. Presentation mode\n" + " 2. Texture mapping mode\n" + " - Press \"<\" and \">\" to select previous or next vertex\n" + " - Press to play/pause the video\n" + " 3. Projection mapping mode\n" + " - Press <,> and <.> to select previous or next surface\n" + " - Press \"<\" and \">\" to select previous or next vertex\n" + " - Press to add new Triangle surface\n" + " - Press to add new Quad surface\n" + " - Press to add a new ciRcle surface\n" + " - Press

to toggle Perspective warping while quad surface selected\n" + " - Press to expand selected quad surface to fill screen\n" + " - Press to add new Grid surface\n" + " - Press <[> and <]> to remove or add columns to selected grid surface\n" + " - Press <{> and <}> to remove or add rows to selected grid surface\n" + " - Press <+> and <-> to scale surface up and down\n" + " - Press <9> and <0> to move selected surface one layer up or down\n" + " - Press to hide/show Layer panel\n" + " - Press to delete selection\n" + " - Press to play/pause the video\n" + " - Type to clear composition\n" + " - Type to exit to command line interface\n" + " - Type to reboot\n" + " - Type to shutdown\n" + " 4. Source selection mode\n\n" + + "You can switch between the modes by using <1>, <2>, <3> and <4> " + "keys on the keyboard.\n\n" + + "Press to save the composition\n" + "Press to undo\n" + "Press to hide this message"; +} + +void Info::draw(){ + if(_visible){ + ofDrawBitmapStringHighlight(_text, 10, 20, + ofColor(0, 0, 0, 100), + ofColor(255, 255, 255, 200)); + } +} + +void Info::toggle(){ + _visible = !_visible; +} + +void Info::setText(std::string text){ + _text = text; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Info/Info.h b/src/Info/Info.h index adc4616..d93d77b 100644 --- a/src/Info/Info.h +++ b/src/Info/Info.h @@ -1,22 +1,22 @@ -#pragma once - -#include "ofMain.h" - -namespace ofx { -namespace piMapper { - -class Info { - public: - Info(); - - void draw(); - void toggle(); - void setText(std::string text); - - private: - bool _visible; - std::string _text; -}; - -} // namespace piMapper +#pragma once + +#include "ofMain.h" + +namespace ofx { +namespace piMapper { + +class Info { + public: + Info(); + + void draw(); + void toggle(); + void setText(std::string text); + + private: + bool _visible; + std::string _text; +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/MediaServer/DirectoryWatcher.cpp b/src/MediaServer/DirectoryWatcher.cpp index 7ad3185..ddf48a9 100644 --- a/src/MediaServer/DirectoryWatcher.cpp +++ b/src/MediaServer/DirectoryWatcher.cpp @@ -1,84 +1,84 @@ -#include "DirectoryWatcher.h" - -namespace ofx { -namespace piMapper { - -DirectoryWatcher::DirectoryWatcher(std::string path, int watcherMediaType){ - directoryPath = path; - _mediaType = watcherMediaType; - - if(_mediaType == SourceType::SOURCE_TYPE_VIDEO){ - _directory.allowExt("mp4"); - _directory.allowExt("h264"); - _directory.allowExt("mov"); - _directory.allowExt("avi"); - _directory.allowExt("ogv"); - _directory.allowExt("mpeg"); - _directory.allowExt("mkv"); - }else if(_mediaType == SourceType::SOURCE_TYPE_IMAGE){ - _directory.allowExt("png"); - _directory.allowExt("jpg"); - _directory.allowExt("jpeg"); - }else{ - ofLogFatalError("DirectoryWatcher::DirectoryWatcher", "Unkonwn media type"); - exit(EXIT_FAILURE); - } - - _directory.listDir(directoryPath); - _directory.sort(); - - for(int i = 0; i < _directory.size(); ++i){ - _filePaths.push_back(directoryPath + _directory.getName(i)); - - ofFile file(directoryPath + _directory.getName(i)); - if(_mediaType == SourceType::SOURCE_TYPE_VIDEO){ - file.copyTo("sources/videos/" + _directory.getName(i)); - }else if(_mediaType == SourceType::SOURCE_TYPE_IMAGE){ - file.copyTo("sources/images/" + _directory.getName(i)); - } - } - - dirSize = _directory.size(); -} - -DirectoryWatcher::~DirectoryWatcher() { - if(isThreadRunning()){ - stopThread(); - } -} - -std::vector & DirectoryWatcher::getFilePaths(){ - return _filePaths; -} - -int DirectoryWatcher::getMediaType(){ - return _mediaType; -} - -void DirectoryWatcher::beginWatch(int intervalInMillis) { - watchInterval = intervalInMillis; - startThread(); -} - -void DirectoryWatcher::threadedFunction() { - - while (isThreadRunning()) { - - int newSize = _directory.listDir(); - if (newSize > dirSize) { - ofLogVerbose("DirectoryWatcher") << "Directory changed"; - dirSize = newSize; - ofNotifyEvent(directoryFileAddedEvent, this); - } else if (newSize < dirSize) { - dirSize = newSize; - ofNotifyEvent(directoryFileRemovedEvent, this); - } - - - - sleep(watchInterval); - } -} - -} // namespace piMapper -} // namespace ofx +#include "DirectoryWatcher.h" + +namespace ofx { +namespace piMapper { + +DirectoryWatcher::DirectoryWatcher(std::string path, int watcherMediaType){ + directoryPath = path; + _mediaType = watcherMediaType; + + if(_mediaType == SourceType::SOURCE_TYPE_VIDEO){ + _directory.allowExt("mp4"); + _directory.allowExt("h264"); + _directory.allowExt("mov"); + _directory.allowExt("avi"); + _directory.allowExt("ogv"); + _directory.allowExt("mpeg"); + _directory.allowExt("mkv"); + }else if(_mediaType == SourceType::SOURCE_TYPE_IMAGE){ + _directory.allowExt("png"); + _directory.allowExt("jpg"); + _directory.allowExt("jpeg"); + }else{ + ofLogFatalError("DirectoryWatcher::DirectoryWatcher", "Unkonwn media type"); + exit(EXIT_FAILURE); + } + + _directory.listDir(directoryPath); + _directory.sort(); + + for(int i = 0; i < _directory.size(); ++i){ + _filePaths.push_back(directoryPath + _directory.getName(i)); + + ofFile file(directoryPath + _directory.getName(i)); + if(_mediaType == SourceType::SOURCE_TYPE_VIDEO){ + file.copyTo("sources/videos/" + _directory.getName(i)); + }else if(_mediaType == SourceType::SOURCE_TYPE_IMAGE){ + file.copyTo("sources/images/" + _directory.getName(i)); + } + } + + dirSize = _directory.size(); +} + +DirectoryWatcher::~DirectoryWatcher() { + if(isThreadRunning()){ + stopThread(); + } +} + +std::vector & DirectoryWatcher::getFilePaths(){ + return _filePaths; +} + +int DirectoryWatcher::getMediaType(){ + return _mediaType; +} + +void DirectoryWatcher::beginWatch(int intervalInMillis) { + watchInterval = intervalInMillis; + startThread(); +} + +void DirectoryWatcher::threadedFunction() { + + while (isThreadRunning()) { + + int newSize = _directory.listDir(); + if (newSize > dirSize) { + ofLogVerbose("DirectoryWatcher") << "Directory changed"; + dirSize = newSize; + ofNotifyEvent(directoryFileAddedEvent, this); + } else if (newSize < dirSize) { + dirSize = newSize; + ofNotifyEvent(directoryFileRemovedEvent, this); + } + + + + sleep(watchInterval); + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/MediaServer/DirectoryWatcher.h b/src/MediaServer/DirectoryWatcher.h index 35ae34b..06f15bd 100644 --- a/src/MediaServer/DirectoryWatcher.h +++ b/src/MediaServer/DirectoryWatcher.h @@ -1,41 +1,41 @@ -#pragma once - -#include "ofMain.h" -#include "SourceType.h" - -namespace ofx { -namespace piMapper { - -class DirectoryWatcher : public ofThread { - public: - DirectoryWatcher(std::string path, int watcherMediaType); - virtual ~DirectoryWatcher(); - std::vector &getFilePaths(); - int getMediaType(); - - void beginWatch(int intervalInMillis = 5000); - void threadedFunction(); - - /** - * Notifies when files are added to this directory. - * Sender is a pointer to this DirectoryWatcher - */ - ofEvent directoryFileAddedEvent; - /** - * Notifies when files are removed from this directory. - * Sender is a pointer to this DirectoryWatcher - */ - ofEvent directoryFileRemovedEvent; - - private: - ofDirectory _directory; - std::vector _filePaths; - std::string directoryPath; - int _mediaType; - - int dirSize; - long watchInterval; // in millis. -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "SourceType.h" + +namespace ofx { +namespace piMapper { + +class DirectoryWatcher : public ofThread { + public: + DirectoryWatcher(std::string path, int watcherMediaType); + virtual ~DirectoryWatcher(); + std::vector &getFilePaths(); + int getMediaType(); + + void beginWatch(int intervalInMillis = 5000); + void threadedFunction(); + + /** + * Notifies when files are added to this directory. + * Sender is a pointer to this DirectoryWatcher + */ + ofEvent directoryFileAddedEvent; + /** + * Notifies when files are removed from this directory. + * Sender is a pointer to this DirectoryWatcher + */ + ofEvent directoryFileRemovedEvent; + + private: + ofDirectory _directory; + std::vector _filePaths; + std::string directoryPath; + int _mediaType; + + int dirSize; + long watchInterval; // in millis. +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/MediaServer/MediaServer.cpp b/src/MediaServer/MediaServer.cpp index d9dd739..e325c1b 100644 --- a/src/MediaServer/MediaServer.cpp +++ b/src/MediaServer/MediaServer.cpp @@ -1,443 +1,443 @@ -#include "MediaServer.h" - - -namespace ofx { -namespace piMapper { - - // relative pathss as default, absolute Paths for RASPI - #ifdef TARGET_RASPBERRY_PI - bool absolutePathSwitch = true; - #else - bool absolutePathSwitch = false; - #endif - MediaServer::MediaServer() : - piVideoWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_VIDEO), - usb0VideoWatcher(USB0_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), - usb1VideoWatcher(USB1_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), - usb2VideoWatcher(USB2_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), - usb3VideoWatcher(USB3_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), - piImageWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), - usb0ImageWatcher(USB0_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), - usb1ImageWatcher(USB1_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), - usb2ImageWatcher(USB2_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), - usb3ImageWatcher(USB3_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), - imageWatcher(ofToDataPath(DEFAULT_IMAGES_DIR, absolutePathSwitch), SourceType::SOURCE_TYPE_IMAGE), - videoWatcher(ofToDataPath(DEFAULT_VIDEOS_DIR, absolutePathSwitch), SourceType::SOURCE_TYPE_VIDEO) -{ - // By initialising all above we also copy files from external media - // to the ofxPiMapper storage. - imageWatcher.beginWatch(); - - -// imageWatcher = DirectoryWatcher( -// ofToDataPath(DEFAULT_IMAGES_DIR, true), -// SourceType::SOURCE_TYPE_IMAGE); -// imageWatcher.beginWatch(); -// -// videoWatcher = DirectoryWatcher( -// ofToDataPath(DEFAULT_VIDEOS_DIR, true), -// SourceType::SOURCE_TYPE_VIDEO); -} - -void MediaServer::setup(){ - // We could setup sources here, but the sources are - // set up while adding them to media server. For now - // This method is here just to keep things consistent. -} - -void MediaServer::update(){ - for(int i = 0; i < fboSources.size(); ++i){ - if (fboSources[i]->isActive() || fboSources[i]->runsInBackground()) fboSources[i]->updateFbo(); - } -} - -void MediaServer::draw(){ - for(int i = 0; i < fboSources.size(); ++i){ - if (fboSources[i]->isActive() || fboSources[i]->runsInBackground()) fboSources[i]->drawFbo(); - } -} - -void MediaServer::restart() { - typedef map ::iterator it_type; - for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ - if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ - static_cast (i->second)->restart(); - } - } -} -void MediaServer::pause() { - typedef map ::iterator it_type; - for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ - if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ - static_cast (i->second)->pause(); - } - } -} -void MediaServer::resume() { - typedef map ::iterator it_type; - for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ - if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ - static_cast (i->second)->resume(); - } - } -} - - -int MediaServer::getNumImages(){ - - return imageWatcher.getFilePaths().size(); -} -int MediaServer::getNumVideos(){ - return videoWatcher.getFilePaths().size(); -} -int MediaServer::getNumFboSources(){ - return fboSources.size(); -} - -std::vector & MediaServer::getImagePaths(){ - return imageWatcher.getFilePaths(); -} - -std::vector MediaServer::getImageNames(){ - std::vector imageNames; - for(int i = 0; i < getNumImages(); i++){ - // Split image path - std::vector pathParts = ofSplitString(getImagePaths()[i], "/"); - // And get only the last piece - std::string name = pathParts[pathParts.size() - 1]; - imageNames.push_back(name); - } - return imageNames; -} - -std::vector MediaServer::getFboSourceNames(){ - std::vector fboSourceNames; - for(int i = 0; i < fboSources.size(); i++){ - fboSourceNames.push_back(fboSources[i]->getName()); - } - return fboSourceNames; -} - -std::vector & MediaServer::getVideoPaths(){ - return videoWatcher.getFilePaths(); -} - -std::vector MediaServer::getVideoNames(){ - std::vector videoNames; - for(int i = 0; i < getNumVideos(); i++){ - // Split video path - std::vector pathParts = ofSplitString(getVideoPaths()[i], "/"); - // And get only the last piece - std::string name = pathParts[pathParts.size() - 1]; - videoNames.push_back(name); - } - return videoNames; -} - -BaseSource * MediaServer::loadMedia(std::string & path, int mediaType){ - // Chose load method depending on type - if(mediaType == SourceType::SOURCE_TYPE_IMAGE){ - return loadImage(path); - }else if(mediaType == SourceType::SOURCE_TYPE_VIDEO){ - return loadVideo(path); - }else if(mediaType == SourceType::SOURCE_TYPE_FBO){ - return loadFboSource(path); - }else{ - std::stringstream ss; - ss << "Can not load media of unknown type: " << mediaType; - ofLogFatalError("MediaServer") << ss.str(); - std::exit(EXIT_FAILURE); - } - return 0; -} - -BaseSource * MediaServer::loadImage(std::string & path){ - ImageSource * imageSource = 0; - // Check if this image is already loaded - bool isImageLoaded = false; - if(loadedSources.count(path)){ - imageSource = static_cast (loadedSources[path]); - isImageLoaded = true; - } - // If image is loaded - if(isImageLoaded){ - // Increase reference count of this source - //referenceCount[path]++; - imageSource->referenceCount++; - std::stringstream refss; - refss << "Current reference count for " << path << " = " << imageSource->referenceCount; - ofLogNotice("MediaServer") << refss.str(); - // Notify objects registered to onImageLoaded event - std::stringstream ss; - ss << "Image " << path << " already loaded"; - ofLogNotice("MediaServer") << ss.str(); - ofNotifyEvent(onImageLoaded, path, this); - return imageSource; - } - // Else load fresh - imageSource = new ImageSource(); - imageSource->loadImage(path); - loadedSources[path] = imageSource; - // Set reference count of this image path to 1 - //referenceCount[path] = 1; - std::stringstream refss; - refss << "Initialized reference count of " << path << " to " << imageSource->referenceCount; - ofLogNotice("MediaServer") << refss.str(); - // Notify objects registered to onImageLoaded event - ofNotifyEvent(onImageLoaded, path, this); - return imageSource; -} - -void MediaServer::unloadImage(std::string & path){ - ImageSource * source = static_cast (getSourceByPath(path)); - ofLogNotice("MediaServer") << "Unload image, current reference count: " << source->referenceCount; - source->referenceCount--; - // Unload only if reference count is less or equal to 0 - ofLogNotice("MediaServer") << "New reference count: " << source->referenceCount; - if(source->referenceCount > 0){ - ofLogNotice("MediaServer") << "Not unloading image as it is being referenced elsewhere"; - return; - } - // Reference count 0 or less, unload image - std::stringstream ss; - ss << "Removing image " << path; - ofLogNotice("MediaServer") << ss.str(); - // Destroy image source - if(loadedSources.count(path)){ - ofLogNotice("MediaServer") << "Source count BEFORE image removal: " << loadedSources.size() << std::endl; - loadedSources[path]->clear(); - map ::iterator it = loadedSources.find(path); - delete it->second; - loadedSources.erase(it); - ofLogNotice("MediaServer") << "Source count AFTER image removal: " << loadedSources.size() << std::endl; - ofNotifyEvent(onImageUnloaded, path, this); - return; - } - // Something wrong here, we should be out of the routine by now - std::stringstream failss; - failss << "Failed to remove image source: " << path; - ofLogFatalError("MediaServer") << failss.str(); - std::exit(EXIT_FAILURE); -} - -BaseSource * MediaServer::loadVideo(std::string & path){ - VideoSource * videoSource = 0; - // Check if this video is already loaded - bool isVideoLoaded = false; - if(loadedSources.count(path)){ - videoSource = static_cast (loadedSources[path]); - isVideoLoaded = true; - } - // If is loaded - if(isVideoLoaded){ - // Increase reference count of this source - videoSource->referenceCount++; - std::stringstream refss; - refss << "Current reference count for " << path << " = " << videoSource->referenceCount; - ofLogNotice("MediaServer") << refss.str(); - // Notify objects registered to onImageLoaded event - std::stringstream ss; - ss << "Video " << path << " already loaded"; - ofLogNotice("MediaServer") << ss.str(); - ofNotifyEvent(onVideoLoaded, path, this); - return videoSource; - } - // Else load fresh - videoSource = new VideoSource(); - videoSource->loadVideo(path); - loadedSources[path] = videoSource; - // Set reference count of this image path to 1 - //referenceCount[path] = 1; - std::stringstream refss; - refss << "Initialized reference count of " << path << " to " << videoSource->referenceCount; - ofLogNotice("MediaServer") << refss.str(); - ofNotifyEvent(onVideoLoaded, path, this); - return videoSource; -} - -void MediaServer::unloadVideo(std::string & path){ - VideoSource * videoSource = static_cast (getSourceByPath(path)); - // Decrease reference count of the video - //referenceCount[path]--; - videoSource->referenceCount--; - // Unload only if reference count is less or equal to 0 - if(videoSource->referenceCount > 0){ - ofLogNotice("MediaServer") << "Not unloading video as it is being referenced elsewhere"; - return; - } - // Reference count 0 or less, let's unload the video - ofLogNotice("MediaServer") << "Removing video " << path; - - // Distroy video source - if(loadedSources.count(path)){ - ofLogNotice("MediaServer") - << "Source count before video removal: " - << loadedSources.size() << std::endl; - videoSource->clear(); - map ::iterator it = loadedSources.find(path); - delete it->second; - loadedSources.erase(it); - ofLogNotice("MediaServer") - << "Source count after video removal: " - << loadedSources.size() << std::endl; - ofNotifyEvent(onVideoUnloaded, path, this); - return; - } - - // Something wrong here, we should be out of the routine by now - std::stringstream failss; - failss << "Failed to remove video source: " << path; - ofLogFatalError("MediaServer") << failss.str(); - std::exit(EXIT_FAILURE); -} - -void MediaServer::unloadMedia(std::string & path){ - if(loadedSources.count(path)){ - BaseSource * mediaSource = getSourceByPath(path); - if(mediaSource->getType() == SourceType::SOURCE_TYPE_IMAGE){ - unloadImage(path); - }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_VIDEO){ - unloadVideo(path); - }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_FBO){ - unloadFboSource(path); - }else{ - // Oh my god, what to do!? Relax and exit. - ofLogFatalError("MediaServer") << "Attempt to unload media of unknown type"; - std::exit(EXIT_FAILURE); - } - }else{ - ofLogNotice("MediaServer") << "Nothing to unload"; - } -} - -// Clear all loaded media -void MediaServer::clear(){ - typedef map ::iterator it_type; - for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ - // Do not delete FBO source pointers as they are (and should be) initialized elsewhere - if(i->second->getType() != SourceType::SOURCE_TYPE_FBO){ - delete i->second; - } - } - loadedSources.clear(); -} - -// TODO: getLoadedSourceByPath -BaseSource * MediaServer::getSourceByPath(std::string & mediaPath){ - if(loadedSources.count(mediaPath)){ - return loadedSources[mediaPath]; - } - // Source not found, exit with error - std::stringstream ss; - ss << "Could not find source by path: " << mediaPath; - ofLogFatalError("MediaServer") << ss.str(); - std::exit(EXIT_FAILURE); -} - -std::string MediaServer::getDefaultImageDir(){ - return DEFAULT_IMAGES_DIR; -} - -std::string MediaServer::getDefaultVideoDir(){ - return DEFAULT_VIDEOS_DIR; -} - -std::string MediaServer::getDefaultMediaDir(int sourceType){ - if(sourceType == SourceType::SOURCE_TYPE_IMAGE){ - return getDefaultImageDir(); - }else if(sourceType == SourceType::SOURCE_TYPE_VIDEO){ - return getDefaultVideoDir(); - }else{ - std::stringstream ss; - ss << "Could not get default media dir. Unknown source type: " << sourceType; - ofLogFatalError("MediaServer") << ss.str(); - std::exit(EXIT_FAILURE); - } -} - -void MediaServer::addFboSource(ofx::piMapper::FboSource & fboSource){ - addFboSource(&fboSource); -} - -void MediaServer::addFboSource(FboSource * fboSource){ - ofLogNotice("MediaServer") << "Attempting to add FBO source with name " << fboSource->getName(); - - // FBO source has to be with unique name - for(int i = 0; i < fboSources.size(); ++i){ - if(fboSources[i]->getName() == fboSource->getName()){ - ofLogWarning("MediaServer") << "Attempt to add FBO source with duplicate name"; - ofExit(EXIT_FAILURE); // Here we definitely need to fail to avoid confusion - std::exit(EXIT_FAILURE); // In case the openFrameworks function fails - } - } - - ofLogNotice("MediaServer") << "Source new, adding"; - fboSources.push_back(fboSource); - - // It is important to run the setup of the FBO - // source from outside as we can see here. - fboSource->setup(); -} - -BaseSource * MediaServer::loadFboSource(std::string & fboSourceName){ - ofLogNotice("MediaServer") << "Attempting to load FBO source with name " << fboSourceName; - // Search for FBO source name in our storage - FboSource * source = 0; - for(int i = 0; i < fboSources.size(); i++){ - if(fboSources[i]->getName() == fboSourceName){ - source = fboSources[i]; - break; - } - } - // Panic if not in storage - if(source == 0){ - ofLogError("MediaServer") << "Attempt to load non existing FBO source: " << fboSourceName; - ofExit(EXIT_FAILURE); - } - // Check if it is loaded/activated - if(loadedSources.count(fboSourceName)){ - // Is loaded, increase reference count and return existing - loadedSources[fboSourceName]->referenceCount++; - ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; - source->setActive(true); - return loadedSources[fboSourceName]; - } - // else - // Not loaded, add to loaded sources and activate - // source var should be set by now - //source->addAppListeners(); - source->referenceCount = 1; - ofLogNotice("MediaServer") << "Current " << fboSourceName << " reference count: " << source->referenceCount; - loadedSources[fboSourceName] = source; - source->setActive(true); - return loadedSources[fboSourceName]; -} // loadFboSource - -void MediaServer::unloadFboSource(std::string & fboSourceName){ - ofLogNotice("MediaServer") << "Attempt to unload FBO source " << fboSourceName; - // Check if loaded at all - if(!loadedSources.count(fboSourceName)){ - ofLogWarning("MediaServer") << "FBO source not loaded"; - return; - } - // TODO: remove static cast, make the sources handle reference counting, - // enabling and disabling by themselves - FboSource * source = static_cast (loadedSources[fboSourceName]); - // else decrease reference count - source->referenceCount--; - ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; - // If no references left, disable - if(source->referenceCount <= 0){ - ofLogNotice("MediaServer") << fboSourceName << " reference count <= 0, removing from loaded sources"; - source->referenceCount = 0; - source->setActive(false); - //source->removeAppListeners(); - map ::iterator it = loadedSources.find(fboSourceName); - loadedSources.erase(it); - ofLogNotice("MediaServer") << "Source count after FBO source removal: " << loadedSources.size() << std::endl; - ofNotifyEvent(onFboSourceUnloaded, fboSourceName, this); - } -} // unloadFboSource - -} // namespace piMapper -} // namespace ofx +#include "MediaServer.h" + + +namespace ofx { +namespace piMapper { + + // relative pathss as default, absolute Paths for RASPI + #ifdef TARGET_RASPBERRY_PI + bool absolutePathSwitch = true; + #else + bool absolutePathSwitch = false; + #endif + MediaServer::MediaServer() : + piVideoWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_VIDEO), + usb0VideoWatcher(USB0_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), + usb1VideoWatcher(USB1_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), + usb2VideoWatcher(USB2_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), + usb3VideoWatcher(USB3_VIDEOS_DIR, SourceType::SOURCE_TYPE_VIDEO), + piImageWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), + usb0ImageWatcher(USB0_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), + usb1ImageWatcher(USB1_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), + usb2ImageWatcher(USB2_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), + usb3ImageWatcher(USB3_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE), + imageWatcher(ofToDataPath(DEFAULT_IMAGES_DIR, absolutePathSwitch), SourceType::SOURCE_TYPE_IMAGE), + videoWatcher(ofToDataPath(DEFAULT_VIDEOS_DIR, absolutePathSwitch), SourceType::SOURCE_TYPE_VIDEO) +{ + // By initialising all above we also copy files from external media + // to the ofxPiMapper storage. + imageWatcher.beginWatch(); + + +// imageWatcher = DirectoryWatcher( +// ofToDataPath(DEFAULT_IMAGES_DIR, true), +// SourceType::SOURCE_TYPE_IMAGE); +// imageWatcher.beginWatch(); +// +// videoWatcher = DirectoryWatcher( +// ofToDataPath(DEFAULT_VIDEOS_DIR, true), +// SourceType::SOURCE_TYPE_VIDEO); +} + +void MediaServer::setup(){ + // We could setup sources here, but the sources are + // set up while adding them to media server. For now + // This method is here just to keep things consistent. +} + +void MediaServer::update(){ + for(int i = 0; i < fboSources.size(); ++i){ + if (fboSources[i]->isActive() || fboSources[i]->runsInBackground()) fboSources[i]->updateFbo(); + } +} + +void MediaServer::draw(){ + for(int i = 0; i < fboSources.size(); ++i){ + if (fboSources[i]->isActive() || fboSources[i]->runsInBackground()) fboSources[i]->drawFbo(); + } +} + +void MediaServer::restart() { + typedef map ::iterator it_type; + for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ + if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ + static_cast (i->second)->restart(); + } + } +} +void MediaServer::pause() { + typedef map ::iterator it_type; + for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ + if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ + static_cast (i->second)->pause(); + } + } +} +void MediaServer::resume() { + typedef map ::iterator it_type; + for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ + if(i->second->getType() == SourceType::SOURCE_TYPE_VIDEO){ + static_cast (i->second)->resume(); + } + } +} + + +int MediaServer::getNumImages(){ + + return imageWatcher.getFilePaths().size(); +} +int MediaServer::getNumVideos(){ + return videoWatcher.getFilePaths().size(); +} +int MediaServer::getNumFboSources(){ + return fboSources.size(); +} + +std::vector & MediaServer::getImagePaths(){ + return imageWatcher.getFilePaths(); +} + +std::vector MediaServer::getImageNames(){ + std::vector imageNames; + for(int i = 0; i < getNumImages(); i++){ + // Split image path + std::vector pathParts = ofSplitString(getImagePaths()[i], "/"); + // And get only the last piece + std::string name = pathParts[pathParts.size() - 1]; + imageNames.push_back(name); + } + return imageNames; +} + +std::vector MediaServer::getFboSourceNames(){ + std::vector fboSourceNames; + for(int i = 0; i < fboSources.size(); i++){ + fboSourceNames.push_back(fboSources[i]->getName()); + } + return fboSourceNames; +} + +std::vector & MediaServer::getVideoPaths(){ + return videoWatcher.getFilePaths(); +} + +std::vector MediaServer::getVideoNames(){ + std::vector videoNames; + for(int i = 0; i < getNumVideos(); i++){ + // Split video path + std::vector pathParts = ofSplitString(getVideoPaths()[i], "/"); + // And get only the last piece + std::string name = pathParts[pathParts.size() - 1]; + videoNames.push_back(name); + } + return videoNames; +} + +BaseSource * MediaServer::loadMedia(std::string & path, int mediaType){ + // Chose load method depending on type + if(mediaType == SourceType::SOURCE_TYPE_IMAGE){ + return loadImage(path); + }else if(mediaType == SourceType::SOURCE_TYPE_VIDEO){ + return loadVideo(path); + }else if(mediaType == SourceType::SOURCE_TYPE_FBO){ + return loadFboSource(path); + }else{ + std::stringstream ss; + ss << "Can not load media of unknown type: " << mediaType; + ofLogFatalError("MediaServer") << ss.str(); + std::exit(EXIT_FAILURE); + } + return 0; +} + +BaseSource * MediaServer::loadImage(std::string & path){ + ImageSource * imageSource = 0; + // Check if this image is already loaded + bool isImageLoaded = false; + if(loadedSources.count(path)){ + imageSource = static_cast (loadedSources[path]); + isImageLoaded = true; + } + // If image is loaded + if(isImageLoaded){ + // Increase reference count of this source + //referenceCount[path]++; + imageSource->referenceCount++; + std::stringstream refss; + refss << "Current reference count for " << path << " = " << imageSource->referenceCount; + ofLogNotice("MediaServer") << refss.str(); + // Notify objects registered to onImageLoaded event + std::stringstream ss; + ss << "Image " << path << " already loaded"; + ofLogNotice("MediaServer") << ss.str(); + ofNotifyEvent(onImageLoaded, path, this); + return imageSource; + } + // Else load fresh + imageSource = new ImageSource(); + imageSource->loadImage(path); + loadedSources[path] = imageSource; + // Set reference count of this image path to 1 + //referenceCount[path] = 1; + std::stringstream refss; + refss << "Initialized reference count of " << path << " to " << imageSource->referenceCount; + ofLogNotice("MediaServer") << refss.str(); + // Notify objects registered to onImageLoaded event + ofNotifyEvent(onImageLoaded, path, this); + return imageSource; +} + +void MediaServer::unloadImage(std::string & path){ + ImageSource * source = static_cast (getSourceByPath(path)); + ofLogNotice("MediaServer") << "Unload image, current reference count: " << source->referenceCount; + source->referenceCount--; + // Unload only if reference count is less or equal to 0 + ofLogNotice("MediaServer") << "New reference count: " << source->referenceCount; + if(source->referenceCount > 0){ + ofLogNotice("MediaServer") << "Not unloading image as it is being referenced elsewhere"; + return; + } + // Reference count 0 or less, unload image + std::stringstream ss; + ss << "Removing image " << path; + ofLogNotice("MediaServer") << ss.str(); + // Destroy image source + if(loadedSources.count(path)){ + ofLogNotice("MediaServer") << "Source count BEFORE image removal: " << loadedSources.size() << std::endl; + loadedSources[path]->clear(); + map ::iterator it = loadedSources.find(path); + delete it->second; + loadedSources.erase(it); + ofLogNotice("MediaServer") << "Source count AFTER image removal: " << loadedSources.size() << std::endl; + ofNotifyEvent(onImageUnloaded, path, this); + return; + } + // Something wrong here, we should be out of the routine by now + std::stringstream failss; + failss << "Failed to remove image source: " << path; + ofLogFatalError("MediaServer") << failss.str(); + std::exit(EXIT_FAILURE); +} + +BaseSource * MediaServer::loadVideo(std::string & path){ + VideoSource * videoSource = 0; + // Check if this video is already loaded + bool isVideoLoaded = false; + if(loadedSources.count(path)){ + videoSource = static_cast (loadedSources[path]); + isVideoLoaded = true; + } + // If is loaded + if(isVideoLoaded){ + // Increase reference count of this source + videoSource->referenceCount++; + std::stringstream refss; + refss << "Current reference count for " << path << " = " << videoSource->referenceCount; + ofLogNotice("MediaServer") << refss.str(); + // Notify objects registered to onImageLoaded event + std::stringstream ss; + ss << "Video " << path << " already loaded"; + ofLogNotice("MediaServer") << ss.str(); + ofNotifyEvent(onVideoLoaded, path, this); + return videoSource; + } + // Else load fresh + videoSource = new VideoSource(); + videoSource->loadVideo(path); + loadedSources[path] = videoSource; + // Set reference count of this image path to 1 + //referenceCount[path] = 1; + std::stringstream refss; + refss << "Initialized reference count of " << path << " to " << videoSource->referenceCount; + ofLogNotice("MediaServer") << refss.str(); + ofNotifyEvent(onVideoLoaded, path, this); + return videoSource; +} + +void MediaServer::unloadVideo(std::string & path){ + VideoSource * videoSource = static_cast (getSourceByPath(path)); + // Decrease reference count of the video + //referenceCount[path]--; + videoSource->referenceCount--; + // Unload only if reference count is less or equal to 0 + if(videoSource->referenceCount > 0){ + ofLogNotice("MediaServer") << "Not unloading video as it is being referenced elsewhere"; + return; + } + // Reference count 0 or less, let's unload the video + ofLogNotice("MediaServer") << "Removing video " << path; + + // Distroy video source + if(loadedSources.count(path)){ + ofLogNotice("MediaServer") + << "Source count before video removal: " + << loadedSources.size() << std::endl; + videoSource->clear(); + map ::iterator it = loadedSources.find(path); + delete it->second; + loadedSources.erase(it); + ofLogNotice("MediaServer") + << "Source count after video removal: " + << loadedSources.size() << std::endl; + ofNotifyEvent(onVideoUnloaded, path, this); + return; + } + + // Something wrong here, we should be out of the routine by now + std::stringstream failss; + failss << "Failed to remove video source: " << path; + ofLogFatalError("MediaServer") << failss.str(); + std::exit(EXIT_FAILURE); +} + +void MediaServer::unloadMedia(std::string & path){ + if(loadedSources.count(path)){ + BaseSource * mediaSource = getSourceByPath(path); + if(mediaSource->getType() == SourceType::SOURCE_TYPE_IMAGE){ + unloadImage(path); + }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_VIDEO){ + unloadVideo(path); + }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_FBO){ + unloadFboSource(path); + }else{ + // Oh my god, what to do!? Relax and exit. + ofLogFatalError("MediaServer") << "Attempt to unload media of unknown type"; + std::exit(EXIT_FAILURE); + } + }else{ + ofLogNotice("MediaServer") << "Nothing to unload"; + } +} + +// Clear all loaded media +void MediaServer::clear(){ + typedef map ::iterator it_type; + for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ + // Do not delete FBO source pointers as they are (and should be) initialized elsewhere + if(i->second->getType() != SourceType::SOURCE_TYPE_FBO){ + delete i->second; + } + } + loadedSources.clear(); +} + +// TODO: getLoadedSourceByPath +BaseSource * MediaServer::getSourceByPath(std::string & mediaPath){ + if(loadedSources.count(mediaPath)){ + return loadedSources[mediaPath]; + } + // Source not found, exit with error + std::stringstream ss; + ss << "Could not find source by path: " << mediaPath; + ofLogFatalError("MediaServer") << ss.str(); + std::exit(EXIT_FAILURE); +} + +std::string MediaServer::getDefaultImageDir(){ + return DEFAULT_IMAGES_DIR; +} + +std::string MediaServer::getDefaultVideoDir(){ + return DEFAULT_VIDEOS_DIR; +} + +std::string MediaServer::getDefaultMediaDir(int sourceType){ + if(sourceType == SourceType::SOURCE_TYPE_IMAGE){ + return getDefaultImageDir(); + }else if(sourceType == SourceType::SOURCE_TYPE_VIDEO){ + return getDefaultVideoDir(); + }else{ + std::stringstream ss; + ss << "Could not get default media dir. Unknown source type: " << sourceType; + ofLogFatalError("MediaServer") << ss.str(); + std::exit(EXIT_FAILURE); + } +} + +void MediaServer::addFboSource(ofx::piMapper::FboSource & fboSource){ + addFboSource(&fboSource); +} + +void MediaServer::addFboSource(FboSource * fboSource){ + ofLogNotice("MediaServer") << "Attempting to add FBO source with name " << fboSource->getName(); + + // FBO source has to be with unique name + for(int i = 0; i < fboSources.size(); ++i){ + if(fboSources[i]->getName() == fboSource->getName()){ + ofLogWarning("MediaServer") << "Attempt to add FBO source with duplicate name"; + ofExit(EXIT_FAILURE); // Here we definitely need to fail to avoid confusion + std::exit(EXIT_FAILURE); // In case the openFrameworks function fails + } + } + + ofLogNotice("MediaServer") << "Source new, adding"; + fboSources.push_back(fboSource); + + // It is important to run the setup of the FBO + // source from outside as we can see here. + fboSource->setup(); +} + +BaseSource * MediaServer::loadFboSource(std::string & fboSourceName){ + ofLogNotice("MediaServer") << "Attempting to load FBO source with name " << fboSourceName; + // Search for FBO source name in our storage + FboSource * source = 0; + for(int i = 0; i < fboSources.size(); i++){ + if(fboSources[i]->getName() == fboSourceName){ + source = fboSources[i]; + break; + } + } + // Panic if not in storage + if(source == 0){ + ofLogError("MediaServer") << "Attempt to load non existing FBO source: " << fboSourceName; + ofExit(EXIT_FAILURE); + } + // Check if it is loaded/activated + if(loadedSources.count(fboSourceName)){ + // Is loaded, increase reference count and return existing + loadedSources[fboSourceName]->referenceCount++; + ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; + source->setActive(true); + return loadedSources[fboSourceName]; + } + // else + // Not loaded, add to loaded sources and activate + // source var should be set by now + //source->addAppListeners(); + source->referenceCount = 1; + ofLogNotice("MediaServer") << "Current " << fboSourceName << " reference count: " << source->referenceCount; + loadedSources[fboSourceName] = source; + source->setActive(true); + return loadedSources[fboSourceName]; +} // loadFboSource + +void MediaServer::unloadFboSource(std::string & fboSourceName){ + ofLogNotice("MediaServer") << "Attempt to unload FBO source " << fboSourceName; + // Check if loaded at all + if(!loadedSources.count(fboSourceName)){ + ofLogWarning("MediaServer") << "FBO source not loaded"; + return; + } + // TODO: remove static cast, make the sources handle reference counting, + // enabling and disabling by themselves + FboSource * source = static_cast (loadedSources[fboSourceName]); + // else decrease reference count + source->referenceCount--; + ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; + // If no references left, disable + if(source->referenceCount <= 0){ + ofLogNotice("MediaServer") << fboSourceName << " reference count <= 0, removing from loaded sources"; + source->referenceCount = 0; + source->setActive(false); + //source->removeAppListeners(); + map ::iterator it = loadedSources.find(fboSourceName); + loadedSources.erase(it); + ofLogNotice("MediaServer") << "Source count after FBO source removal: " << loadedSources.size() << std::endl; + ofNotifyEvent(onFboSourceUnloaded, fboSourceName, this); + } +} // unloadFboSource + +} // namespace piMapper +} // namespace ofx diff --git a/src/MediaServer/MediaServer.h b/src/MediaServer/MediaServer.h index 8962895..1c306a4 100644 --- a/src/MediaServer/MediaServer.h +++ b/src/MediaServer/MediaServer.h @@ -1,128 +1,128 @@ -#pragma once - -#include "ofMain.h" -#include "DirectoryWatcher.h" - -#include "BaseSource.h" -#include "ImageSource.h" -#include "VideoSource.h" -#include "FboSource.h" -#include "SourceType.h" - -#define DEFAULT_IMAGES_DIR "sources/images/" -#define DEFAULT_VIDEOS_DIR "sources/videos/" - -#define PI_IMAGES_DIR "/boot/ofxpimapper/sources/images/" -#define PI_VIDEOS_DIR "/boot/ofxpimapper/sources/videos/" - -/* - * These you can get when you apt-get install usbmount - */ -#define USB0_IMAGES_DIR "/media/usb0/" -#define USB1_IMAGES_DIR "/media/usb1/" -#define USB2_IMAGES_DIR "/media/usb2/" -#define USB3_IMAGES_DIR "/media/usb3/" - -#define USB0_VIDEOS_DIR "/media/usb0/" -#define USB1_VIDEOS_DIR "/media/usb1/" -#define USB2_VIDEOS_DIR "/media/usb2/" -#define USB3_VIDEOS_DIR "/media/usb3/" - -// TODO: Change this into a externally configurable list - -/* - -Considering that the pi has 4 USB ports, there is a possibility to connect 4 USB flash drives. The paths to them would be - /media/usb0 - /media/usb1 - /media/usb2 - /media/usb3 -We need all of them and we search for mp4, jpg and png files there. - -*/ - -namespace ofx { -namespace piMapper { - -class MediaServer { - public: - MediaServer(); - - void setup(); - void update(); - void draw(); - - void restart(); - void pause(); - void resume(); - - int getNumVideos(); - int getNumImages(); - int getNumFboSources(); // new - std::vector & getVideoPaths(); - std::vector getVideoNames(); - std::vector & getImagePaths(); - std::vector getImageNames(); - std::vector getFboSourceNames(); // new - - BaseSource * loadMedia(std::string & path, int mediaType); - BaseSource * loadImage(std::string & path); - void unloadImage(std::string & path); - BaseSource * loadVideo(std::string & path); - void unloadVideo(std::string & path); - void unloadMedia(std::string & path); - void clear(); // Force all loaded source unload - BaseSource * getSourceByPath(std::string & mediaPath); - std::string getDefaultImageDir(); - std::string getDefaultVideoDir(); - std::string getDefaultMediaDir(int sourceType); - - // Do things with FBO sources - void addFboSource(FboSource & fboSource); // could be called also as register FBO source - void addFboSource(FboSource * fboSource); - - BaseSource * loadFboSource(std::string & fboSourceName); - void unloadFboSource(std::string & fboSourceName); - - // Custom events, add/remove - ofEvent onImageAdded; - ofEvent onImageRemoved; - ofEvent onVideoAdded; - ofEvent onVideoRemoved; - ofEvent onFboSourceAdded; - ofEvent onFboSourceRemoved; - // load/unload - ofEvent onImageLoaded; - ofEvent onImageUnloaded; - ofEvent onVideoLoaded; - ofEvent onVideoUnloaded; - ofEvent onFboSourceLoaded; - ofEvent onFboSourceUnloaded; - - private: - // Directory Watchers - DirectoryWatcher videoWatcher; - DirectoryWatcher piVideoWatcher; - DirectoryWatcher usb0VideoWatcher; - DirectoryWatcher usb1VideoWatcher; - DirectoryWatcher usb2VideoWatcher; - DirectoryWatcher usb3VideoWatcher; - - DirectoryWatcher imageWatcher; - DirectoryWatcher piImageWatcher; - DirectoryWatcher usb0ImageWatcher; - DirectoryWatcher usb1ImageWatcher; - DirectoryWatcher usb2ImageWatcher; - DirectoryWatcher usb3ImageWatcher; - - std::vector _tempImagePaths; - std::vector _tempVideoPaths; - - map loadedSources; - - // FBO source storage before they go to loadedSources - std::vector fboSources; // FBO source storage -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "DirectoryWatcher.h" + +#include "BaseSource.h" +#include "ImageSource.h" +#include "VideoSource.h" +#include "FboSource.h" +#include "SourceType.h" + +#define DEFAULT_IMAGES_DIR "sources/images/" +#define DEFAULT_VIDEOS_DIR "sources/videos/" + +#define PI_IMAGES_DIR "/boot/ofxpimapper/sources/images/" +#define PI_VIDEOS_DIR "/boot/ofxpimapper/sources/videos/" + +/* + * These you can get when you apt-get install usbmount + */ +#define USB0_IMAGES_DIR "/media/usb0/" +#define USB1_IMAGES_DIR "/media/usb1/" +#define USB2_IMAGES_DIR "/media/usb2/" +#define USB3_IMAGES_DIR "/media/usb3/" + +#define USB0_VIDEOS_DIR "/media/usb0/" +#define USB1_VIDEOS_DIR "/media/usb1/" +#define USB2_VIDEOS_DIR "/media/usb2/" +#define USB3_VIDEOS_DIR "/media/usb3/" + +// TODO: Change this into a externally configurable list + +/* + +Considering that the pi has 4 USB ports, there is a possibility to connect 4 USB flash drives. The paths to them would be + /media/usb0 + /media/usb1 + /media/usb2 + /media/usb3 +We need all of them and we search for mp4, jpg and png files there. + +*/ + +namespace ofx { +namespace piMapper { + +class MediaServer { + public: + MediaServer(); + + void setup(); + void update(); + void draw(); + + void restart(); + void pause(); + void resume(); + + int getNumVideos(); + int getNumImages(); + int getNumFboSources(); // new + std::vector & getVideoPaths(); + std::vector getVideoNames(); + std::vector & getImagePaths(); + std::vector getImageNames(); + std::vector getFboSourceNames(); // new + + BaseSource * loadMedia(std::string & path, int mediaType); + BaseSource * loadImage(std::string & path); + void unloadImage(std::string & path); + BaseSource * loadVideo(std::string & path); + void unloadVideo(std::string & path); + void unloadMedia(std::string & path); + void clear(); // Force all loaded source unload + BaseSource * getSourceByPath(std::string & mediaPath); + std::string getDefaultImageDir(); + std::string getDefaultVideoDir(); + std::string getDefaultMediaDir(int sourceType); + + // Do things with FBO sources + void addFboSource(FboSource & fboSource); // could be called also as register FBO source + void addFboSource(FboSource * fboSource); + + BaseSource * loadFboSource(std::string & fboSourceName); + void unloadFboSource(std::string & fboSourceName); + + // Custom events, add/remove + ofEvent onImageAdded; + ofEvent onImageRemoved; + ofEvent onVideoAdded; + ofEvent onVideoRemoved; + ofEvent onFboSourceAdded; + ofEvent onFboSourceRemoved; + // load/unload + ofEvent onImageLoaded; + ofEvent onImageUnloaded; + ofEvent onVideoLoaded; + ofEvent onVideoUnloaded; + ofEvent onFboSourceLoaded; + ofEvent onFboSourceUnloaded; + + private: + // Directory Watchers + DirectoryWatcher videoWatcher; + DirectoryWatcher piVideoWatcher; + DirectoryWatcher usb0VideoWatcher; + DirectoryWatcher usb1VideoWatcher; + DirectoryWatcher usb2VideoWatcher; + DirectoryWatcher usb3VideoWatcher; + + DirectoryWatcher imageWatcher; + DirectoryWatcher piImageWatcher; + DirectoryWatcher usb0ImageWatcher; + DirectoryWatcher usb1ImageWatcher; + DirectoryWatcher usb2ImageWatcher; + DirectoryWatcher usb3ImageWatcher; + + std::vector _tempImagePaths; + std::vector _tempVideoPaths; + + map loadedSources; + + // FBO source storage before they go to loadedSources + std::vector fboSources; // FBO source storage +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Mode.h b/src/Mode.h index 07b2b83..a945a9c 100644 --- a/src/Mode.h +++ b/src/Mode.h @@ -1,14 +1,14 @@ -#pragma once - -namespace ofx { -namespace piMapper { - -enum Mode { - PRESENTATION_MODE, - TEXTURE_MODE, - MAPPING_MODE, - SOURCE_MODE -}; - -} // namespace piMapper +#pragma once + +namespace ofx { +namespace piMapper { + +enum Mode { + PRESENTATION_MODE, + TEXTURE_MODE, + MAPPING_MODE, + SOURCE_MODE +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Sources/BaseSource.cpp b/src/Sources/BaseSource.cpp index fdba7f4..c612a94 100644 --- a/src/Sources/BaseSource.cpp +++ b/src/Sources/BaseSource.cpp @@ -1,76 +1,76 @@ -#include "BaseSource.h" - -namespace ofx { -namespace piMapper { - -BaseSource::BaseSource(){ - //std::cout << "BaseSource" << std::endl; - init(); - runInBackground = false; - displayed = false; -} - -BaseSource::BaseSource(ofTexture * newTexture){ - init(); - texture = newTexture; -} - -BaseSource::~BaseSource(){} - -ofTexture * BaseSource::getTexture(){ - return texture; -} - -std::string & BaseSource::getName(){ - return name; -} - -bool BaseSource::isLoadable(){ - return loadable; -} - -bool BaseSource::isLoaded(){ - return loaded; -} - -SourceType BaseSource::getType(){ - return type; -} - -std::string & BaseSource::getPath(){ - return path; -} - -void BaseSource::init(){ - texture = 0; - name = ""; - path = ""; - loadable = false; - loaded = false; - type = SourceType::SOURCE_TYPE_NONE; - referenceCount = 1; // We have one instance on init -} - -void BaseSource::setActive(bool value){ - displayed = value; -} - -bool BaseSource::isActive(){ - return displayed; -} - -bool BaseSource::runsInBackground(){ - return runInBackground; -} - -void BaseSource::setNameFromPath(std::string & fullPath){ - std::vector pathParts; - //std::cout << "fullPath: " << fullPath << std::endl; - - pathParts = ofSplitString(fullPath, "/"); // Maybe on win "/" is "\", have to test - //std::cout << "lastPathPart: " << pathParts[pathParts.size() - 1] << std::endl; - name = pathParts[pathParts.size() - 1]; -} - -} // namespace piMapper -} // namespace ofx +#include "BaseSource.h" + +namespace ofx { +namespace piMapper { + +BaseSource::BaseSource(){ + //std::cout << "BaseSource" << std::endl; + init(); + runInBackground = false; + displayed = false; +} + +BaseSource::BaseSource(ofTexture * newTexture){ + init(); + texture = newTexture; +} + +BaseSource::~BaseSource(){} + +ofTexture * BaseSource::getTexture(){ + return texture; +} + +std::string & BaseSource::getName(){ + return name; +} + +bool BaseSource::isLoadable(){ + return loadable; +} + +bool BaseSource::isLoaded(){ + return loaded; +} + +SourceType BaseSource::getType(){ + return type; +} + +std::string & BaseSource::getPath(){ + return path; +} + +void BaseSource::init(){ + texture = 0; + name = ""; + path = ""; + loadable = false; + loaded = false; + type = SourceType::SOURCE_TYPE_NONE; + referenceCount = 1; // We have one instance on init +} + +void BaseSource::setActive(bool value){ + displayed = value; +} + +bool BaseSource::isActive(){ + return displayed; +} + +bool BaseSource::runsInBackground(){ + return runInBackground; +} + +void BaseSource::setNameFromPath(std::string & fullPath){ + std::vector pathParts; + //std::cout << "fullPath: " << fullPath << std::endl; + + pathParts = ofSplitString(fullPath, "/"); // Maybe on win "/" is "\", have to test + //std::cout << "lastPathPart: " << pathParts[pathParts.size() - 1] << std::endl; + name = pathParts[pathParts.size() - 1]; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/BaseSource.h b/src/Sources/BaseSource.h index e637251..dc31578 100644 --- a/src/Sources/BaseSource.h +++ b/src/Sources/BaseSource.h @@ -1,49 +1,49 @@ -#pragma once - -#include "ofMain.h" -#include "SourceType.h" - -namespace ofx { -namespace piMapper { - -// Use this for adding generative sources to your surfaces -class BaseSource { - public: - BaseSource(); - BaseSource(ofTexture * newTexture); // Only one clean way of passing the texture - ~BaseSource(); - ofTexture * getTexture(); - std::string & getName(); - bool isLoadable(); // Maybe the loading features shoud go to a derrived class - bool isLoaded(); // as BaseSourceLoadable - SourceType getType(); - std::string & getPath(); - virtual void clear(){} - virtual void togglePause(){} - bool isActive(); - bool runsInBackground(); - void setActive(bool); - - virtual void reset(){} // called by surfaceManager to optionally allow users to reset a source's variables - - // TODO: add virtual increaseReferenceCount and decreaseReferenceCount methods - // and make the variable protected - int referenceCount; - - private: - void init(); - - protected: - void setNameFromPath(std::string & fullPath); - ofTexture * texture; - std::string name; - std::string path; // This is set only if loadable is true - bool loadable; // If the source can be loaded from disk like image and video - bool loaded; // Is the source loaded? - SourceType type; - bool displayed; - bool runInBackground; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "SourceType.h" + +namespace ofx { +namespace piMapper { + +// Use this for adding generative sources to your surfaces +class BaseSource { + public: + BaseSource(); + BaseSource(ofTexture * newTexture); // Only one clean way of passing the texture + ~BaseSource(); + ofTexture * getTexture(); + std::string & getName(); + bool isLoadable(); // Maybe the loading features shoud go to a derrived class + bool isLoaded(); // as BaseSourceLoadable + SourceType getType(); + std::string & getPath(); + virtual void clear(){} + virtual void togglePause(){} + bool isActive(); + bool runsInBackground(); + void setActive(bool); + + virtual void reset(){} // called by surfaceManager to optionally allow users to reset a source's variables + + // TODO: add virtual increaseReferenceCount and decreaseReferenceCount methods + // and make the variable protected + int referenceCount; + + private: + void init(); + + protected: + void setNameFromPath(std::string & fullPath); + ofTexture * texture; + std::string name; + std::string path; // This is set only if loadable is true + bool loadable; // If the source can be loaded from disk like image and video + bool loaded; // Is the source loaded? + SourceType type; + bool displayed; + bool runInBackground; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/FboSource.cpp b/src/Sources/FboSource.cpp index ea38f23..e26d4d8 100644 --- a/src/Sources/FboSource.cpp +++ b/src/Sources/FboSource.cpp @@ -1,104 +1,104 @@ -#include "FboSource.h" - -namespace ofx { -namespace piMapper { - -FboSource::FboSource(){ - fbo = 0; - name = PIMAPPER_FBO_SOURCE_DEF_NAME; - loadable = false; - loaded = false; - type = SourceType::SOURCE_TYPE_FBO; - _disableDraw = false; -} - -FboSource::~FboSource(){ - clear(); -} - -void FboSource::updateFbo(){ - if(fbo == 0 || !fbo->isAllocated()){ - ofLogWarning("FboSource") << "FBO not allocated"; - return; - } - update(); -} - -void FboSource::beginFbo(){ - if(fbo == 0 || !fbo->isAllocated()){ - ofLogWarning("FboSource") << "FBO not allocated"; - return; - } - fbo->begin(); -} - -void FboSource::endFbo(){ - if(fbo == 0 || !fbo->isAllocated()){ - ofLogWarning("FboSource") << "FBO not allocated"; - return; - } - fbo->end(); -} - -void FboSource::drawFbo(){ - if(fbo == 0 || !fbo->isAllocated()){ - ofLogWarning("FboSource") << "FBO not allocated"; - return; - } - - if(_disableDraw){ - return; - } - - fbo->begin(); - draw(); - fbo->end(); -} - -void FboSource::setDisableDraw(bool b){ - _disableDraw = b; -} - -void FboSource::allocate(int width, int height){ - clear(); - fbo = new ofFbo(); - fbo->allocate(width, height); - - // Clear FBO - fbo->begin(); - ofClear(0); - fbo->end(); - - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - texture = &(fbo->getTexture()); - #else - texture = &(fbo->getTextureReference()); - #endif -} - -void FboSource::clear(){ - texture = 0; - if(fbo != 0){ - delete fbo; - fbo = 0; - } -} - -int FboSource::getWidth(){ - if(fbo->isAllocated()){ - return fbo->getWidth(); - }else{ - return 0; - } -} - -int FboSource::getHeight(){ - if(fbo->isAllocated()){ - return fbo->getHeight(); - }else{ - return 0; - } -} - -} // namespace piMapper -} // namespace ofx +#include "FboSource.h" + +namespace ofx { +namespace piMapper { + +FboSource::FboSource(){ + fbo = 0; + name = PIMAPPER_FBO_SOURCE_DEF_NAME; + loadable = false; + loaded = false; + type = SourceType::SOURCE_TYPE_FBO; + _disableDraw = false; +} + +FboSource::~FboSource(){ + clear(); +} + +void FboSource::updateFbo(){ + if(fbo == 0 || !fbo->isAllocated()){ + ofLogWarning("FboSource") << "FBO not allocated"; + return; + } + update(); +} + +void FboSource::beginFbo(){ + if(fbo == 0 || !fbo->isAllocated()){ + ofLogWarning("FboSource") << "FBO not allocated"; + return; + } + fbo->begin(); +} + +void FboSource::endFbo(){ + if(fbo == 0 || !fbo->isAllocated()){ + ofLogWarning("FboSource") << "FBO not allocated"; + return; + } + fbo->end(); +} + +void FboSource::drawFbo(){ + if(fbo == 0 || !fbo->isAllocated()){ + ofLogWarning("FboSource") << "FBO not allocated"; + return; + } + + if(_disableDraw){ + return; + } + + fbo->begin(); + draw(); + fbo->end(); +} + +void FboSource::setDisableDraw(bool b){ + _disableDraw = b; +} + +void FboSource::allocate(int width, int height){ + clear(); + fbo = new ofFbo(); + fbo->allocate(width, height); + + // Clear FBO + fbo->begin(); + ofClear(0); + fbo->end(); + + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + texture = &(fbo->getTexture()); + #else + texture = &(fbo->getTextureReference()); + #endif +} + +void FboSource::clear(){ + texture = 0; + if(fbo != 0){ + delete fbo; + fbo = 0; + } +} + +int FboSource::getWidth(){ + if(fbo->isAllocated()){ + return fbo->getWidth(); + }else{ + return 0; + } +} + +int FboSource::getHeight(){ + if(fbo->isAllocated()){ + return fbo->getHeight(); + }else{ + return 0; + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/FboSource.h b/src/Sources/FboSource.h index 24e1826..4b33c3e 100644 --- a/src/Sources/FboSource.h +++ b/src/Sources/FboSource.h @@ -1,52 +1,52 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSource.h" - -#define PIMAPPER_FBO_SOURCE_DEF_NAME "FBO Source" - -namespace ofx { -namespace piMapper { - -class FboSource : public BaseSource { - - public: - FboSource(); - ~FboSource(); - - // Override these in your custom FBO source - virtual void setup(){} - virtual void update(){} - virtual void draw(){} - - // We use this as replacement of draw internally in ofxPiMapper - // to populate the FBO texture that then can be drawn again by - // calling normal draw(); - // Or maybe this should be simplified? By leaving only one draw? - // And the user would have to allocate the fbo himself? - void updateFbo(); - void drawFbo(); - - // The only method from BaseSource to be overriden - void clear(); - - // App listeners - void setDisableDraw(bool b); // Use in cases with external ofFbo - - // fbo accessor functions to allow us to wrap any function with begin/end calls to fbo - void beginFbo(); - void endFbo(); - - protected: - ofFbo * fbo; - void allocate(int width, int height); - - // Some handy getters - int getWidth(); - int getHeight(); - - bool _disableDraw; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSource.h" + +#define PIMAPPER_FBO_SOURCE_DEF_NAME "FBO Source" + +namespace ofx { +namespace piMapper { + +class FboSource : public BaseSource { + + public: + FboSource(); + ~FboSource(); + + // Override these in your custom FBO source + virtual void setup(){} + virtual void update(){} + virtual void draw(){} + + // We use this as replacement of draw internally in ofxPiMapper + // to populate the FBO texture that then can be drawn again by + // calling normal draw(); + // Or maybe this should be simplified? By leaving only one draw? + // And the user would have to allocate the fbo himself? + void updateFbo(); + void drawFbo(); + + // The only method from BaseSource to be overriden + void clear(); + + // App listeners + void setDisableDraw(bool b); // Use in cases with external ofFbo + + // fbo accessor functions to allow us to wrap any function with begin/end calls to fbo + void beginFbo(); + void endFbo(); + + protected: + ofFbo * fbo; + void allocate(int width, int height); + + // Some handy getters + int getWidth(); + int getHeight(); + + bool _disableDraw; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/ImageSource.cpp b/src/Sources/ImageSource.cpp index 08db4b6..b88ed49 100644 --- a/src/Sources/ImageSource.cpp +++ b/src/Sources/ImageSource.cpp @@ -1,42 +1,42 @@ -#include "ImageSource.h" - -namespace ofx { -namespace piMapper { - -ImageSource::ImageSource(){ - loadable = true; - loaded = false; - type = SourceType::SOURCE_TYPE_IMAGE; -} - -ImageSource::~ImageSource(){} - -void ImageSource::loadImage(std::string & filePath){ - path = filePath; - setNameFromPath(filePath); - image = new ofImage(); - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - if(!image->load(filePath)){ - #else - if(!image->loadImage(filePath)){ - #endif - ofLogWarning("ImageSource") << "Could not load image"; - } - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - texture = &image->getTexture(); - #else - texture = &image->getTextureReference(); - #endif - loaded = true; -} - -void ImageSource::clear(){ - texture = 0; - image->clear(); - delete image; - image = 0; - loaded = false; -} - -} // namespace piMapper +#include "ImageSource.h" + +namespace ofx { +namespace piMapper { + +ImageSource::ImageSource(){ + loadable = true; + loaded = false; + type = SourceType::SOURCE_TYPE_IMAGE; +} + +ImageSource::~ImageSource(){} + +void ImageSource::loadImage(std::string & filePath){ + path = filePath; + setNameFromPath(filePath); + image = new ofImage(); + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + if(!image->load(filePath)){ + #else + if(!image->loadImage(filePath)){ + #endif + ofLogWarning("ImageSource") << "Could not load image"; + } + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + texture = &image->getTexture(); + #else + texture = &image->getTextureReference(); + #endif + loaded = true; +} + +void ImageSource::clear(){ + texture = 0; + image->clear(); + delete image; + image = 0; + loaded = false; +} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Sources/ImageSource.h b/src/Sources/ImageSource.h index 2d34270..ea0ba53 100644 --- a/src/Sources/ImageSource.h +++ b/src/Sources/ImageSource.h @@ -1,22 +1,22 @@ -#pragma once - -#include "BaseSource.h" - -namespace ofx { -namespace piMapper { - -class ImageSource : public BaseSource { - - public: - ImageSource(); - ~ImageSource(); - std::string & getPath(); - void loadImage(std::string & filePath); - void clear(); - private: - ofImage * image; - -}; - -} // namespace piMapper +#pragma once + +#include "BaseSource.h" + +namespace ofx { +namespace piMapper { + +class ImageSource : public BaseSource { + + public: + ImageSource(); + ~ImageSource(); + std::string & getPath(); + void loadImage(std::string & filePath); + void clear(); + private: + ofImage * image; + +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Sources/OMXPlayerCache.cpp b/src/Sources/OMXPlayerCache.cpp index df98ac9..b3195d3 100644 --- a/src/Sources/OMXPlayerCache.cpp +++ b/src/Sources/OMXPlayerCache.cpp @@ -1,46 +1,46 @@ -#include "OMXPlayerCache.h" - -#ifdef TARGET_RASPBERRY_PI - -namespace ofx { -namespace piMapper { - -OMXPlayerCache * OMXPlayerCache::_instance = 0; - -OMXPlayerCache * OMXPlayerCache::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::OMXPlayerCache(); - } - return _instance; -} - -ofxOMXPlayer * OMXPlayerCache::load(std::string moviePath){ - if(_players.find(moviePath) == _players.end()){ - ofxOMXPlayerSettings settings; - settings.videoPath = moviePath; - settings.useHDMIForAudio = VideoSource::useHDMIForAudio; - settings.enableTexture = true; - settings.enableLooping = true; - settings.enableAudio = VideoSource::enableAudio; - - ofxOMXPlayer * p = new ofxOMXPlayer(); - p->setup(settings); - _players[moviePath] = p; - - return p; - } - - _players[moviePath]->restartMovie(); - return _players[moviePath]; -} - -void OMXPlayerCache::unload(std::string moviePath){ - if(_players.find(moviePath) != _players.end()){ - _players[moviePath]->setPaused(true); - } -} - -} // namespace piMapper -} // namespace ofx - +#include "OMXPlayerCache.h" + +#ifdef TARGET_RASPBERRY_PI + +namespace ofx { +namespace piMapper { + +OMXPlayerCache * OMXPlayerCache::_instance = 0; + +OMXPlayerCache * OMXPlayerCache::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::OMXPlayerCache(); + } + return _instance; +} + +ofxOMXPlayer * OMXPlayerCache::load(std::string moviePath){ + if(_players.find(moviePath) == _players.end()){ + ofxOMXPlayerSettings settings; + settings.videoPath = moviePath; + settings.useHDMIForAudio = VideoSource::useHDMIForAudio; + settings.enableTexture = true; + settings.enableLooping = true; + settings.enableAudio = VideoSource::enableAudio; + + ofxOMXPlayer * p = new ofxOMXPlayer(); + p->setup(settings); + _players[moviePath] = p; + + return p; + } + + _players[moviePath]->restartMovie(); + return _players[moviePath]; +} + +void OMXPlayerCache::unload(std::string moviePath){ + if(_players.find(moviePath) != _players.end()){ + _players[moviePath]->setPaused(true); + } +} + +} // namespace piMapper +} // namespace ofx + #endif \ No newline at end of file diff --git a/src/Sources/OMXPlayerCache.h b/src/Sources/OMXPlayerCache.h index c01d382..ebc0e36 100644 --- a/src/Sources/OMXPlayerCache.h +++ b/src/Sources/OMXPlayerCache.h @@ -1,28 +1,28 @@ -#pragma once - -#ifdef TARGET_RASPBERRY_PI - -#include "ofMain.h" -#include "ofxOMXPlayer.h" -#include "VideoSource.h" - -namespace ofx { -namespace piMapper { - -class OMXPlayerCache { - - public: - static OMXPlayerCache * instance(); - ofxOMXPlayer * load(std::string moviePath); - void unload(std::string moviePath); - - private: - static OMXPlayerCache * _instance; - map _players; - -}; - -} // namespace piMapper -} // namespace ofx - -#endif +#pragma once + +#ifdef TARGET_RASPBERRY_PI + +#include "ofMain.h" +#include "ofxOMXPlayer.h" +#include "VideoSource.h" + +namespace ofx { +namespace piMapper { + +class OMXPlayerCache { + + public: + static OMXPlayerCache * instance(); + ofxOMXPlayer * load(std::string moviePath); + void unload(std::string moviePath); + + private: + static OMXPlayerCache * _instance; + map _players; + +}; + +} // namespace piMapper +} // namespace ofx + +#endif diff --git a/src/Sources/SourceType.h b/src/Sources/SourceType.h index 7b66bb8..3bb9d6d 100644 --- a/src/Sources/SourceType.h +++ b/src/Sources/SourceType.h @@ -1,14 +1,14 @@ -#pragma once - -namespace ofx { -namespace piMapper { - -enum SourceType { - SOURCE_TYPE_NONE, - SOURCE_TYPE_IMAGE, - SOURCE_TYPE_VIDEO, - SOURCE_TYPE_FBO -}; - -} // namespace piMapper +#pragma once + +namespace ofx { +namespace piMapper { + +enum SourceType { + SOURCE_TYPE_NONE, + SOURCE_TYPE_IMAGE, + SOURCE_TYPE_VIDEO, + SOURCE_TYPE_FBO +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Sources/SourceTypeHelper.h b/src/Sources/SourceTypeHelper.h index b6e3b77..becff7a 100644 --- a/src/Sources/SourceTypeHelper.h +++ b/src/Sources/SourceTypeHelper.h @@ -1,52 +1,52 @@ -#pragma once - -#include "ofLog.h" -#include "SourceType.h" - -#define SOURCE_TYPE_NAME_NONE "none" -#define SOURCE_TYPE_NAME_IMAGE "image" -#define SOURCE_TYPE_NAME_VIDEO "video" -#define SOURCE_TYPE_NAME_FBO "fbo" - -namespace ofx { -namespace piMapper { - -class SourceTypeHelper { - public: - static std::string GetSourceTypeHelperName(SourceType sourceTypeEnum){ - if(sourceTypeEnum == SOURCE_TYPE_IMAGE){ - return SOURCE_TYPE_NAME_IMAGE; - }else if(sourceTypeEnum == SOURCE_TYPE_VIDEO){ - return SOURCE_TYPE_NAME_VIDEO; - }else if(sourceTypeEnum == SOURCE_TYPE_NONE){ - return SOURCE_TYPE_NAME_NONE; - }else if(sourceTypeEnum == SOURCE_TYPE_FBO){ - return SOURCE_TYPE_NAME_FBO; - }else{ - std::stringstream ss; - ss << "Invalid source type: " << sourceTypeEnum; - ofLogFatalError("SourceTypeHelper") << ss.str(); - exit(EXIT_FAILURE); - } - } - - static SourceType GetSourceTypeHelperEnum(std::string sourceTypeName){ - if(sourceTypeName == SOURCE_TYPE_NAME_IMAGE){ - return SOURCE_TYPE_IMAGE; - }else if(sourceTypeName == SOURCE_TYPE_NAME_VIDEO){ - return SOURCE_TYPE_VIDEO; - }else if(sourceTypeName == SOURCE_TYPE_NAME_NONE){ - return SOURCE_TYPE_NONE; - }else if(sourceTypeName == SOURCE_TYPE_NAME_FBO){ - return SOURCE_TYPE_FBO; - }else{ - std::stringstream ss; - ss << "Invalid source type name: " << sourceTypeName; - ofLogFatalError("SourceTypeHelper") << ss.str(); - exit(EXIT_FAILURE); - } - } -}; - -} // namespace piMapper +#pragma once + +#include "ofLog.h" +#include "SourceType.h" + +#define SOURCE_TYPE_NAME_NONE "none" +#define SOURCE_TYPE_NAME_IMAGE "image" +#define SOURCE_TYPE_NAME_VIDEO "video" +#define SOURCE_TYPE_NAME_FBO "fbo" + +namespace ofx { +namespace piMapper { + +class SourceTypeHelper { + public: + static std::string GetSourceTypeHelperName(SourceType sourceTypeEnum){ + if(sourceTypeEnum == SOURCE_TYPE_IMAGE){ + return SOURCE_TYPE_NAME_IMAGE; + }else if(sourceTypeEnum == SOURCE_TYPE_VIDEO){ + return SOURCE_TYPE_NAME_VIDEO; + }else if(sourceTypeEnum == SOURCE_TYPE_NONE){ + return SOURCE_TYPE_NAME_NONE; + }else if(sourceTypeEnum == SOURCE_TYPE_FBO){ + return SOURCE_TYPE_NAME_FBO; + }else{ + std::stringstream ss; + ss << "Invalid source type: " << sourceTypeEnum; + ofLogFatalError("SourceTypeHelper") << ss.str(); + exit(EXIT_FAILURE); + } + } + + static SourceType GetSourceTypeHelperEnum(std::string sourceTypeName){ + if(sourceTypeName == SOURCE_TYPE_NAME_IMAGE){ + return SOURCE_TYPE_IMAGE; + }else if(sourceTypeName == SOURCE_TYPE_NAME_VIDEO){ + return SOURCE_TYPE_VIDEO; + }else if(sourceTypeName == SOURCE_TYPE_NAME_NONE){ + return SOURCE_TYPE_NONE; + }else if(sourceTypeName == SOURCE_TYPE_NAME_FBO){ + return SOURCE_TYPE_FBO; + }else{ + std::stringstream ss; + ss << "Invalid source type name: " << sourceTypeName; + ofLogFatalError("SourceTypeHelper") << ss.str(); + exit(EXIT_FAILURE); + } + } +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Sources/VideoSource.cpp b/src/Sources/VideoSource.cpp index 72e1092..88fefa6 100644 --- a/src/Sources/VideoSource.cpp +++ b/src/Sources/VideoSource.cpp @@ -1,134 +1,134 @@ -#include "VideoSource.h" - -namespace ofx { -namespace piMapper { - -bool VideoSource::enableAudio = true; -bool VideoSource::useHDMIForAudio = false; - -VideoSource::VideoSource(){ - loadable = true; - loaded = false; - _loop = true; - type = SourceType::SOURCE_TYPE_VIDEO; - #ifdef TARGET_RASPBERRY_PI - _omxPlayer = 0; - #else - _videoPlayer = 0; - _initialVolumeSet = false; - #endif -} - -void VideoSource::loadVideo(std::string & filePath){ - path = filePath; - setNameFromPath(filePath); - - #ifdef TARGET_RASPBERRY_PI - _omxPlayer = OMXPlayerCache::instance()->load(filePath); - texture = &(_omxPlayer->getTextureReference()); - #else - _videoPlayer = make_unique(); - _videoPlayer->load(filePath); - _videoPlayer->setLoopState(OF_LOOP_NORMAL); - _videoPlayer->play(); - _videoPlayer->setVolume(VideoSource::enableAudio ? 1.0f : 0.0f); - texture = &(_videoPlayer->getTexture()); - #endif - - ofAddListener(ofEvents().update, this, &VideoSource::update); - loaded = true; -} - -void VideoSource::setLoop(bool loop){ - _loop = loop; - #ifndef TARGET_RASPBERRY_PI - if(_videoPlayer == 0) return; - if(loop) _videoPlayer->setLoopState(OF_LOOP_NORMAL); - else _videoPlayer->setLoopState(OF_LOOP_NONE); - #endif -} - -bool VideoSource::getLoop(){ - return _loop; -} - -void VideoSource::clear(){ - texture = 0; - - #ifdef TARGET_RASPBERRY_PI - OMXPlayerCache::instance()->unload(path); - #else - _videoPlayer->stop(); - _videoPlayer->close(); - _videoPlayer.reset(); - _videoPlayer = 0; - #endif - - ofRemoveListener(ofEvents().update, this, &VideoSource::update); - loaded = false; -} - -void VideoSource::togglePause(){ - #ifdef TARGET_RASPBERRY_PI - _omxPlayer->togglePause(); - #else - _videoPlayer->setPaused(!_videoPlayer->isPaused()); - #endif -} - -void VideoSource::stop(){ - #ifdef TARGET_RASPBERRY_PI - _omxPlayer->setPaused(true); - #else - _videoPlayer->setPaused(true); - #endif -} - -#ifndef TARGET_RASPBERRY_PI - void VideoSource::update(ofEventArgs & args){ - if(_videoPlayer != 0){ - if(!_initialVolumeSet){ - if(_videoPlayer->isInitialized()){ - _videoPlayer->setVolume(VideoSource::enableAudio ? 1.0f : 0.0f); - _initialVolumeSet = true; - } - } - _videoPlayer->update(); - } - } -#else - void VideoSource::update(ofEventArgs & args){ - if(!_loop && _omxPlayer != 0){ - if(_omxPlayer->getCurrentFrame() >= _omxPlayer->getTotalNumFrames() - 1){ - _omxPlayer->setPaused(true); - } - } - } -#endif - -void VideoSource::restart(){ - #ifdef TARGET_RASPBERRY_PI - _omxPlayer->restartMovie(); - #else - _videoPlayer->setPosition(0); - _videoPlayer->play(); - #endif -} - -void VideoSource::pause() { - #ifdef TARGET_RASPBERRY_PI - _omxPlayer->setPaused(true); - #else - _videoPlayer->setPaused(true); - #endif -} -void VideoSource::resume() { - #ifdef TARGET_RASPBERRY_PI - _omxPlayer->setPaused(false); - #else - _videoPlayer->setPaused(false); - #endif -} - -} // namespace piMapper -} // namespace ofx +#include "VideoSource.h" + +namespace ofx { +namespace piMapper { + +bool VideoSource::enableAudio = true; +bool VideoSource::useHDMIForAudio = false; + +VideoSource::VideoSource(){ + loadable = true; + loaded = false; + _loop = true; + type = SourceType::SOURCE_TYPE_VIDEO; + #ifdef TARGET_RASPBERRY_PI + _omxPlayer = 0; + #else + _videoPlayer = 0; + _initialVolumeSet = false; + #endif +} + +void VideoSource::loadVideo(std::string & filePath){ + path = filePath; + setNameFromPath(filePath); + + #ifdef TARGET_RASPBERRY_PI + _omxPlayer = OMXPlayerCache::instance()->load(filePath); + texture = &(_omxPlayer->getTextureReference()); + #else + _videoPlayer = std::make_unique(); + _videoPlayer->load(filePath); + _videoPlayer->setLoopState(OF_LOOP_NORMAL); + _videoPlayer->play(); + _videoPlayer->setVolume(VideoSource::enableAudio ? 1.0f : 0.0f); + texture = &(_videoPlayer->getTexture()); + #endif + + ofAddListener(ofEvents().update, this, &VideoSource::update); + loaded = true; +} + +void VideoSource::setLoop(bool loop){ + _loop = loop; + #ifndef TARGET_RASPBERRY_PI + if(_videoPlayer == 0) return; + if(loop) _videoPlayer->setLoopState(OF_LOOP_NORMAL); + else _videoPlayer->setLoopState(OF_LOOP_NONE); + #endif +} + +bool VideoSource::getLoop(){ + return _loop; +} + +void VideoSource::clear(){ + texture = 0; + + #ifdef TARGET_RASPBERRY_PI + OMXPlayerCache::instance()->unload(path); + #else + _videoPlayer->stop(); + _videoPlayer->close(); + _videoPlayer.reset(); + _videoPlayer = 0; + #endif + + ofRemoveListener(ofEvents().update, this, &VideoSource::update); + loaded = false; +} + +void VideoSource::togglePause(){ + #ifdef TARGET_RASPBERRY_PI + _omxPlayer->togglePause(); + #else + _videoPlayer->setPaused(!_videoPlayer->isPaused()); + #endif +} + +void VideoSource::stop(){ + #ifdef TARGET_RASPBERRY_PI + _omxPlayer->setPaused(true); + #else + _videoPlayer->setPaused(true); + #endif +} + +#ifndef TARGET_RASPBERRY_PI + void VideoSource::update(ofEventArgs & args){ + if(_videoPlayer != 0){ + if(!_initialVolumeSet){ + if(_videoPlayer->isInitialized()){ + _videoPlayer->setVolume(VideoSource::enableAudio ? 1.0f : 0.0f); + _initialVolumeSet = true; + } + } + _videoPlayer->update(); + } + } +#else + void VideoSource::update(ofEventArgs & args){ + if(!_loop && _omxPlayer != 0){ + if(_omxPlayer->getCurrentFrame() >= _omxPlayer->getTotalNumFrames() - 1){ + _omxPlayer->setPaused(true); + } + } + } +#endif + +void VideoSource::restart(){ + #ifdef TARGET_RASPBERRY_PI + _omxPlayer->restartMovie(); + #else + _videoPlayer->setPosition(0); + _videoPlayer->play(); + #endif +} + +void VideoSource::pause() { + #ifdef TARGET_RASPBERRY_PI + _omxPlayer->setPaused(true); + #else + _videoPlayer->setPaused(true); + #endif +} +void VideoSource::resume() { + #ifdef TARGET_RASPBERRY_PI + _omxPlayer->setPaused(false); + #else + _videoPlayer->setPaused(false); + #endif +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/VideoSource.h b/src/Sources/VideoSource.h index f1af7d3..d415db1 100644 --- a/src/Sources/VideoSource.h +++ b/src/Sources/VideoSource.h @@ -1,51 +1,52 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSource.h" - -#ifdef TARGET_RASPBERRY_PI - #include "ofxOMXPlayer.h" - #include "OMXPlayerCache.h" -#endif - -namespace ofx { -namespace piMapper { - -class VideoSource : public BaseSource { - - public: - - // TODO: Create enableAudio() and disableAudio() methods - // for live audio enabling and disabling. - static bool enableAudio; - static bool useHDMIForAudio; - - VideoSource(); - - std::string & getPath(); - void loadVideo(std::string & path); - void setLoop(bool loop); - bool getLoop(); - void clear(); - void togglePause(); - void stop(); - void update(ofEventArgs & args); - void restart(); - void pause(); - void resume(); - - private: - - #ifdef TARGET_RASPBERRY_PI - ofxOMXPlayer * _omxPlayer; - #else - unique_ptr _videoPlayer; - bool _initialVolumeSet; - #endif - - bool _loop; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSource.h" +#include + +#ifdef TARGET_RASPBERRY_PI + #include "ofxOMXPlayer.h" + #include "OMXPlayerCache.h" +#endif + +namespace ofx { +namespace piMapper { + +class VideoSource : public BaseSource { + + public: + + // TODO: Create enableAudio() and disableAudio() methods + // for live audio enabling and disabling. + static bool enableAudio; + static bool useHDMIForAudio; + + VideoSource(); + + std::string & getPath(); + void loadVideo(std::string & path); + void setLoop(bool loop); + bool getLoop(); + void clear(); + void togglePause(); + void stop(); + void update(ofEventArgs & args); + void restart(); + void pause(); + void resume(); + + private: + + #ifdef TARGET_RASPBERRY_PI + ofxOMXPlayer * _omxPlayer; + #else + std::unique_ptr _videoPlayer; + bool _initialVolumeSet; + #endif + + bool _loop; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/BaseSurface.cpp b/src/Surfaces/BaseSurface.cpp index 952742b..763a580 100644 --- a/src/Surfaces/BaseSurface.cpp +++ b/src/Surfaces/BaseSurface.cpp @@ -1,169 +1,169 @@ -#include "BaseSurface.h" - -namespace ofx { -namespace piMapper { - -BaseSurface::BaseSurface(){ - _moved = false; - _scale = 1.0f; - createDefaultTexture(); -} - -BaseSurface::~BaseSurface(){ - delete defaultSource; - defaultSource = 0; - defaultTexture.clear(); -} - -void BaseSurface::createDefaultTexture(){ - ofPixels pixels; - pixels.allocate(500, 500, 1); - for(int i = 0; i < pixels.size(); i++){ - pixels[i] = 255; - } - - // size of each test pattern square - int squareSize = 10; - - bool sy = false; - for(int y = 0; y < pixels.getWidth(); y += squareSize){ - bool sx = false; - for(int x = 0; x < pixels.getHeight(); x += squareSize){ - for(int yi = 0; yi < squareSize; yi++){ - for(int xi = 0; xi < squareSize; xi++){ - if(sx && sy){ - pixels[(y + yi) * pixels.getWidth() + x + xi] = 255; - }else if(sx && !sy){ - pixels[(y + yi) * pixels.getWidth() + x + xi] = 0; - }else if(!sx && sy){ - pixels[(y + yi) * pixels.getWidth() + x + xi] = 0; - }else{ - pixels[(y + yi) * pixels.getWidth() + x + xi] = 255; - } - } - } - sx = !sx; - } - sy = !sy; - } - - // load pixels into texture - defaultTexture.loadData(pixels); - - // Create new source to be the default - defaultSource = new BaseSource(&defaultTexture); - source = defaultSource; -} - -void BaseSurface::drawTexture(Vec3 position){ - if(source->getTexture() == 0){ - ofLogWarning("BaseSurface") << "Source texture empty. Not drawing."; - return; - } - - // TODO: Do not recreate this in each draw loop - ofMesh texMesh; - - // Add vertices to the mesh - texMesh.addVertex(position.toOf()); - Vec3 topRight(source->getTexture()->getWidth(), 0.0f, 0.0f); - texMesh.addVertex((position + topRight).toOf()); - Vec3 bottomRight(source->getTexture()->getWidth(), source->getTexture()->getHeight(), 0.0f); - texMesh.addVertex((position + bottomRight).toOf()); - Vec3 bottomLeft(0.0f, source->getTexture()->getHeight(), 0.0f); - texMesh.addVertex((position + bottomLeft).toOf()); - - // Make triangles out of added vertices - texMesh.addTriangle(0, 2, 3); - texMesh.addTriangle(0, 1, 2); - - // Add texture coordinates for the added vertices - texMesh.addTexCoord(Vec2(0.0f, 0.0f).toOf()); - texMesh.addTexCoord(Vec2(1.0f, 0.0f).toOf()); - texMesh.addTexCoord(Vec2(1.0f, 1.0f).toOf()); - texMesh.addTexCoord(Vec2(0.0f, 1.0f).toOf()); - - // Draw mesh - source->getTexture()->bind(); - texMesh.draw(); - source->getTexture()->unbind(); -} - -void BaseSurface::setSource(BaseSource * newSource){ - source = newSource; -} - -BaseSource * BaseSurface::getSource(){ - return source; -} - -BaseSource * BaseSurface::getDefaultSource(){ - return defaultSource; -} - -void BaseSurface::setMoved(bool moved){ - _moved = moved; -} - -void BaseSurface::scaleTo(float scale){ - Vec3 centroid( - getBoundingBox().getCenter().x, - getBoundingBox().getCenter().y, - getBoundingBox().getCenter().z); - for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ - Vec3 d = (Vec3(mesh.getVertices()[i]) - centroid) / _scale; - d *= scale; - mesh.getVertices()[i] = (centroid + d).toOf(); - } - - _scale = scale; - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -bool BaseSurface::getMoved(){ - return _moved; -} - -float BaseSurface::getScale(){ - return _scale; -} - -ofMesh & BaseSurface::getMesh(){ - return mesh; -} - -ofRectangle & BaseSurface::getBoundingBox(){ - - // Get top left - _boundingBox.x = 999999; - _boundingBox.y = 999999; - for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ - if(mesh.getVertices()[i].x < _boundingBox.x){ - _boundingBox.x = mesh.getVertices()[i].x; - } - - if(mesh.getVertices()[i].y < _boundingBox.y){ - _boundingBox.y = mesh.getVertices()[i].y; - } - } - - // Get bottom right - _boundingBox.width = -999999; - _boundingBox.height = -999999; - for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ - if(mesh.getVertices()[i].x > _boundingBox.x + _boundingBox.width){ - _boundingBox.width = mesh.getVertices()[i].x - _boundingBox.x; - } - - if(mesh.getVertices()[i].y > _boundingBox.y + _boundingBox.height){ - _boundingBox.height = mesh.getVertices()[i].y - _boundingBox.y; - } - } - - return _boundingBox; -} - -} // namespace piMapper -} // namespace ofx +#include "BaseSurface.h" + +namespace ofx { +namespace piMapper { + +BaseSurface::BaseSurface(){ + _moved = false; + _scale = 1.0f; + createDefaultTexture(); +} + +BaseSurface::~BaseSurface(){ + delete defaultSource; + defaultSource = 0; + defaultTexture.clear(); +} + +void BaseSurface::createDefaultTexture(){ + ofPixels pixels; + pixels.allocate(500, 500, 1); + for(int i = 0; i < pixels.size(); i++){ + pixels[i] = 255; + } + + // size of each test pattern square + int squareSize = 10; + + bool sy = false; + for(int y = 0; y < pixels.getWidth(); y += squareSize){ + bool sx = false; + for(int x = 0; x < pixels.getHeight(); x += squareSize){ + for(int yi = 0; yi < squareSize; yi++){ + for(int xi = 0; xi < squareSize; xi++){ + if(sx && sy){ + pixels[(y + yi) * pixels.getWidth() + x + xi] = 255; + }else if(sx && !sy){ + pixels[(y + yi) * pixels.getWidth() + x + xi] = 0; + }else if(!sx && sy){ + pixels[(y + yi) * pixels.getWidth() + x + xi] = 0; + }else{ + pixels[(y + yi) * pixels.getWidth() + x + xi] = 255; + } + } + } + sx = !sx; + } + sy = !sy; + } + + // load pixels into texture + defaultTexture.loadData(pixels); + + // Create new source to be the default + defaultSource = new BaseSource(&defaultTexture); + source = defaultSource; +} + +void BaseSurface::drawTexture(Vec3 position){ + if(source->getTexture() == 0){ + ofLogWarning("BaseSurface") << "Source texture empty. Not drawing."; + return; + } + + // TODO: Do not recreate this in each draw loop + ofMesh texMesh; + + // Add vertices to the mesh + texMesh.addVertex(position.toOf()); + Vec3 topRight(source->getTexture()->getWidth(), 0.0f, 0.0f); + texMesh.addVertex((position + topRight).toOf()); + Vec3 bottomRight(source->getTexture()->getWidth(), source->getTexture()->getHeight(), 0.0f); + texMesh.addVertex((position + bottomRight).toOf()); + Vec3 bottomLeft(0.0f, source->getTexture()->getHeight(), 0.0f); + texMesh.addVertex((position + bottomLeft).toOf()); + + // Make triangles out of added vertices + texMesh.addTriangle(0, 2, 3); + texMesh.addTriangle(0, 1, 2); + + // Add texture coordinates for the added vertices + texMesh.addTexCoord(Vec2(0.0f, 0.0f).toOf()); + texMesh.addTexCoord(Vec2(1.0f, 0.0f).toOf()); + texMesh.addTexCoord(Vec2(1.0f, 1.0f).toOf()); + texMesh.addTexCoord(Vec2(0.0f, 1.0f).toOf()); + + // Draw mesh + source->getTexture()->bind(); + texMesh.draw(); + source->getTexture()->unbind(); +} + +void BaseSurface::setSource(BaseSource * newSource){ + source = newSource; +} + +BaseSource * BaseSurface::getSource(){ + return source; +} + +BaseSource * BaseSurface::getDefaultSource(){ + return defaultSource; +} + +void BaseSurface::setMoved(bool moved){ + _moved = moved; +} + +void BaseSurface::scaleTo(float scale){ + Vec3 centroid( + getBoundingBox().getCenter().x, + getBoundingBox().getCenter().y, + getBoundingBox().getCenter().z); + for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ + Vec3 d = (Vec3(mesh.getVertices()[i]) - centroid) / _scale; + d *= scale; + mesh.getVertices()[i] = (centroid + d).toOf(); + } + + _scale = scale; + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +bool BaseSurface::getMoved(){ + return _moved; +} + +float BaseSurface::getScale(){ + return _scale; +} + +ofMesh & BaseSurface::getMesh(){ + return mesh; +} + +ofRectangle & BaseSurface::getBoundingBox(){ + + // Get top left + _boundingBox.x = 999999; + _boundingBox.y = 999999; + for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ + if(mesh.getVertices()[i].x < _boundingBox.x){ + _boundingBox.x = mesh.getVertices()[i].x; + } + + if(mesh.getVertices()[i].y < _boundingBox.y){ + _boundingBox.y = mesh.getVertices()[i].y; + } + } + + // Get bottom right + _boundingBox.width = -999999; + _boundingBox.height = -999999; + for(unsigned int i = 0; i < mesh.getVertices().size(); ++i){ + if(mesh.getVertices()[i].x > _boundingBox.x + _boundingBox.width){ + _boundingBox.width = mesh.getVertices()[i].x - _boundingBox.x; + } + + if(mesh.getVertices()[i].y > _boundingBox.y + _boundingBox.height){ + _boundingBox.height = mesh.getVertices()[i].y - _boundingBox.y; + } + } + + return _boundingBox; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/BaseSurface.h b/src/Surfaces/BaseSurface.h index 3faf9d8..69c540e 100644 --- a/src/Surfaces/BaseSurface.h +++ b/src/Surfaces/BaseSurface.h @@ -1,66 +1,66 @@ -#pragma once - -#include "ofMain.h" -#include -#include "BaseSource.h" -#include "Vec2.h" -#include "Vec3.h" - -using namespace std; - -namespace ofx { -namespace piMapper { - -class BaseSurface { - - public: - BaseSurface(); - virtual ~BaseSurface(); - - virtual void setup() = 0; - virtual void draw() = 0; - virtual void setVertex(int index, Vec3 p) = 0; - virtual void setVertices(std::vector v) = 0; - virtual void setTexCoord(int index, Vec2 t) = 0; - virtual void setTexCoords(std::vector t) = 0; - virtual void moveBy(Vec3 v) = 0; - virtual void fullScreen() = 0; - virtual int getType() = 0; - virtual bool hitTest(Vec2 p) = 0; - virtual ofPolyline getHitArea() = 0; - virtual ofPolyline getTextureHitArea() = 0; - virtual std::vector getVertices() = 0; - virtual std::vector getTexCoords() = 0; - virtual BaseSurface * clone() = 0; - - void drawTexture(Vec3 position); - void setSource(BaseSource * newSource); - void setMoved(bool moved); - void scaleTo(float scale); - - BaseSource * getSource(); - BaseSource * getDefaultSource(); - - bool getMoved(); - float getScale(); - - ofMesh & getMesh(); - ofRectangle & getBoundingBox(); - - ofEvent> verticesChangedEvent; - ofEvent vertexChangedEvent; - - protected: - ofMesh mesh; - ofRectangle _boundingBox; - ofTexture defaultTexture; - BaseSource * source; - BaseSource * defaultSource; - - void createDefaultTexture(); - bool _moved; - float _scale; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include +#include "BaseSource.h" +#include "Vec2.h" +#include "Vec3.h" + +using namespace std; + +namespace ofx { +namespace piMapper { + +class BaseSurface { + + public: + BaseSurface(); + virtual ~BaseSurface(); + + virtual void setup() = 0; + virtual void draw() = 0; + virtual void setVertex(int index, Vec3 p) = 0; + virtual void setVertices(std::vector v) = 0; + virtual void setTexCoord(int index, Vec2 t) = 0; + virtual void setTexCoords(std::vector t) = 0; + virtual void moveBy(Vec3 v) = 0; + virtual void fullScreen() = 0; + virtual int getType() = 0; + virtual bool hitTest(Vec2 p) = 0; + virtual ofPolyline getHitArea() = 0; + virtual ofPolyline getTextureHitArea() = 0; + virtual std::vector getVertices() = 0; + virtual std::vector getTexCoords() = 0; + virtual BaseSurface * clone() = 0; + + void drawTexture(Vec3 position); + void setSource(BaseSource * newSource); + void setMoved(bool moved); + void scaleTo(float scale); + + BaseSource * getSource(); + BaseSource * getDefaultSource(); + + bool getMoved(); + float getScale(); + + ofMesh & getMesh(); + ofRectangle & getBoundingBox(); + + ofEvent> verticesChangedEvent; + ofEvent vertexChangedEvent; + + protected: + ofMesh mesh; + ofRectangle _boundingBox; + ofTexture defaultTexture; + BaseSource * source; + BaseSource * defaultSource; + + void createDefaultTexture(); + bool _moved; + float _scale; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/CircleSurface.cpp b/src/Surfaces/CircleSurface.cpp index e8a5c0d..ea6b5c0 100755 --- a/src/Surfaces/CircleSurface.cpp +++ b/src/Surfaces/CircleSurface.cpp @@ -1,304 +1,304 @@ -// -// CircleSurface.cpp -// Copyright (c) 2017 Cristobal Mendoza -// With modifications by Krisjanis Rijnieks (c) 2017 -// http://cuppetellimendoza.com - -#include "CircleSurface.h" - -namespace ofx { -namespace piMapper { - -CircleSurface::CircleSurface() : QuadSurface() { - setup(); -} - -CircleSurface::CircleSurface(QuadSurface &surface) { - setup(); - setVertices(surface.getVertices()); - setTexCoords(surface.getTexCoords()); - setPerspectiveWarping(surface.getPerspectiveWarping()); -} - -void CircleSurface::setup() { - - QuadSurface::setup(); - setPerspectiveWarping(true); - - lastSourceTextureId = UINT_MAX; - updateMask = true; -// maskIsReady = false; - -// glESVertexShader = CIRCLE_SURFACE_STRINGIFY( -// attribute vec4 position; -// attribute vec4 color; -// attribute vec4 normal; -// attribute vec2 texcoord; -// -// uniform mat4 modelViewMatrix; -// uniform mat4 projectionMatrix; -// uniform sampler2D maskTex; -// -// varying vec4 colorVarying; -// varying vec2 texCoordVarying; -// -// void main() { -// -// //get our current vertex position so we can modify it -// vec4 pos = projectionMatrix*modelViewMatrix*position; -// -// gl_Position = pos; -// colorVarying = color; -// texCoordVarying = texcoord; -// } -// ); -// -// glESFragmentShader = CIRCLE_SURFACE_STRINGIFY( -////#ifdef GL_ES -//// define default precision for float, vec, mat. -// precision highp float; -////#endif -// -// uniform sampler2D tex0; -// uniform sampler2D maskTex; -// uniform vec4 globalColor; -// -// varying vec2 texCoordVarying; -// -// void main (void) -// { -// vec2 pos = texCoordVarying; -// vec3 src = texture2D(tex0, pos).rgb; -// float mask = texture2D(maskTex, pos).r; -// gl_FragColor = vec4( src , mask); -// } -// ); -// -// gl2FragmentShader = "#version 120\n #extension GL_ARB_texture_rectangle : enable\n"; -// gl2FragmentShader += CIRCLE_SURFACE_STRINGIFY( -// uniform sampler2DRect tex0; -// uniform sampler2DRect maskTex; -// -// void main (void) { -// vec2 pos = gl_TexCoord[0].st; -// -// vec3 src = texture2DRect(tex0, pos).rgb; -// float mask = texture2DRect(maskTex, pos).r; -// -// gl_FragColor = vec4(src, mask); -// } -// ); -// -//#ifdef TARGET_OPENGLES -// maskShader.setupShaderFromSource(GL_VERTEX_SHADER, glESVertexShader); -// maskShader.setupShaderFromSource(GL_FRAGMENT_SHADER, glESFragmentShader); -// maskShader.bindDefaults(); -// maskShader.linkProgram(); -//#else -// if (ofIsGLProgrammableRenderer()) { -// -// } else { -// maskShader.setupShaderFromSource(GL_FRAGMENT_SHADER, gl2FragmentShader); -// maskShader.linkProgram(); -// } -//#endif - - Vec2 t1 = Vec2(0.0f, 0.0f); - Vec2 t2 = Vec2(1.0f, 0.0f); - Vec2 t3 = Vec2(1.0f, 1.0f); - Vec2 t4 = Vec2(0.0f, 1.0f); - - defaultTexCoords.push_back(t1); - defaultTexCoords.push_back(t2); - defaultTexCoords.push_back(t3); - defaultTexCoords.push_back(t4); -} - -void CircleSurface::draw() { - - ofEnableAlphaBlending(); - if (source->getTexture() == 0) - { - return; - } - if (!source->getTexture()->isAllocated()){ - return; - } - - if (source != currentSource) { // Pointer comparison - // Create the mask here - setupTextures(); - lastSourceTextureId = UINT_MAX; - currentSource = source; - } - - - // Save Normie state: - auto isNorm = ofGetUsingNormalizedTexCoords(); - - // If we get to this part of the function, the mask fbo - // should already be allocated and the mask texture created. - - ofEnableNormalizedTexCoords(); - // Get the texture from the source an store a copy - // of the source texture's id: - auto sourceTex = ofTexture(*(source->getTexture())); - auto sourceTexId = sourceTex.getTextureData().textureID; - - // Draw the mask only if the sources are FBO's, videos, - // or if the last texture id was UINT_MAX (which means that - // the mask has not yet been draw). -// if (source->getType() == SOURCE_TYPE_FBO || -// source->getType() == SOURCE_TYPE_VIDEO || -// lastSourceTextureId == UINT_MAX) { - - lastSourceTextureId = sourceTexId; - drawMaskForSource(sourceTex); - - // Swap the texture id of the source with the one of our - // newly drawn outputFbo: - source->getTexture()->getTextureData().textureID = outputFbo.getTexture().getTextureData().textureID; - auto texCoords = getMesh().getTexCoords(); - getMesh().clearTexCoords(); - getMesh().addTexCoords(Vec2::toOf(defaultTexCoords)); - // Draw the Quad: - QuadSurface::draw(); - - // Reset the texture id of the source - source->getTexture()->getTextureData().textureID = lastSourceTextureId; - - // Reset the texture coords of the QuadSurface mesh: - getMesh().clearTexCoords(); - getMesh().addTexCoords(texCoords); - - if (!isNorm) ofDisableNormalizedTexCoords(); -} - -void CircleSurface::setFeathering(float f) { - feathering = f; - updateMask = true; -} - - -void CircleSurface::drawMaskForSource(ofTexture &sourceTex) { - auto quadTexCoords = getMesh().getTexCoords(); - - maskMesh.clearTexCoords(); - - // Set the mesh's texture coords to the quads. - // This gets us the coordinates set in the TextureEditor - maskMesh.addTexCoords(quadTexCoords); - outputFbo.begin(true); - { - ofClear(0, 0, 0, 0); - ofEnableNormalizedTexCoords(); - ofSetColor(255); - ofFill(); - ofSetRectMode(OF_RECTMODE_CORNER); -//#ifdef TARGET_RASPBERRY_PI - sourceTex.bind(); - maskMesh.draw(); - sourceTex.unbind(); - // Masking without shaders... - ofPushStyle(); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); - ofSetColor(255); - ofFill(); - ofDisableNormalizedTexCoords(); - maskFbo.draw(0, 0); - ofPopStyle(); -//#else -// maskShader.begin(); -// maskShader.setUniformTexture("maskTex", maskFbo.getTexture(), 1); -// ofSetColor(255); -// ofFill(); -// ofSetRectMode(OF_RECTMODE_CORNER); -// scaledSourceFbo.getTexture().bind(); -// maskMesh.draw(); -// scaledSourceFbo.getTexture().unbind(); -// maskShader.end(); -//#endif - - } - outputFbo.end(); - -} - -void CircleSurface::setupTextures() { - float w = source->getTexture()->getWidth(); - float h = source->getTexture()->getHeight(); - float dia = 0; - if (w > h) { - dia = h; - } else { - dia = w; - } - - float padding = 10; - - maskFbo.allocate(w, h); - maskFbo.begin(false); - ofPushStyle(); - ofSetupScreenOrtho(w, h, -1, 1); - ofClear(0, 0, 0, 0); - ofFill(); - ofSetColor(255); - ofSetCircleResolution(300); - ofDrawEllipse(w/2, h/2, w-padding, h-padding); - ofPopStyle(); - maskFbo.end(); - - outputFbo.allocate(w, h); - outputFbo.begin(); - ofClear(0, 0, 0, 0); - outputFbo.end(); - -// scaledSourceFbo.allocate(w, h); -// scaledSourceFbo.begin(); -// ofClear(0, 0, 0, 255); -// scaledSourceFbo.end(); - - // This is lifted from QuadSurface::setup to ensure that the two - // meshes are similar: - - // Create 4 points for the 2 triangles - Vec3 p1 = Vec3(0.0f, 0.0f, 0.0f); - Vec3 p2 = Vec3(0.0f, h, 0.0f); - Vec3 p3 = Vec3(w, h, 0.0f); - Vec3 p4 = Vec3(w, 0.0f, 0.0f); - - // Create 4 point for the texture coordinates - Vec2 t1 = Vec2(Vec2(0.0f, 1.0f)); - Vec2 t2 = Vec2(Vec2(1.0f, 1.0f)); - Vec2 t3 = Vec2(Vec2(1.0f, 0.0f)); - Vec2 t4 = Vec2(Vec2(0.0f, 0.0f)); - - // Clear maskMesh - maskMesh.clear(); - - // Create a surface with the points - maskMesh.addVertex(p1.toOf()); - maskMesh.addVertex(p2.toOf()); - maskMesh.addVertex(p3.toOf()); - maskMesh.addVertex(p4.toOf()); - - // Add 2 triangles - maskMesh.addTriangle(0, 2, 3); - maskMesh.addTriangle(0, 1, 2); - - // Add texture coordinates - maskMesh.addTexCoord(t1.toOf()); - maskMesh.addTexCoord(t2.toOf()); - maskMesh.addTexCoord(t3.toOf()); - maskMesh.addTexCoord(t4.toOf()); -} - - - -int CircleSurface::getType() { - return SurfaceType::CIRCLE_SURFACE; -} - -} -} +// +// CircleSurface.cpp +// Copyright (c) 2017 Cristobal Mendoza +// With modifications by Krisjanis Rijnieks (c) 2017 +// http://cuppetellimendoza.com + +#include "CircleSurface.h" + +namespace ofx { +namespace piMapper { + +CircleSurface::CircleSurface() : QuadSurface() { + setup(); +} + +CircleSurface::CircleSurface(QuadSurface &surface) { + setup(); + setVertices(surface.getVertices()); + setTexCoords(surface.getTexCoords()); + setPerspectiveWarping(surface.getPerspectiveWarping()); +} + +void CircleSurface::setup() { + + QuadSurface::setup(); + setPerspectiveWarping(true); + + lastSourceTextureId = UINT_MAX; + updateMask = true; +// maskIsReady = false; + +// glESVertexShader = CIRCLE_SURFACE_STRINGIFY( +// attribute vec4 position; +// attribute vec4 color; +// attribute vec4 normal; +// attribute vec2 texcoord; +// +// uniform mat4 modelViewMatrix; +// uniform mat4 projectionMatrix; +// uniform sampler2D maskTex; +// +// varying vec4 colorVarying; +// varying vec2 texCoordVarying; +// +// void main() { +// +// //get our current vertex position so we can modify it +// vec4 pos = projectionMatrix*modelViewMatrix*position; +// +// gl_Position = pos; +// colorVarying = color; +// texCoordVarying = texcoord; +// } +// ); +// +// glESFragmentShader = CIRCLE_SURFACE_STRINGIFY( +////#ifdef GL_ES +//// define default precision for float, vec, mat. +// precision highp float; +////#endif +// +// uniform sampler2D tex0; +// uniform sampler2D maskTex; +// uniform vec4 globalColor; +// +// varying vec2 texCoordVarying; +// +// void main (void) +// { +// vec2 pos = texCoordVarying; +// vec3 src = texture2D(tex0, pos).rgb; +// float mask = texture2D(maskTex, pos).r; +// gl_FragColor = vec4( src , mask); +// } +// ); +// +// gl2FragmentShader = "#version 120\n #extension GL_ARB_texture_rectangle : enable\n"; +// gl2FragmentShader += CIRCLE_SURFACE_STRINGIFY( +// uniform sampler2DRect tex0; +// uniform sampler2DRect maskTex; +// +// void main (void) { +// vec2 pos = gl_TexCoord[0].st; +// +// vec3 src = texture2DRect(tex0, pos).rgb; +// float mask = texture2DRect(maskTex, pos).r; +// +// gl_FragColor = vec4(src, mask); +// } +// ); +// +//#ifdef TARGET_OPENGLES +// maskShader.setupShaderFromSource(GL_VERTEX_SHADER, glESVertexShader); +// maskShader.setupShaderFromSource(GL_FRAGMENT_SHADER, glESFragmentShader); +// maskShader.bindDefaults(); +// maskShader.linkProgram(); +//#else +// if (ofIsGLProgrammableRenderer()) { +// +// } else { +// maskShader.setupShaderFromSource(GL_FRAGMENT_SHADER, gl2FragmentShader); +// maskShader.linkProgram(); +// } +//#endif + + Vec2 t1 = Vec2(0.0f, 0.0f); + Vec2 t2 = Vec2(1.0f, 0.0f); + Vec2 t3 = Vec2(1.0f, 1.0f); + Vec2 t4 = Vec2(0.0f, 1.0f); + + defaultTexCoords.push_back(t1); + defaultTexCoords.push_back(t2); + defaultTexCoords.push_back(t3); + defaultTexCoords.push_back(t4); +} + +void CircleSurface::draw() { + + ofEnableAlphaBlending(); + if (source->getTexture() == 0) + { + return; + } + if (!source->getTexture()->isAllocated()){ + return; + } + + if (source != currentSource) { // Pointer comparison + // Create the mask here + setupTextures(); + lastSourceTextureId = UINT_MAX; + currentSource = source; + } + + + // Save Normie state: + auto isNorm = ofGetUsingNormalizedTexCoords(); + + // If we get to this part of the function, the mask fbo + // should already be allocated and the mask texture created. + + ofEnableNormalizedTexCoords(); + // Get the texture from the source an store a copy + // of the source texture's id: + auto sourceTex = ofTexture(*(source->getTexture())); + auto sourceTexId = sourceTex.getTextureData().textureID; + + // Draw the mask only if the sources are FBO's, videos, + // or if the last texture id was UINT_MAX (which means that + // the mask has not yet been draw). +// if (source->getType() == SOURCE_TYPE_FBO || +// source->getType() == SOURCE_TYPE_VIDEO || +// lastSourceTextureId == UINT_MAX) { + + lastSourceTextureId = sourceTexId; + drawMaskForSource(sourceTex); + + // Swap the texture id of the source with the one of our + // newly drawn outputFbo: + source->getTexture()->getTextureData().textureID = outputFbo.getTexture().getTextureData().textureID; + auto texCoords = getMesh().getTexCoords(); + getMesh().clearTexCoords(); + getMesh().addTexCoords(Vec2::toOf(defaultTexCoords)); + // Draw the Quad: + QuadSurface::draw(); + + // Reset the texture id of the source + source->getTexture()->getTextureData().textureID = lastSourceTextureId; + + // Reset the texture coords of the QuadSurface mesh: + getMesh().clearTexCoords(); + getMesh().addTexCoords(texCoords); + + if (!isNorm) ofDisableNormalizedTexCoords(); +} + +void CircleSurface::setFeathering(float f) { + feathering = f; + updateMask = true; +} + + +void CircleSurface::drawMaskForSource(ofTexture &sourceTex) { + auto quadTexCoords = getMesh().getTexCoords(); + + maskMesh.clearTexCoords(); + + // Set the mesh's texture coords to the quads. + // This gets us the coordinates set in the TextureEditor + maskMesh.addTexCoords(quadTexCoords); + outputFbo.begin(true); + { + ofClear(0, 0, 0, 0); + ofEnableNormalizedTexCoords(); + ofSetColor(255); + ofFill(); + ofSetRectMode(OF_RECTMODE_CORNER); +//#ifdef TARGET_RASPBERRY_PI + sourceTex.bind(); + maskMesh.draw(); + sourceTex.unbind(); + // Masking without shaders... + ofPushStyle(); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + ofSetColor(255); + ofFill(); + ofDisableNormalizedTexCoords(); + maskFbo.draw(0, 0); + ofPopStyle(); +//#else +// maskShader.begin(); +// maskShader.setUniformTexture("maskTex", maskFbo.getTexture(), 1); +// ofSetColor(255); +// ofFill(); +// ofSetRectMode(OF_RECTMODE_CORNER); +// scaledSourceFbo.getTexture().bind(); +// maskMesh.draw(); +// scaledSourceFbo.getTexture().unbind(); +// maskShader.end(); +//#endif + + } + outputFbo.end(); + +} + +void CircleSurface::setupTextures() { + float w = source->getTexture()->getWidth(); + float h = source->getTexture()->getHeight(); + float dia = 0; + if (w > h) { + dia = h; + } else { + dia = w; + } + + float padding = 10; + + maskFbo.allocate(w, h); + maskFbo.begin(false); + ofPushStyle(); + ofSetupScreenOrtho(w, h, -1, 1); + ofClear(0, 0, 0, 0); + ofFill(); + ofSetColor(255); + ofSetCircleResolution(300); + ofDrawEllipse(w/2, h/2, w-padding, h-padding); + ofPopStyle(); + maskFbo.end(); + + outputFbo.allocate(w, h); + outputFbo.begin(); + ofClear(0, 0, 0, 0); + outputFbo.end(); + +// scaledSourceFbo.allocate(w, h); +// scaledSourceFbo.begin(); +// ofClear(0, 0, 0, 255); +// scaledSourceFbo.end(); + + // This is lifted from QuadSurface::setup to ensure that the two + // meshes are similar: + + // Create 4 points for the 2 triangles + Vec3 p1 = Vec3(0.0f, 0.0f, 0.0f); + Vec3 p2 = Vec3(0.0f, h, 0.0f); + Vec3 p3 = Vec3(w, h, 0.0f); + Vec3 p4 = Vec3(w, 0.0f, 0.0f); + + // Create 4 point for the texture coordinates + Vec2 t1 = Vec2(Vec2(0.0f, 1.0f)); + Vec2 t2 = Vec2(Vec2(1.0f, 1.0f)); + Vec2 t3 = Vec2(Vec2(1.0f, 0.0f)); + Vec2 t4 = Vec2(Vec2(0.0f, 0.0f)); + + // Clear maskMesh + maskMesh.clear(); + + // Create a surface with the points + maskMesh.addVertex(p1.toOf()); + maskMesh.addVertex(p2.toOf()); + maskMesh.addVertex(p3.toOf()); + maskMesh.addVertex(p4.toOf()); + + // Add 2 triangles + maskMesh.addTriangle(0, 2, 3); + maskMesh.addTriangle(0, 1, 2); + + // Add texture coordinates + maskMesh.addTexCoord(t1.toOf()); + maskMesh.addTexCoord(t2.toOf()); + maskMesh.addTexCoord(t3.toOf()); + maskMesh.addTexCoord(t4.toOf()); +} + + + +int CircleSurface::getType() { + return SurfaceType::CIRCLE_SURFACE; +} + +} +} diff --git a/src/Surfaces/CircleSurface.h b/src/Surfaces/CircleSurface.h index 831f42f..8139bdd 100644 --- a/src/Surfaces/CircleSurface.h +++ b/src/Surfaces/CircleSurface.h @@ -1,66 +1,66 @@ -// -// CircleSurface.h -// Copyright (c) 2017 Cristobal Mendoza -// With modifications by Krisjanis Rijnieks (c) 2017 -// http://cuppetellimendoza.com - -#ifndef OFXPIMAPPER_CIRCLESURFACE_H -#define OFXPIMAPPER_CIRCLESURFACE_H - -#include "QuadSurface.h" -#include "Vec2.h" -#include "Vec3.h" - -#define CIRCLE_SURFACE_STRINGIFY(A) #A - -namespace ofx { -namespace piMapper { - -class CircleSurface : public QuadSurface { - public: - CircleSurface(); - CircleSurface(QuadSurface &surface); - int getType() override; - void draw() override; - void setup() override; - - // TODO: Feathering - void setFeathering(float f); - - protected: - void setupTextures(); - void drawMaskForSource(ofTexture &sourceTexture); - ofFbo maskFbo; -// ofFbo scaledSourceFbo; - ofFbo outputFbo; -// ofShader maskShader; - float feathering = 0.0f; - bool updateMask; - bool maskIsReady; - -// std::string glESFragmentShader; -// std::string glESVertexShader; -// -// std::string gl2FragmentShader; -// std::string gl2VertexShader; - - ofMesh maskMesh; - - // TODO: gl3 Shaders -// std::string gl3VertexShader; -// std::string gl3FragmentShader; - - private: - std::vector defaultTexCoords; - // We will use this pointer to determine if the source has changed. - // This is a total kludge, but it keeps me from messing with the - // upstream source. - BaseSource* currentSource = 0; - unsigned int lastSourceTextureId; -}; - -} -} - - -#endif //OFXPIMAPPER_CIRCLESURFACE_H +// +// CircleSurface.h +// Copyright (c) 2017 Cristobal Mendoza +// With modifications by Krisjanis Rijnieks (c) 2017 +// http://cuppetellimendoza.com + +#ifndef OFXPIMAPPER_CIRCLESURFACE_H +#define OFXPIMAPPER_CIRCLESURFACE_H + +#include "QuadSurface.h" +#include "Vec2.h" +#include "Vec3.h" + +#define CIRCLE_SURFACE_STRINGIFY(A) #A + +namespace ofx { +namespace piMapper { + +class CircleSurface : public QuadSurface { + public: + CircleSurface(); + CircleSurface(QuadSurface &surface); + int getType() override; + void draw() override; + void setup() override; + + // TODO: Feathering + void setFeathering(float f); + + protected: + void setupTextures(); + void drawMaskForSource(ofTexture &sourceTexture); + ofFbo maskFbo; +// ofFbo scaledSourceFbo; + ofFbo outputFbo; +// ofShader maskShader; + float feathering = 0.0f; + bool updateMask; + bool maskIsReady; + +// std::string glESFragmentShader; +// std::string glESVertexShader; +// +// std::string gl2FragmentShader; +// std::string gl2VertexShader; + + ofMesh maskMesh; + + // TODO: gl3 Shaders +// std::string gl3VertexShader; +// std::string gl3FragmentShader; + + private: + std::vector defaultTexCoords; + // We will use this pointer to determine if the source has changed. + // This is a total kludge, but it keeps me from messing with the + // upstream source. + BaseSource* currentSource = 0; + unsigned int lastSourceTextureId; +}; + +} +} + + +#endif //OFXPIMAPPER_CIRCLESURFACE_H diff --git a/src/Surfaces/GridWarpSurface.cpp b/src/Surfaces/GridWarpSurface.cpp index 11c9705..7a6c081 100644 --- a/src/Surfaces/GridWarpSurface.cpp +++ b/src/Surfaces/GridWarpSurface.cpp @@ -1,255 +1,255 @@ -#include "GridWarpSurface.h" - -namespace ofx { -namespace piMapper { - -GridWarpSurface::GridWarpSurface(){ - _gridCols = 2; - _gridRows = 2; - createGridMesh(); -} - -void GridWarpSurface::draw(){ - if(source->getTexture() == 0){ - return; - } - - if(!source->getTexture()->isAllocated()){ - return; - } - - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - source->getTexture()->bind(); - mesh.draw(); - source->getTexture()->unbind(); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } -} - -void GridWarpSurface::moveBy(Vec3 v){ - for(int i = 0; i < mesh.getVertices().size(); i++){ - mesh.getVertices()[i] += v.toOf(); - } - - setMoved(true); - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void GridWarpSurface::fullScreen(){ - -} - -int GridWarpSurface::getType(){ - return SurfaceType::GRID_WARP_SURFACE; -} - -int GridWarpSurface::getGridRows(){ - return _gridRows; -} - -int GridWarpSurface::getGridCols(){ - return _gridCols; -} - -int GridWarpSurface::setGridRows(int r){ - _gridRows = r; - createGridMesh(); - return r; -} - -int GridWarpSurface::setGridCols(int c){ - _gridCols = c; - createGridMesh(); - return c; -} - -bool GridWarpSurface::hitTest(Vec2 p){ - ofPolyline pl; - int vertsPerRow = _gridCols + 1; - - for(int iy = 0; iy < _gridRows; ++iy){ - for(int ix = 0; ix < _gridCols; ++ix){ - int a = (iy * vertsPerRow) + ix; - int b = (iy * vertsPerRow) + ix + 1; - int c = ((iy + 1) * vertsPerRow) + ix + 1; - int d = ((iy + 1) * vertsPerRow) + ix; - - pl.clear(); - pl.addVertex(mesh.getVertex(a)); - pl.addVertex(mesh.getVertex(b)); - pl.addVertex(mesh.getVertex(c)); - pl.addVertex(mesh.getVertex(d)); - pl.close(); - - if(pl.inside(p.x, p.y)){ - return true; - } - } - } - - return false; -} - -ofPolyline GridWarpSurface::getHitArea(){ - ofPolyline pl; - int vertsPerRow = _gridCols + 1; - - // Get the top border - for(int ix = 0; ix <= _gridCols; ++ix){ - pl.addVertex(mesh.getVertex(ix)); - } - - // Get right border from top down - for(int iy = 1; iy <= _gridRows; ++iy){ - int i = iy * vertsPerRow + vertsPerRow - 1; - pl.addVertex(mesh.getVertex(i)); - } - - // Get bottom border from right to left - for(int ix = _gridCols; ix >= 0; --ix){ - int i = _gridRows * vertsPerRow + vertsPerRow - 2; - pl.addVertex(mesh.getVertex(i)); - } - - // Get left border from bottom to top - for(int iy = _gridRows; iy > 0; --iy){ - int i = iy * vertsPerRow; - pl.addVertex(mesh.getVertex(i)); - } - - pl.close(); - return pl; -} - -ofPolyline GridWarpSurface::getTextureHitArea(){ - ofPolyline line; - Vec2 textureSize = Vec2(source->getTexture()->getWidth(), source->getTexture()->getHeight()); - - int vertsPerRow = _gridCols + 1; - int vertsPerCol = _gridRows + 1; - - int a = 0; - int b = _gridCols; - int c = (_gridRows * vertsPerRow) + (vertsPerRow - 1); - int d = (_gridRows * vertsPerRow); - - line.addVertex(ofPoint(mesh.getTexCoords()[a] * textureSize.toOf())); - line.addVertex(ofPoint(mesh.getTexCoords()[b] * textureSize.toOf())); - line.addVertex(ofPoint(mesh.getTexCoords()[c] * textureSize.toOf())); - line.addVertex(ofPoint(mesh.getTexCoords()[d] * textureSize.toOf())); - line.close(); - - return line; -} - -void GridWarpSurface::setVertex(int index, Vec3 vert){ - if(index >= mesh.getVertices().size()){ - throw runtime_error("Vertex with provided index does not exist"); - } - - mesh.setVertex(index, vert.toOf()); - ofNotifyEvent(vertexChangedEvent, index, this); -} - -void GridWarpSurface::setVertices(std::vector v){ - if(v.size() != mesh.getVertices().size()){ - throw runtime_error("Wrong number of vertices"); - } - - for(int i = 0; i < v.size(); ++i){ - mesh.setVertex(i, v[i].toOf()); - } - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void GridWarpSurface::setTexCoord(int index, Vec2 t){ - if(index >= mesh.getVertices().size()){ - throw runtime_error("Texture coordinate with provided index does not exist"); - } - mesh.setTexCoord(index, t.toOf()); -} - -void GridWarpSurface::setTexCoords(std::vector t){ - if(t.size() != mesh.getVertices().size()){ - throw runtime_error("Wrong number of texture coordinates"); - } - for(int i = 0; i < t.size(); ++i){ - mesh.setTexCoord(i, t[i].toOf()); - } -} - - -std::vector GridWarpSurface::getVertices(){ - return Vec3::fromOf(mesh.getVertices()); -} - -std::vector GridWarpSurface::getTexCoords(){ - return Vec2::fromOf(mesh.getTexCoords()); -} - -void GridWarpSurface::createGridMesh(){ - mesh.clear(); - - float margin = 100.0f; - float surfaceWidth = (float)ofGetWidth() - margin * 2.0f; - float surfaceHeight = (float)ofGetHeight() - margin * 2.0f; - float vertexDistanceX = surfaceWidth / (float)_gridCols; - float vertexDistanceY = surfaceHeight / (float)_gridRows; - - // Add vertices for each col and row - for(int iy = 0; iy <= _gridRows; ++iy){ - for(int ix = 0; ix <= _gridCols; ++ix){ - mesh.addVertex(Vec3( - margin + (vertexDistanceX * (float)ix), - margin + (vertexDistanceY * (float)iy), - 0.0f).toOf()); - } - } - - int vertsPerCol = _gridRows + 1; - int vertsPerRow = _gridCols + 1; - - // Form triangles for all grid cols and rows - for(int iy = 0; iy < _gridRows; ++iy){ - for(int ix = 0; ix < _gridCols; ++ix){ - int a = (iy * vertsPerRow) + ix; - int b = (iy * vertsPerRow) + ix + 1; - int c = ((iy + 1) * vertsPerRow) + ix + 1; - int d = ((iy + 1) * vertsPerRow) + ix; - mesh.addTriangle(a, b, c); - mesh.addTriangle(a, c, d); - } - } - - // Add texture coordinates for each of the vertices - for(int iy = 0; iy <= _gridRows; ++iy){ - for(int ix = 0; ix <= _gridCols; ++ix){ - float xc = (ix == 0) ? 0.0f : (float)ix / (float)_gridCols; - float yc = (iy == 0) ? 0.0f : (float)iy / (float)_gridRows; - mesh.addTexCoord(Vec2(xc, yc).toOf()); - } - } - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -BaseSurface * GridWarpSurface::clone(){ - GridWarpSurface * s = new GridWarpSurface(); - s->setVertices(getVertices()); - s->setTexCoords(getTexCoords()); - BaseSource * src = getSource(); - src->referenceCount++; - s->setSource(src); - return s; -} - -} // namespace piMapper -} // namespace ofx +#include "GridWarpSurface.h" + +namespace ofx { +namespace piMapper { + +GridWarpSurface::GridWarpSurface(){ + _gridCols = 2; + _gridRows = 2; + createGridMesh(); +} + +void GridWarpSurface::draw(){ + if(source->getTexture() == 0){ + return; + } + + if(!source->getTexture()->isAllocated()){ + return; + } + + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + source->getTexture()->bind(); + mesh.draw(); + source->getTexture()->unbind(); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } +} + +void GridWarpSurface::moveBy(Vec3 v){ + for(int i = 0; i < mesh.getVertices().size(); i++){ + mesh.getVertices()[i] += v.toOf(); + } + + setMoved(true); + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void GridWarpSurface::fullScreen(){ + +} + +int GridWarpSurface::getType(){ + return SurfaceType::GRID_WARP_SURFACE; +} + +int GridWarpSurface::getGridRows(){ + return _gridRows; +} + +int GridWarpSurface::getGridCols(){ + return _gridCols; +} + +int GridWarpSurface::setGridRows(int r){ + _gridRows = r; + createGridMesh(); + return r; +} + +int GridWarpSurface::setGridCols(int c){ + _gridCols = c; + createGridMesh(); + return c; +} + +bool GridWarpSurface::hitTest(Vec2 p){ + ofPolyline pl; + int vertsPerRow = _gridCols + 1; + + for(int iy = 0; iy < _gridRows; ++iy){ + for(int ix = 0; ix < _gridCols; ++ix){ + int a = (iy * vertsPerRow) + ix; + int b = (iy * vertsPerRow) + ix + 1; + int c = ((iy + 1) * vertsPerRow) + ix + 1; + int d = ((iy + 1) * vertsPerRow) + ix; + + pl.clear(); + pl.addVertex(mesh.getVertex(a)); + pl.addVertex(mesh.getVertex(b)); + pl.addVertex(mesh.getVertex(c)); + pl.addVertex(mesh.getVertex(d)); + pl.close(); + + if(pl.inside(p.x, p.y)){ + return true; + } + } + } + + return false; +} + +ofPolyline GridWarpSurface::getHitArea(){ + ofPolyline pl; + int vertsPerRow = _gridCols + 1; + + // Get the top border + for(int ix = 0; ix <= _gridCols; ++ix){ + pl.addVertex(mesh.getVertex(ix)); + } + + // Get right border from top down + for(int iy = 1; iy <= _gridRows; ++iy){ + int i = iy * vertsPerRow + vertsPerRow - 1; + pl.addVertex(mesh.getVertex(i)); + } + + // Get bottom border from right to left + for(int ix = _gridCols; ix >= 0; --ix){ + int i = _gridRows * vertsPerRow + vertsPerRow - 2; + pl.addVertex(mesh.getVertex(i)); + } + + // Get left border from bottom to top + for(int iy = _gridRows; iy > 0; --iy){ + int i = iy * vertsPerRow; + pl.addVertex(mesh.getVertex(i)); + } + + pl.close(); + return pl; +} + +ofPolyline GridWarpSurface::getTextureHitArea(){ + ofPolyline line; + Vec2 textureSize = Vec2(source->getTexture()->getWidth(), source->getTexture()->getHeight()); + + int vertsPerRow = _gridCols + 1; + int vertsPerCol = _gridRows + 1; + + int a = 0; + int b = _gridCols; + int c = (_gridRows * vertsPerRow) + (vertsPerRow - 1); + int d = (_gridRows * vertsPerRow); + + line.addVertex(ofPoint(mesh.getTexCoords()[a] * textureSize.toOf())); + line.addVertex(ofPoint(mesh.getTexCoords()[b] * textureSize.toOf())); + line.addVertex(ofPoint(mesh.getTexCoords()[c] * textureSize.toOf())); + line.addVertex(ofPoint(mesh.getTexCoords()[d] * textureSize.toOf())); + line.close(); + + return line; +} + +void GridWarpSurface::setVertex(int index, Vec3 vert){ + if(index >= mesh.getVertices().size()){ + throw runtime_error("Vertex with provided index does not exist"); + } + + mesh.setVertex(index, vert.toOf()); + ofNotifyEvent(vertexChangedEvent, index, this); +} + +void GridWarpSurface::setVertices(std::vector v){ + if(v.size() != mesh.getVertices().size()){ + throw runtime_error("Wrong number of vertices"); + } + + for(int i = 0; i < v.size(); ++i){ + mesh.setVertex(i, v[i].toOf()); + } + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void GridWarpSurface::setTexCoord(int index, Vec2 t){ + if(index >= mesh.getVertices().size()){ + throw runtime_error("Texture coordinate with provided index does not exist"); + } + mesh.setTexCoord(index, t.toOf()); +} + +void GridWarpSurface::setTexCoords(std::vector t){ + if(t.size() != mesh.getVertices().size()){ + throw runtime_error("Wrong number of texture coordinates"); + } + for(int i = 0; i < t.size(); ++i){ + mesh.setTexCoord(i, t[i].toOf()); + } +} + + +std::vector GridWarpSurface::getVertices(){ + return Vec3::fromOf(mesh.getVertices()); +} + +std::vector GridWarpSurface::getTexCoords(){ + return Vec2::fromOf(mesh.getTexCoords()); +} + +void GridWarpSurface::createGridMesh(){ + mesh.clear(); + + float margin = 100.0f; + float surfaceWidth = (float)ofGetWidth() - margin * 2.0f; + float surfaceHeight = (float)ofGetHeight() - margin * 2.0f; + float vertexDistanceX = surfaceWidth / (float)_gridCols; + float vertexDistanceY = surfaceHeight / (float)_gridRows; + + // Add vertices for each col and row + for(int iy = 0; iy <= _gridRows; ++iy){ + for(int ix = 0; ix <= _gridCols; ++ix){ + mesh.addVertex(Vec3( + margin + (vertexDistanceX * (float)ix), + margin + (vertexDistanceY * (float)iy), + 0.0f).toOf()); + } + } + + int vertsPerCol = _gridRows + 1; + int vertsPerRow = _gridCols + 1; + + // Form triangles for all grid cols and rows + for(int iy = 0; iy < _gridRows; ++iy){ + for(int ix = 0; ix < _gridCols; ++ix){ + int a = (iy * vertsPerRow) + ix; + int b = (iy * vertsPerRow) + ix + 1; + int c = ((iy + 1) * vertsPerRow) + ix + 1; + int d = ((iy + 1) * vertsPerRow) + ix; + mesh.addTriangle(a, b, c); + mesh.addTriangle(a, c, d); + } + } + + // Add texture coordinates for each of the vertices + for(int iy = 0; iy <= _gridRows; ++iy){ + for(int ix = 0; ix <= _gridCols; ++ix){ + float xc = (ix == 0) ? 0.0f : (float)ix / (float)_gridCols; + float yc = (iy == 0) ? 0.0f : (float)iy / (float)_gridRows; + mesh.addTexCoord(Vec2(xc, yc).toOf()); + } + } + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +BaseSurface * GridWarpSurface::clone(){ + GridWarpSurface * s = new GridWarpSurface(); + s->setVertices(getVertices()); + s->setTexCoords(getTexCoords()); + BaseSource * src = getSource(); + src->referenceCount++; + s->setSource(src); + return s; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/GridWarpSurface.h b/src/Surfaces/GridWarpSurface.h index 71fcd92..6d0e791 100644 --- a/src/Surfaces/GridWarpSurface.h +++ b/src/Surfaces/GridWarpSurface.h @@ -1,50 +1,50 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" -#include "SurfaceType.h" -#include "HomographyHelper.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class GridWarpSurface : public BaseSurface { - public: - GridWarpSurface(); - - void setup(){}; - void draw(); - void moveBy(Vec3 v); - void fullScreen(); - - int getType(); - int getGridRows(); - int getGridCols(); - int setGridRows(int r); - int setGridCols(int c); - - bool hitTest(Vec2 p); - - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - - void setVertex(int index, Vec3 p); - void setVertices(std::vector v); - void setTexCoord(int index, Vec2 t); - void setTexCoords(std::vector t); - std::vector getVertices(); - std::vector getTexCoords(); - - void createGridMesh(); - - BaseSurface * clone(); - - private: - int _gridCols; - int _gridRows; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" +#include "HomographyHelper.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class GridWarpSurface : public BaseSurface { + public: + GridWarpSurface(); + + void setup(){}; + void draw(); + void moveBy(Vec3 v); + void fullScreen(); + + int getType(); + int getGridRows(); + int getGridCols(); + int setGridRows(int r); + int setGridCols(int c); + + bool hitTest(Vec2 p); + + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + + void setVertex(int index, Vec3 p); + void setVertices(std::vector v); + void setTexCoord(int index, Vec2 t); + void setTexCoords(std::vector t); + std::vector getVertices(); + std::vector getTexCoords(); + + void createGridMesh(); + + BaseSurface * clone(); + + private: + int _gridCols; + int _gridRows; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/HexagonSurface.cpp b/src/Surfaces/HexagonSurface.cpp index 57bed9a..fb1edda 100644 --- a/src/Surfaces/HexagonSurface.cpp +++ b/src/Surfaces/HexagonSurface.cpp @@ -1,243 +1,243 @@ -#include "HexagonSurface.h" - -namespace ofx { -namespace piMapper { - -HexagonSurface::HexagonSurface(){ - setup(); -} - -void HexagonSurface::setup(){ - - // Create 6 + 1 points for the hexagon surface. - - std::vector verts; - verts.resize(7); - - // Start with the center. - verts[0] = Vec3((float)ofGetWidth() / 2.0f, (float)ofGetHeight() / 2.0f, 0.0f); - - // Then from top left clockwise. - verts[1] = Vec3((float)ofGetWidth() / 3.0f, 0.0f, 0.0f); - verts[2] = Vec3((float)ofGetWidth() / 3.0f * 2.0f, 0.0f, 0.0f); - verts[3] = Vec3(ofGetWidth(), (float)ofGetHeight() / 2.0f, 0.0f); - verts[4] = Vec3((float)ofGetWidth() / 3.0f * 2.0f, ofGetHeight(), 0.0f); - verts[5] = Vec3((float)ofGetWidth() / 3.0f, ofGetHeight(), 0.0f); - verts[6] = Vec3(0, (float)ofGetHeight() / 2.0f, 0.0f); - - // No create the texture coordinates. - std::vector coords; - coords.resize(7); - - // Start with center. - coords[0] = Vec2(0.5f, 0.5f); - - // Then from top left and go clockwise. - coords[1] = Vec2(1.0f / 3.0f, 0.0f); - coords[2] = Vec2(1.0f / 3.0f * 2.0f, 0.0f); - coords[3] = Vec2(1.0f, 0.5f); - coords[4] = Vec2(1.0f / 3.0f * 2.0f, 1.0f); - coords[5] = Vec2(1.0f / 3.0f, 1.0f); - coords[6] = Vec2(0.0f, 0.5f); - - // And finally setup - setup(verts, coords, source); -} - -void HexagonSurface::setup( - std::vector & verts, - std::vector & coords, - BaseSource * newSource){ - - // Assign texture - source = newSource; - - // Clear mesh - mesh.clear(); - - // Add vertices to the mesh - for(unsigned int i = 0; i < verts.size(); ++i){ - mesh.addVertex(verts[i].toOf()); - } - - // Form triangles - for(unsigned int i = 1; i < verts.size() - 1; ++i){ - unsigned int v1 = 0; // Center vertex always there - unsigned int v2 = i; - unsigned int v3 = i + 1; - mesh.addTriangle(v1, v2, v3); - - // Add the last triangle - if(i == verts.size() - 2){ - v1 = 0; - v2 = i + 1; - v3 = 1; - mesh.addTriangle(v1, v2, v3); - } - } - - // Add texture coords - for(unsigned int i = 0; i < coords.size(); ++i){ - mesh.addTexCoord(coords[i].toOf()); - } -} - -void HexagonSurface::draw(){ - if(source->getTexture() == 0){ - return; - } - - if(!source->getTexture()->isAllocated()){ - return; - } - - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - source->getTexture()->bind(); - mesh.draw(); - source->getTexture()->unbind(); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } -} - -void HexagonSurface::setVertex(int index, Vec3 p){ - if(index >= mesh.getVertices().size()){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - return; - } - - mesh.setVertex(index, p.toOf()); - ofNotifyEvent(vertexChangedEvent, index, this); -} - -void HexagonSurface::setVertices(std::vector v){ - if(v.size() != mesh.getVertices().size()){ - throw runtime_error("Wrong number of vertices"); - } - - for(int i = 0; i < v.size(); ++i){ - mesh.setVertex(i, v[i].toOf()); - } - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void HexagonSurface::setTexCoord(int index, Vec2 t){ - if(index >= mesh.getTexCoords().size()){ - ofLog() << "Texture coordinate with this index does not exist: " << index - << std::endl; - return; - } - - mesh.setTexCoord(index, t.toOf()); -} - -void HexagonSurface::setTexCoords(std::vector t){ - if(t.size() != mesh.getTexCoords().size()){ - throw runtime_error("Wrong number of texture coordinates"); - } - - for(int i = 0; i < t.size(); ++i){ - mesh.setTexCoord(i, t[i].toOf()); - } -} - -void HexagonSurface::moveBy(Vec3 v){ - for(int i = 0; i < mesh.getVertices().size(); i++){ - mesh.getVertices()[i] += v.toOf(); - } - - setMoved(true); - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void HexagonSurface::fullScreen(){ - -} - -int HexagonSurface::getType(){ - return SurfaceType::HEXAGON_SURFACE; -} - -bool HexagonSurface::hitTest(Vec2 p){ - ofPolyline line = getHitArea(); - - if(line.inside(p.x, p.y)){ - return true; - }else{ - return false; - } -} - -Vec3 HexagonSurface::getVertex(int index){ - if(index > 2){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - throw runtime_error("Vertex index out of bounds."); - } - - return Vec3( - mesh.getVertex(index).x, - mesh.getVertex(index).y, - mesh.getVertex(index).z); -} - -Vec2 HexagonSurface::getTexCoord(int index){ - if(index > 1){ - throw runtime_error("Texture coordinate index out of bounds."); - } - - return Vec2( - mesh.getTexCoord(index).x, - mesh.getTexCoord(index).y); -} - -ofPolyline HexagonSurface::getHitArea(){ - ofPolyline line; - - for(unsigned int i = 1; i < mesh.getVertices().size(); ++i){ - line.addVertex(ofPoint(mesh.getVertex(i).x, mesh.getVertex(i).y)); - } - - line.close(); - return line; -} - -ofPolyline HexagonSurface::getTextureHitArea(){ - ofPolyline line; - Vec2 textureSize = Vec2( - source->getTexture()->getWidth(), - source->getTexture()->getHeight()); - - for(int i = 1; i < mesh.getTexCoords().size(); i++){ - line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); - } - - line.close(); - return line; -} - -std::vector HexagonSurface::getVertices(){ - return Vec3::fromOf(mesh.getVertices()); -} - -std::vector HexagonSurface::getTexCoords(){ - return Vec2::fromOf(mesh.getTexCoords()); -} - -BaseSurface * HexagonSurface::clone(){ - HexagonSurface * s = new HexagonSurface(); - s->setVertices(getVertices()); - s->setTexCoords(getTexCoords()); - BaseSource * src = getSource(); - src->referenceCount++; - s->setSource(src); - return s; -} - -} // namespace piMapper -} // namespace ofx +#include "HexagonSurface.h" + +namespace ofx { +namespace piMapper { + +HexagonSurface::HexagonSurface(){ + setup(); +} + +void HexagonSurface::setup(){ + + // Create 6 + 1 points for the hexagon surface. + + std::vector verts; + verts.resize(7); + + // Start with the center. + verts[0] = Vec3((float)ofGetWidth() / 2.0f, (float)ofGetHeight() / 2.0f, 0.0f); + + // Then from top left clockwise. + verts[1] = Vec3((float)ofGetWidth() / 3.0f, 0.0f, 0.0f); + verts[2] = Vec3((float)ofGetWidth() / 3.0f * 2.0f, 0.0f, 0.0f); + verts[3] = Vec3(ofGetWidth(), (float)ofGetHeight() / 2.0f, 0.0f); + verts[4] = Vec3((float)ofGetWidth() / 3.0f * 2.0f, ofGetHeight(), 0.0f); + verts[5] = Vec3((float)ofGetWidth() / 3.0f, ofGetHeight(), 0.0f); + verts[6] = Vec3(0, (float)ofGetHeight() / 2.0f, 0.0f); + + // No create the texture coordinates. + std::vector coords; + coords.resize(7); + + // Start with center. + coords[0] = Vec2(0.5f, 0.5f); + + // Then from top left and go clockwise. + coords[1] = Vec2(1.0f / 3.0f, 0.0f); + coords[2] = Vec2(1.0f / 3.0f * 2.0f, 0.0f); + coords[3] = Vec2(1.0f, 0.5f); + coords[4] = Vec2(1.0f / 3.0f * 2.0f, 1.0f); + coords[5] = Vec2(1.0f / 3.0f, 1.0f); + coords[6] = Vec2(0.0f, 0.5f); + + // And finally setup + setup(verts, coords, source); +} + +void HexagonSurface::setup( + std::vector & verts, + std::vector & coords, + BaseSource * newSource){ + + // Assign texture + source = newSource; + + // Clear mesh + mesh.clear(); + + // Add vertices to the mesh + for(unsigned int i = 0; i < verts.size(); ++i){ + mesh.addVertex(verts[i].toOf()); + } + + // Form triangles + for(unsigned int i = 1; i < verts.size() - 1; ++i){ + unsigned int v1 = 0; // Center vertex always there + unsigned int v2 = i; + unsigned int v3 = i + 1; + mesh.addTriangle(v1, v2, v3); + + // Add the last triangle + if(i == verts.size() - 2){ + v1 = 0; + v2 = i + 1; + v3 = 1; + mesh.addTriangle(v1, v2, v3); + } + } + + // Add texture coords + for(unsigned int i = 0; i < coords.size(); ++i){ + mesh.addTexCoord(coords[i].toOf()); + } +} + +void HexagonSurface::draw(){ + if(source->getTexture() == 0){ + return; + } + + if(!source->getTexture()->isAllocated()){ + return; + } + + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + source->getTexture()->bind(); + mesh.draw(); + source->getTexture()->unbind(); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } +} + +void HexagonSurface::setVertex(int index, Vec3 p){ + if(index >= mesh.getVertices().size()){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + return; + } + + mesh.setVertex(index, p.toOf()); + ofNotifyEvent(vertexChangedEvent, index, this); +} + +void HexagonSurface::setVertices(std::vector v){ + if(v.size() != mesh.getVertices().size()){ + throw runtime_error("Wrong number of vertices"); + } + + for(int i = 0; i < v.size(); ++i){ + mesh.setVertex(i, v[i].toOf()); + } + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void HexagonSurface::setTexCoord(int index, Vec2 t){ + if(index >= mesh.getTexCoords().size()){ + ofLog() << "Texture coordinate with this index does not exist: " << index + << std::endl; + return; + } + + mesh.setTexCoord(index, t.toOf()); +} + +void HexagonSurface::setTexCoords(std::vector t){ + if(t.size() != mesh.getTexCoords().size()){ + throw runtime_error("Wrong number of texture coordinates"); + } + + for(int i = 0; i < t.size(); ++i){ + mesh.setTexCoord(i, t[i].toOf()); + } +} + +void HexagonSurface::moveBy(Vec3 v){ + for(int i = 0; i < mesh.getVertices().size(); i++){ + mesh.getVertices()[i] += v.toOf(); + } + + setMoved(true); + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void HexagonSurface::fullScreen(){ + +} + +int HexagonSurface::getType(){ + return SurfaceType::HEXAGON_SURFACE; +} + +bool HexagonSurface::hitTest(Vec2 p){ + ofPolyline line = getHitArea(); + + if(line.inside(p.x, p.y)){ + return true; + }else{ + return false; + } +} + +Vec3 HexagonSurface::getVertex(int index){ + if(index > 2){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + throw runtime_error("Vertex index out of bounds."); + } + + return Vec3( + mesh.getVertex(index).x, + mesh.getVertex(index).y, + mesh.getVertex(index).z); +} + +Vec2 HexagonSurface::getTexCoord(int index){ + if(index > 1){ + throw runtime_error("Texture coordinate index out of bounds."); + } + + return Vec2( + mesh.getTexCoord(index).x, + mesh.getTexCoord(index).y); +} + +ofPolyline HexagonSurface::getHitArea(){ + ofPolyline line; + + for(unsigned int i = 1; i < mesh.getVertices().size(); ++i){ + line.addVertex(ofPoint(mesh.getVertex(i).x, mesh.getVertex(i).y)); + } + + line.close(); + return line; +} + +ofPolyline HexagonSurface::getTextureHitArea(){ + ofPolyline line; + Vec2 textureSize = Vec2( + source->getTexture()->getWidth(), + source->getTexture()->getHeight()); + + for(int i = 1; i < mesh.getTexCoords().size(); i++){ + line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); + } + + line.close(); + return line; +} + +std::vector HexagonSurface::getVertices(){ + return Vec3::fromOf(mesh.getVertices()); +} + +std::vector HexagonSurface::getTexCoords(){ + return Vec2::fromOf(mesh.getTexCoords()); +} + +BaseSurface * HexagonSurface::clone(){ + HexagonSurface * s = new HexagonSurface(); + s->setVertices(getVertices()); + s->setTexCoords(getTexCoords()); + BaseSource * src = getSource(); + src->referenceCount++; + s->setSource(src); + return s; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/HexagonSurface.h b/src/Surfaces/HexagonSurface.h index 056ba68..eb87c4e 100644 --- a/src/Surfaces/HexagonSurface.h +++ b/src/Surfaces/HexagonSurface.h @@ -1,44 +1,44 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" -#include "SurfaceType.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -// TODO: Transform this into CircleSurface. - -class HexagonSurface : public BaseSurface { - public: - HexagonSurface(); - - void setup(); - void setup( - std::vector & verts, - std::vector & coords, - BaseSource * newSource); - void draw(); - void setVertex(int index, Vec3 p); - void setVertices(std::vector v); - void setTexCoord(int index, Vec2 t); - void setTexCoords(std::vector t); - void moveBy(Vec3 v); - void fullScreen(); - - int getType(); - bool hitTest(Vec2 p); - Vec3 getVertex(int index); - Vec2 getTexCoord(int index); - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - std::vector getVertices(); - std::vector getTexCoords(); - - BaseSurface * clone(); -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +// TODO: Transform this into CircleSurface. + +class HexagonSurface : public BaseSurface { + public: + HexagonSurface(); + + void setup(); + void setup( + std::vector & verts, + std::vector & coords, + BaseSource * newSource); + void draw(); + void setVertex(int index, Vec3 p); + void setVertices(std::vector v); + void setTexCoord(int index, Vec2 t); + void setTexCoords(std::vector t); + void moveBy(Vec3 v); + void fullScreen(); + + int getType(); + bool hitTest(Vec2 p); + Vec3 getVertex(int index); + Vec2 getTexCoord(int index); + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + std::vector getVertices(); + std::vector getTexCoords(); + + BaseSurface * clone(); +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/QuadSurface.cpp b/src/Surfaces/QuadSurface.cpp index 873dec0..127b506 100644 --- a/src/Surfaces/QuadSurface.cpp +++ b/src/Surfaces/QuadSurface.cpp @@ -1,340 +1,340 @@ -#include "QuadSurface.h" - -namespace ofx { -namespace piMapper { - -QuadSurface::QuadSurface(){ - _perspectiveWarping = false; - setup(); -} - -QuadSurface::~QuadSurface(){ - std::cout << "QuadSurface destructor." << std::endl; -} - -void QuadSurface::setup(){ - // Create 4 points for the 2 triangles - Vec3 p1 = Vec3(0.0f, 0.0f, 0.0f); - Vec3 p2 = Vec3(0.0f, ofGetHeight(), 0.0f); - Vec3 p3 = Vec3(ofGetWidth(), ofGetHeight(), 0.0f); - Vec3 p4 = Vec3(ofGetWidth(), 0.0f, 0.0f); - - // Create 4 point for the texture coordinates - Vec2 t1 = Vec2(0.0f, 0.0f); - Vec2 t2 = Vec2(1.0f, 0.0f); - Vec2 t3 = Vec2(1.0f, 1.0f); - Vec2 t4 = Vec2(0.0f, 1.0f); - - setup(p1, p2, p3, p4, t1, t2, t3, t4, source); -} - -void QuadSurface::setup(Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, - Vec2 t1, Vec2 t2, Vec2 t3, Vec2 t4, - BaseSource * newSource){ - // Assign texture - source = newSource; - - // Clear mesh - mesh.clear(); - - // Create a surface with the points - mesh.addVertex(p1.toOf()); - mesh.addVertex(p2.toOf()); - mesh.addVertex(p3.toOf()); - mesh.addVertex(p4.toOf()); - - // Add 2 triangles - mesh.addTriangle(0, 2, 3); - mesh.addTriangle(0, 1, 2); - - // Add texture coordinates - mesh.addTexCoord(t1.toOf()); - mesh.addTexCoord(t2.toOf()); - mesh.addTexCoord(t3.toOf()); - mesh.addTexCoord(t4.toOf()); - - _meshCache = mesh; - calculateHomography(); -} - -void QuadSurface::draw(){ - if(source->getTexture() == 0){ - return; - } - - if(!source->getTexture()->isAllocated()){ - return; - } - - if(_perspectiveWarping){ - bool meshChanged = false; - - if( - mesh.getVertices()[0] != _meshCache.getVertices()[0] || - mesh.getVertices()[1] != _meshCache.getVertices()[1] || - mesh.getVertices()[2] != _meshCache.getVertices()[2] || - mesh.getVertices()[3] != _meshCache.getVertices()[3]) - { - meshChanged = true; - } - - if(meshChanged){ - calculateHomography(); - _meshCache = mesh; - } - - ofRectangle box = getMeshBoundingBox(); - ofMesh m = mesh; - - m.setVertex(0, Vec3(0, 0, 0).toOf()); - m.setVertex(1, Vec3(box.width, 0, 0).toOf()); - m.setVertex(2, Vec3(box.width, box.height, 0).toOf()); - m.setVertex(3, Vec3(0, box.height, 0).toOf()); - - ofPushMatrix(); - if(true){ - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - glMultMatrixf(_matrix); - source->getTexture()->bind(); - m.draw(); - source->getTexture()->unbind(); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } - } - ofPopMatrix(); - }else{ - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - ofPushStyle(); - ofSetColor(255, 255, 255); - - source->getTexture()->bind(); - mesh.draw(); - source->getTexture()->unbind(); - - ofPopStyle(); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } - } -} - -void QuadSurface::setVertex(int index, Vec3 p){ - if(index > 3){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - return; - } - - mesh.setVertex(index, p.toOf()); - ofNotifyEvent(vertexChangedEvent, index, this); -} - -void QuadSurface::setVertices(std::vector v){ - if(v.size() != 4){ - throw runtime_error("Wrong number of vertices"); - } - - for(int i = 0; i < 4; ++i){ - mesh.setVertex(i, v[i].toOf()); - } - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void QuadSurface::setTexCoord(int index, Vec2 t){ - if(index > 3){ - ofLog() << "Texture coordinate with this index does not exist: " << index - << std::endl; - return; - } - - mesh.setTexCoord(index, t.toOf()); -} - -void QuadSurface::setTexCoords(std::vector t){ - if(t.size() != 4){ - throw runtime_error("Wrong number of vertices"); - } - for(int i = 0; i < 4; ++i){ - mesh.setTexCoord(i, t[i].toOf()); - } -} - -void QuadSurface::moveBy(Vec3 v){ - for(int i = 0; i < mesh.getVertices().size(); i++){ - mesh.getVertices()[i] += v.toOf(); - } - - setMoved(true); - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void QuadSurface::fullScreen(){ - mesh.getVertices()[0] = Vec3(0, 0, 0.0f).toOf(); - mesh.getVertices()[1] = Vec3((float)ofGetWidth(), 0, 0.0f).toOf(); - mesh.getVertices()[2] = Vec3((float)ofGetWidth(), (float)ofGetHeight(), 0.0f).toOf(); - mesh.getVertices()[3] = Vec3(0, (float)ofGetHeight(), 0.0f).toOf(); - - setMoved(true); - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -int QuadSurface::getType(){ - return SurfaceType::QUAD_SURFACE; -} - -bool QuadSurface::hitTest(Vec2 p){ - ofPolyline line = getHitArea(); - - if(line.inside(p.x, p.y)){ - return true; - }else{ - return false; - } -} - -Vec3 QuadSurface::getVertex(int index){ - if(index > 3){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - throw runtime_error("Vertex index out of bounds."); - } - - return Vec3( - mesh.getVertex(index).x, - mesh.getVertex(index).y, - mesh.getVertex(index).z); -} - -Vec2 QuadSurface::getTexCoord(int index){ - if(index > 3){ - throw runtime_error("Texture coordinate index out of bounds."); - } - - return Vec2( - mesh.getTexCoord(index).x, - mesh.getTexCoord(index).y); -} - -ofPolyline QuadSurface::getHitArea(){ - ofPolyline line; - - line.addVertex(ofPoint(mesh.getVertex(0).x, mesh.getVertex(0).y)); - line.addVertex(ofPoint(mesh.getVertex(1).x, mesh.getVertex(1).y)); - line.addVertex(ofPoint(mesh.getVertex(2).x, mesh.getVertex(2).y)); - line.addVertex(ofPoint(mesh.getVertex(3).x, mesh.getVertex(3).y)); - line.close(); - - return line; -} - -ofPolyline QuadSurface::getTextureHitArea(){ - ofPolyline line; - Vec2 textureSize = - Vec2(source->getTexture()->getWidth(), - source->getTexture()->getHeight()); - for(int i = 0; i < mesh.getTexCoords().size(); i++){ - line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); - } - line.close(); - - return line; -} - -std::vector QuadSurface::getVertices(){ - return Vec3::fromOf(mesh.getVertices()); -} - -std::vector QuadSurface::getTexCoords(){ - return Vec2::fromOf(mesh.getTexCoords()); -} - -void QuadSurface::calculateHomography(){ - float src[4][2]; - float dst[4][2]; - - ofRectangle box = getMeshBoundingBox(); - - src[0][0] = 0; - src[0][1] = 0; - src[1][0] = box.width; - src[1][1] = 0; - src[2][0] = box.width; - src[2][1] = box.height; - src[3][0] = 0; - src[3][1] = box.height; - - Vec3 p0(mesh.getVertex(0).x, mesh.getVertex(0).y, mesh.getVertex(0).z); - Vec3 p1(mesh.getVertex(1).x, mesh.getVertex(1).y, mesh.getVertex(1).z); - Vec3 p2(mesh.getVertex(2).x, mesh.getVertex(2).y, mesh.getVertex(2).z); - Vec3 p3(mesh.getVertex(3).x, mesh.getVertex(3).y, mesh.getVertex(3).z); - - dst[0][0] = p0.x; - dst[0][1] = p0.y; - dst[1][0] = p1.x; - dst[1][1] = p1.y; - dst[2][0] = p2.x; - dst[2][1] = p2.y; - dst[3][0] = p3.x; - dst[3][1] = p3.y; - - HomographyHelper::findHomography(src, dst, _matrix); -} - -void QuadSurface::setPerspectiveWarping(bool b){ - _perspectiveWarping = b; -} - -bool QuadSurface::getPerspectiveWarping(){ - return _perspectiveWarping; -} - -ofRectangle QuadSurface::getMeshBoundingBox(){ - float minX = 10000.0f; - float minY = 10000.0f; - float maxX = 0.0f; - float maxY = 0.0f; - - for(int i = 0; i < mesh.getVertices().size(); ++i){ - if(mesh.getVertices()[i].x < minX){ - minX = mesh.getVertices()[i].x; - } - - if(mesh.getVertices()[i].y < minY){ - minY = mesh.getVertices()[i].y; - } - - if(mesh.getVertices()[i].x > maxX){ - maxX = mesh.getVertices()[i].x; - } - - if(mesh.getVertices()[i].y > maxY){ - maxY = mesh.getVertices()[i].y; - } - } - - ofRectangle boundingBox = ofRectangle(ofPoint(minX, minY), ofPoint(maxX, maxY)); - return boundingBox; -} - -BaseSurface * QuadSurface::clone(){ - QuadSurface * s = new QuadSurface(); - s->setVertices(getVertices()); - s->setTexCoords(getTexCoords()); - s->setPerspectiveWarping(getPerspectiveWarping()); - BaseSource * src = getSource(); - src->referenceCount++; - s->setSource(src); - return s; -} - -} // namespace piMapper -} // namespace ofx +#include "QuadSurface.h" + +namespace ofx { +namespace piMapper { + +QuadSurface::QuadSurface(){ + _perspectiveWarping = false; + setup(); +} + +QuadSurface::~QuadSurface(){ + std::cout << "QuadSurface destructor." << std::endl; +} + +void QuadSurface::setup(){ + // Create 4 points for the 2 triangles + Vec3 p1 = Vec3(0.0f, 0.0f, 0.0f); + Vec3 p2 = Vec3(0.0f, ofGetHeight(), 0.0f); + Vec3 p3 = Vec3(ofGetWidth(), ofGetHeight(), 0.0f); + Vec3 p4 = Vec3(ofGetWidth(), 0.0f, 0.0f); + + // Create 4 point for the texture coordinates + Vec2 t1 = Vec2(0.0f, 0.0f); + Vec2 t2 = Vec2(1.0f, 0.0f); + Vec2 t3 = Vec2(1.0f, 1.0f); + Vec2 t4 = Vec2(0.0f, 1.0f); + + setup(p1, p2, p3, p4, t1, t2, t3, t4, source); +} + +void QuadSurface::setup(Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, + Vec2 t1, Vec2 t2, Vec2 t3, Vec2 t4, + BaseSource * newSource){ + // Assign texture + source = newSource; + + // Clear mesh + mesh.clear(); + + // Create a surface with the points + mesh.addVertex(p1.toOf()); + mesh.addVertex(p2.toOf()); + mesh.addVertex(p3.toOf()); + mesh.addVertex(p4.toOf()); + + // Add 2 triangles + mesh.addTriangle(0, 2, 3); + mesh.addTriangle(0, 1, 2); + + // Add texture coordinates + mesh.addTexCoord(t1.toOf()); + mesh.addTexCoord(t2.toOf()); + mesh.addTexCoord(t3.toOf()); + mesh.addTexCoord(t4.toOf()); + + _meshCache = mesh; + calculateHomography(); +} + +void QuadSurface::draw(){ + if(source->getTexture() == 0){ + return; + } + + if(!source->getTexture()->isAllocated()){ + return; + } + + if(_perspectiveWarping){ + bool meshChanged = false; + + if( + mesh.getVertices()[0] != _meshCache.getVertices()[0] || + mesh.getVertices()[1] != _meshCache.getVertices()[1] || + mesh.getVertices()[2] != _meshCache.getVertices()[2] || + mesh.getVertices()[3] != _meshCache.getVertices()[3]) + { + meshChanged = true; + } + + if(meshChanged){ + calculateHomography(); + _meshCache = mesh; + } + + ofRectangle box = getMeshBoundingBox(); + ofMesh m = mesh; + + m.setVertex(0, Vec3(0, 0, 0).toOf()); + m.setVertex(1, Vec3(box.width, 0, 0).toOf()); + m.setVertex(2, Vec3(box.width, box.height, 0).toOf()); + m.setVertex(3, Vec3(0, box.height, 0).toOf()); + + ofPushMatrix(); + if(true){ + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + glMultMatrixf(_matrix); + source->getTexture()->bind(); + m.draw(); + source->getTexture()->unbind(); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } + } + ofPopMatrix(); + }else{ + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + ofPushStyle(); + ofSetColor(255, 255, 255); + + source->getTexture()->bind(); + mesh.draw(); + source->getTexture()->unbind(); + + ofPopStyle(); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } + } +} + +void QuadSurface::setVertex(int index, Vec3 p){ + if(index > 3){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + return; + } + + mesh.setVertex(index, p.toOf()); + ofNotifyEvent(vertexChangedEvent, index, this); +} + +void QuadSurface::setVertices(std::vector v){ + if(v.size() != 4){ + throw runtime_error("Wrong number of vertices"); + } + + for(int i = 0; i < 4; ++i){ + mesh.setVertex(i, v[i].toOf()); + } + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void QuadSurface::setTexCoord(int index, Vec2 t){ + if(index > 3){ + ofLog() << "Texture coordinate with this index does not exist: " << index + << std::endl; + return; + } + + mesh.setTexCoord(index, t.toOf()); +} + +void QuadSurface::setTexCoords(std::vector t){ + if(t.size() != 4){ + throw runtime_error("Wrong number of vertices"); + } + for(int i = 0; i < 4; ++i){ + mesh.setTexCoord(i, t[i].toOf()); + } +} + +void QuadSurface::moveBy(Vec3 v){ + for(int i = 0; i < mesh.getVertices().size(); i++){ + mesh.getVertices()[i] += v.toOf(); + } + + setMoved(true); + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void QuadSurface::fullScreen(){ + mesh.getVertices()[0] = Vec3(0, 0, 0.0f).toOf(); + mesh.getVertices()[1] = Vec3((float)ofGetWidth(), 0, 0.0f).toOf(); + mesh.getVertices()[2] = Vec3((float)ofGetWidth(), (float)ofGetHeight(), 0.0f).toOf(); + mesh.getVertices()[3] = Vec3(0, (float)ofGetHeight(), 0.0f).toOf(); + + setMoved(true); + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +int QuadSurface::getType(){ + return SurfaceType::QUAD_SURFACE; +} + +bool QuadSurface::hitTest(Vec2 p){ + ofPolyline line = getHitArea(); + + if(line.inside(p.x, p.y)){ + return true; + }else{ + return false; + } +} + +Vec3 QuadSurface::getVertex(int index){ + if(index > 3){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + throw runtime_error("Vertex index out of bounds."); + } + + return Vec3( + mesh.getVertex(index).x, + mesh.getVertex(index).y, + mesh.getVertex(index).z); +} + +Vec2 QuadSurface::getTexCoord(int index){ + if(index > 3){ + throw runtime_error("Texture coordinate index out of bounds."); + } + + return Vec2( + mesh.getTexCoord(index).x, + mesh.getTexCoord(index).y); +} + +ofPolyline QuadSurface::getHitArea(){ + ofPolyline line; + + line.addVertex(ofPoint(mesh.getVertex(0).x, mesh.getVertex(0).y)); + line.addVertex(ofPoint(mesh.getVertex(1).x, mesh.getVertex(1).y)); + line.addVertex(ofPoint(mesh.getVertex(2).x, mesh.getVertex(2).y)); + line.addVertex(ofPoint(mesh.getVertex(3).x, mesh.getVertex(3).y)); + line.close(); + + return line; +} + +ofPolyline QuadSurface::getTextureHitArea(){ + ofPolyline line; + Vec2 textureSize = + Vec2(source->getTexture()->getWidth(), + source->getTexture()->getHeight()); + for(int i = 0; i < mesh.getTexCoords().size(); i++){ + line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); + } + line.close(); + + return line; +} + +std::vector QuadSurface::getVertices(){ + return Vec3::fromOf(mesh.getVertices()); +} + +std::vector QuadSurface::getTexCoords(){ + return Vec2::fromOf(mesh.getTexCoords()); +} + +void QuadSurface::calculateHomography(){ + float src[4][2]; + float dst[4][2]; + + ofRectangle box = getMeshBoundingBox(); + + src[0][0] = 0; + src[0][1] = 0; + src[1][0] = box.width; + src[1][1] = 0; + src[2][0] = box.width; + src[2][1] = box.height; + src[3][0] = 0; + src[3][1] = box.height; + + Vec3 p0(mesh.getVertex(0).x, mesh.getVertex(0).y, mesh.getVertex(0).z); + Vec3 p1(mesh.getVertex(1).x, mesh.getVertex(1).y, mesh.getVertex(1).z); + Vec3 p2(mesh.getVertex(2).x, mesh.getVertex(2).y, mesh.getVertex(2).z); + Vec3 p3(mesh.getVertex(3).x, mesh.getVertex(3).y, mesh.getVertex(3).z); + + dst[0][0] = p0.x; + dst[0][1] = p0.y; + dst[1][0] = p1.x; + dst[1][1] = p1.y; + dst[2][0] = p2.x; + dst[2][1] = p2.y; + dst[3][0] = p3.x; + dst[3][1] = p3.y; + + HomographyHelper::findHomography(src, dst, _matrix); +} + +void QuadSurface::setPerspectiveWarping(bool b){ + _perspectiveWarping = b; +} + +bool QuadSurface::getPerspectiveWarping(){ + return _perspectiveWarping; +} + +ofRectangle QuadSurface::getMeshBoundingBox(){ + float minX = 10000.0f; + float minY = 10000.0f; + float maxX = 0.0f; + float maxY = 0.0f; + + for(int i = 0; i < mesh.getVertices().size(); ++i){ + if(mesh.getVertices()[i].x < minX){ + minX = mesh.getVertices()[i].x; + } + + if(mesh.getVertices()[i].y < minY){ + minY = mesh.getVertices()[i].y; + } + + if(mesh.getVertices()[i].x > maxX){ + maxX = mesh.getVertices()[i].x; + } + + if(mesh.getVertices()[i].y > maxY){ + maxY = mesh.getVertices()[i].y; + } + } + + ofRectangle boundingBox = ofRectangle(ofPoint(minX, minY), ofPoint(maxX, maxY)); + return boundingBox; +} + +BaseSurface * QuadSurface::clone(){ + QuadSurface * s = new QuadSurface(); + s->setVertices(getVertices()); + s->setTexCoords(getTexCoords()); + s->setPerspectiveWarping(getPerspectiveWarping()); + BaseSource * src = getSource(); + src->referenceCount++; + s->setSource(src); + return s; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/QuadSurface.h b/src/Surfaces/QuadSurface.h index ab4dc7e..590dbb0 100644 --- a/src/Surfaces/QuadSurface.h +++ b/src/Surfaces/QuadSurface.h @@ -1,54 +1,54 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" -#include "SurfaceType.h" -#include "HomographyHelper.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class QuadSurface : public BaseSurface { - public: - QuadSurface(); - ~QuadSurface(); - - void setup(); - void setup( - Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, - Vec2 t1, Vec2 t2, Vec2 t3, Vec2 t4, - BaseSource * newSource); - void draw(); - void setVertex(int index, Vec3 p); - void setVertices(std::vector v); - void setTexCoord(int index, Vec2 t); - void setTexCoords(std::vector t); - void moveBy(Vec3 v); - void fullScreen(); - - int getType(); - bool hitTest(Vec2 p); - Vec3 getVertex(int index); - Vec2 getTexCoord(int index); - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - std::vector getVertices(); - std::vector getTexCoords(); - - void setPerspectiveWarping(bool b); - bool getPerspectiveWarping(); - - ofRectangle getMeshBoundingBox(); - BaseSurface * clone(); - - private: - void calculateHomography(); - float _matrix[16]; - bool _perspectiveWarping; - ofMesh _meshCache; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" +#include "HomographyHelper.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class QuadSurface : public BaseSurface { + public: + QuadSurface(); + ~QuadSurface(); + + void setup(); + void setup( + Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, + Vec2 t1, Vec2 t2, Vec2 t3, Vec2 t4, + BaseSource * newSource); + void draw(); + void setVertex(int index, Vec3 p); + void setVertices(std::vector v); + void setTexCoord(int index, Vec2 t); + void setTexCoords(std::vector t); + void moveBy(Vec3 v); + void fullScreen(); + + int getType(); + bool hitTest(Vec2 p); + Vec3 getVertex(int index); + Vec2 getTexCoord(int index); + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + std::vector getVertices(); + std::vector getTexCoords(); + + void setPerspectiveWarping(bool b); + bool getPerspectiveWarping(); + + ofRectangle getMeshBoundingBox(); + BaseSurface * clone(); + + private: + void calculateHomography(); + float _matrix[16]; + bool _perspectiveWarping; + ofMesh _meshCache; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceFactory.cpp b/src/Surfaces/SurfaceFactory.cpp index 847f13c..1f175bc 100644 --- a/src/Surfaces/SurfaceFactory.cpp +++ b/src/Surfaces/SurfaceFactory.cpp @@ -1,94 +1,94 @@ -#include "SurfaceFactory.h" - -namespace ofx { -namespace piMapper { - -SurfaceFactory * SurfaceFactory::_instance = 0; - -SurfaceFactory * SurfaceFactory::instance(){ - if(_instance == 0){ - _instance = new ofx::piMapper::SurfaceFactory(); - } - return _instance; -} - -BaseSurface * SurfaceFactory::createSurface(SurfaceType type){ - if(type == SurfaceType::TRIANGLE_SURFACE){ - return createTriangleSurface(); - }else if(type == SurfaceType::QUAD_SURFACE){ - return createQuadSurface(); - }else if(type == SurfaceType::GRID_WARP_SURFACE){ - return createGridWarpSurface(); - }else if(type == SurfaceType::HEXAGON_SURFACE){ - return createHexagonSurface(); - }else if(type == SurfaceType::CIRCLE_SURFACE){ - return createCircleSurface(); - }else{ - throw runtime_error("Undefined surface type"); - } -} - -TriangleSurface * SurfaceFactory::createTriangleSurface(){ - std::vector vertices; - float margin = 50.0f; - vertices.push_back(Vec3((float)ofGetWidth() / 2.0f, margin, 0.0f)); - vertices.push_back(Vec3((float)ofGetWidth() - margin, (float)ofGetHeight() - margin, 0.0f)); - vertices.push_back(Vec3(margin, (float)ofGetHeight() - margin, 0.0f)); - - std::vector texCoords; - texCoords.push_back(Vec2(0.5f, 0.0f)); - texCoords.push_back(Vec2(1.0f, 1.0f)); - texCoords.push_back(Vec2(0.0f, 1.0f)); - - TriangleSurface * triangleSurface = new TriangleSurface(); - - for(int i = 0; i < 3; i++){ - triangleSurface->setVertex(i, vertices[i]); - triangleSurface->setTexCoord(i, texCoords[i]); - } - - return triangleSurface; -} - -QuadSurface * SurfaceFactory::createQuadSurface(){ - std::vector vertices; - float margin = 50.0f; - vertices.push_back(Vec3(margin, margin, 0.0f)); - vertices.push_back(Vec3((float)ofGetWidth() - margin, margin, 0.0f)); - vertices.push_back(Vec3((float)ofGetWidth() - margin, (float)ofGetHeight() - margin, 0.0f)); - vertices.push_back(Vec3(margin, (float)ofGetHeight() - margin, 0.0f)); - - std::vector texCoords; - texCoords.push_back(Vec2(Vec2(0.0f, 0.0f))); - texCoords.push_back(Vec2(Vec2(1.0f, 0.0f))); - texCoords.push_back(Vec2(Vec2(1.0f, 1.0f))); - texCoords.push_back(Vec2(Vec2(0.0f, 1.0f))); - - QuadSurface * quadSurface = new QuadSurface(); - quadSurface->setPerspectiveWarping(true); - - for(int i = 0; i < 4; i++){ - quadSurface->setVertex(i, vertices[i]); - quadSurface->setTexCoord(i, texCoords[i]); - } - - return quadSurface; -} - -GridWarpSurface * SurfaceFactory::createGridWarpSurface(){ - GridWarpSurface * gridWarpSurface = new GridWarpSurface(); - return gridWarpSurface; -} - -HexagonSurface * SurfaceFactory::createHexagonSurface(){ - HexagonSurface * hexagonSurface = new HexagonSurface(); - return hexagonSurface; -} - -CircleSurface * SurfaceFactory::createCircleSurface() { - CircleSurface * circleSurface = new CircleSurface(); - return circleSurface; -} - -} // namespace piMapper -} // namespace ofx +#include "SurfaceFactory.h" + +namespace ofx { +namespace piMapper { + +SurfaceFactory * SurfaceFactory::_instance = 0; + +SurfaceFactory * SurfaceFactory::instance(){ + if(_instance == 0){ + _instance = new ofx::piMapper::SurfaceFactory(); + } + return _instance; +} + +BaseSurface * SurfaceFactory::createSurface(SurfaceType type){ + if(type == SurfaceType::TRIANGLE_SURFACE){ + return createTriangleSurface(); + }else if(type == SurfaceType::QUAD_SURFACE){ + return createQuadSurface(); + }else if(type == SurfaceType::GRID_WARP_SURFACE){ + return createGridWarpSurface(); + }else if(type == SurfaceType::HEXAGON_SURFACE){ + return createHexagonSurface(); + }else if(type == SurfaceType::CIRCLE_SURFACE){ + return createCircleSurface(); + }else{ + throw runtime_error("Undefined surface type"); + } +} + +TriangleSurface * SurfaceFactory::createTriangleSurface(){ + std::vector vertices; + float margin = 50.0f; + vertices.push_back(Vec3((float)ofGetWidth() / 2.0f, margin, 0.0f)); + vertices.push_back(Vec3((float)ofGetWidth() - margin, (float)ofGetHeight() - margin, 0.0f)); + vertices.push_back(Vec3(margin, (float)ofGetHeight() - margin, 0.0f)); + + std::vector texCoords; + texCoords.push_back(Vec2(0.5f, 0.0f)); + texCoords.push_back(Vec2(1.0f, 1.0f)); + texCoords.push_back(Vec2(0.0f, 1.0f)); + + TriangleSurface * triangleSurface = new TriangleSurface(); + + for(int i = 0; i < 3; i++){ + triangleSurface->setVertex(i, vertices[i]); + triangleSurface->setTexCoord(i, texCoords[i]); + } + + return triangleSurface; +} + +QuadSurface * SurfaceFactory::createQuadSurface(){ + std::vector vertices; + float margin = 50.0f; + vertices.push_back(Vec3(margin, margin, 0.0f)); + vertices.push_back(Vec3((float)ofGetWidth() - margin, margin, 0.0f)); + vertices.push_back(Vec3((float)ofGetWidth() - margin, (float)ofGetHeight() - margin, 0.0f)); + vertices.push_back(Vec3(margin, (float)ofGetHeight() - margin, 0.0f)); + + std::vector texCoords; + texCoords.push_back(Vec2(Vec2(0.0f, 0.0f))); + texCoords.push_back(Vec2(Vec2(1.0f, 0.0f))); + texCoords.push_back(Vec2(Vec2(1.0f, 1.0f))); + texCoords.push_back(Vec2(Vec2(0.0f, 1.0f))); + + QuadSurface * quadSurface = new QuadSurface(); + quadSurface->setPerspectiveWarping(true); + + for(int i = 0; i < 4; i++){ + quadSurface->setVertex(i, vertices[i]); + quadSurface->setTexCoord(i, texCoords[i]); + } + + return quadSurface; +} + +GridWarpSurface * SurfaceFactory::createGridWarpSurface(){ + GridWarpSurface * gridWarpSurface = new GridWarpSurface(); + return gridWarpSurface; +} + +HexagonSurface * SurfaceFactory::createHexagonSurface(){ + HexagonSurface * hexagonSurface = new HexagonSurface(); + return hexagonSurface; +} + +CircleSurface * SurfaceFactory::createCircleSurface() { + CircleSurface * circleSurface = new CircleSurface(); + return circleSurface; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceFactory.h b/src/Surfaces/SurfaceFactory.h index 14cd012..829fe8c 100644 --- a/src/Surfaces/SurfaceFactory.h +++ b/src/Surfaces/SurfaceFactory.h @@ -1,34 +1,34 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" -#include "SurfaceType.h" -#include "TriangleSurface.h" -#include "QuadSurface.h" -#include "GridWarpSurface.h" -#include "HexagonSurface.h" -#include "CircleSurface.h" - -namespace ofx { -namespace piMapper { - -// The surface factory singleton -class SurfaceFactory { - public: - static SurfaceFactory * instance(); - - // Create new surface based on type - BaseSurface * createSurface(SurfaceType type); - - private: - static SurfaceFactory * _instance; - - TriangleSurface * createTriangleSurface(); - QuadSurface * createQuadSurface(); - GridWarpSurface * createGridWarpSurface(); - HexagonSurface * createHexagonSurface(); - CircleSurface* createCircleSurface(); - }; - -} // namespace piMapper +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" +#include "TriangleSurface.h" +#include "QuadSurface.h" +#include "GridWarpSurface.h" +#include "HexagonSurface.h" +#include "CircleSurface.h" + +namespace ofx { +namespace piMapper { + +// The surface factory singleton +class SurfaceFactory { + public: + static SurfaceFactory * instance(); + + // Create new surface based on type + BaseSurface * createSurface(SurfaceType type); + + private: + static SurfaceFactory * _instance; + + TriangleSurface * createTriangleSurface(); + QuadSurface * createQuadSurface(); + GridWarpSurface * createGridWarpSurface(); + HexagonSurface * createHexagonSurface(); + CircleSurface* createCircleSurface(); + }; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Surfaces/SurfaceManager.cpp b/src/Surfaces/SurfaceManager.cpp index f05815f..efafb7f 100644 --- a/src/Surfaces/SurfaceManager.cpp +++ b/src/Surfaces/SurfaceManager.cpp @@ -1,538 +1,538 @@ -#include "SurfaceManager.h" - -namespace ofx { -namespace piMapper { - -SurfaceManager::SurfaceManager(){ - mediaServer = 0; - selectedSurface = 0; - - //SurfaceStack * preset = new SurfaceStack(); - //_presets.push_back(preset); - //_activePresetIndex = 0; - - _activePresetIndex = -1; - _selectedVertexIndex = -1; -} - -void SurfaceManager::draw(){ - if(_activePresetIndex < 0){ - return; - } - - _presets[_activePresetIndex]->draw(); -} - -void SurfaceManager::addSurface(BaseSurface * surface){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::addSurface", "Can not add surface. No active preset."); - return; - } - - _presets[_activePresetIndex]->push_back(surface); -} - -void SurfaceManager::removeSelectedSurface(){ - if(_activePresetIndex < 0){ - ofLogWarning( - "SurfaceManager::removeSelectedSurface", - "Can not remove surface. No Active preset"); - return; - } - - if(selectedSurface == 0){ - return; - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); i++){ - if(_presets[_activePresetIndex]->at(i) == selectedSurface){ - _presets[_activePresetIndex]->erase(i); - selectedSurface = 0; - _selectedVertexIndex = -1; - break; - } - } -} - -void SurfaceManager::removeSurface(int i){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::removeSurface", "Can not remove surface. No active preset."); - return; - } - - if(_presets[_activePresetIndex]->size() <= 0){ - return; - } - - //_presets[_activePresetIndex]->erase(i); - _presets[_activePresetIndex]->swap(i, _presets[_activePresetIndex]->size() - 1); - _presets[_activePresetIndex]->pop_back(); - selectedSurface = 0; -} - -void SurfaceManager::removeSurface(){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::removeSurface", "Can not remove surface. No active preset."); - return; - } - - if(_presets[_activePresetIndex]->size() <= 0){ - return; - } - - BaseSurface * s = _presets[_activePresetIndex]->back(); - _presets[_activePresetIndex]->pop_back(); - selectedSurface = 0; - delete s; -} - -void SurfaceManager::deleteSurface(ofx::piMapper::BaseSurface * surface){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::deleteSurface", "Can not delete surface. No active preset."); - return; - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ - if(_presets[_activePresetIndex]->at(i) == surface){ - _presets[_activePresetIndex]->erase(i); - break; - } - } -} - -void SurfaceManager::clearPresets(){ - for(unsigned int i = 0; i < _presets.size(); ++i){ - while(_presets[i]->size()){ - delete _presets[i]->back(); - _presets[i]->pop_back(); - } - } - _presets.clear(); -} - -// TODO: Do serious adjustment here. We need to save all presets. Not just the active one. -void SurfaceManager::saveXmlSettings(std::string fileName){ - if(_presets.size() <= 0){ - ofLogWarning( - "SurfaceManager::saveXmlSettings", - "Can not save XML settings. No presets."); - return; - } - - if(mediaServer == 0){ - ofLogFatalError("SurfaceManager") << "Media server not set"; - exit(EXIT_FAILURE); - } - - SettingsLoader::instance()->save(*this, fileName); -} - -// TODO: We need to load all presets. Not just the active one. -bool SurfaceManager::loadXmlSettings(std::string fileName){ - if(mediaServer == 0){ - ofLogFatalError("SurfaceManager") << "Media server not set"; - exit(EXIT_FAILURE); - } - bool success = SettingsLoader::instance()->load(*this, *mediaServer, fileName); - - for (int i=0; i<_presets.size(); i++){ - setPresetSourcesActiveState(i, false); - } - - setPresetSourcesActiveState(_activePresetIndex, true); - return success; -} - -void SurfaceManager::setMediaServer(MediaServer * newMediaServer){ - mediaServer = newMediaServer; -} - -BaseSurface * SurfaceManager::selectSurface(int index){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::selectSurface", "Can not select surface. No active preset."); - return 0; - } - - if(index >= _presets[_activePresetIndex]->size()){ - throw runtime_error("Surface index out of bounds."); - } - - selectedSurface = _presets[_activePresetIndex]->at(index); - _selectedVertexIndex = -1; - ofSendMessage("surfaceSelected"); - return selectedSurface; -} - -BaseSurface * SurfaceManager::selectSurface(BaseSurface * surface){ - if(_activePresetIndex < 0){ - ofLogWarning("SurfaceManager::selectSurface", "Can not select surface. No active preset."); - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); i++){ - if(_presets[_activePresetIndex]->at(i) == surface){ - selectedSurface = surface; - _selectedVertexIndex = -1; - ofSendMessage("surfaceSelected"); - ofNotifyEvent(surfaceSelectedEvent, i, this); - return selectedSurface; - } - } - - deselectSurface(); - return 0; -} - -BaseSurface * SurfaceManager::selectNextSurface(){ - if(_activePresetIndex < 0){ - ofLogWarning( - "SurfaceManager::selectNextSurface", - "Can not select next surface. No active preset."); - return 0; - } - - int next; - _selectedVertexIndex = -1; - - if(selectedSurface == 0){ - next = 0; - selectedSurface = selectSurface(next); - ofNotifyEvent(surfaceSelectedEvent, next, this); - return selectedSurface; - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ - if(_presets[_activePresetIndex]->at(i) == selectedSurface){ - if(i < _presets[_activePresetIndex]->size() - 1){ - next = i + 1; - }else{ - next = 0; - } - - selectedSurface = _presets[_activePresetIndex]->at(next); - ofNotifyEvent(surfaceSelectedEvent, next, this); - return selectedSurface; - } - } - - return 0; -} - -BaseSurface * SurfaceManager::selectPrevSurface(){ - if(_activePresetIndex < 0){ - ofLogWarning( - "SurfaceManager::selectPrevSurface", - "Can not select prev surface. No active preset."); - return 0; - } - - int prev; - _selectedVertexIndex = -1; - - if(selectedSurface == 0){ - prev = _presets[_activePresetIndex]->size() - 1; - selectedSurface = selectSurface(prev); - ofNotifyEvent(surfaceSelectedEvent, prev, this); - return selectedSurface; - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ - if(_presets[_activePresetIndex]->at(i) == selectedSurface){ - if(i > 0){ - prev = i - 1; - }else{ - prev = _presets[_activePresetIndex]->size() - 1; - } - - selectedSurface = _presets[_activePresetIndex]->at(prev); - ofNotifyEvent(surfaceSelectedEvent, prev, this); - return selectedSurface; - } - } - - return 0; -} - -BaseSurface * SurfaceManager::getSelectedSurface(){ - return selectedSurface; -} - -// TODO: select vertex should be implemented ad BaseSurface level -void SurfaceManager::selectNextVertex(){ - if(selectedSurface == 0){ - return; - } - - int numVertices = selectedSurface->getVertices().size(); - - if(_selectedVertexIndex == -1){ - _selectedVertexIndex = 0; - }else if(_selectedVertexIndex < numVertices - 1){ - _selectedVertexIndex += 1; - }else{ - _selectedVertexIndex = 0; - } - - ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); -} - -// TODO: select vertex should be implemented at BaseSurface level -void SurfaceManager::selectPrevVertex(){ - if(selectedSurface == 0){ - return; - } - - int numVertices = selectedSurface->getVertices().size(); - - if(_selectedVertexIndex > 0){ - _selectedVertexIndex -= 1; - }else{ - _selectedVertexIndex = numVertices - 1; - } - - ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); -} - -void SurfaceManager::selectVertex(int i){ - if(selectedSurface == 0){ - return; - } - - if(i > selectedSurface->getVertices().size() - 1){ - ofLogError("SurfaceManager::selectVertex") << "index (" << i << ") out of bounds" << std::endl; - int prevVertIndex = _selectedVertexIndex; - ofNotifyEvent(vertexUnselectedEvent, prevVertIndex, this); - _selectedVertexIndex = -1; - return; - } - - _selectedVertexIndex = i; - ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); -} - -void SurfaceManager::moveSelectionBy(Vec3 v){ - if(selectedSurface == 0){ - moveAllSurfacesBy(v); - return; - } - - if(_selectedVertexIndex != -1){ - selectedSurface->getMesh().getVertices()[_selectedVertexIndex] += v.toOf(); - ofNotifyEvent(vertexChangedEvent, _selectedVertexIndex, this); - }else{ - selectedSurface->moveBy(v); - } - - // TODO: instead of having single selected surface - // we want to have a selection of one or more. - // it could be implemented as vector here. -} - -void SurfaceManager::moveAllSurfacesBy(Vec3 v){ - if(_activePresetIndex < 0){ - ofLogWarning( - "SurfaceManager::moveAllSurfacesBy", - "Can not move surfaces. No active preset."); - return; - } - - for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ - _presets[_activePresetIndex]->at(i)->moveBy(v); - } -} - -void SurfaceManager::deselectSurface(){ - selectedSurface = 0; - _selectedVertexIndex = -1; -} - -BaseSurface * SurfaceManager::getSurface(int index){ - if(_activePresetIndex < 0){ - throw runtime_error("No active preset."); - return 0; - } - - if(index >= _presets[_activePresetIndex]->size()){ - throw runtime_error("Surface index out of bounds."); - return 0; - } - - return _presets[_activePresetIndex]->at(index); -} - -/* TODO: Solve fundamental question - * What size are we talking about here? - * Is it the number of presets or surfaces? - */ -int SurfaceManager::size(){ - if(_activePresetIndex < 0){ - return 0; - } - - return _presets[_activePresetIndex]->size(); -} - -int SurfaceManager::getSelectedVertexIndex(){ - return _selectedVertexIndex; -} - -int SurfaceManager::getActivePresetIndex(){ - return _activePresetIndex; -} - -int SurfaceManager::getSelectedSurfaceIndex(){ - if(selectedSurface == 0){ - return -1; - } - for(unsigned int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ - if(_presets[_activePresetIndex]->getSurfaces()[i] == selectedSurface){ - return i; - } - } - return -1; -} - -unsigned int SurfaceManager::getNumPresets(){ - return _presets.size(); -} - -void SurfaceManager::onVertexChanged(int & i){ - ofNotifyEvent(vertexChangedEvent, i, this); -} - -void SurfaceManager::onVerticesChanged(std::vector & vertices){ - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -SurfaceStack * SurfaceManager::getActivePreset(){ - if(_activePresetIndex < 0){ - throw runtime_error( - "SurfaceManager::getActivePreset: Can not getActivePreset. No active preset."); - } - - return _presets[_activePresetIndex]; -} - -SurfaceStack * SurfaceManager::createPreset(){ - SurfaceStack * preset = new SurfaceStack(); - _presets.push_back(preset); - - // If we did not have any presets before, set the new as active one. - if(_presets.size() == 1){ - _activePresetIndex = 0; - } - - // Remember to remove these listeners when adding a removePreset method. - ofAddListener( - preset->vertexChangedEvent, - this, - &SurfaceManager::onVertexChanged); - ofAddListener( - preset->verticesChangedEvent, - this, - &SurfaceManager::onVerticesChanged); - - return preset; - - // TODO: Create command for this. And what not. -} - -SurfaceStack * SurfaceManager::getPresetAt(unsigned int i){ - if(i >= _presets.size()){ - throw runtime_error("SurfaceManager::getPresetAt index out of bounds."); - } - return _presets[i]; -} - -void SurfaceManager::setNextPreset(){ - if(_presets.size() <= 1){ - return; - } - - if(_activePresetIndex == _presets.size() - 1){ - _activePresetIndex = 0; - }else{ - _activePresetIndex += 1; - } - - // TODO: Create command for this. -} - -void SurfaceManager::setPresetSourcesActiveState(unsigned int presetIndex, bool state){ - // tell sources associated with current preset that they are not displayed any more - // this is so that we can optionally update the buffers or not. - for (int j=0; j<_presets[presetIndex]->getSurfaces().size(); j++){ - _presets[presetIndex]->getSurfaces()[j]->getSource()->setActive(state); - } -} - -void SurfaceManager::setPreset(unsigned int i){ - cout << "CALLED IT" << endl; - if(_presets.size() <= 1){ - throw runtime_error("ofxPiMapper: No presets to set."); - } - - if(i >= _presets.size()){ - throw runtime_error("ofxPiMapper: Preset index out of bounds."); - } - - //let sources associated with all preset know that they are not being displayed any more - setPresetSourcesActiveState(_activePresetIndex, false); - - //change preset - _activePresetIndex = i; - //let sources associated with NEW preset know that they are now being displayed - setPresetSourcesActiveState(_activePresetIndex, true); - - - //when preset it changed, call reset on all sources, if it's defined - for (int i=0; i<_presets[_activePresetIndex]->getSurfaces().size(); i++){ - - //if source is of type FBO then cast it from BaseSource to FboSource and call the beginFbo function - if (_presets[_activePresetIndex]->getSurfaces()[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ - FboSource *fboSource; - fboSource = (FboSource*)_presets[_activePresetIndex]->getSurfaces()[i]->getSource(); - fboSource->beginFbo(); - } - - _presets[_activePresetIndex]->getSurfaces()[i]->getSource()->reset(); - - //if source is of type FBO then cast it from BaseSource to FboSource and call the endFbo function - if (_presets[_activePresetIndex]->getSurfaces()[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ - FboSource *fboSource; - fboSource = (FboSource*)_presets[_activePresetIndex]->getSurfaces()[i]->getSource(); - fboSource->endFbo(); - } - } -} - -void SurfaceManager::cloneActivePreset(){ - if(_presets.size() <= 0){ - return; - } - - SurfaceStack * preset = _presets[_activePresetIndex]->clone(); - _presets.push_back(preset); - _activePresetIndex = _presets.size() - 1; -} - -void SurfaceManager::eraseActivePreset(){ - if(_presets.size() <= 0){ - return; - } - - _presets[_activePresetIndex]->clear(); - _presets.erase(_presets.begin() + _activePresetIndex); - - _activePresetIndex--; - - if(_presets.size() > 0 && _activePresetIndex < 0){ - _activePresetIndex = 0; - } - - if(_activePresetIndex < 0){ - createPreset(); - } -} - -} // namespace piMapper -} // namespace ofx +#include "SurfaceManager.h" + +namespace ofx { +namespace piMapper { + +SurfaceManager::SurfaceManager(){ + mediaServer = 0; + selectedSurface = 0; + + //SurfaceStack * preset = new SurfaceStack(); + //_presets.push_back(preset); + //_activePresetIndex = 0; + + _activePresetIndex = -1; + _selectedVertexIndex = -1; +} + +void SurfaceManager::draw(){ + if(_activePresetIndex < 0){ + return; + } + + _presets[_activePresetIndex]->draw(); +} + +void SurfaceManager::addSurface(BaseSurface * surface){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::addSurface", "Can not add surface. No active preset."); + return; + } + + _presets[_activePresetIndex]->push_back(surface); +} + +void SurfaceManager::removeSelectedSurface(){ + if(_activePresetIndex < 0){ + ofLogWarning( + "SurfaceManager::removeSelectedSurface", + "Can not remove surface. No Active preset"); + return; + } + + if(selectedSurface == 0){ + return; + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); i++){ + if(_presets[_activePresetIndex]->at(i) == selectedSurface){ + _presets[_activePresetIndex]->erase(i); + selectedSurface = 0; + _selectedVertexIndex = -1; + break; + } + } +} + +void SurfaceManager::removeSurface(int i){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::removeSurface", "Can not remove surface. No active preset."); + return; + } + + if(_presets[_activePresetIndex]->size() <= 0){ + return; + } + + //_presets[_activePresetIndex]->erase(i); + _presets[_activePresetIndex]->swap(i, _presets[_activePresetIndex]->size() - 1); + _presets[_activePresetIndex]->pop_back(); + selectedSurface = 0; +} + +void SurfaceManager::removeSurface(){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::removeSurface", "Can not remove surface. No active preset."); + return; + } + + if(_presets[_activePresetIndex]->size() <= 0){ + return; + } + + BaseSurface * s = _presets[_activePresetIndex]->back(); + _presets[_activePresetIndex]->pop_back(); + selectedSurface = 0; + delete s; +} + +void SurfaceManager::deleteSurface(ofx::piMapper::BaseSurface * surface){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::deleteSurface", "Can not delete surface. No active preset."); + return; + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ + if(_presets[_activePresetIndex]->at(i) == surface){ + _presets[_activePresetIndex]->erase(i); + break; + } + } +} + +void SurfaceManager::clearPresets(){ + for(unsigned int i = 0; i < _presets.size(); ++i){ + while(_presets[i]->size()){ + delete _presets[i]->back(); + _presets[i]->pop_back(); + } + } + _presets.clear(); +} + +// TODO: Do serious adjustment here. We need to save all presets. Not just the active one. +void SurfaceManager::saveXmlSettings(std::string fileName){ + if(_presets.size() <= 0){ + ofLogWarning( + "SurfaceManager::saveXmlSettings", + "Can not save XML settings. No presets."); + return; + } + + if(mediaServer == 0){ + ofLogFatalError("SurfaceManager") << "Media server not set"; + exit(EXIT_FAILURE); + } + + SettingsLoader::instance()->save(*this, fileName); +} + +// TODO: We need to load all presets. Not just the active one. +bool SurfaceManager::loadXmlSettings(std::string fileName){ + if(mediaServer == 0){ + ofLogFatalError("SurfaceManager") << "Media server not set"; + exit(EXIT_FAILURE); + } + bool success = SettingsLoader::instance()->load(*this, *mediaServer, fileName); + + for (int i=0; i<_presets.size(); i++){ + setPresetSourcesActiveState(i, false); + } + + setPresetSourcesActiveState(_activePresetIndex, true); + return success; +} + +void SurfaceManager::setMediaServer(MediaServer * newMediaServer){ + mediaServer = newMediaServer; +} + +BaseSurface * SurfaceManager::selectSurface(int index){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::selectSurface", "Can not select surface. No active preset."); + return 0; + } + + if(index >= _presets[_activePresetIndex]->size()){ + throw runtime_error("Surface index out of bounds."); + } + + selectedSurface = _presets[_activePresetIndex]->at(index); + _selectedVertexIndex = -1; + ofSendMessage("surfaceSelected"); + return selectedSurface; +} + +BaseSurface * SurfaceManager::selectSurface(BaseSurface * surface){ + if(_activePresetIndex < 0){ + ofLogWarning("SurfaceManager::selectSurface", "Can not select surface. No active preset."); + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); i++){ + if(_presets[_activePresetIndex]->at(i) == surface){ + selectedSurface = surface; + _selectedVertexIndex = -1; + ofSendMessage("surfaceSelected"); + ofNotifyEvent(surfaceSelectedEvent, i, this); + return selectedSurface; + } + } + + deselectSurface(); + return 0; +} + +BaseSurface * SurfaceManager::selectNextSurface(){ + if(_activePresetIndex < 0){ + ofLogWarning( + "SurfaceManager::selectNextSurface", + "Can not select next surface. No active preset."); + return 0; + } + + int next; + _selectedVertexIndex = -1; + + if(selectedSurface == 0){ + next = 0; + selectedSurface = selectSurface(next); + ofNotifyEvent(surfaceSelectedEvent, next, this); + return selectedSurface; + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ + if(_presets[_activePresetIndex]->at(i) == selectedSurface){ + if(i < _presets[_activePresetIndex]->size() - 1){ + next = i + 1; + }else{ + next = 0; + } + + selectedSurface = _presets[_activePresetIndex]->at(next); + ofNotifyEvent(surfaceSelectedEvent, next, this); + return selectedSurface; + } + } + + return 0; +} + +BaseSurface * SurfaceManager::selectPrevSurface(){ + if(_activePresetIndex < 0){ + ofLogWarning( + "SurfaceManager::selectPrevSurface", + "Can not select prev surface. No active preset."); + return 0; + } + + int prev; + _selectedVertexIndex = -1; + + if(selectedSurface == 0){ + prev = _presets[_activePresetIndex]->size() - 1; + selectedSurface = selectSurface(prev); + ofNotifyEvent(surfaceSelectedEvent, prev, this); + return selectedSurface; + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ + if(_presets[_activePresetIndex]->at(i) == selectedSurface){ + if(i > 0){ + prev = i - 1; + }else{ + prev = _presets[_activePresetIndex]->size() - 1; + } + + selectedSurface = _presets[_activePresetIndex]->at(prev); + ofNotifyEvent(surfaceSelectedEvent, prev, this); + return selectedSurface; + } + } + + return 0; +} + +BaseSurface * SurfaceManager::getSelectedSurface(){ + return selectedSurface; +} + +// TODO: select vertex should be implemented ad BaseSurface level +void SurfaceManager::selectNextVertex(){ + if(selectedSurface == 0){ + return; + } + + int numVertices = selectedSurface->getVertices().size(); + + if(_selectedVertexIndex == -1){ + _selectedVertexIndex = 0; + }else if(_selectedVertexIndex < numVertices - 1){ + _selectedVertexIndex += 1; + }else{ + _selectedVertexIndex = 0; + } + + ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); +} + +// TODO: select vertex should be implemented at BaseSurface level +void SurfaceManager::selectPrevVertex(){ + if(selectedSurface == 0){ + return; + } + + int numVertices = selectedSurface->getVertices().size(); + + if(_selectedVertexIndex > 0){ + _selectedVertexIndex -= 1; + }else{ + _selectedVertexIndex = numVertices - 1; + } + + ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); +} + +void SurfaceManager::selectVertex(int i){ + if(selectedSurface == 0){ + return; + } + + if(i > selectedSurface->getVertices().size() - 1){ + ofLogError("SurfaceManager::selectVertex") << "index (" << i << ") out of bounds" << std::endl; + int prevVertIndex = _selectedVertexIndex; + ofNotifyEvent(vertexUnselectedEvent, prevVertIndex, this); + _selectedVertexIndex = -1; + return; + } + + _selectedVertexIndex = i; + ofNotifyEvent(vertexSelectedEvent, _selectedVertexIndex, this); +} + +void SurfaceManager::moveSelectionBy(Vec3 v){ + if(selectedSurface == 0){ + moveAllSurfacesBy(v); + return; + } + + if(_selectedVertexIndex != -1){ + selectedSurface->getMesh().getVertices()[_selectedVertexIndex] += v.toOf(); + ofNotifyEvent(vertexChangedEvent, _selectedVertexIndex, this); + }else{ + selectedSurface->moveBy(v); + } + + // TODO: instead of having single selected surface + // we want to have a selection of one or more. + // it could be implemented as vector here. +} + +void SurfaceManager::moveAllSurfacesBy(Vec3 v){ + if(_activePresetIndex < 0){ + ofLogWarning( + "SurfaceManager::moveAllSurfacesBy", + "Can not move surfaces. No active preset."); + return; + } + + for(int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ + _presets[_activePresetIndex]->at(i)->moveBy(v); + } +} + +void SurfaceManager::deselectSurface(){ + selectedSurface = 0; + _selectedVertexIndex = -1; +} + +BaseSurface * SurfaceManager::getSurface(int index){ + if(_activePresetIndex < 0){ + throw runtime_error("No active preset."); + return 0; + } + + if(index >= _presets[_activePresetIndex]->size()){ + throw runtime_error("Surface index out of bounds."); + return 0; + } + + return _presets[_activePresetIndex]->at(index); +} + +/* TODO: Solve fundamental question + * What size are we talking about here? + * Is it the number of presets or surfaces? + */ +int SurfaceManager::size(){ + if(_activePresetIndex < 0){ + return 0; + } + + return _presets[_activePresetIndex]->size(); +} + +int SurfaceManager::getSelectedVertexIndex(){ + return _selectedVertexIndex; +} + +int SurfaceManager::getActivePresetIndex(){ + return _activePresetIndex; +} + +int SurfaceManager::getSelectedSurfaceIndex(){ + if(selectedSurface == 0){ + return -1; + } + for(unsigned int i = 0; i < _presets[_activePresetIndex]->size(); ++i){ + if(_presets[_activePresetIndex]->getSurfaces()[i] == selectedSurface){ + return i; + } + } + return -1; +} + +unsigned int SurfaceManager::getNumPresets(){ + return _presets.size(); +} + +void SurfaceManager::onVertexChanged(int & i){ + ofNotifyEvent(vertexChangedEvent, i, this); +} + +void SurfaceManager::onVerticesChanged(std::vector & vertices){ + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +SurfaceStack * SurfaceManager::getActivePreset(){ + if(_activePresetIndex < 0){ + throw runtime_error( + "SurfaceManager::getActivePreset: Can not getActivePreset. No active preset."); + } + + return _presets[_activePresetIndex]; +} + +SurfaceStack * SurfaceManager::createPreset(){ + SurfaceStack * preset = new SurfaceStack(); + _presets.push_back(preset); + + // If we did not have any presets before, set the new as active one. + if(_presets.size() == 1){ + _activePresetIndex = 0; + } + + // Remember to remove these listeners when adding a removePreset method. + ofAddListener( + preset->vertexChangedEvent, + this, + &SurfaceManager::onVertexChanged); + ofAddListener( + preset->verticesChangedEvent, + this, + &SurfaceManager::onVerticesChanged); + + return preset; + + // TODO: Create command for this. And what not. +} + +SurfaceStack * SurfaceManager::getPresetAt(unsigned int i){ + if(i >= _presets.size()){ + throw runtime_error("SurfaceManager::getPresetAt index out of bounds."); + } + return _presets[i]; +} + +void SurfaceManager::setNextPreset(){ + if(_presets.size() <= 1){ + return; + } + + if(_activePresetIndex == _presets.size() - 1){ + _activePresetIndex = 0; + }else{ + _activePresetIndex += 1; + } + + // TODO: Create command for this. +} + +void SurfaceManager::setPresetSourcesActiveState(unsigned int presetIndex, bool state){ + // tell sources associated with current preset that they are not displayed any more + // this is so that we can optionally update the buffers or not. + for (int j=0; j<_presets[presetIndex]->getSurfaces().size(); j++){ + _presets[presetIndex]->getSurfaces()[j]->getSource()->setActive(state); + } +} + +void SurfaceManager::setPreset(unsigned int i){ + cout << "CALLED IT" << endl; + if(_presets.size() <= 1){ + throw runtime_error("ofxPiMapper: No presets to set."); + } + + if(i >= _presets.size()){ + throw runtime_error("ofxPiMapper: Preset index out of bounds."); + } + + //let sources associated with all preset know that they are not being displayed any more + setPresetSourcesActiveState(_activePresetIndex, false); + + //change preset + _activePresetIndex = i; + //let sources associated with NEW preset know that they are now being displayed + setPresetSourcesActiveState(_activePresetIndex, true); + + + //when preset it changed, call reset on all sources, if it's defined + for (int i=0; i<_presets[_activePresetIndex]->getSurfaces().size(); i++){ + + //if source is of type FBO then cast it from BaseSource to FboSource and call the beginFbo function + if (_presets[_activePresetIndex]->getSurfaces()[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ + FboSource *fboSource; + fboSource = (FboSource*)_presets[_activePresetIndex]->getSurfaces()[i]->getSource(); + fboSource->beginFbo(); + } + + _presets[_activePresetIndex]->getSurfaces()[i]->getSource()->reset(); + + //if source is of type FBO then cast it from BaseSource to FboSource and call the endFbo function + if (_presets[_activePresetIndex]->getSurfaces()[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ + FboSource *fboSource; + fboSource = (FboSource*)_presets[_activePresetIndex]->getSurfaces()[i]->getSource(); + fboSource->endFbo(); + } + } +} + +void SurfaceManager::cloneActivePreset(){ + if(_presets.size() <= 0){ + return; + } + + SurfaceStack * preset = _presets[_activePresetIndex]->clone(); + _presets.push_back(preset); + _activePresetIndex = _presets.size() - 1; +} + +void SurfaceManager::eraseActivePreset(){ + if(_presets.size() <= 0){ + return; + } + + _presets[_activePresetIndex]->clear(); + _presets.erase(_presets.begin() + _activePresetIndex); + + _activePresetIndex--; + + if(_presets.size() > 0 && _activePresetIndex < 0){ + _activePresetIndex = 0; + } + + if(_activePresetIndex < 0){ + createPreset(); + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceManager.h b/src/Surfaces/SurfaceManager.h index ff2b2ff..8e18205 100644 --- a/src/Surfaces/SurfaceManager.h +++ b/src/Surfaces/SurfaceManager.h @@ -1,96 +1,96 @@ -#pragma once - -#include "BaseSurface.h" -#include "TriangleSurface.h" -#include "QuadSurface.h" -#include "SurfaceType.h" -#include "MediaServer.h" -#include "BaseSource.h" -#include "SourceType.h" -#include "SurfaceStack.h" -#include "SurfaceFactory.h" -#include "Vec2.h" - -#include "ofEvents.h" -#include "ofxXmlSettings.h" -#include "SettingsLoader.h" - -using namespace std; - -namespace ofx { -namespace piMapper { - -class SurfaceManager { - - public: - SurfaceManager(); - - void draw(); - - void addSurface(BaseSurface * surface); - void removeSelectedSurface(); - void removeSurface(); - void removeSurface(int i); - void deleteSurface(BaseSurface * surface); - void deselectSurface(); - void saveXmlSettings(std::string fileName); - void setMediaServer(MediaServer * newMediaServer); - void clearPresets(); - - bool loadXmlSettings(std::string fileName); - - BaseSurface * getSurface(int index); - BaseSurface * selectSurface(int index); - BaseSurface * selectSurface(BaseSurface * surface); - BaseSurface * selectNextSurface(); - BaseSurface * selectPrevSurface(); - BaseSurface * getSelectedSurface(); - - // These should trigger an event for the GUI layer to catch - void selectNextVertex(); - void selectPrevVertex(); - void selectVertex(int i); - - void fullscreenSurface(); - void moveSelectionBy(Vec3 v); - void moveAllSurfacesBy(Vec3 v); - - int size(); - int getSelectedVertexIndex(); - int getActivePresetIndex(); - int getSelectedSurfaceIndex(); - unsigned int getNumPresets(); - - ofEvent vertexChangedEvent; - ofEvent > verticesChangedEvent; - ofEvent surfaceSelectedEvent; - ofEvent vertexSelectedEvent; - ofEvent vertexUnselectedEvent; - - void onVertexChanged(int & i); - void onVerticesChanged(std::vector & vertices); - - SurfaceStack * getActivePreset(); - SurfaceStack * createPreset(); - SurfaceStack * getPresetAt(unsigned int i); - - void setNextPreset(); - void setPreset(unsigned int i); - void cloneActivePreset(); - void eraseActivePreset(); - void setPresetSourcesActiveState(unsigned int presetIndex, bool state); - - private: - BaseSurface * selectedSurface; - ofxXmlSettings xmlSettings; - MediaServer * mediaServer; - - int _selectedVertexIndex; - int _activePresetIndex; - - std::vector _presets; - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "BaseSurface.h" +#include "TriangleSurface.h" +#include "QuadSurface.h" +#include "SurfaceType.h" +#include "MediaServer.h" +#include "BaseSource.h" +#include "SourceType.h" +#include "SurfaceStack.h" +#include "SurfaceFactory.h" +#include "Vec2.h" + +#include "ofEvents.h" +#include "ofxXmlSettings.h" +#include "SettingsLoader.h" + +using namespace std; + +namespace ofx { +namespace piMapper { + +class SurfaceManager { + + public: + SurfaceManager(); + + void draw(); + + void addSurface(BaseSurface * surface); + void removeSelectedSurface(); + void removeSurface(); + void removeSurface(int i); + void deleteSurface(BaseSurface * surface); + void deselectSurface(); + void saveXmlSettings(std::string fileName); + void setMediaServer(MediaServer * newMediaServer); + void clearPresets(); + + bool loadXmlSettings(std::string fileName); + + BaseSurface * getSurface(int index); + BaseSurface * selectSurface(int index); + BaseSurface * selectSurface(BaseSurface * surface); + BaseSurface * selectNextSurface(); + BaseSurface * selectPrevSurface(); + BaseSurface * getSelectedSurface(); + + // These should trigger an event for the GUI layer to catch + void selectNextVertex(); + void selectPrevVertex(); + void selectVertex(int i); + + void fullscreenSurface(); + void moveSelectionBy(Vec3 v); + void moveAllSurfacesBy(Vec3 v); + + int size(); + int getSelectedVertexIndex(); + int getActivePresetIndex(); + int getSelectedSurfaceIndex(); + unsigned int getNumPresets(); + + ofEvent vertexChangedEvent; + ofEvent > verticesChangedEvent; + ofEvent surfaceSelectedEvent; + ofEvent vertexSelectedEvent; + ofEvent vertexUnselectedEvent; + + void onVertexChanged(int & i); + void onVerticesChanged(std::vector & vertices); + + SurfaceStack * getActivePreset(); + SurfaceStack * createPreset(); + SurfaceStack * getPresetAt(unsigned int i); + + void setNextPreset(); + void setPreset(unsigned int i); + void cloneActivePreset(); + void eraseActivePreset(); + void setPresetSourcesActiveState(unsigned int presetIndex, bool state); + + private: + BaseSurface * selectedSurface; + ofxXmlSettings xmlSettings; + MediaServer * mediaServer; + + int _selectedVertexIndex; + int _activePresetIndex; + + std::vector _presets; + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceStack.cpp b/src/Surfaces/SurfaceStack.cpp index c11a7c9..2c77915 100644 --- a/src/Surfaces/SurfaceStack.cpp +++ b/src/Surfaces/SurfaceStack.cpp @@ -1,86 +1,86 @@ -#include "SurfaceStack.h" - -namespace ofx { -namespace piMapper { - -void SurfaceStack::push_back(BaseSurface * s){ - ofAddListener(s->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); - ofAddListener(s->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); - _surfaces.push_back(s); -} - -void SurfaceStack::pop_back(){ - ofRemoveListener(_surfaces.back()->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); - ofRemoveListener(_surfaces.back()->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); - _surfaces.pop_back(); -} - -void SurfaceStack::erase(int i){ - ofRemoveListener(_surfaces[i]->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); - ofRemoveListener(_surfaces[i]->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); - _surfaces.erase(_surfaces.begin() + i); -} - -void SurfaceStack::swap(int a, int b){ - std::swap(_surfaces[a], _surfaces[b]); -} - -void SurfaceStack::draw(){ - for(int i = 0; i < _surfaces.size(); ++i){ - if(_surfaces[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - }else{ - ofEnableAlphaBlending(); - } - - _surfaces[i]->draw(); - } -} - -void SurfaceStack::clear(){ - for(int i = 0; i < size(); ++i){ - ofRemoveListener(_surfaces[i]->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); - ofRemoveListener(_surfaces[i]->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); - } - _surfaces.clear(); -} - -int SurfaceStack::size(){ - return _surfaces.size(); -} - -BaseSurface * SurfaceStack::operator[](int i){ - return at(i); -} - -BaseSurface * SurfaceStack::at(int i){ - if(i >= _surfaces.size()){ - throw runtime_error("SurfaceStack index out of bounds"); - } - return _surfaces[i]; -} - -BaseSurface * SurfaceStack::back(){ - return _surfaces.back(); -} - -void SurfaceStack::onVerticesChanged(std::vector & vertices){ - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void SurfaceStack::onVertexChanged(int & i){ - ofNotifyEvent(vertexChangedEvent, i, this); -} - -SurfaceStack * SurfaceStack::clone(){ - SurfaceStack * stack = new SurfaceStack(); - for(unsigned int i = 0; i < _surfaces.size(); ++i){ - BaseSurface * surface = _surfaces[i]->clone(); - stack->push_back(surface); - } - return stack; -} - -} // namespace piMapper -} // namespace ofx +#include "SurfaceStack.h" + +namespace ofx { +namespace piMapper { + +void SurfaceStack::push_back(BaseSurface * s){ + ofAddListener(s->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); + ofAddListener(s->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); + _surfaces.push_back(s); +} + +void SurfaceStack::pop_back(){ + ofRemoveListener(_surfaces.back()->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); + ofRemoveListener(_surfaces.back()->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); + _surfaces.pop_back(); +} + +void SurfaceStack::erase(int i){ + ofRemoveListener(_surfaces[i]->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); + ofRemoveListener(_surfaces[i]->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); + _surfaces.erase(_surfaces.begin() + i); +} + +void SurfaceStack::swap(int a, int b){ + std::swap(_surfaces[a], _surfaces[b]); +} + +void SurfaceStack::draw(){ + for(int i = 0; i < _surfaces.size(); ++i){ + if(_surfaces[i]->getSource()->getType() == SourceType::SOURCE_TYPE_FBO){ + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + }else{ + ofEnableAlphaBlending(); + } + + _surfaces[i]->draw(); + } +} + +void SurfaceStack::clear(){ + for(int i = 0; i < size(); ++i){ + ofRemoveListener(_surfaces[i]->verticesChangedEvent, this, &SurfaceStack::onVerticesChanged); + ofRemoveListener(_surfaces[i]->vertexChangedEvent, this, &SurfaceStack::onVertexChanged); + } + _surfaces.clear(); +} + +int SurfaceStack::size(){ + return _surfaces.size(); +} + +BaseSurface * SurfaceStack::operator[](int i){ + return at(i); +} + +BaseSurface * SurfaceStack::at(int i){ + if(i >= _surfaces.size()){ + throw runtime_error("SurfaceStack index out of bounds"); + } + return _surfaces[i]; +} + +BaseSurface * SurfaceStack::back(){ + return _surfaces.back(); +} + +void SurfaceStack::onVerticesChanged(std::vector & vertices){ + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void SurfaceStack::onVertexChanged(int & i){ + ofNotifyEvent(vertexChangedEvent, i, this); +} + +SurfaceStack * SurfaceStack::clone(){ + SurfaceStack * stack = new SurfaceStack(); + for(unsigned int i = 0; i < _surfaces.size(); ++i){ + BaseSurface * surface = _surfaces[i]->clone(); + stack->push_back(surface); + } + return stack; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceStack.h b/src/Surfaces/SurfaceStack.h index 98d19b6..37a3cf2 100644 --- a/src/Surfaces/SurfaceStack.h +++ b/src/Surfaces/SurfaceStack.h @@ -1,39 +1,39 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" - -namespace ofx { -namespace piMapper { - -class SurfaceStack { - public: - void push_back(BaseSurface * s); - void pop_back(); - void erase(int i); - void swap(int a, int b); - void draw(); - void clear(); - - int size(); - - BaseSurface * operator[](int i); - BaseSurface * at(int i); - BaseSurface * back(); - - ofEvent > verticesChangedEvent; - ofEvent vertexChangedEvent; - - void onVerticesChanged(std::vector & vertices); - void onVertexChanged(int & i); - - std::vector & getSurfaces(){ return _surfaces; }; - - SurfaceStack * clone(); - - private: - std::vector _surfaces; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" + +namespace ofx { +namespace piMapper { + +class SurfaceStack { + public: + void push_back(BaseSurface * s); + void pop_back(); + void erase(int i); + void swap(int a, int b); + void draw(); + void clear(); + + int size(); + + BaseSurface * operator[](int i); + BaseSurface * at(int i); + BaseSurface * back(); + + ofEvent > verticesChangedEvent; + ofEvent vertexChangedEvent; + + void onVerticesChanged(std::vector & vertices); + void onVertexChanged(int & i); + + std::vector & getSurfaces(){ return _surfaces; }; + + SurfaceStack * clone(); + + private: + std::vector _surfaces; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/SurfaceType.h b/src/Surfaces/SurfaceType.h index b039427..1f37c66 100644 --- a/src/Surfaces/SurfaceType.h +++ b/src/Surfaces/SurfaceType.h @@ -1,16 +1,16 @@ -#pragma once - -namespace ofx { -namespace piMapper { - -enum SurfaceType{ - TRIANGLE_SURFACE, - QUAD_SURFACE, - GRID_WARP_SURFACE, - HEXAGON_SURFACE, - NONE, - CIRCLE_SURFACE -}; - -} // namespace piMapper +#pragma once + +namespace ofx { +namespace piMapper { + +enum SurfaceType{ + TRIANGLE_SURFACE, + QUAD_SURFACE, + GRID_WARP_SURFACE, + HEXAGON_SURFACE, + NONE, + CIRCLE_SURFACE +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Surfaces/TriangleSurface.cpp b/src/Surfaces/TriangleSurface.cpp index 512bee9..a965d48 100644 --- a/src/Surfaces/TriangleSurface.cpp +++ b/src/Surfaces/TriangleSurface.cpp @@ -1,203 +1,203 @@ -#include "TriangleSurface.h" - -namespace ofx { -namespace piMapper { - -TriangleSurface::TriangleSurface(){ - setup(); -} - -void TriangleSurface::setup(){ - - // Create 3 points for the triangle - Vec3 p1 = Vec3((float)ofGetWidth() / 2.0f, 0.0f, 0.0f); - Vec3 p2 = Vec3(0.0f, (float)ofGetHeight(), 0.0f); - Vec3 p3 = Vec3((float)ofGetWidth(), (float)ofGetHeight(), 0.0f); - - // Create 3 point for the texture coordinates - Vec2 t1 = Vec2(0.5f, 0.0f); - Vec2 t2 = Vec2(0.0f, 1.0f); - Vec2 t3 = Vec2(1.0f, 1.0f); - - setup(p1, p2, p3, t1, t2, t3, source); -} - -void TriangleSurface::setup(Vec3 p1, Vec3 p2, Vec3 p3, Vec2 t1, - Vec2 t2, Vec2 t3, BaseSource * newSource){ - // Assign texture - source = newSource; - - // Clear mesh - mesh.clear(); - - // Create a surface with the points - mesh.addVertex(p1.toOf()); - mesh.addVertex(p2.toOf()); - mesh.addVertex(p3.toOf()); - - // Add texture coordinates - mesh.addTexCoord(t1.toOf()); - mesh.addTexCoord(t2.toOf()); - mesh.addTexCoord(t3.toOf()); -} - -void TriangleSurface::draw(){ - if(source->getTexture() == 0){ - return; - } - - if(!source->getTexture()->isAllocated()){ - return; - } - - bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); - ofEnableNormalizedTexCoords(); - - source->getTexture()->bind(); - mesh.draw(); - source->getTexture()->unbind(); - - if(!normalizedTexCoords){ - ofDisableNormalizedTexCoords(); - } -} - -void TriangleSurface::setVertex(int index, Vec3 p){ - if(index > 2){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - return; - } - - mesh.setVertex(index, p.toOf()); - ofNotifyEvent(vertexChangedEvent, index, this); -} - -void TriangleSurface::setVertices(std::vector v){ - if(v.size() != 3){ - throw runtime_error("Wrong number of vertices"); - } - - for(int i = 0; i < 3; ++i){ - mesh.setVertex(i, v[i].toOf()); - } - - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void TriangleSurface::setTexCoord(int index, Vec2 t){ - if(index > 2){ - ofLog() << "Texture coordinate with this index does not exist: " << index - << std::endl; - return; - } - - mesh.setTexCoord(index, t.toOf()); -} - -void TriangleSurface::setTexCoords(std::vector t){ - if(t.size() != 3){ - throw runtime_error("Wrong number of texture coordinates"); - } - - for(int i = 0; i < 3; ++i){ - mesh.setTexCoord(i, t[i].toOf()); - } -} - -void TriangleSurface::moveBy(Vec3 v){ - for(auto i = 0; i < mesh.getVertices().size(); ++i){ - mesh.getVertices()[i] += v.toOf(); - } - - setMoved(true); - std::vector vertices = Vec3::fromOf(mesh.getVertices()); - ofNotifyEvent(verticesChangedEvent, vertices, this); -} - -void TriangleSurface::fullScreen(){ - -} - -int TriangleSurface::getType(){ - return SurfaceType::TRIANGLE_SURFACE; -} - -bool TriangleSurface::hitTest(Vec2 p){ - ofPolyline line = getHitArea(); - - if(line.inside(p.x, p.y)){ - return true; - }else{ - return false; - } -} - -Vec2 TriangleSurface::getVertex(int index){ - if(index > 2){ - ofLog() << "Vertex with this index does not exist: " << index << std::endl; - throw runtime_error("Vertex index out of bounds."); - } - - return Vec2( - mesh.getVertex(index).x, - mesh.getVertex(index).y); -} - -Vec2 TriangleSurface::getTexCoord(int index){ - if(index > 2){ - ofLog() << "Texture coordinate with this index does not exist: " << index << std::endl; - throw runtime_error("Texture coordinate index out of bounds."); - } - - return Vec2( - mesh.getTexCoord(index).x, - mesh.getTexCoord(index).y); -} - -ofPolyline TriangleSurface::getHitArea(){ - ofPolyline line; - - line.addVertex(ofPoint(mesh.getVertex(0).x, mesh.getVertex(0).y)); - line.addVertex(ofPoint(mesh.getVertex(1).x, mesh.getVertex(1).y)); - line.addVertex(ofPoint(mesh.getVertex(2).x, mesh.getVertex(2).y)); - line.close(); - - return line; -} - -ofPolyline TriangleSurface::getTextureHitArea(){ - ofPolyline line; - - Vec2 textureSize = Vec2( - source->getTexture()->getWidth(), - source->getTexture()->getHeight()); - - for(int i = 0; i < mesh.getTexCoords().size(); i++){ - line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); - } - - line.close(); - return line; -} - -std::vector TriangleSurface::getVertices(){ - return Vec3::fromOf(mesh.getVertices()); -} - -std::vector TriangleSurface::getTexCoords(){ - return Vec2::fromOf(mesh.getTexCoords()); -} - -BaseSurface * TriangleSurface::clone(){ - TriangleSurface * s = new TriangleSurface(); - s->setVertices(getVertices()); - s->setTexCoords(getTexCoords()); - BaseSource * src = getSource(); - src->referenceCount++; - s->setSource(src); - return s; -} - -} // namespace piMapper -} // namespace ofx +#include "TriangleSurface.h" + +namespace ofx { +namespace piMapper { + +TriangleSurface::TriangleSurface(){ + setup(); +} + +void TriangleSurface::setup(){ + + // Create 3 points for the triangle + Vec3 p1 = Vec3((float)ofGetWidth() / 2.0f, 0.0f, 0.0f); + Vec3 p2 = Vec3(0.0f, (float)ofGetHeight(), 0.0f); + Vec3 p3 = Vec3((float)ofGetWidth(), (float)ofGetHeight(), 0.0f); + + // Create 3 point for the texture coordinates + Vec2 t1 = Vec2(0.5f, 0.0f); + Vec2 t2 = Vec2(0.0f, 1.0f); + Vec2 t3 = Vec2(1.0f, 1.0f); + + setup(p1, p2, p3, t1, t2, t3, source); +} + +void TriangleSurface::setup(Vec3 p1, Vec3 p2, Vec3 p3, Vec2 t1, + Vec2 t2, Vec2 t3, BaseSource * newSource){ + // Assign texture + source = newSource; + + // Clear mesh + mesh.clear(); + + // Create a surface with the points + mesh.addVertex(p1.toOf()); + mesh.addVertex(p2.toOf()); + mesh.addVertex(p3.toOf()); + + // Add texture coordinates + mesh.addTexCoord(t1.toOf()); + mesh.addTexCoord(t2.toOf()); + mesh.addTexCoord(t3.toOf()); +} + +void TriangleSurface::draw(){ + if(source->getTexture() == 0){ + return; + } + + if(!source->getTexture()->isAllocated()){ + return; + } + + bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); + ofEnableNormalizedTexCoords(); + + source->getTexture()->bind(); + mesh.draw(); + source->getTexture()->unbind(); + + if(!normalizedTexCoords){ + ofDisableNormalizedTexCoords(); + } +} + +void TriangleSurface::setVertex(int index, Vec3 p){ + if(index > 2){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + return; + } + + mesh.setVertex(index, p.toOf()); + ofNotifyEvent(vertexChangedEvent, index, this); +} + +void TriangleSurface::setVertices(std::vector v){ + if(v.size() != 3){ + throw runtime_error("Wrong number of vertices"); + } + + for(int i = 0; i < 3; ++i){ + mesh.setVertex(i, v[i].toOf()); + } + + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void TriangleSurface::setTexCoord(int index, Vec2 t){ + if(index > 2){ + ofLog() << "Texture coordinate with this index does not exist: " << index + << std::endl; + return; + } + + mesh.setTexCoord(index, t.toOf()); +} + +void TriangleSurface::setTexCoords(std::vector t){ + if(t.size() != 3){ + throw runtime_error("Wrong number of texture coordinates"); + } + + for(int i = 0; i < 3; ++i){ + mesh.setTexCoord(i, t[i].toOf()); + } +} + +void TriangleSurface::moveBy(Vec3 v){ + for(auto i = 0; i < mesh.getVertices().size(); ++i){ + mesh.getVertices()[i] += v.toOf(); + } + + setMoved(true); + std::vector vertices = Vec3::fromOf(mesh.getVertices()); + ofNotifyEvent(verticesChangedEvent, vertices, this); +} + +void TriangleSurface::fullScreen(){ + +} + +int TriangleSurface::getType(){ + return SurfaceType::TRIANGLE_SURFACE; +} + +bool TriangleSurface::hitTest(Vec2 p){ + ofPolyline line = getHitArea(); + + if(line.inside(p.x, p.y)){ + return true; + }else{ + return false; + } +} + +Vec2 TriangleSurface::getVertex(int index){ + if(index > 2){ + ofLog() << "Vertex with this index does not exist: " << index << std::endl; + throw runtime_error("Vertex index out of bounds."); + } + + return Vec2( + mesh.getVertex(index).x, + mesh.getVertex(index).y); +} + +Vec2 TriangleSurface::getTexCoord(int index){ + if(index > 2){ + ofLog() << "Texture coordinate with this index does not exist: " << index << std::endl; + throw runtime_error("Texture coordinate index out of bounds."); + } + + return Vec2( + mesh.getTexCoord(index).x, + mesh.getTexCoord(index).y); +} + +ofPolyline TriangleSurface::getHitArea(){ + ofPolyline line; + + line.addVertex(ofPoint(mesh.getVertex(0).x, mesh.getVertex(0).y)); + line.addVertex(ofPoint(mesh.getVertex(1).x, mesh.getVertex(1).y)); + line.addVertex(ofPoint(mesh.getVertex(2).x, mesh.getVertex(2).y)); + line.close(); + + return line; +} + +ofPolyline TriangleSurface::getTextureHitArea(){ + ofPolyline line; + + Vec2 textureSize = Vec2( + source->getTexture()->getWidth(), + source->getTexture()->getHeight()); + + for(int i = 0; i < mesh.getTexCoords().size(); i++){ + line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); + } + + line.close(); + return line; +} + +std::vector TriangleSurface::getVertices(){ + return Vec3::fromOf(mesh.getVertices()); +} + +std::vector TriangleSurface::getTexCoords(){ + return Vec2::fromOf(mesh.getTexCoords()); +} + +BaseSurface * TriangleSurface::clone(){ + TriangleSurface * s = new TriangleSurface(); + s->setVertices(getVertices()); + s->setTexCoords(getTexCoords()); + BaseSource * src = getSource(); + src->referenceCount++; + s->setSource(src); + return s; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Surfaces/TriangleSurface.h b/src/Surfaces/TriangleSurface.h index 764aa8b..64cef46 100644 --- a/src/Surfaces/TriangleSurface.h +++ b/src/Surfaces/TriangleSurface.h @@ -1,42 +1,42 @@ -#pragma once - -#include "ofMain.h" -#include "BaseSurface.h" -#include "SurfaceType.h" -#include "Vec2.h" -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -class TriangleSurface : public BaseSurface { - public: - TriangleSurface(); - - void setup(); - void setup( - Vec3 p1, Vec3 p2, Vec3 p3, - Vec2 t1, Vec2 t2, Vec2 t3, - BaseSource * newSource); - void draw(); - void setVertex(int index, Vec3 p); - void setVertices(std::vector v); - void setTexCoord(int index, Vec2 t); - void setTexCoords(std::vector t); - void moveBy(Vec3 v); - void fullScreen(); - - int getType(); - bool hitTest(Vec2 p); - Vec2 getVertex(int index); - Vec2 getTexCoord(int index); - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - std::vector getVertices(); - std::vector getTexCoords(); - - BaseSurface * clone(); -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" +#include "Vec2.h" +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +class TriangleSurface : public BaseSurface { + public: + TriangleSurface(); + + void setup(); + void setup( + Vec3 p1, Vec3 p2, Vec3 p3, + Vec2 t1, Vec2 t2, Vec2 t3, + BaseSource * newSource); + void draw(); + void setVertex(int index, Vec3 p); + void setVertices(std::vector v); + void setTexCoord(int index, Vec2 t); + void setTexCoords(std::vector t); + void moveBy(Vec3 v); + void fullScreen(); + + int getType(); + bool hitTest(Vec2 p); + Vec2 getVertex(int index); + Vec2 getTexCoord(int index); + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + std::vector getVertices(); + std::vector getTexCoords(); + + BaseSurface * clone(); +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Types/Vec2.cpp b/src/Types/Vec2.cpp index a812fcf..f6daec4 100644 --- a/src/Types/Vec2.cpp +++ b/src/Types/Vec2.cpp @@ -1,129 +1,94 @@ -#include "Vec2.h" - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR > 9 - #include "glm/geometric.hpp" -#endif - -namespace ofx { -namespace piMapper { - -Vec2::Vec2(){ - Vec2(0.0f, 0.0f); -} - -Vec2::Vec2(float ix, float iy){ - x = ix; - y = iy; -} - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - Vec2::Vec2(ofVec2f & src){ - x = src.x; - y = src.y; - } - - ofVec2f Vec2::toOf(){ - return ofVec2f(x, y); - } - - std::vector Vec2::toOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(itm.toOf()); - } - return retVal; - } - - std::vector Vec2::fromOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(Vec2(itm)); - } - return retVal; - } - - float Vec2::distance(const Vec2 & other){ - ofVec2f v1(x, y); - ofVec2f v2(other.x, other.y); - return v1.distance(v2); - } -#else - Vec2::Vec2(glm::vec2 & src){ - x = src.x; - y = src.y; - } - - glm::vec2 Vec2::toOf(){ - return glm::vec2(x, y); - } - - std::vector Vec2::toOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(itm.toOf()); - } - return retVal; - } - - std::vector Vec2::fromOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(Vec2(itm)); - } - return retVal; - } - - float Vec2::distance(const Vec2 & other){ - glm::vec2 v1(x, y); - glm::vec2 v2(other.x, other.y); - - return glm::distance(v1, v2); - } -#endif - -void Vec2::operator=(const Vec2 & other){ - x = other.x; - y = other.y; -} - -void Vec2::operator+=(const Vec2 & other){ - x += other.x; - y += other.y; -} - -Vec2 Vec2::operator+(const Vec2 & other){ - return Vec2(x + other.x, y + other.y); -} - -Vec2 Vec2::operator-(){ - return Vec2(-x, -y); -} - -Vec2 Vec2::operator-(const Vec2 & other){ - return Vec2(x - other.x, y - other.y); -} - -Vec2 Vec2::operator*(const Vec2 & other){ - return Vec2(x * other.x, y * other.y); -} - -Vec2 Vec2::operator/(const Vec2 & other){ - return Vec2(x / other.x, y / other.y); -} - -bool Vec2::operator==(const Vec2 & other){ - if(x == other.x && y == other.y){ - return true; - } - return false; -} - -bool Vec2::operator!=(const Vec2 & other){ - if(x != other.x && y != other.y){ - return true; - } - return false; -} - -} // namespace piMapper -} // namespace ofx +#include "Vec2.h" + +#include "glm/geometric.hpp" + +namespace ofx { +namespace piMapper { + +Vec2::Vec2() : x(0.0f), y(0.0f) {} + + +Vec2::Vec2(float ix, float iy){ + x = ix; + y = iy; +} + + +Vec2::Vec2(glm::vec2 & src){ + x = src.x; + y = src.y; +} + +glm::vec2 Vec2::toOf(){ + return glm::vec2(x, y); +} + +std::vector Vec2::toOf(std::vector & src){ + std::vector retVal; + for(auto itm : src){ + retVal.push_back(itm.toOf()); + } + return retVal; +} + +std::vector Vec2::fromOf(std::vector & src){ + std::vector retVal; + for(auto itm : src){ + retVal.push_back(Vec2(itm)); + } + return retVal; +} + +float Vec2::distance(const Vec2 & other){ + glm::vec2 v1(x, y); + glm::vec2 v2(other.x, other.y); + + return glm::distance(v1, v2); +} + +void Vec2::operator=(const Vec2 & other){ + x = other.x; + y = other.y; +} + +void Vec2::operator+=(const Vec2 & other){ + x += other.x; + y += other.y; +} + +Vec2 Vec2::operator+(const Vec2 & other){ + return Vec2(x + other.x, y + other.y); +} + +Vec2 Vec2::operator-(){ + return Vec2(-x, -y); +} + +Vec2 Vec2::operator-(const Vec2 & other){ + return Vec2(x - other.x, y - other.y); +} + +Vec2 Vec2::operator*(const Vec2 & other){ + return Vec2(x * other.x, y * other.y); +} + +Vec2 Vec2::operator/(const Vec2 & other){ + return Vec2(x / other.x, y / other.y); +} + +bool Vec2::operator==(const Vec2 & other){ + if(x == other.x && y == other.y){ + return true; + } + return false; +} + +bool Vec2::operator!=(const Vec2 & other){ + if(x != other.x && y != other.y){ + return true; + } + return false; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Types/Vec2.h b/src/Types/Vec2.h index 80a86fe..8242e39 100644 --- a/src/Types/Vec2.h +++ b/src/Types/Vec2.h @@ -1,49 +1,39 @@ -#pragma once - -#include - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - #include "ofVec2f.h" -#else - #include "glm/vec2.hpp" -#endif - -namespace ofx { -namespace piMapper { - -class Vec2{ -public: - Vec2(); - Vec2(float ix, float iy); - - // TODO: Achieve this with templates - #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - Vec2(ofVec2f & src); - ofVec2f toOf(); - static std::vector toOf(std::vector & src); - static std::vector fromOf(std::vector & src); - #else - Vec2(glm::vec2 & src); - glm::vec2 toOf(); - static std::vector toOf(std::vector & src); - static std::vector fromOf(std::vector & src); - #endif - - float distance(const Vec2 & other); - - void operator=(const Vec2 & other); - void operator+=(const Vec2 & other); - Vec2 operator+(const Vec2 & other); - Vec2 operator-(); - Vec2 operator-(const Vec2 & other); - Vec2 operator*(const Vec2 & other); - Vec2 operator/(const Vec2 & other); - bool operator==(const Vec2 & other); - bool operator!=(const Vec2 & other); - - float x; - float y; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include +#include "glm/vec2.hpp" + + +namespace ofx { +namespace piMapper { + +class Vec2{ +public: + Vec2(); + Vec2(float ix, float iy); + + + Vec2(glm::vec2 & src); + glm::vec2 toOf(); + static std::vector toOf(std::vector & src); + static std::vector fromOf(std::vector & src); + + + float distance(const Vec2 & other); + + void operator=(const Vec2 & other); + void operator+=(const Vec2 & other); + Vec2 operator+(const Vec2 & other); + Vec2 operator-(); + Vec2 operator-(const Vec2 & other); + Vec2 operator*(const Vec2 & other); + Vec2 operator/(const Vec2 & other); + bool operator==(const Vec2 & other); + bool operator!=(const Vec2 & other); + + float x; + float y; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/Types/Vec3.cpp b/src/Types/Vec3.cpp index dda8c91..9e84781 100644 --- a/src/Types/Vec3.cpp +++ b/src/Types/Vec3.cpp @@ -1,149 +1,121 @@ -#include "Vec3.h" - -namespace ofx { -namespace piMapper { - -Vec3::Vec3(){ - Vec3(0.0f, 0.0f, 0.0f); -} - -Vec3::Vec3(float ix, float iy, float iz){ - x = ix; - y = iy; - z = iz; -} - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - Vec3::Vec3(ofVec3f & src){ - x = src.x; - y = src.y; - z = src.z; - } - - ofVec3f Vec3::toOf(){ - return ofVec3f(x, y, z); - } - - std::vector Vec3::toOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(itm.toOf()); - } - return retVal; - } - - std::vector Vec3::fromOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(Vec3(itm)); - } - return retVal; - } -#else - Vec3::Vec3(glm::vec3 & src){ - x = src.x; - y = src.y; - z = src.z; - } - - glm::vec3 Vec3::toOf(){ - return ofVec3f(x, y, z); - } - - std::vector Vec3::toOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(itm.toOf()); - } - return retVal; - } - - std::vector Vec3::fromOf(std::vector & src){ - std::vector retVal; - for(auto itm : src){ - retVal.push_back(Vec3(itm)); - } - return retVal; - } -#endif - -void Vec3::operator=(const Vec3 & other){ - x = other.x; - y = other.y; - z = other.z; -} - -void Vec3::operator+=(const Vec3 & other){ - x += other.x; - y += other.y; - z += other.z; -} - -void Vec3::operator*=(const Vec3 & other){ - x *= other.x; - y *= other.y; - z *= other.z; -} - -void Vec3::operator*=(float n){ - x *= n; - y *= n; - z *= n; -} - -void Vec3::operator/=(const Vec3 & other){ - x /= other.x; - y /= other.y; - z /= other.z; -} - -void Vec3::operator/=(float n){ - x /= n; - y /= n; - z /= n; -} - -Vec3 Vec3::operator+(const Vec3 & other){ - return Vec3(x + other.x, y + other.y, z + other.z); -} - -Vec3 Vec3::operator-(){ - return Vec3(-x, -y, -z); -} - -Vec3 Vec3::operator-(const Vec3 & other){ - return Vec3(x - other.x, y - other.y, z - other.z); -} - -Vec3 Vec3::operator*(const Vec3 & other){ - return Vec3(x * other.x, y * other.y, z * other.z); -} - -Vec3 Vec3::operator*(float n){ - return Vec3(x * n, y * n, z * n); -} - -Vec3 Vec3::operator/(const Vec3 & other){ - return Vec3(x / other.x, y / other.y, z / other.z); -} - -Vec3 Vec3::operator/(float n){ - return Vec3(x / n, y / n, z / n); -} - -bool Vec3::operator==(const Vec3 & other){ - if(x == other.x && y == other.y && z == other.z){ - return true; - } - return false; -} - -bool Vec3::operator!=(const Vec3 & other){ - if(x != other.x && y != other.y && z != other.z){ - return true; - } - return false; -} - -} // namespace piMapper -} // namespace ofx +#include "Vec3.h" + +namespace ofx { +namespace piMapper { + +Vec3::Vec3() : x(0.0f), y(0.0f), z(0.0f) {} + + +Vec3::Vec3(float ix, float iy, float iz){ + x = ix; + y = iy; + z = iz; +} + + +Vec3::Vec3(glm::vec3 & src){ + x = src.x; + y = src.y; + z = src.z; +} + +glm::vec3 Vec3::toOf(){ + return ofVec3f(x, y, z); +} + +std::vector Vec3::toOf(std::vector & src){ + std::vector retVal; + for(auto itm : src){ + retVal.push_back(itm.toOf()); + } + return retVal; +} + +std::vector Vec3::fromOf(std::vector & src){ + std::vector retVal; + for(auto itm : src){ + retVal.push_back(Vec3(itm)); + } + return retVal; +} + +void Vec3::operator=(const Vec3 & other){ + x = other.x; + y = other.y; + z = other.z; +} + +void Vec3::operator+=(const Vec3 & other){ + x += other.x; + y += other.y; + z += other.z; +} + +void Vec3::operator*=(const Vec3 & other){ + x *= other.x; + y *= other.y; + z *= other.z; +} + +void Vec3::operator*=(float n){ + x *= n; + y *= n; + z *= n; +} + +void Vec3::operator/=(const Vec3 & other){ + x /= other.x; + y /= other.y; + z /= other.z; +} + +void Vec3::operator/=(float n){ + x /= n; + y /= n; + z /= n; +} + +Vec3 Vec3::operator+(const Vec3 & other){ + return Vec3(x + other.x, y + other.y, z + other.z); +} + +Vec3 Vec3::operator-(){ + return Vec3(-x, -y, -z); +} + +Vec3 Vec3::operator-(const Vec3 & other){ + return Vec3(x - other.x, y - other.y, z - other.z); +} + +Vec3 Vec3::operator*(const Vec3 & other){ + return Vec3(x * other.x, y * other.y, z * other.z); +} + +Vec3 Vec3::operator*(float n){ + return Vec3(x * n, y * n, z * n); +} + +Vec3 Vec3::operator/(const Vec3 & other){ + return Vec3(x / other.x, y / other.y, z / other.z); +} + +Vec3 Vec3::operator/(float n){ + return Vec3(x / n, y / n, z / n); +} + +bool Vec3::operator==(const Vec3 & other){ + if(x == other.x && y == other.y && z == other.z){ + return true; + } + return false; +} + +bool Vec3::operator!=(const Vec3 & other){ + if(x != other.x && y != other.y && z != other.z){ + return true; + } + return false; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/Types/Vec3.h b/src/Types/Vec3.h index edce17f..b16e7d0 100644 --- a/src/Types/Vec3.h +++ b/src/Types/Vec3.h @@ -1,54 +1,48 @@ -#pragma once - -#include - -#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - #include "ofVec3f.h" -#else - #include "glm/vec3.hpp" -#endif - -namespace ofx { -namespace piMapper { - -class Vec3{ -public: - Vec3(); - Vec3(float ix, float iy, float iz); - - // TODO: achieve this with templates - #if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 - Vec3(ofVec3f & src); - ofVec3f toOf(); - static std::vector toOf(std::vector & src); - static std::vector fromOf(std::vector & src); - #else - Vec3(glm::vec3 & src); - glm::vec3 toOf(); - static std::vector toOf(std::vector & src); - static std::vector fromOf(std::vector & src); - #endif - - void operator=(const Vec3 & other); - void operator+=(const Vec3 & other); - void operator*=(const Vec3 & other); - void operator*=(float n); - void operator/=(const Vec3 & other); - void operator/=(float n); - Vec3 operator+(const Vec3 & other); - Vec3 operator-(); - Vec3 operator-(const Vec3 & other); - Vec3 operator*(const Vec3 & other); - Vec3 operator*(float n); - Vec3 operator/(const Vec3 & other); - Vec3 operator/(float n); - bool operator==(const Vec3 & other); - bool operator!=(const Vec3 & other); - - float x; - float y; - float z; -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include + +#if OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR <= 9 + #include "ofVec3f.h" +#else + #include "glm/vec3.hpp" +#endif + +namespace ofx { +namespace piMapper { + +class Vec3{ +public: + Vec3(); + Vec3(float ix, float iy, float iz); + + + Vec3(glm::vec3 & src); + glm::vec3 toOf(); + static std::vector toOf(std::vector & src); + static std::vector fromOf(std::vector & src); + + + void operator=(const Vec3 & other); + void operator+=(const Vec3 & other); + void operator*=(const Vec3 & other); + void operator*=(float n); + void operator/=(const Vec3 & other); + void operator/=(float n); + Vec3 operator+(const Vec3 & other); + Vec3 operator-(); + Vec3 operator-(const Vec3 & other); + Vec3 operator*(const Vec3 & other); + Vec3 operator*(float n); + Vec3 operator/(const Vec3 & other); + Vec3 operator/(float n); + bool operator==(const Vec3 & other); + bool operator!=(const Vec3 & other); + + float x; + float y; + float z; +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/UserInterface/BaseJoint.cpp b/src/UserInterface/BaseJoint.cpp index ea81453..8d718f0 100644 --- a/src/UserInterface/BaseJoint.cpp +++ b/src/UserInterface/BaseJoint.cpp @@ -1,75 +1,75 @@ -#include "BaseJoint.h" - -namespace ofx { -namespace piMapper { - -BaseJoint::BaseJoint(){ - setDefaultColors(); - setDefaultProperties(); -} - -void BaseJoint::mousePressed(ofMouseEventArgs & args){ - if(hitTest(Vec2(args.x, args.y))){ - Vec2 clickPosition(args.x, args.y); - clickDistance = position - clickPosition; - } -} - -void BaseJoint::mouseReleased(int x, int y, int button){ - stopDrag(); -} - -void BaseJoint::mouseDragged(ofMouseEventArgs & args){ - if(!bDrag){ - return; - } - position = Vec2(args.x, args.y) + clickDistance; -} - -void BaseJoint::startDrag(){ - bDrag = true; -} - -void BaseJoint::stopDrag(){ - bDrag = false; -} - -void BaseJoint::select(){ - selected = true; -} - -void BaseJoint::unselect(){ - selected = false; -} - -void BaseJoint::setClickDistance(Vec2 newClickDistance){ - clickDistance = newClickDistance; -} - -bool BaseJoint::isDragged(){ - return bDrag; -} - -bool BaseJoint::isSelected(){ - return selected; -} - -void BaseJoint::setDefaultColors(){ - fillColor = ofColor(0, 255, 255, 0); - strokeColor = ofColor(255, 255, 255); - fillColorSelected = ofColor(255, 255, 0, 0); - strokeColorSelected = ofColor(255, 0, 0); -} - -void BaseJoint::setDefaultProperties(){ - enabled = true; - visible = true; - position = Vec2(20.0f, 20.0f); - clickDistance = Vec2(0.0f, 0.0f); - bDrag = false; - selected = false; - strokeWidth = 1.5f; -} - -} // namespace piMapper -} // namespace ofx +#include "BaseJoint.h" + +namespace ofx { +namespace piMapper { + +BaseJoint::BaseJoint(){ + setDefaultColors(); + setDefaultProperties(); +} + +void BaseJoint::mousePressed(ofMouseEventArgs & args){ + if(hitTest(Vec2(args.x, args.y))){ + Vec2 clickPosition(args.x, args.y); + clickDistance = position - clickPosition; + } +} + +void BaseJoint::mouseReleased(int x, int y, int button){ + stopDrag(); +} + +void BaseJoint::mouseDragged(ofMouseEventArgs & args){ + if(!bDrag){ + return; + } + position = Vec2(args.x, args.y) + clickDistance; +} + +void BaseJoint::startDrag(){ + bDrag = true; +} + +void BaseJoint::stopDrag(){ + bDrag = false; +} + +void BaseJoint::select(){ + selected = true; +} + +void BaseJoint::unselect(){ + selected = false; +} + +void BaseJoint::setClickDistance(Vec2 newClickDistance){ + clickDistance = newClickDistance; +} + +bool BaseJoint::isDragged(){ + return bDrag; +} + +bool BaseJoint::isSelected(){ + return selected; +} + +void BaseJoint::setDefaultColors(){ + fillColor = ofColor(0, 255, 255, 0); + strokeColor = ofColor(255, 255, 255); + fillColorSelected = ofColor(255, 255, 0, 0); + strokeColorSelected = ofColor(255, 0, 0); +} + +void BaseJoint::setDefaultProperties(){ + enabled = true; + visible = true; + position = Vec2(20.0f, 20.0f); + clickDistance = Vec2(0.0f, 0.0f); + bDrag = false; + selected = false; + strokeWidth = 1.5f; +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/UserInterface/BaseJoint.h b/src/UserInterface/BaseJoint.h index ddae2a8..66c8490 100644 --- a/src/UserInterface/BaseJoint.h +++ b/src/UserInterface/BaseJoint.h @@ -1,51 +1,51 @@ -#pragma once - -#include "ofMain.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { - -class BaseJoint { - - public: - BaseJoint(); - - Vec2 position; - bool enabled; - bool visible; - bool selected; - - void mousePressed(ofMouseEventArgs & args); - void mouseReleased(int x, int y, int button); - void mouseDragged(ofMouseEventArgs & args); - void startDrag(); - void stopDrag(); - void select(); - void unselect(); - void setClickDistance(Vec2 newClickDistance); - bool isDragged(); - bool isSelected(); - - virtual void update(){} - virtual void draw(){} - virtual bool hitTest(Vec2 position){ return false; } - - protected: - ofColor fillColor; - ofColor strokeColor; - ofColor fillColorSelected; - ofColor strokeColorSelected; - float strokeWidth; - Vec2 clickDistance; // How far from the center of the joint the user has - // clicked? - bool bDrag; - - private: - void setDefaultColors(); - void setDefaultProperties(); - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { + +class BaseJoint { + + public: + BaseJoint(); + + Vec2 position; + bool enabled; + bool visible; + bool selected; + + void mousePressed(ofMouseEventArgs & args); + void mouseReleased(int x, int y, int button); + void mouseDragged(ofMouseEventArgs & args); + void startDrag(); + void stopDrag(); + void select(); + void unselect(); + void setClickDistance(Vec2 newClickDistance); + bool isDragged(); + bool isSelected(); + + virtual void update(){} + virtual void draw(){} + virtual bool hitTest(Vec2 position){ return false; } + + protected: + ofColor fillColor; + ofColor strokeColor; + ofColor fillColorSelected; + ofColor strokeColorSelected; + float strokeWidth; + Vec2 clickDistance; // How far from the center of the joint the user has + // clicked? + bool bDrag; + + private: + void setDefaultColors(); + void setDefaultProperties(); + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/UserInterface/CircleJoint.cpp b/src/UserInterface/CircleJoint.cpp index 193d5b1..c9ef4f4 100644 --- a/src/UserInterface/CircleJoint.cpp +++ b/src/UserInterface/CircleJoint.cpp @@ -1,72 +1,72 @@ -#include "CircleJoint.h" - -namespace ofx { -namespace piMapper { - -CircleJoint::CircleJoint(){ - setDefaultProperties(); -} - -void CircleJoint::update(){ - if(!enabled){ - return; - } -} - -void CircleJoint::draw(){ - if(!visible){ - return; - } - - if(!enabled){ - return; - } - - ofEnableAlphaBlending(); - - ofPushStyle(); - ofFill(); - - if(selected){ - ofSetColor(fillColorSelected); - }else{ - ofSetColor(fillColor); - } - - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - ofDrawCircle(position.x, position.y, radius); - #else - ofCircle(position.x, position.y, radius); - #endif - ofNoFill(); - - if(selected){ - ofSetColor(strokeColorSelected); - }else{ - ofSetColor(strokeColor); - } - - ofSetLineWidth(strokeWidth); - #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 - ofDrawCircle(position.x, position.y, radius); - #else - ofCircle(position.x, position.y, radius); - #endif - ofPopStyle(); -} - -void CircleJoint::setDefaultProperties(){ - radius = 10.0f; -} - -bool CircleJoint::hitTest(Vec2 pos){ - float distance = position.distance(pos); - if(distance < radius){ - return true; - }else{ - return false; - } -} - -} // namespace piMapper +#include "CircleJoint.h" + +namespace ofx { +namespace piMapper { + +CircleJoint::CircleJoint(){ + setDefaultProperties(); +} + +void CircleJoint::update(){ + if(!enabled){ + return; + } +} + +void CircleJoint::draw(){ + if(!visible){ + return; + } + + if(!enabled){ + return; + } + + ofEnableAlphaBlending(); + + ofPushStyle(); + ofFill(); + + if(selected){ + ofSetColor(fillColorSelected); + }else{ + ofSetColor(fillColor); + } + + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + ofDrawCircle(position.x, position.y, radius); + #else + ofCircle(position.x, position.y, radius); + #endif + ofNoFill(); + + if(selected){ + ofSetColor(strokeColorSelected); + }else{ + ofSetColor(strokeColor); + } + + ofSetLineWidth(strokeWidth); + #if (OF_VERSION_MAJOR == 0 && OF_VERSION_MINOR >= 9) || OF_VERSION_MAJOR > 0 + ofDrawCircle(position.x, position.y, radius); + #else + ofCircle(position.x, position.y, radius); + #endif + ofPopStyle(); +} + +void CircleJoint::setDefaultProperties(){ + radius = 10.0f; +} + +bool CircleJoint::hitTest(Vec2 pos){ + float distance = position.distance(pos); + if(distance < radius){ + return true; + }else{ + return false; + } +} + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/UserInterface/CircleJoint.h b/src/UserInterface/CircleJoint.h index 070412d..d319bfd 100644 --- a/src/UserInterface/CircleJoint.h +++ b/src/UserInterface/CircleJoint.h @@ -1,26 +1,26 @@ -#pragma once - -#include "ofMain.h" -#include "BaseJoint.h" -#include "Vec2.h" - -namespace ofx { -namespace piMapper { -class CircleJoint : public BaseJoint { - - public: - CircleJoint(); - - void update(); - void draw(); - bool hitTest(Vec2 position); - - private: - float radius; - - void setDefaultProperties(); - -}; - -} // namespace piMapper -} // namespace ofx +#pragma once + +#include "ofMain.h" +#include "BaseJoint.h" +#include "Vec2.h" + +namespace ofx { +namespace piMapper { +class CircleJoint : public BaseJoint { + + public: + CircleJoint(); + + void update(); + void draw(); + bool hitTest(Vec2 position); + + private: + float radius; + + void setDefaultProperties(); + +}; + +} // namespace piMapper +} // namespace ofx diff --git a/src/UserInterface/EditorType.h b/src/UserInterface/EditorType.h index 71f2053..9e93201 100644 --- a/src/UserInterface/EditorType.h +++ b/src/UserInterface/EditorType.h @@ -1,13 +1,13 @@ -#pragma once - -namespace ofx { -namespace piMapper { - -struct EditorType { - enum { - TEXTURE, PROJECTION - }; -}; - -} // namespace piMapper +#pragma once + +namespace ofx { +namespace piMapper { + +struct EditorType { + enum { + TEXTURE, PROJECTION + }; +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/UserInterface/GuiMode.h b/src/UserInterface/GuiMode.h index 926eeb6..46a4c8b 100644 --- a/src/UserInterface/GuiMode.h +++ b/src/UserInterface/GuiMode.h @@ -1,13 +1,13 @@ -#pragma once - -namespace ofx { -namespace piMapper { - -struct GuiMode { - enum { - NONE, TEXTURE_MAPPING, PROJECTION_MAPPING, SOURCE_SELECTION - }; -}; - -} // namespace piMapper +#pragma once + +namespace ofx { +namespace piMapper { + +struct GuiMode { + enum { + NONE, TEXTURE_MAPPING, PROJECTION_MAPPING, SOURCE_SELECTION + }; +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/UserInterface/RadioList.cpp b/src/UserInterface/RadioList.cpp index eff3ea9..e43e818 100644 --- a/src/UserInterface/RadioList.cpp +++ b/src/UserInterface/RadioList.cpp @@ -1,200 +1,200 @@ -#include "RadioList.h" - -namespace ofx { -namespace piMapper { - -RadioList::RadioList(){ - storedTitle = ""; - storedSelectedItem = 0; -} - -RadioList::RadioList(std::vector & labels, std::vector & values){ - RadioList(); - setup(labels, values); -} - -RadioList::RadioList(std::string title, std::vector & labels, std::vector & values){ - RadioList(); - setup(title, labels, values); -} - -RadioList::~RadioList(){ - clear(); -} - -void RadioList::setup(std::vector & labels, std::vector & values){ - - // Copy incomming labels for later use - storedLabels = labels; - storedValues = values; - - // Create toggles with labels from the labels arg - int i; - for(i = 0; i < labels.size(); i++){ - ofxToggle * toggle = new ofxToggle(); - toggle->setup(false); - toggle->setName(labels[i]); - toggle->addListener(this, &RadioList::onToggleClicked); - guiGroup.add(toggle); - #if OF_VERSION_MAJOR == 0 && (OF_VERSION_MINOR >= 8 && OF_VERSION_PATCH >= 2) || (OF_VERSION_MINOR >= 9 && OF_VERSION_PATCH >= 0) - toggle->registerMouseEvents(); - #endif - } -} - -void RadioList::setup(std::string title, std::vector & labels, std::vector & values){ - - // Store title for later use - storedTitle = title; - guiGroup.setName(title); - setup(labels, values); -} - -void RadioList::draw(){ - guiGroup.draw(); -} - -void RadioList::setTitle(std::string title){ - storedTitle = title; - guiGroup.setName(title); -} - -void RadioList::setPosition(ofPoint p){ - guiGroup.setPosition(p); -} - -void RadioList::setPosition(float x, float y){ - guiGroup.setPosition(x, y); -} - -void RadioList::selectItem(int index){ - if(index >= guiGroup.getNumControls()){ - return; - } - - unselectAll(); - - ofxToggle * toggle = static_cast (guiGroup.getControl(index)); - toggle->removeListener(this, &RadioList::onToggleClicked); - *toggle = true; // Select the specific radio button - toggle->addListener(this, &RadioList::onToggleClicked); - //std::string name = toggle->getName(); - // Throw event with value that is image path instead of name - std::string value = storedValues[index]; - ofNotifyEvent(onRadioSelected, value, this); - storedSelectedItem = index; -} - -bool RadioList::selectItemByValue(std::string itemValue){ - if(itemValue == ""){ - ofLogNotice("RadioList") << "Item value empty"; - return false; - } - unselectAll(); - int itemIndex = -1; - for(int i = 0; i < storedValues.size(); i++){ - if(itemValue == storedValues[i]){ - itemIndex = i; - break; - } - } - if(itemIndex >= 0){ - ofxToggle * toggle = static_cast (guiGroup.getControl(itemIndex)); - toggle->removeListener(this, &RadioList::onToggleClicked); - *toggle = true; // Select the specific radio button - toggle->addListener(this, &RadioList::onToggleClicked); - return true; - } - ofLogNotice("RadioList") << "Item with value " << itemValue << " not found"; - return false; -} - -void RadioList::enable(){ - if(guiGroup.getNumControls() > 0){ - clear(); - } - - // Rebuild everyting - setup(storedTitle, storedLabels, storedValues); - - // Select the stored selected item without throwing an event - ofxToggle * toggle = static_cast (guiGroup.getControl(storedSelectedItem)); - toggle->removeListener(this, &RadioList::onToggleClicked); - *toggle = true; - toggle->addListener(this, &RadioList::onToggleClicked); - - std::cout << "num items after enable: " << guiGroup.getNumControls() << std::endl; -} - -void RadioList::disable(){ - // Just remove everything - clear(); -} - -void RadioList::clear(){ - int i; - for(i = 0; i < guiGroup.getNumControls(); i++){ - ofxToggle * toggle = static_cast (guiGroup.getControl(i)); - toggle->removeListener(this, &RadioList::onToggleClicked); - delete toggle; - } - guiGroup.clear(); -} - -void RadioList::unselectAll(){ - int i; - for(i = 0; i < guiGroup.getNumControls(); i++){ - ofxToggle * toggle = static_cast (guiGroup.getControl(i)); - toggle->removeListener(this, &RadioList::onToggleClicked); - *toggle = false; - toggle->addListener(this, &RadioList::onToggleClicked); - } -} - -ofPoint RadioList::getPosition(){ - return guiGroup.getPosition(); -} - -float RadioList::getWidth(){ - return guiGroup.getWidth(); -} - -float RadioList::getHeight(){ - return guiGroup.getHeight(); -} - -std::string RadioList::getTitle(){ - return guiGroup.getName(); -} - -std::string RadioList::getItemName(int index){ - if(index >= guiGroup.getNumControls()){ - return ""; - } - - ofxToggle * toggle = static_cast (guiGroup.getControl(index)); - return toggle->getName(); -} - -int RadioList::size(){ - return storedValues.size(); -} - -void RadioList::onToggleClicked(bool & toggleValue){ - unselectAll(); - - // Search for the actual toggle triggering the event - int i; - for(i = 0; i < guiGroup.getNumControls(); i++){ - ofxToggle * toggle = static_cast (guiGroup.getControl(i)); - ofParameter * paramPtr = static_cast *>(&toggle->getParameter()); - - if(&(paramPtr->get()) == &toggleValue){ - selectItem(i); - break; - } - } -} - -} // namespace piMapper -} // namespace ofx +#include "RadioList.h" + +namespace ofx { +namespace piMapper { + +RadioList::RadioList(){ + storedTitle = ""; + storedSelectedItem = 0; +} + +RadioList::RadioList(std::vector & labels, std::vector & values){ + RadioList(); + setup(labels, values); +} + +RadioList::RadioList(std::string title, std::vector & labels, std::vector & values){ + RadioList(); + setup(title, labels, values); +} + +RadioList::~RadioList(){ + clear(); +} + +void RadioList::setup(std::vector & labels, std::vector & values){ + + // Copy incomming labels for later use + storedLabels = labels; + storedValues = values; + + // Create toggles with labels from the labels arg + int i; + for(i = 0; i < labels.size(); i++){ + ofxToggle * toggle = new ofxToggle(); + toggle->setup(false); + toggle->setName(labels[i]); + toggle->addListener(this, &RadioList::onToggleClicked); + guiGroup.add(toggle); + #if OF_VERSION_MAJOR == 0 && (OF_VERSION_MINOR >= 8 && OF_VERSION_PATCH >= 2) || (OF_VERSION_MINOR >= 9 && OF_VERSION_PATCH >= 0) + toggle->registerMouseEvents(); + #endif + } +} + +void RadioList::setup(std::string title, std::vector & labels, std::vector & values){ + + // Store title for later use + storedTitle = title; + guiGroup.setName(title); + setup(labels, values); +} + +void RadioList::draw(){ + guiGroup.draw(); +} + +void RadioList::setTitle(std::string title){ + storedTitle = title; + guiGroup.setName(title); +} + +void RadioList::setPosition(ofPoint p){ + guiGroup.setPosition(p); +} + +void RadioList::setPosition(float x, float y){ + guiGroup.setPosition(x, y); +} + +void RadioList::selectItem(int index){ + if(index >= guiGroup.getNumControls()){ + return; + } + + unselectAll(); + + ofxToggle * toggle = static_cast (guiGroup.getControl(index)); + toggle->removeListener(this, &RadioList::onToggleClicked); + *toggle = true; // Select the specific radio button + toggle->addListener(this, &RadioList::onToggleClicked); + //std::string name = toggle->getName(); + // Throw event with value that is image path instead of name + std::string value = storedValues[index]; + ofNotifyEvent(onRadioSelected, value, this); + storedSelectedItem = index; +} + +bool RadioList::selectItemByValue(std::string itemValue){ + if(itemValue == ""){ + ofLogNotice("RadioList") << "Item value empty"; + return false; + } + unselectAll(); + int itemIndex = -1; + for(int i = 0; i < storedValues.size(); i++){ + if(itemValue == storedValues[i]){ + itemIndex = i; + break; + } + } + if(itemIndex >= 0){ + ofxToggle * toggle = static_cast (guiGroup.getControl(itemIndex)); + toggle->removeListener(this, &RadioList::onToggleClicked); + *toggle = true; // Select the specific radio button + toggle->addListener(this, &RadioList::onToggleClicked); + return true; + } + ofLogNotice("RadioList") << "Item with value " << itemValue << " not found"; + return false; +} + +void RadioList::enable(){ + if(guiGroup.getNumControls() > 0){ + clear(); + } + + // Rebuild everyting + setup(storedTitle, storedLabels, storedValues); + + // Select the stored selected item without throwing an event + ofxToggle * toggle = static_cast (guiGroup.getControl(storedSelectedItem)); + toggle->removeListener(this, &RadioList::onToggleClicked); + *toggle = true; + toggle->addListener(this, &RadioList::onToggleClicked); + + std::cout << "num items after enable: " << guiGroup.getNumControls() << std::endl; +} + +void RadioList::disable(){ + // Just remove everything + clear(); +} + +void RadioList::clear(){ + int i; + for(i = 0; i < guiGroup.getNumControls(); i++){ + ofxToggle * toggle = static_cast (guiGroup.getControl(i)); + toggle->removeListener(this, &RadioList::onToggleClicked); + delete toggle; + } + guiGroup.clear(); +} + +void RadioList::unselectAll(){ + int i; + for(i = 0; i < guiGroup.getNumControls(); i++){ + ofxToggle * toggle = static_cast (guiGroup.getControl(i)); + toggle->removeListener(this, &RadioList::onToggleClicked); + *toggle = false; + toggle->addListener(this, &RadioList::onToggleClicked); + } +} + +ofPoint RadioList::getPosition(){ + return guiGroup.getPosition(); +} + +float RadioList::getWidth(){ + return guiGroup.getWidth(); +} + +float RadioList::getHeight(){ + return guiGroup.getHeight(); +} + +std::string RadioList::getTitle(){ + return guiGroup.getName(); +} + +std::string RadioList::getItemName(int index){ + if(index >= guiGroup.getNumControls()){ + return ""; + } + + ofxToggle * toggle = static_cast (guiGroup.getControl(index)); + return toggle->getName(); +} + +int RadioList::size(){ + return storedValues.size(); +} + +void RadioList::onToggleClicked(bool & toggleValue){ + unselectAll(); + + // Search for the actual toggle triggering the event + int i; + for(i = 0; i < guiGroup.getNumControls(); i++){ + ofxToggle * toggle = static_cast (guiGroup.getControl(i)); + ofParameter * paramPtr = static_cast *>(&toggle->getParameter()); + + if(&(paramPtr->get()) == &toggleValue){ + selectItem(i); + break; + } + } +} + +} // namespace piMapper +} // namespace ofx diff --git a/src/UserInterface/RadioList.h b/src/UserInterface/RadioList.h index 9ce66c4..f24051c 100644 --- a/src/UserInterface/RadioList.h +++ b/src/UserInterface/RadioList.h @@ -1,56 +1,56 @@ -#pragma once - -#include "ofGraphics.h" -#include "ofxGuiGroup.h" -#include "ofxToggle.h" -#include "ofxLabel.h" - -namespace ofx { -namespace piMapper { - -class RadioList { - public: - RadioList(); - RadioList(std::vector & labels, std::vector & values); - RadioList(std::string title, std::vector & labels, std::vector & values); - ~RadioList(); - - void setup(std::vector & labels, std::vector & values); - void setup(std::string title, std::vector & labels, std::vector & values); - void draw(); - void setTitle(std::string title); - void setPosition(ofPoint p); - void setPosition(float x, float y); - void selectItem(int index); - bool selectItemByValue(std::string itemValue); - void enable(); - void disable(); - void clear(); - void unselectAll(); - ofPoint getPosition(); - float getWidth(); - float getHeight(); - std::string getTitle(); - std::string getItemName(int index); - int size(); - - // This event notifies about a toggle being selected and passes it's name to - // the listeners. - // Use ofAddListener(RadioListInstance.radioSelectedEvent, listenerClassPtr, - // &listenerClass::listenerMethod) - // to listen to this. Listner method void listenerMethod(std::string & radioName) - ofEvent onRadioSelected; - - private: - std::vector storedLabels; - std::vector storedValues; - std::string storedTitle; - ofxGuiGroup guiGroup; - int storedSelectedItem; - - void onToggleClicked(bool & toggleValue); - -}; - -} // namespace piMapper +#pragma once + +#include "ofGraphics.h" +#include "ofxGuiGroup.h" +#include "ofxToggle.h" +#include "ofxLabel.h" + +namespace ofx { +namespace piMapper { + +class RadioList { + public: + RadioList(); + RadioList(std::vector & labels, std::vector & values); + RadioList(std::string title, std::vector & labels, std::vector & values); + ~RadioList(); + + void setup(std::vector & labels, std::vector & values); + void setup(std::string title, std::vector & labels, std::vector & values); + void draw(); + void setTitle(std::string title); + void setPosition(ofPoint p); + void setPosition(float x, float y); + void selectItem(int index); + bool selectItemByValue(std::string itemValue); + void enable(); + void disable(); + void clear(); + void unselectAll(); + ofPoint getPosition(); + float getWidth(); + float getHeight(); + std::string getTitle(); + std::string getItemName(int index); + int size(); + + // This event notifies about a toggle being selected and passes it's name to + // the listeners. + // Use ofAddListener(RadioListInstance.radioSelectedEvent, listenerClassPtr, + // &listenerClass::listenerMethod) + // to listen to this. Listner method void listenerMethod(std::string & radioName) + ofEvent onRadioSelected; + + private: + std::vector storedLabels; + std::vector storedValues; + std::string storedTitle; + ofxGuiGroup guiGroup; + int storedSelectedItem; + + void onToggleClicked(bool & toggleValue); + +}; + +} // namespace piMapper } // namespace ofx \ No newline at end of file diff --git a/src/Utils/HomographyHelper.cpp b/src/Utils/HomographyHelper.cpp index 43f6181..e5baa62 100644 --- a/src/Utils/HomographyHelper.cpp +++ b/src/Utils/HomographyHelper.cpp @@ -1,120 +1,120 @@ -/* - * HomographyHelper - * Created by Elliot Woods on 26/11/2010. - * Edited by Krisjanis Rijnieks on 23/01/2016 - * - * Based entirely on arturo castro's homography implementation - * Created 08/01/2010, arturo castro - * - * http://www.openframeworks.cc/forum/viewtopic.php?f=9&t=3121 - */ - -#include "HomographyHelper.h" - -namespace ofx { -namespace piMapper { - -void HomographyHelper::gaussian_elimination(float *input, int n){ - // ported to c from pseudocode in - // http://en.wikipedia.org/wiki/Gaussian_elimination - - float * A = input; - int i = 0; - int j = 0; - int m = n-1; - while (i < m && j < n){ - // Find pivot in column j, starting in row i: - int maxi = i; - for(int k = i+1; k fabs(A[maxi*n+j])){ - maxi = k; - } - } - if (A[maxi*n+j] != 0){ - //swap rows i and maxi, but do not change the value of i - if(i!=maxi) - for(int k=0;k=0;i--){ - for(int j=i+1;j fabs(A[maxi*n+j])){ + maxi = k; + } + } + if (A[maxi*n+j] != 0){ + //swap rows i and maxi, but do not change the value of i + if(i!=maxi) + for(int k=0;k=0;i--){ + for(int j=i+1;jdeselectSurface(); - _application.getSurfaceManager()->cloneActivePreset(); -} - -void ofxPiMapper::eraseActivePreset(){ - _application.getSurfaceManager()->deselectSurface(); - _application.getSurfaceManager()->eraseActivePreset(); -} - -void ofxPiMapper::selectSurface(int i){ - _application.selectSurface(i); -} - -void ofxPiMapper::togglePerspective(){ - _application.togglePerspective(); -} - -void ofxPiMapper::selectNextSurface(){ - _application.selectNextSurface(); -} - -void ofxPiMapper::selectPrevSurface(){ - _application.selectPrevSurface(); -} - -void ofxPiMapper::duplicateSurface(){ - _application.duplicateSurface(); -} - -void ofxPiMapper::selectNextVertex(){ - _application.selectNextVertex(); -} - -void ofxPiMapper::selectPrevVertex(){ - _application.selectPrevVertex(); -} - -void ofxPiMapper::selectVertex(int surface, int vertex){ - _application.selectVertex(surface, vertex); -} - -void ofxPiMapper::selectNextTexCoord(){ - _application.selectNextTexCoord(); -} - -void ofxPiMapper::selectPrevTexCoord(){ - _application.selectPrevTexCoord(); -} - -void ofxPiMapper::moveLayerUp(){ - _application.moveLayerUp(); -} - -void ofxPiMapper::moveLayerDown(){ - _application.moveLayerDown(); -} - -void ofxPiMapper::scaleUp(){ - _application.scaleUp(); -} - -void ofxPiMapper::scaleDown(){ - _application.scaleDown(); -} - -void ofxPiMapper::togglePauseForSurface(unsigned int i){ - ofx::piMapper::BaseSource * s = - _application.getSurfaceManager()->getActivePreset()->getSurfaces().at(i)->getSource(); - if(s->getType() == ofx::piMapper::SourceType::SOURCE_TYPE_VIDEO){ - s->togglePause(); - } -} - -void ofxPiMapper::togglePause(){ - _application.togglePause(); -} - -void ofxPiMapper::moveSelection(ofx::piMapper::Vec3 by){ - _application.moveSelection(by); -} - -void ofxPiMapper::createSurface(ofx::piMapper::SurfaceType type){ - _application.createSurface(type); -} - -void ofxPiMapper::eraseSurface(int i){ - std::cout << "numSurfaces: " << getNumSurfaces() << ", i: " << i << std::endl; - if(getNumSurfaces() > 0 && i < getNumSurfaces()){ - _application.eraseSurface(i); - } -} - -void ofxPiMapper::addGridColumn(){ - _application.addGridColumn(); -} - -void ofxPiMapper::removeGridColumn(){ - _application.removeGridColumn(); -} - -void ofxPiMapper::addGridRow(){ - _application.addGridRow(); -} - -void ofxPiMapper::removeGridRow(){ - _application.removeGridRow(); -} - -void ofxPiMapper::setNextSource(){ - _application.setNextSource(); -} - -void ofxPiMapper::setFboSource(std::string sourceId){ - _application.setFboSource(sourceId); -} - -void ofxPiMapper::setVideoSource(std::string fileName, bool loop){ - _application.setVideoSource(fileName, loop); -} - -void ofxPiMapper::setImageSource(std::string fileName){ - _application.setImageSource(fileName); -} - -void ofxPiMapper::setDrawGui(bool drawGui){ - _application.setDrawGui(drawGui); -} - -void ofxPiMapper::reboot(){ - _application.reboot(); -} - -void ofxPiMapper::shutdown(){ - _application.shutdown(); -} - -void ofxPiMapper::saveProject(){ - _application.saveProject(); -} - -bool ofxPiMapper::loadProject(std::string filename){ - return _application.loadXmlSettings(filename); -} - -unsigned int ofxPiMapper::getNumPresets(){ - return _application.getSurfaceManager()->getNumPresets(); -} - -unsigned int ofxPiMapper::getActivePresetIndex(){ - return _application.getSurfaceManager()->getActivePresetIndex(); -} - -unsigned int ofxPiMapper::getNumSurfaces(){ - return _application.getSurfaceManager()->getActivePreset()->getSurfaces().size(); -} - -int ofxPiMapper::getSelectedSurface(){ - return _application.getSurfaceManager()->getSelectedSurfaceIndex(); -} - -int ofxPiMapper::getSelectedVertex(){ - return _application.getSurfaceManager()->getSelectedVertexIndex(); -} - -void ofxPiMapper::setInfoText(std::string text){ - _application.setInfoText(text); -} - -void ofxPiMapper::toggleInfo(){ - _application.toggleInfo(); -} - -void ofxPiMapper::undo(){ - _application.undo(); -} - -void ofxPiMapper::deselect(){ - _application.deselect(); -} - -bool ofxPiMapper::toggleShift(){ - return _application.toggleShift(); -} - -void ofxPiMapper::setMode(ofx::piMapper::Mode m){ - if(m == ofx::piMapper::PRESENTATION_MODE){ - _application.setPresentationMode(); - }else if(m == ofx::piMapper::TEXTURE_MODE){ - _application.setTextureMode(); - }else if(m == ofx::piMapper::MAPPING_MODE){ - _application.setProjectionMode(); - }else if(m == ofx::piMapper::SOURCE_MODE){ - _application.setSourceMode(); - }else{ - ofLogWarning("ofxPiMapper::setMode", "Please specify valid mode"); - } -} - -ofx::piMapper::Mode ofxPiMapper::getMode(){ - if(_application.getState() == ofx::piMapper::PresentationMode::instance()){ - return ofx::piMapper::PRESENTATION_MODE; - }else if(_application.getState() == ofx::piMapper::TextureMappingMode::instance()){ - return ofx::piMapper::TEXTURE_MODE; - }else if(_application.getState() == ofx::piMapper::ProjectionMappingMode::instance()){ - return ofx::piMapper::MAPPING_MODE; - }else{ - return ofx::piMapper::SOURCE_MODE; - } - return ofx::piMapper::PRESENTATION_MODE; -} - -void ofxPiMapper::toggleLayerPanel(){ - _application.toggleLayerPanel(); -} - -void ofxPiMapper::restart() { - _application.restart(); -} - -void ofxPiMapper::pause() { - _application.pause(); -} - -void ofxPiMapper::resume() { - _application.resume(); -} +#include "ofxPiMapper.h" + +ofxPiMapper::ofxPiMapper(){} + +void ofxPiMapper::setup(){ + _application.setup(); +} + +void ofxPiMapper::update(){ + _application.update(); +} + +void ofxPiMapper::draw(){ + _application.draw(); +} + +void ofxPiMapper::keyPressed(int key){ + ofKeyEventArgs args; + args.key = key; + _application.onKeyPressed(args); +} + +void ofxPiMapper::keyReleased(int key){ + ofKeyEventArgs args; + args.key = key; + _application.onKeyReleased(args); +} + +void ofxPiMapper::mousePressed(int x, int y, int button){ + ofMouseEventArgs args; + args.x = x; + args.y = y; + args.button = button; + args.type = ofMouseEventArgs::Pressed; + _application.onMousePressed(args); +} + +void ofxPiMapper::mouseReleased(int x, int y, int button){ + ofMouseEventArgs args; + args.x = x; + args.y = y; + args.button = button; + args.type = ofMouseEventArgs::Released; + _application.onMouseReleased(args); +} + +void ofxPiMapper::mouseDragged(int x, int y, int button){ + ofMouseEventArgs args; + args.x = x; + args.y = y; + args.button = button; + args.type = ofMouseEventArgs::Dragged; + _application.onMouseDragged(args); +} + +void ofxPiMapper::registerFboSource(ofx::piMapper::FboSource & fboSource){ + _application.addFboSource(fboSource); +} + +void ofxPiMapper::registerFboSource(ofx::piMapper::FboSource * fboSource){ + _application.addFboSource(fboSource); +} + +void ofxPiMapper::setPreset(unsigned int i){ + _application.setPreset(i); +} + +void ofxPiMapper::setNextPreset(){ + _application.setNextPreset(); +} + +void ofxPiMapper::cloneActivePreset(){ + _application.getSurfaceManager()->deselectSurface(); + _application.getSurfaceManager()->cloneActivePreset(); +} + +void ofxPiMapper::eraseActivePreset(){ + _application.getSurfaceManager()->deselectSurface(); + _application.getSurfaceManager()->eraseActivePreset(); +} + +void ofxPiMapper::selectSurface(int i){ + _application.selectSurface(i); +} + +void ofxPiMapper::togglePerspective(){ + _application.togglePerspective(); +} + +void ofxPiMapper::selectNextSurface(){ + _application.selectNextSurface(); +} + +void ofxPiMapper::selectPrevSurface(){ + _application.selectPrevSurface(); +} + +void ofxPiMapper::duplicateSurface(){ + _application.duplicateSurface(); +} + +void ofxPiMapper::selectNextVertex(){ + _application.selectNextVertex(); +} + +void ofxPiMapper::selectPrevVertex(){ + _application.selectPrevVertex(); +} + +void ofxPiMapper::selectVertex(int surface, int vertex){ + _application.selectVertex(surface, vertex); +} + +void ofxPiMapper::selectNextTexCoord(){ + _application.selectNextTexCoord(); +} + +void ofxPiMapper::selectPrevTexCoord(){ + _application.selectPrevTexCoord(); +} + +void ofxPiMapper::moveLayerUp(){ + _application.moveLayerUp(); +} + +void ofxPiMapper::moveLayerDown(){ + _application.moveLayerDown(); +} + +void ofxPiMapper::scaleUp(){ + _application.scaleUp(); +} + +void ofxPiMapper::scaleDown(){ + _application.scaleDown(); +} + +void ofxPiMapper::togglePauseForSurface(unsigned int i){ + ofx::piMapper::BaseSource * s = + _application.getSurfaceManager()->getActivePreset()->getSurfaces().at(i)->getSource(); + if(s->getType() == ofx::piMapper::SourceType::SOURCE_TYPE_VIDEO){ + s->togglePause(); + } +} + +void ofxPiMapper::togglePause(){ + _application.togglePause(); +} + +void ofxPiMapper::moveSelection(ofx::piMapper::Vec3 by){ + _application.moveSelection(by); +} + +void ofxPiMapper::createSurface(ofx::piMapper::SurfaceType type){ + _application.createSurface(type); +} + +void ofxPiMapper::eraseSurface(int i){ + std::cout << "numSurfaces: " << getNumSurfaces() << ", i: " << i << std::endl; + if(getNumSurfaces() > 0 && i < getNumSurfaces()){ + _application.eraseSurface(i); + } +} + +void ofxPiMapper::addGridColumn(){ + _application.addGridColumn(); +} + +void ofxPiMapper::removeGridColumn(){ + _application.removeGridColumn(); +} + +void ofxPiMapper::addGridRow(){ + _application.addGridRow(); +} + +void ofxPiMapper::removeGridRow(){ + _application.removeGridRow(); +} + +void ofxPiMapper::setNextSource(){ + _application.setNextSource(); +} + +void ofxPiMapper::setFboSource(std::string sourceId){ + _application.setFboSource(sourceId); +} + +void ofxPiMapper::setVideoSource(std::string fileName, bool loop){ + _application.setVideoSource(fileName, loop); +} + +void ofxPiMapper::setImageSource(std::string fileName){ + _application.setImageSource(fileName); +} + +void ofxPiMapper::setDrawGui(bool drawGui){ + _application.setDrawGui(drawGui); +} + +void ofxPiMapper::reboot(){ + _application.reboot(); +} + +void ofxPiMapper::shutdown(){ + _application.shutdown(); +} + +void ofxPiMapper::saveProject(){ + _application.saveProject(); +} + +bool ofxPiMapper::loadProject(std::string filename){ + return _application.loadXmlSettings(filename); +} + +unsigned int ofxPiMapper::getNumPresets(){ + return _application.getSurfaceManager()->getNumPresets(); +} + +unsigned int ofxPiMapper::getActivePresetIndex(){ + return _application.getSurfaceManager()->getActivePresetIndex(); +} + +unsigned int ofxPiMapper::getNumSurfaces(){ + return _application.getSurfaceManager()->getActivePreset()->getSurfaces().size(); +} + +int ofxPiMapper::getSelectedSurface(){ + return _application.getSurfaceManager()->getSelectedSurfaceIndex(); +} + +int ofxPiMapper::getSelectedVertex(){ + return _application.getSurfaceManager()->getSelectedVertexIndex(); +} + +void ofxPiMapper::setInfoText(std::string text){ + _application.setInfoText(text); +} + +void ofxPiMapper::toggleInfo(){ + _application.toggleInfo(); +} + +void ofxPiMapper::undo(){ + _application.undo(); +} + +void ofxPiMapper::deselect(){ + _application.deselect(); +} + +bool ofxPiMapper::toggleShift(){ + return _application.toggleShift(); +} + +void ofxPiMapper::setMode(ofx::piMapper::Mode m){ + if(m == ofx::piMapper::PRESENTATION_MODE){ + _application.setPresentationMode(); + }else if(m == ofx::piMapper::TEXTURE_MODE){ + _application.setTextureMode(); + }else if(m == ofx::piMapper::MAPPING_MODE){ + _application.setProjectionMode(); + }else if(m == ofx::piMapper::SOURCE_MODE){ + _application.setSourceMode(); + }else{ + ofLogWarning("ofxPiMapper::setMode", "Please specify valid mode"); + } +} + +ofx::piMapper::Mode ofxPiMapper::getMode(){ + if(_application.getState() == ofx::piMapper::PresentationMode::instance()){ + return ofx::piMapper::PRESENTATION_MODE; + }else if(_application.getState() == ofx::piMapper::TextureMappingMode::instance()){ + return ofx::piMapper::TEXTURE_MODE; + }else if(_application.getState() == ofx::piMapper::ProjectionMappingMode::instance()){ + return ofx::piMapper::MAPPING_MODE; + }else{ + return ofx::piMapper::SOURCE_MODE; + } + return ofx::piMapper::PRESENTATION_MODE; +} + +void ofxPiMapper::toggleLayerPanel(){ + _application.toggleLayerPanel(); +} + +void ofxPiMapper::restart() { + _application.restart(); +} + +void ofxPiMapper::pause() { + _application.pause(); +} + +void ofxPiMapper::resume() { + _application.resume(); +} diff --git a/src/ofxPiMapper.h b/src/ofxPiMapper.h index 2797f46..f361614 100644 --- a/src/ofxPiMapper.h +++ b/src/ofxPiMapper.h @@ -1,104 +1,104 @@ -#pragma once - -#include "ofEvents.h" -#include "ofLog.h" -#include "FboSource.h" -#include "Application.h" -#include "SurfaceType.h" -#include "Mode.h" -#include "Vec2.h" -#include "Vec3.h" - -class ofxPiMapper { - public: - ofxPiMapper(); - - void setup(); - void update(); - void draw(); - - void keyPressed(int key); - void keyReleased(int key); - - void mousePressed(int x, int y, int button); - void mouseReleased(int x, int y, int button); - void mouseDragged(int x, int y, int button); - - void registerFboSource(ofx::piMapper::FboSource & fboSource); - void registerFboSource(ofx::piMapper::FboSource * fboSource); - - // Application - void setInfoText(std::string text); - void toggleInfo(); - void undo(); - void deselect(); - bool toggleShift(); - - // Modes - void setMode(ofx::piMapper::Mode m); - ofx::piMapper::Mode getMode(); - - // Projection mapping mode only - void toggleLayerPanel(); - - // Project - void saveProject(); - bool loadProject(std::string filename); - - // Presets - unsigned int getNumPresets(); - unsigned int getActivePresetIndex(); - void setPreset(unsigned int i); - void setNextPreset(); - void cloneActivePreset(); - void eraseActivePreset(); - - // Surfaces, active preset - unsigned int getNumSurfaces(); - int getSelectedSurface(); - int getSelectedVertex(); - void selectSurface(int i); - void togglePerspective(); - void selectNextSurface(); - void selectPrevSurface(); - void duplicateSurface(); - void selectNextVertex(); - void selectPrevVertex(); - void selectVertex(int surface, int vertex); - void selectNextTexCoord(); - void selectPrevTexCoord(); - void moveLayerUp(); - void moveLayerDown(); - void scaleUp(); - void scaleDown(); - void togglePauseForSurface(unsigned int i); - void togglePause(); - void moveSelection(ofx::piMapper::Vec3 by); - void createSurface(ofx::piMapper::SurfaceType type); - void eraseSurface(int i); - - // Specifically for GridWarpSurface - void addGridColumn(); - void removeGridColumn(); - void addGridRow(); - void removeGridRow(); - - // Sources, selected surface - void setNextSource(); - void setFboSource(std::string sourceId); - void setVideoSource(std::string fileName, bool loop); - void setImageSource(std::string fileName); - void setDrawGui(bool drawGui); - - // System commands - void reboot(); - void shutdown(); - - // video play control - void restart(); - void pause(); - void resume(); - - private: - ofx::piMapper::Application _application; -}; +#pragma once + +#include "ofEvents.h" +#include "ofLog.h" +#include "FboSource.h" +#include "Application.h" +#include "SurfaceType.h" +#include "Mode.h" +#include "Vec2.h" +#include "Vec3.h" + +class ofxPiMapper { + public: + ofxPiMapper(); + + void setup(); + void update(); + void draw(); + + void keyPressed(int key); + void keyReleased(int key); + + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseDragged(int x, int y, int button); + + void registerFboSource(ofx::piMapper::FboSource & fboSource); + void registerFboSource(ofx::piMapper::FboSource * fboSource); + + // Application + void setInfoText(std::string text); + void toggleInfo(); + void undo(); + void deselect(); + bool toggleShift(); + + // Modes + void setMode(ofx::piMapper::Mode m); + ofx::piMapper::Mode getMode(); + + // Projection mapping mode only + void toggleLayerPanel(); + + // Project + void saveProject(); + bool loadProject(std::string filename); + + // Presets + unsigned int getNumPresets(); + unsigned int getActivePresetIndex(); + void setPreset(unsigned int i); + void setNextPreset(); + void cloneActivePreset(); + void eraseActivePreset(); + + // Surfaces, active preset + unsigned int getNumSurfaces(); + int getSelectedSurface(); + int getSelectedVertex(); + void selectSurface(int i); + void togglePerspective(); + void selectNextSurface(); + void selectPrevSurface(); + void duplicateSurface(); + void selectNextVertex(); + void selectPrevVertex(); + void selectVertex(int surface, int vertex); + void selectNextTexCoord(); + void selectPrevTexCoord(); + void moveLayerUp(); + void moveLayerDown(); + void scaleUp(); + void scaleDown(); + void togglePauseForSurface(unsigned int i); + void togglePause(); + void moveSelection(ofx::piMapper::Vec3 by); + void createSurface(ofx::piMapper::SurfaceType type); + void eraseSurface(int i); + + // Specifically for GridWarpSurface + void addGridColumn(); + void removeGridColumn(); + void addGridRow(); + void removeGridRow(); + + // Sources, selected surface + void setNextSource(); + void setFboSource(std::string sourceId); + void setVideoSource(std::string fileName, bool loop); + void setImageSource(std::string fileName); + void setDrawGui(bool drawGui); + + // System commands + void reboot(); + void shutdown(); + + // video play control + void restart(); + void pause(); + void resume(); + + private: + ofx::piMapper::Application _application; +};