Browse Source

Merge branch 'release-v0.2.1'

master
Krisjanis Rijnieks 11 years ago
parent
commit
f22713d324
  1. 35
      README.md
  2. 5
      example/.gitignore
  3. 17
      example/Project.xcconfig
  4. 152
      example/bin/data/defaultSurfaces.xml
  5. 1157
      example/example.xcodeproj/project.pbxproj
  6. 86
      example/example.xcodeproj/xcshareddata/xcschemes/example Debug.xcscheme
  7. 86
      example/example.xcodeproj/xcshareddata/xcschemes/example Release.xcscheme
  8. 22
      example/openFrameworks-Info.plist
  9. 43
      example/src/CustomSource.cpp
  10. 17
      example/src/CustomSource.h
  11. 34
      example/src/main.cpp
  12. 193
      example/src/ofApp.cpp
  13. 27
      example/src/ofApp.h
  14. 96
      src/MediaServer/MediaServer.cpp
  15. 37
      src/MediaServer/MediaServer.h
  16. 3
      src/Sources/BaseSource.h
  17. 81
      src/Sources/FboSource.cpp
  18. 49
      src/Sources/FboSource.h
  19. 7
      src/Sources/SourceType.h
  20. 19
      src/Surfaces/SurfaceManager.cpp
  21. 148
      src/UserInterface/SourcesEditor.cpp
  22. 19
      src/UserInterface/SourcesEditor.h
  23. 2
      src/UserInterface/TextureEditor.cpp
  24. 160
      src/ofxPiMapper.cpp
  25. 38
      src/ofxPiMapper.h

35
README.md

@ -5,11 +5,18 @@ ofxPiMapper
This project is an attempt to create optimized version of an openFrameworks projection mapping addon for the Raspberry Pi. It is also my master thesis project at Aalto University, School of Arts, Design and Architecture (Helsinki Media Lab).
ofxPiMapper is mainly for people who want to use the Raspberry Pi as a cheaper way to create standalone mapping installations. Let's say someone has 10 generative mapping pieces and gets an offer to exhibit them in an art gallery, museum or any other kind of place. 10 Mac computers? No! PiMapper is here to save you!
ofxPiMapper is mainly for people who want to use the Raspberry Pi as a cheaper way to create standalone mapping installations. Let's say someone has 10 generative mapping pieces and gets an offer to exhibit them in an art gallery, museum or any other kind of place. 10 expensive computers? No! PiMapper is here to save you!
The addon itself is intended to be flexible as the separate components of it can be reusable. The main example of the addon can be used as a standalone application for experimenting, testing as well as production state of a project. If you need to save memory and processing power, reusing ofxPiMapper classes without adding the GUI layer can help you.
ofxPiMapper features FBO sources that allow you to create generative openFrameworks patches to be used with ofxPiMapper. Extend the `FboSource` class, override `setup()`, `update()` and `draw()` methods and then create an instance of your custom source to add it to your ofxPiMapper object.
As ofxPiMapper is optimized for the Pi, there is no doubt that it will run smoothly on other machines. It has been tested on OS X so far.
```
ofxPiMapper* mapper = new ofxPiMapper();
CustomSource* source = new CustomSource();
mapper.addFboSource(source);
mapper.setup(); // Setup must be run after adding the FBO source
```
Since version 0.2.0 ofxPiMapper supports video sources.
Development
-----------
@ -80,7 +87,7 @@ In this mode you can adjust the texture coordinates of the surface you have sele
Here you can select, move and distort the surfaces you have created.
####Souce assignment mode
####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.
@ -91,9 +98,8 @@ These other shortcuts that you can use while using the example app. Remember tha
Key | Function
:--- | :---
i | Show info
n | Add triangle surface
t | Add triangle surface
q | Add quad surface
r | Add random triangle surface
f | Toggle fullscreen
s | Save composition
BACKSPACE | Delete surface
@ -108,10 +114,7 @@ Dependencies
To install dependencies, `cd` into `openFrameworks/addons` directory and execute the following:
```
git clone https://github.com/jvcleave/ofxOMXPlayer.git
... many lines inbetween
git clone https://github.com/bakercp/ofxIO.git
... many lines here as well
git clone https://github.com/jvcleave/ofxOMXPlayer.git && git clone https://github.com/bakercp/ofxIO.git
```
And you are good to go!
@ -158,7 +161,17 @@ A short wishlist for the next releases:
- Refined directoryWatcher mechanism, source lists should react on added and removed files
- OSC remote control module
- Webserver with simple interface for remote mapping
- Syphon source for Mac
- Spout source for Win
- Streaming source for RPi (fb sharing, network streams...)
- Even better structure
### Version 0.2.1 (2014-11-05):
- Added single instance feature. Now you can use ofxPiMapper as single object for your project.
- Added FBO source. You can create a custom openFrameworks application for piMapper by extending the FboSource class. Add/register your custom object as source in piMapper and you will be able to select it in the source editor. Source is saved and loaded from the settings as well.
- Fixed issue #15
- Added -f (fullscreen) flag for the Raspberry Pi version. Use `./yourApp -f` to launch it fullscreen on start.
### Version 0.2.0 (2014-10-18):
- Added logo (thanks [Irina Spicaka](http://irina.spicaka.info/))
@ -172,7 +185,7 @@ A short wishlist for the next releases:
### Version 0.1.4 (2014-07-10):
- Added fbo texture example
- Replaced the main example with the fbo texture one
- Added simple quad surface
- Added simple quad surface (thanks [sebllll](https://github.com/sebllll))
- Fixed a couple of bugs
- Introduced new branching model
- Added joint snapping

5
example/.gitignore

@ -1,6 +1,5 @@
obj
*.xcodeproj
*.plist
*.xcconfig
*.xcworkspace
*.xcuserdatad
*~
config.make

17
example/Project.xcconfig

@ -0,0 +1,17 @@
//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT.
//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED
OF_PATH = ../../..
//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE
#include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig"
//ICONS - NEW IN 0072
ICON_NAME_DEBUG = icon-debug.icns
ICON_NAME_RELEASE = icon.icns
ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/
//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to:
//ICON_FILE_PATH = bin/data/
OTHER_LDFLAGS = $(OF_CORE_LIBS)
HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS)

152
example/bin/data/defaultSurfaces.xml

@ -2,137 +2,179 @@
<surface>
<vertices>
<vertex>
<x>250.000000000</x>
<y>34.000000000</y>
<x>26.396118164</x>
<y>223.170288086</y>
</vertex>
<vertex>
<x>374.000000000</x>
<y>201.000000000</y>
<x>241.000000000</x>
<y>118.000000000</y>
</vertex>
<vertex>
<x>535.000000000</x>
<y>35.000000000</y>
<x>213.630920410</x>
<y>352.926849365</y>
</vertex>
</vertices>
<texCoords>
<texCoord>
<x>0.101999998</x>
<y>0.335999995</y>
<x>0.251666665</x>
<y>0.090000004</y>
</texCoord>
<texCoord>
<x>0.328000009</x>
<y>0.689999998</y>
<x>0.449999988</x>
<y>0.696666658</y>
</texCoord>
<texCoord>
<x>0.705999970</x>
<y>0.393999994</y>
<x>0.870000005</x>
<y>0.173333332</y>
</texCoord>
</texCoords>
<source>
<source-type>image</source-type>
<source-name>image1.jpg</source-name>
<source-name>image5.jpg</source-name>
</source>
</surface>
<surface>
<vertices>
<vertex>
<x>24.396121979</x>
<y>259.170288086</y>
<x>84.709846497</x>
<y>462.636596680</y>
</vertex>
<vertex>
<x>250.000000000</x>
<y>34.000000000</y>
<x>293.630920410</x>
<y>228.926849365</y>
</vertex>
<vertex>
<x>214.630920410</x>
<y>282.926849365</y>
<x>33.396121979</x>
<y>271.170288086</y>
</vertex>
</vertices>
<texCoords>
<texCoord>
<x>0.251666665</x>
<y>0.090000004</y>
<x>0.981523871</x>
<y>0.471785098</y>
</texCoord>
<texCoord>
<x>0.449999988</x>
<y>0.696666658</y>
<x>0.245601788</x>
<y>0.110941604</y>
</texCoord>
<texCoord>
<x>0.870000005</x>
<y>0.173333332</y>
<x>0.662217021</x>
<y>0.714698017</y>
</texCoord>
</texCoords>
<source>
<source-type>image</source-type>
<source-name>image5.jpg</source-name>
<source-type>fbo</source-type>
<source-name>Custom FBO Source</source-name>
</source>
</surface>
<surface>
<vertices>
<vertex>
<x>75.709846497</x>
<y>450.636596680</y>
<x>510.148498535</x>
<y>97.815002441</y>
</vertex>
<vertex>
<x>214.630920410</x>
<y>282.926849365</y>
<x>372.000000000</x>
<y>434.000000000</y>
</vertex>
<vertex>
<x>24.396121979</x>
<y>259.170288086</y>
<x>159.000000000</x>
<y>158.000000000</y>
</vertex>
</vertices>
<texCoords>
<texCoord>
<x>0.981523871</x>
<y>0.471785098</y>
<x>0.331067860</x>
<y>0.732035518</y>
</texCoord>
<texCoord>
<x>0.245601788</x>
<y>0.110941604</y>
<x>0.782209992</x>
<y>0.181442097</y>
</texCoord>
<texCoord>
<x>0.662217021</x>
<y>0.714698017</y>
<x>0.877761841</x>
<y>0.894570410</y>
</texCoord>
</texCoords>
<source>
<source-type>image</source-type>
<source-name>image4.jpg</source-name>
<source-type>video</source-type>
<source-name>test.mov</source-name>
</source>
</surface>
<surface>
<vertices>
<vertex>
<x>527.148498535</x>
<y>277.815002441</y>
<x>152.000000000</x>
<y>343.000000000</y>
</vertex>
<vertex>
<x>377.000000000</x>
<y>246.000000000</y>
</vertex>
<vertex>
<x>320.170959473</x>
<y>461.102355957</y>
<x>538.000000000</x>
<y>490.000000000</y>
</vertex>
<vertex>
<x>285.250427246</x>
<y>209.424682617</y>
<x>160.000000000</x>
<y>551.000000000</y>
</vertex>
</vertices>
<texCoords>
<texCoord>
<x>0.031067841</x>
<y>0.511202157</y>
<x>0.172656253</x>
<y>0.134333342</y>
</texCoord>
<texCoord>
<x>0.450178742</x>
<y>0.116164304</y>
<x>0.480374992</x>
<y>0.134333342</y>
</texCoord>
<texCoord>
<x>0.543386877</x>
<y>0.609848201</y>
<x>0.480374992</x>
<y>0.570833325</y>
</texCoord>
<texCoord>
<x>0.172656253</x>
<y>0.570833325</y>
</texCoord>
</texCoords>
<source>
<source-type>image</source-type>
<source-name>none</source-name>
<source-type>video</source-type>
<source-name>test.mov</source-name>
</source>
</surface>
<surface>
<vertices>
<vertex>
<x>509.000000000</x>
<y>50.000000000</y>
</vertex>
<vertex>
<x>629.000000000</x>
<y>383.000000000</y>
</vertex>
<vertex>
<x>276.000000000</x>
<y>358.000000000</y>
</vertex>
</vertices>
<texCoords>
<texCoord>
<x>0.500000000</x>
<y>0.000000000</y>
</texCoord>
<texCoord>
<x>1.000000000</x>
<y>1.000000000</y>
</texCoord>
<texCoord>
<x>0.000000000</x>
<y>1.000000000</y>
</texCoord>
</texCoords>
<source>
<source-type>fbo</source-type>
<source-name>Custom FBO Source</source-name>
</source>
</surface>
</surfaces>

1157
example/example.xcodeproj/project.pbxproj

File diff suppressed because it is too large

86
example/example.xcodeproj/xcshareddata/xcschemes/example Debug.xcscheme

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Debug"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

86
example/example.xcodeproj/xcshareddata/xcschemes/example Release.xcscheme

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0460"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Release">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E4B69B5A0A3A1756003C02F2"
BuildableName = "example.app"
BlueprintName = "example"
ReferencedContainer = "container:example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Release">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

22
example/openFrameworks-Info.plist

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>cc.openFrameworks.ofapp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFBundleIconFile</key>
<string>${ICON}</string>
</dict>
</plist>

43
example/src/CustomSource.cpp

@ -0,0 +1,43 @@
#include "CustomSource.h"
// Don't do any drawing here
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);
//ofBackground(0);
ofSetColor(255);
for (int i = 0; i < rects.size(); i++) {
ofRect(rects[i]);
}
}

17
example/src/CustomSource.h

@ -0,0 +1,17 @@
#pragma once
#include "ofMain.h"
#include "FboSource.h"
class CustomSource : public ofx::piMapper::FboSource {
public:
// These are overrides of FboSource virtual functions.
// FBO sources are not executing before they have been assigned to a surface.
void setup();
void update();
void draw(); // You don't have to care about fbo.begin() or fbo.end() here
private:
vector<ofRectangle> rects;
vector<float> rectSpeeds;
};

34
example/src/main.cpp

@ -1,12 +1,34 @@
#include "ofMain.h"
#include "ofApp.h"
#include <string>
int main()
{
#ifdef TARGET_RASPBERRY_PI
ofSetupOpenGL(600, 500, OF_FULLSCREEN);
// Accept arguments in the Pi version
int main(int argc, char* argv[]) {
bool fullscreen = false;
if (argc > 0) {
std::string fullscreenFlag = "-f";
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], fullscreenFlag.c_str()) == 0) {
fullscreen = true;
break;
}
}
}
if (fullscreen) {
ofSetupOpenGL(600, 500, OF_FULLSCREEN);
} else {
ofSetupOpenGL(800, 450, OF_WINDOW);
}
ofRunApp(new ofApp());
}
#else
ofSetupOpenGL(600, 500, OF_WINDOW);
int main() {
ofSetupOpenGL(800, 600, OF_WINDOW);
ofRunApp(new ofApp());
}
#endif
ofRunApp(new ofApp());
}

193
example/src/ofApp.cpp

@ -1,190 +1,19 @@
#include "ofApp.h"
void ofApp::setup() {
bShowInfo = false;
// Pass pointers to our media server instance to both:
// surface manager and it's gui, only then we will be able to
// load surface data from xml settings files
surfaceManager.setMediaServer(&mediaServer);
gui.setMediaServer(&mediaServer);
// check if the surfaces.xml file is there
// if not - load defaultSurfaces.xml
if (ofFile::doesFileExist("surfaces.xml")) {
surfaceManager.loadXmlSettings("surfaces.xml");
} else {
surfaceManager.loadXmlSettings("defaultSurfaces.xml");
}
// Pass the surface manager to the mapper graphical user interface
gui.setSurfaceManager(&surfaceManager);
// Create FBO
fbo = new ofFbo();
fbo->allocate(500, 500);
fboSource = new ofx::piMapper::BaseSource(&fbo->getTextureReference());
setFboAsSource();
// Genereate rects
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)));
}
}
void ofApp::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();
}
}
// Fill FBO
fbo->begin();
ofClear(0);
ofBackground(0);
ofSetColor(255);
for (int i = 0; i < rects.size(); i++) {
ofRect(rects[i]);
}
fbo->end();
// 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.
piMapper.addFboSource(customSource);
piMapper.setup();
// The info layer is hidden by default, press <i> to toggle
// piMapper.showInfo();
}
void ofApp::draw() {
// Draw the piMapper GUI
gui.draw();
if (bShowInfo) {
// Draw instructions
stringstream ss;
ss << "There are 4 modes:\n\n";
ss << " 1. Presentation mode\n";
ss << " 2. Texture mapping mode\n";
ss << " 3. Projection mapping mode\n";
ss << " 4. Source selection mode\n\n";
ss << "You can switch between the modes by using <1>, <2>, <3> and <4> "
"keys on the keyboard.\n\n";
ss << "Press <r> or <n> to add random or normal surface.\n";
ss << "Press <q> to add a new quad surface.\n";
ss << "Press <s> to save the composition.\n";
ss << "Press <f> to toggle fullscreen.\n";
ss << "Press <a> to reassign the fbo texture to the first surface\n";
ss << "Hit <i> to hide this message.";
ofDrawBitmapStringHighlight(ss.str(), 10, 20, ofColor(0, 0, 0, 100),
ofColor(255, 255, 255, 200));
}
}
void ofApp::exit() {
// Clear FBO from mem
delete fbo;
}
void ofApp::keyPressed(int key) {
cout << "Key pressed: " << static_cast<char>(key) << endl;
switch (key) {
case '1':
gui.setMode(ofx::piMapper::GuiMode::NONE);
break;
case '2':
gui.setMode(ofx::piMapper::GuiMode::TEXTURE_MAPPING);
break;
case '3':
gui.setMode(ofx::piMapper::GuiMode::PROJECTION_MAPPING);
break;
case '4':
gui.setMode(ofx::piMapper::GuiMode::SOURCE_SELECTION);
break;
case 'i':
bShowInfo = !bShowInfo;
break;
case 'r':
addRandomSurface();
break;
case 'q':
addQuadSurface();
break;
case 'n':
addSurface();
break;
case 'f':
ofToggleFullscreen();
break;
case 's':
surfaceManager.saveXmlSettings("surfaces.xml");
break;
case 'a':
setFboAsSource();
break;
case OF_KEY_BACKSPACE:
surfaceManager.removeSelectedSurface();
break;
default:
break;
}
}
void ofApp::addRandomSurface() {
int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::addQuadSurface() {
int surfaceType = ofx::piMapper::SurfaceType::QUAD_SURFACE;
vector<ofVec2f> vertices;
int border = 50;
vertices.push_back(ofVec2f(border, border));
vertices.push_back(ofVec2f(ofGetWidth() - border, border));
vertices.push_back(ofVec2f(ofGetWidth() - border, ofGetHeight() - border));
vertices.push_back(ofVec2f(border, ofGetHeight() - border));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 1.0f)));
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 1.0f)));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::addSurface() {
int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back(ofVec2f((float)ofGetWidth() / 2.0f, 0.0f));
vertices.push_back(ofVec2f((float)ofGetWidth(), (float)ofGetHeight()));
vertices.push_back(ofVec2f(0.0f, (float)ofGetHeight()));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(0.5f, 0.0f));
texCoords.push_back(ofVec2f(1.0f, 1.0f));
texCoords.push_back(ofVec2f(0.0f, 1.0f));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::setFboAsSource() {
surfaceManager.getSurface(0)->setSource(fboSource);
piMapper.draw();
}

27
example/src/ofApp.h

@ -2,29 +2,16 @@
#include "ofMain.h"
#include "ofxPiMapper.h"
#include "BaseSource.h"
#include "CustomSource.h"
class ofApp : public ofBaseApp {
public:
public:
void setup();
void update();
void draw();
void exit();
void keyPressed(int key);
void addRandomSurface();
void addQuadSurface();
void addSurface();
void setFboAsSource();
ofImage image;
ofx::piMapper::MediaServer mediaServer;
ofx::piMapper::SurfaceManager surfaceManager;
ofx::piMapper::SurfaceManagerGui gui;
bool bShowInfo;
ofFbo* fbo;
ofx::piMapper::BaseSource* fboSource;
vector<ofRectangle> rects;
vector<float> rectSpeeds;
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;
};

96
src/MediaServer/MediaServer.cpp

@ -23,6 +23,7 @@ namespace piMapper {
int MediaServer::getNumImages() { return imageWatcher.getFilePaths().size(); }
int MediaServer::getNumVideos() { return videoWatcher.getFilePaths().size(); }
int MediaServer::getNumFboSources() { return fboSources.size(); }
std::vector<std::string>& MediaServer::getImagePaths() {
return imageWatcher.getFilePaths();
@ -40,6 +41,14 @@ namespace piMapper {
return imageNames;
}
std::vector<std::string> MediaServer::getFboSourceNames() {
std::vector<std::string> fboSourceNames;
for (int i = 0; i < fboSources.size(); i++) {
fboSourceNames.push_back(fboSources[i]->getName());
}
return fboSourceNames;
}
std::vector<std::string>& MediaServer::getVideoPaths() {
return videoWatcher.getFilePaths();
}
@ -56,14 +65,14 @@ namespace piMapper {
return videoNames;
}
BaseSource* MediaServer::loadMedia(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;
@ -214,16 +223,15 @@ namespace piMapper {
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 {
std:stringstream ss;
ss << "Media with path " << path << " is not loaded and thus can't be unloaded";
ofLogFatalError("MediaServer") << ss.str();
std::exit(EXIT_FAILURE);
ofLogNotice("MediaServer") << "Nothing to unload";
}
}
@ -231,11 +239,15 @@ namespace piMapper {
void MediaServer::clear() {
typedef std::map<std::string, BaseSource*>::iterator it_type;
for (it_type i = loadedSources.begin(); i != loadedSources.end(); i++) {
delete i->second;
// 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];
@ -268,6 +280,76 @@ namespace piMapper {
}
}
void MediaServer::addFboSource(ofx::piMapper::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
}
}
ofLogNotice("MediaServer") << "Source new, adding";
fboSources.push_back(&fboSource);
} // addFboSource
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 = NULL;
for (int i = 0; i < fboSources.size(); i++) {
if (fboSources[i]->getName() == fboSourceName) {
source = fboSources[i];
break;
}
}
// Panic if not in storage
if (source == NULL) {
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;
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;
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<FboSource*>(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->removeAppListeners();
std::map<std::string, BaseSource*>::iterator it = loadedSources.find(fboSourceName);
loadedSources.erase(it);
ofLogNotice("MediaServer") << "Source count after FBO source removal: " << loadedSources.size() << endl;
ofNotifyEvent(onFboSourceUnloaded, fboSourceName, this);
}
} // unloadFboSource
void MediaServer::handleImageAdded(string& path) {
ofNotifyEvent(onImageAdded, path, this);
}

37
src/MediaServer/MediaServer.h

@ -6,6 +6,9 @@
//
//
// TODO: move reference counting, enabling and disabling of sources
// to source classes themselves
#pragma once
#include "ofMain.h"
@ -13,6 +16,7 @@
#include "BaseSource.h"
#include "ImageSource.h"
#include "VideoSource.h"
#include "FboSource.h"
#include "SourceType.h"
#define DEFAULT_IMAGES_DIR "sources/images/"
@ -28,10 +32,12 @@ class MediaServer {
int getNumVideos();
int getNumImages();
int getNumFboSources(); // new
std::vector<std::string>& getVideoPaths();
std::vector<std::string> getVideoNames();
std::vector<std::string>& getImagePaths();
std::vector<std::string> getImageNames();
std::vector<std::string> getFboSourceNames(); // new
BaseSource* loadMedia(string& path, int mediaType);
BaseSource* loadImage(string& path);
@ -45,15 +51,25 @@ class MediaServer {
std::string getDefaultVideoDir();
std::string getDefaultMediaDir(int sourceType);
// Custom events
ofEvent<string> onImageAdded;
ofEvent<string> onImageRemoved;
ofEvent<string> onVideoAdded;
ofEvent<string> onVideoRemoved;
ofEvent<string> onImageLoaded;
ofEvent<string> onImageUnloaded;
ofEvent<string> onVideoLoaded;
ofEvent<string> onVideoUnloaded;
// Do things with FBO sources
void addFboSource(FboSource& fboSource); // could be called also as register FBO source
BaseSource* loadFboSource(std::string& fboSourceName);
void unloadFboSource(std::string& fboSourceName);
// Custom events, add/remove
ofEvent<std::string> onImageAdded;
ofEvent<std::string> onImageRemoved;
ofEvent<std::string> onVideoAdded;
ofEvent<std::string> onVideoRemoved;
ofEvent<std::string> onFboSourceAdded;
ofEvent<std::string> onFboSourceRemoved;
// load/unload
ofEvent<std::string> onImageLoaded;
ofEvent<std::string> onImageUnloaded;
ofEvent<std::string> onVideoLoaded;
ofEvent<std::string> onVideoUnloaded;
ofEvent<std::string> onFboSourceLoaded;
ofEvent<std::string> onFboSourceUnloaded;
private:
// Directory Watchers
@ -86,6 +102,9 @@ class MediaServer {
// Remove event listeners to image and video watcher events
void removeWatcherListeners();
// FBO source storage before they go to loadedSources
std::vector<FboSource*> fboSources; // FBO source storage
};
} // namespace piMapper
} // namespace ofx

3
src/Sources/BaseSource.h

@ -18,6 +18,9 @@ namespace ofx {
int getType();
std::string& getPath();
virtual void clear() {};
// TODO: add virtual increaseReferenceCount and decreaseReferenceCount methods
// and make the variable protected
int referenceCount;
private:

81
src/Sources/FboSource.cpp

@ -0,0 +1,81 @@
#include "FboSource.h"
namespace ofx {
namespace piMapper {
FboSource::FboSource() : fbo(NULL) {
name = PIMAPPER_DEF_FBO_SOURCE_NAME;
loadable = false;
loaded = false;
type = SourceType::SOURCE_TYPE_FBO;
ofAddListener(ofEvents().setup, this, &FboSource::onAppSetup, OF_EVENT_ORDER_BEFORE_APP);
}
FboSource::~FboSource() {
removeAppListeners();
clear();
}
void FboSource::addAppListeners() {
ofLogNotice("FboSource") << "Adding app listeners";
ofAddListener(ofEvents().update, this, &FboSource::onAppUpdate, OF_EVENT_ORDER_BEFORE_APP);
ofAddListener(ofEvents().draw, this, &FboSource::onAppDraw, OF_EVENT_ORDER_BEFORE_APP);
ofAddListener(ofEvents().exit, this, &FboSource::onAppExit, OF_EVENT_ORDER_AFTER_APP);
}
void FboSource::removeAppListeners() {
ofLogNotice("FboSource") << "Removing app listeners";
ofRemoveListener(ofEvents().update, this, &FboSource::onAppUpdate, OF_EVENT_ORDER_BEFORE_APP);
ofRemoveListener(ofEvents().draw, this, &FboSource::onAppDraw, OF_EVENT_ORDER_BEFORE_APP);
ofRemoveListener(ofEvents().exit, this, &FboSource::onAppExit, OF_EVENT_ORDER_AFTER_APP);
}
void FboSource::onAppSetup(ofEventArgs &args) {
ofRemoveListener(ofEvents().setup, this, &FboSource::onAppSetup, OF_EVENT_ORDER_BEFORE_APP);
setup();
}
void FboSource::onAppUpdate(ofEventArgs &args) {
if (fbo == NULL || !fbo->isAllocated()) {
ofLogWarning("FboSource") << "FBO not allocated";
return;
}
update();
}
void FboSource::onAppDraw(ofEventArgs &args) {
if (fbo == NULL || !fbo->isAllocated()) {
ofLogWarning("FboSource") << "FBO not allocated";
return;
}
fbo->begin();
draw();
fbo->end();
}
void FboSource::onAppExit(ofEventArgs &args) {
exit();
}
void FboSource::allocate(int width, int height) {
clear();
fbo = new ofFbo();
fbo->allocate(width, height);
// Clear FBO
fbo->begin();
ofClear(0);
fbo->end();
texture = &(fbo->getTextureReference());
}
void FboSource::clear() {
texture = NULL;
if (fbo != NULL) {
delete fbo;
fbo = NULL;
}
}
} // namespace piMapper
} // namespace ofx

49
src/Sources/FboSource.h

@ -0,0 +1,49 @@
/*
Use this as base class for your generative sources:
class YourGenerativeSource : public FboSource {
// Your code here
}
*/
#pragma once
#include "ofMain.h"
#include "BaseSource.h"
#define PIMAPPER_DEF_FBO_SOURCE_NAME "FBO Source"
namespace ofx {
namespace piMapper {
class FboSource : public BaseSource {
public:
FboSource();
~FboSource();
// Add/remove calls to update and draw
// App listeners are added once the source is assigned to at least one surface
// App listeners are removed once the source is not assigned anywhere
void addAppListeners();
void removeAppListeners();
// These are called on app events
void onAppSetup(ofEventArgs& args);
void onAppUpdate(ofEventArgs& args);
void onAppDraw(ofEventArgs& args);
void onAppExit(ofEventArgs& args);
// Override these in your custom FBO source
virtual void setup() {}; // Don't do any drawing here
virtual void update() {}; // Don't do any drawing here
// You don't need to take care of fbo.begin() and fbo.end() here;
virtual void draw() {}; // But this is the only place where you shoud do drawing
virtual void exit() {};
// Use these to set up FBo itself
void allocate(int width, int height);
void clear(); // The only method from BaseSource to be overriden
protected:
ofFbo* fbo;
};
} // namespace piMapper
} // namespace ofx

7
src/Sources/SourceType.h

@ -5,12 +5,13 @@
#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 SourceType {
public:
enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IMAGE, SOURCE_TYPE_VIDEO };
enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IMAGE, SOURCE_TYPE_VIDEO, SOURCE_TYPE_FBO };
static std::string GetSourceTypeName(int sourceTypeEnum) {
if (sourceTypeEnum == SOURCE_TYPE_IMAGE) {
@ -19,6 +20,8 @@ namespace ofx {
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;
@ -34,6 +37,8 @@ namespace ofx {
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;

19
src/Surfaces/SurfaceManager.cpp

@ -225,13 +225,18 @@ void SurfaceManager::loadXmlSettings(string fileName) {
if (sourceName != "" && sourceName != "none" && sourceType != "") {
// Load source depending on type
int typeEnum = SourceType::GetSourceTypeEnum(sourceType);
// Construct full path
string dir = mediaServer->getDefaultMediaDir(typeEnum);
std::stringstream pathss;
pathss << ofToDataPath(dir, true) << sourceName;
string sourcePath = pathss.str();
// Load media by using full path
source = mediaServer->loadMedia(sourcePath, typeEnum);
if (typeEnum == SourceType::SOURCE_TYPE_FBO) {
// Load FBO source using sourceName
source = mediaServer->loadMedia(sourceName, typeEnum);
} else {
// Construct full path
string dir = mediaServer->getDefaultMediaDir(typeEnum);
std::stringstream pathss;
pathss << ofToDataPath(dir, true) << sourceName;
string sourcePath = pathss.str();
// Load media by using full path
source = mediaServer->loadMedia(sourcePath, typeEnum);
}
}
xmlSettings.popTag(); // source
xmlSettings.pushTag("vertices");

148
src/UserInterface/SourcesEditor.cpp

@ -11,6 +11,12 @@ namespace piMapper {
addMediaServerListeners();
}
void SourcesEditor::init() {
mediaServer = NULL; // Pointers to NULL pointer so we can check later
isMediaServerExternal = false;
registerAppEvents();
}
SourcesEditor::SourcesEditor(MediaServer* externalMediaServer) {
init();
// Assign external MediaServer instance pointer
@ -23,6 +29,7 @@ namespace piMapper {
unregisterAppEvents();
delete imageSelector;
delete videoSelector;
delete fboSelector;
removeMediaServerListeners();
clearMediaServer();
}
@ -38,10 +45,12 @@ namespace piMapper {
void SourcesEditor::setup(ofEventArgs& args) {
imageSelector = new RadioList();
videoSelector = new RadioList();
fboSelector = new RadioList();
// Get media count
int numImages = mediaServer->getNumImages();
int numVideos = mediaServer->getNumVideos();
int numFbos = mediaServer->getNumFboSources();
// Depending on media count, decide what to load and initialize
if (numImages) {
@ -55,16 +64,25 @@ namespace piMapper {
videoSelector->setup("Videos", videoNames, mediaServer->getVideoPaths());
ofAddListener(videoSelector->onRadioSelected, this, &SourcesEditor::handleVideoSelected);
}
if (numFbos) {
std::vector<std::string> fboNames = mediaServer->getFboSourceNames();
fboSelector->setup("FBOs", fboNames, fboNames);
ofAddListener(fboSelector->onRadioSelected, this, &SourcesEditor::handleFboSelected);
}
// Align menus
int menuPosX = 20;
int distX = 230;
if (numImages) {
imageSelector->setPosition(20, 20);
if (numVideos) {
videoSelector->setPosition(250, 20);
}
} else {
if (numVideos) {
videoSelector->setPosition(20, 20);
}
imageSelector->setPosition(menuPosX, 20);
menuPosX += distX;
}
if (numVideos) {
videoSelector->setPosition(menuPosX, 20);
menuPosX += distX;
}
if (numFbos) {
fboSelector->setPosition(menuPosX, 20);
}
}
@ -81,6 +99,9 @@ namespace piMapper {
if (videoSelector->size()) {
videoSelector->draw();
}
if (fboSelector->size()) {
fboSelector->draw();
}
}
@ -91,6 +112,9 @@ namespace piMapper {
if (videoSelector->size()) {
videoSelector->disable();
}
if (fboSelector->size()) {
fboSelector->disable();
}
}
void SourcesEditor::enable() {
@ -105,6 +129,9 @@ namespace piMapper {
if (videoSelector->size()) {
videoSelector->enable();
}
if (fboSelector->size()) {
fboSelector->enable();
}
BaseSource* source = surfaceManager->getSelectedSurface()->getSource();
selectSourceRadioButton(source->getPath());
}
@ -137,18 +164,25 @@ namespace piMapper {
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 (imageRadioSelected || videoRadioSelected) {
if (fboSelector->size()) {
fboRadioSelected = fboSelector->selectItemByValue(sourcePath);
}
if (imageRadioSelected || videoRadioSelected || fboRadioSelected) {
return;
}
// Log warning if we are still here
@ -156,12 +190,6 @@ namespace piMapper {
}
}
void SourcesEditor::init() {
mediaServer = NULL; // Pointers to NULL pointer so we can check later
isMediaServerExternal = false;
registerAppEvents();
}
void SourcesEditor::addMediaServerListeners() {
// Check if the media server is valid
if (mediaServer == NULL) {
@ -176,6 +204,11 @@ namespace piMapper {
ofAddListener(mediaServer->onImageLoaded, this, &SourcesEditor::handleImageLoaded);
ofAddListener(mediaServer->onImageUnloaded, this, &SourcesEditor::handleImageUnloaded);
ofAddListener(mediaServer->onFboSourceAdded, this, &SourcesEditor::handleFboSourceAdded);
ofAddListener(mediaServer->onFboSourceRemoved, this, &SourcesEditor::handleFboSourceRemoved);
ofAddListener(mediaServer->onFboSourceLoaded, this, &SourcesEditor::handleFboSourceLoaded);
ofAddListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditor::handleFboSourceUnloaded);
}
void SourcesEditor::removeMediaServerListeners() {
@ -191,42 +224,81 @@ namespace piMapper {
ofRemoveListener(mediaServer->onVideoRemoved, this, &SourcesEditor::handleVideoRemoved);
ofRemoveListener(mediaServer->onImageLoaded, this, &SourcesEditor::handleImageLoaded);
ofRemoveListener(mediaServer->onImageUnloaded, this, &SourcesEditor::handleImageUnloaded);
ofRemoveListener(mediaServer->onFboSourceAdded, this, &SourcesEditor::handleFboSourceAdded);
ofRemoveListener(mediaServer->onFboSourceRemoved, this, &SourcesEditor::handleFboSourceRemoved);
ofRemoveListener(mediaServer->onFboSourceLoaded, this, &SourcesEditor::handleFboSourceLoaded);
ofRemoveListener(mediaServer->onFboSourceUnloaded, this, &SourcesEditor::handleFboSourceUnloaded);
}
void SourcesEditor::handleImageSelected(string& imagePath) {
// Unselect video item if any selected
// Unselect selected items
videoSelector->unselectAll();
fboSelector->unselectAll();
BaseSurface* surface = surfaceManager->getSelectedSurface();
if (surface == NULL) {
ofLogNotice("SourcesEditor") << "No surface selected";
ofLogWarning("SourcesEditor") << "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 SourcesEditor::handleVideoSelected(string& videoPath) {
// Unselect image item if any selected
// Unselect any selected items
fboSelector->unselectAll();
imageSelector->unselectAll();
BaseSurface* surface = surfaceManager->getSelectedSurface();
if (surface == NULL) {
ofLogNotice("SourcesEditor") << "No surface selected";
ofLogWarning("SourcesEditor") << "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 SourcesEditor::handleFboSelected(string &fboName) {
videoSelector->unselectAll();
imageSelector->unselectAll();
// Get selected surface
BaseSurface* surface = surfaceManager->getSelectedSurface();
if (surface == NULL) {
ofLogWarning("SourcesEditor") << "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 SourcesEditor::clearMediaServer() {
// If mediaServer is local, clear it
if (!isMediaServerExternal) {
@ -238,34 +310,16 @@ namespace piMapper {
}
}
void SourcesEditor::handleImageAdded(string& path) {
cout << "image added: " << path << endl;
}
void SourcesEditor::handleImageRemoved(string& path) {
cout << "image removed: " << path << endl;
}
void SourcesEditor::handleVideoAdded(string& path) {
cout << "video added: " << path << endl;
}
void SourcesEditor::handleVideoRemoved(string& path) {
cout << "video removed: " << path << endl;
}
void SourcesEditor::handleImageLoaded(string& path) {
cout << "Image loaded: " << path << endl;
// Test image unload
// mediaServer->unloadImage(path);
//BaseSource* source = mediaServer->getSourceByPath(path);
//surfaceManager->getSelectedSurface()->setSource(source);
}
void SourcesEditor::handleImageAdded(std::string& path) {}
void SourcesEditor::handleImageRemoved(std::string& path) {}
void SourcesEditor::handleVideoAdded(std::string& path) {}
void SourcesEditor::handleVideoRemoved(std::string& path) {}
void SourcesEditor::handleImageLoaded(std::string& path) {}
void SourcesEditor::handleImageUnloaded(std::string& path) {}
void SourcesEditor::handleFboSourceAdded(std::string& name) {}
void SourcesEditor::handleFboSourceRemoved(std::string& name) {}
void SourcesEditor::handleFboSourceLoaded(std::string& name) {}
void SourcesEditor::handleFboSourceUnloaded(std::string& name) {}
void SourcesEditor::handleImageUnloaded(string& path) {
cout << "Image unloaded: " << path << endl;
}
}
}

19
src/UserInterface/SourcesEditor.h

@ -41,6 +41,7 @@ class SourcesEditor {
SurfaceManager* surfaceManager;
RadioList* imageSelector;
RadioList* videoSelector;
RadioList* fboSelector;
// Is the media server pointer local or from somewhere else?
// We use this to determine if we are allowed to clear media server locally.
@ -56,18 +57,24 @@ class SourcesEditor {
// Handles GUI event, whenever someone has clicked on a radio button
void handleImageSelected(string& imagePath);
void handleVideoSelected(string& videoPath);
void handleFboSelected(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(string& path);
void handleImageRemoved(string& path);
void handleVideoAdded(string& path);
void handleVideoRemoved(string& path);
void handleImageLoaded(string& path);
void handleImageUnloaded(string& path);
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);
};
}
}

2
src/UserInterface/TextureEditor.cpp

@ -167,7 +167,7 @@ void TextureEditor::moveTexCoords(ofVec2f by) {
surface->getSource()->getTexture()->getHeight());
for (int i = 0; i < texCoords.size(); i++) {
joints[i]->position += by;
texCoords[i] = joints[i]->position / textureSize;
surface->setTexCoord(i, joints[i]->position / textureSize);
}
}

160
src/ofxPiMapper.cpp

@ -0,0 +1,160 @@
#include "ofxPiMapper.h"
ofxPiMapper::ofxPiMapper():
bShowInfo(false),
isSetUp(false){
ofAddListener(ofEvents().keyPressed, this, &ofxPiMapper::keyPressed);
}
ofxPiMapper::~ofxPiMapper() {
ofRemoveListener(ofEvents().keyPressed, this, &ofxPiMapper::keyPressed);
}
void ofxPiMapper::setup() {
ofLogNotice("ofxPiMapper") << "Setting up...";
// Assign media server to other pi mapper components
surfaceManager.setMediaServer(&mediaServer);
gui.setMediaServer(&mediaServer);
// Check if we have user surfaces defined, if not - load default
if (ofFile::doesFileExist(PIMAPPER_USER_SURFACES_XML_FILE)) {
ofLogNotice("ofxPiMapper") << "Loading user surfaces from " << PIMAPPER_USER_SURFACES_XML_FILE;
surfaceManager.loadXmlSettings(PIMAPPER_USER_SURFACES_XML_FILE);
} else {
ofLogNotice("ofxPiMapper") << "Loading default surfaces from " << PIMAPPER_DEF_SURFACES_XML_FILE;
surfaceManager.loadXmlSettings(PIMAPPER_DEF_SURFACES_XML_FILE);
}
// The GUI needs something to interface with
gui.setSurfaceManager(&surfaceManager);
isSetUp = true;
ofLogNotice("ofxPiMapper") << "Done setting up";
}
void ofxPiMapper::draw() {
if (!isSetUp) {
return;
}
// Draw the piMapper GUI
gui.draw();
if (bShowInfo) {
// Draw instructions
stringstream ss;
ss << "There are 4 modes:\n\n";
ss << " 1. Presentation mode\n";
ss << " 2. Texture mapping mode\n";
ss << " 3. Projection mapping mode\n";
ss << " 4. Source selection mode\n\n";
ss << "You can switch between the modes by using <1>, <2>, <3> and <4> "
"keys on the keyboard.\n\n";
ss << "Press <t> to add new triangle surface\n";
ss << "Press <q> to add new quad surface\n";
ss << "Press <s> to save the composition\n";
ss << "Press <f> to toggle fullscreen\n";
ss << "Press <i> to hide this message";
ofDrawBitmapStringHighlight(ss.str(), 10, 20, ofColor(0, 0, 0, 100),
ofColor(255, 255, 255, 200));
}
} // draw
void ofxPiMapper::keyPressed(ofKeyEventArgs &args) {
ofLogNotice("ofxPiMapper") << "Key pressed: " << static_cast<char>(args.key);
switch (args.key) {
case '1':
gui.setMode(ofx::piMapper::GuiMode::NONE);
break;
case '2':
gui.setMode(ofx::piMapper::GuiMode::TEXTURE_MAPPING);
break;
case '3':
gui.setMode(ofx::piMapper::GuiMode::PROJECTION_MAPPING);
break;
case '4':
gui.setMode(ofx::piMapper::GuiMode::SOURCE_SELECTION);
break;
case 'i':
bShowInfo = !bShowInfo;
break;
case 'q':
addQuadSurface();
break;
case 't':
addTriangleSurface();
break;
case 'f':
ofToggleFullscreen();
break;
case 's':
surfaceManager.saveXmlSettings(PIMAPPER_USER_SURFACES_XML_FILE);
break;
case OF_KEY_BACKSPACE:
surfaceManager.removeSelectedSurface();
break;
default:
break;
}
} // keyPressed
void ofxPiMapper::addFboSource(ofx::piMapper::FboSource &fboSource) {
mediaServer.addFboSource(fboSource);
} // addFboSource
void ofxPiMapper::addTriangleSurface() {
int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
float margin = 50.0f;
vertices.push_back(ofVec2f((float)ofGetWidth() / 2.0f, margin));
vertices.push_back(ofVec2f((float)ofGetWidth() - margin, (float)ofGetHeight() - margin));
vertices.push_back(ofVec2f(margin, (float)ofGetHeight() - margin));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(0.5f, 0.0f));
texCoords.push_back(ofVec2f(1.0f, 1.0f));
texCoords.push_back(ofVec2f(0.0f, 1.0f));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// Select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
} // addTriangleSurface
void ofxPiMapper::addQuadSurface() {
int surfaceType = ofx::piMapper::SurfaceType::QUAD_SURFACE;
vector<ofVec2f> vertices;
float margin = 50.0f;
vertices.push_back(ofVec2f(margin, margin));
vertices.push_back(ofVec2f((float)ofGetWidth() - margin, margin));
vertices.push_back(ofVec2f((float)ofGetWidth() - margin, (float)ofGetHeight() - margin));
vertices.push_back(ofVec2f(margin, (float)ofGetHeight() - margin));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 1.0f)));
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 1.0f)));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
} // addQuadSurface
ofx::piMapper::MediaServer& ofxPiMapper::getMediaServer() {
return mediaServer;
}
ofx::piMapper::SurfaceManager& ofxPiMapper::getSurfaceManager() {
return surfaceManager;
}

38
src/ofxPiMapper.h

@ -1,6 +1,42 @@
#pragma once
#include "ofMain.h"
#include "SurfaceManager.h"
#include "SurfaceManagerGui.h"
#include "MediaServer.h"
#include "FboSource.h"
#include "MediaServer.h"
#define PIMAPPER_DEF_SURFACES_XML_FILE "defaultSurfaces.xml"
#define PIMAPPER_USER_SURFACES_XML_FILE "surfaces.xml"
class ofxPiMapper {
public:
ofxPiMapper();
~ofxPiMapper();
void setup();
void draw(); // Called manually to make custom layering possible
void keyPressed(ofKeyEventArgs& args);
// Use this to add custom FBO source
void addFboSource(ofx::piMapper::FboSource& fboSource);
// TODO: Copy/move these methods to SurfaceManager
void addTriangleSurface();
void addQuadSurface();
// Toggle help / info
void showInfo() { bShowInfo = true; };
void hideInfo() { bShowInfo = false; };
// Getters
ofx::piMapper::MediaServer& getMediaServer();
ofx::piMapper::SurfaceManager& getSurfaceManager();
private:
bool isSetUp;
bool bShowInfo;
ofx::piMapper::MediaServer mediaServer;
ofx::piMapper::SurfaceManager surfaceManager;
ofx::piMapper::SurfaceManagerGui gui;
};
Loading…
Cancel
Save