diff --git a/example/example.xcodeproj/project.pbxproj b/example/example.xcodeproj/project.pbxproj index f83a8eb..f9654e4 100644 --- a/example/example.xcodeproj/project.pbxproj +++ b/example/example.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 3933D5D919BB87BD000ACA55 /* ofxSliderGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3933D5CF19BB87BD000ACA55 /* ofxSliderGroup.cpp */; }; 3933D5DA19BB87BD000ACA55 /* ofxToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3933D5D119BB87BD000ACA55 /* ofxToggle.cpp */; }; 397EFC7C1A08E7680009286E /* ofxPiMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 397EFC7B1A08E7680009286E /* ofxPiMapper.cpp */; }; + 397EFC7F1A08FE720009286E /* FboSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 397EFC7D1A08FE720009286E /* FboSource.cpp */; }; + 397EFC821A09047C0009286E /* CustomSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 397EFC801A09047C0009286E /* CustomSource.cpp */; }; 39C1243319EE9589005DF557 /* lz4.c in Sources */ = {isa = PBXBuildFile; fileRef = 39C123EA19EE9589005DF557 /* lz4.c */; }; 39C1243419EE9589005DF557 /* Base64Encoding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C1241219EE9589005DF557 /* Base64Encoding.cpp */; }; 39C1243519EE9589005DF557 /* ByteBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C1241319EE9589005DF557 /* ByteBuffer.cpp */; }; @@ -138,6 +140,10 @@ 3933D5D219BB87BD000ACA55 /* ofxToggle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxToggle.h; sourceTree = ""; }; 39366FD519BDA95E006E5BE6 /* ofxPiMapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxPiMapper.h; sourceTree = ""; }; 397EFC7B1A08E7680009286E /* ofxPiMapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxPiMapper.cpp; sourceTree = ""; }; + 397EFC7D1A08FE720009286E /* FboSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FboSource.cpp; sourceTree = ""; }; + 397EFC7E1A08FE720009286E /* FboSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FboSource.h; sourceTree = ""; }; + 397EFC801A09047C0009286E /* CustomSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomSource.cpp; sourceTree = ""; }; + 397EFC811A09047C0009286E /* CustomSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomSource.h; sourceTree = ""; }; 39C123E719EE9589005DF557 /* alphanum.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = alphanum.hpp; sourceTree = ""; }; 39C123EA19EE9589005DF557 /* lz4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lz4.c; sourceTree = ""; }; 39C123EB19EE9589005DF557 /* lz4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lz4.h; sourceTree = ""; }; @@ -577,6 +583,8 @@ 39C1245B19F08965005DF557 /* ImageSource.h */, 39C1245C19F08965005DF557 /* VideoSource.cpp */, 39C1245D19F08965005DF557 /* VideoSource.h */, + 397EFC7D1A08FE720009286E /* FboSource.cpp */, + 397EFC7E1A08FE720009286E /* FboSource.h */, ); path = Sources; sourceTree = ""; @@ -696,6 +704,8 @@ E4B69E1D0A3A1BDC003C02F2 /* main.cpp */, E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */, E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */, + 397EFC801A09047C0009286E /* CustomSource.cpp */, + 397EFC811A09047C0009286E /* CustomSource.h */, ); path = src; sourceTree = SOURCE_ROOT; @@ -810,6 +820,7 @@ 39C1246A19F0AB96005DF557 /* QuadSurface.cpp in Sources */, 39C1247F19F187D5005DF557 /* RadioList.cpp in Sources */, 39C1243419EE9589005DF557 /* Base64Encoding.cpp in Sources */, + 397EFC7F1A08FE720009286E /* FboSource.cpp in Sources */, E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */, 39C1244719EE9589005DF557 /* RegexPathFilter.cpp in Sources */, 39C1247C19F187D5005DF557 /* BaseJoint.cpp in Sources */, @@ -850,6 +861,7 @@ 39264842192224F90008A7F5 /* tinyxmlerror.cpp in Sources */, 3926483B192224DA0008A7F5 /* ofxXmlSettings.cpp in Sources */, 39C1245119EE95DD005DF557 /* DirectoryWatcher.cpp in Sources */, + 397EFC821A09047C0009286E /* CustomSource.cpp in Sources */, 39C1243819EE9589005DF557 /* ByteBufferWriter.cpp in Sources */, 3933D5D519BB87BD000ACA55 /* ofxGuiGroup.cpp in Sources */, ); diff --git a/example/src/CustomSource.cpp b/example/src/CustomSource.cpp new file mode 100644 index 0000000..08d0f9a --- /dev/null +++ b/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]); + } +} \ No newline at end of file diff --git a/example/src/CustomSource.h b/example/src/CustomSource.h new file mode 100644 index 0000000..5993d80 --- /dev/null +++ b/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 rects; + vector rectSpeeds; +}; \ No newline at end of file diff --git a/example/src/ofApp.cpp b/example/src/ofApp.cpp index bacbe47..6ca4ba8 100755 --- a/example/src/ofApp.cpp +++ b/example/src/ofApp.cpp @@ -1,53 +1,19 @@ #include "ofApp.h" void ofApp::setup() { + ofBackground(0); - // The ofxPiMapper is being set up automatically before the first - // ofApp setup call - piMapper.showInfo(); // The info layer is hidden by default, press to toggle - - // Create our custom FBO - fbo = new ofFbo(); - fbo->allocate(500, 500); - fboSource = new ofx::piMapper::BaseSource(&fbo->getTextureReference()); - - // Assign the FBO's texture to one of the surfaces ofxPiMapper has created - piMapper.getSurfaceManager().getSurface(0)->setSource(fboSource); - - // 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))); - } -} - -void ofApp::update() { + // 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(); - // 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 with our rects - fbo->begin(); - ofClear(0); - ofBackground(0); - ofSetColor(255); - for (int i = 0; i < rects.size(); i++) { - ofRect(rects[i]); - } - fbo->end(); + // The info layer is hidden by default, press to toggle + piMapper.showInfo(); } void ofApp::draw() { piMapper.draw(); -} - -void ofApp::exit() { - delete fbo; } \ No newline at end of file diff --git a/example/src/ofApp.h b/example/src/ofApp.h index e6cb415..008239f 100755 --- a/example/src/ofApp.h +++ b/example/src/ofApp.h @@ -2,21 +2,16 @@ #include "ofMain.h" #include "ofxPiMapper.h" -#include "BaseSource.h" +#include "CustomSource.h" class ofApp : public ofBaseApp { public: void setup(); - void update(); void draw(); - void exit(); ofxPiMapper piMapper; - // Custom FBO surface variables - ofImage image; - ofFbo* fbo; - ofx::piMapper::BaseSource* fboSource; - vector rects; - vector rectSpeeds; + // By using a custom source that is derived from FboSource + // you will be able to see the source listed in sources editor + CustomSource customSource; }; \ No newline at end of file diff --git a/src/MediaServer/MediaServer.cpp b/src/MediaServer/MediaServer.cpp index f8539bc..eee31cb 100644 --- a/src/MediaServer/MediaServer.cpp +++ b/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& MediaServer::getImagePaths() { return imageWatcher.getFilePaths(); @@ -40,6 +41,14 @@ namespace piMapper { 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(); } @@ -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::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(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::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); } diff --git a/src/MediaServer/MediaServer.h b/src/MediaServer/MediaServer.h index 3e700e1..f49f0ea 100644 --- a/src/MediaServer/MediaServer.h +++ b/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& getVideoPaths(); std::vector getVideoNames(); std::vector& getImagePaths(); std::vector getImageNames(); + std::vector 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 onImageAdded; - ofEvent onImageRemoved; - ofEvent onVideoAdded; - ofEvent onVideoRemoved; - ofEvent onImageLoaded; - ofEvent onImageUnloaded; - ofEvent onVideoLoaded; - ofEvent 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 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 @@ -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 fboSources; // FBO source storage }; } // namespace piMapper } // namespace ofx diff --git a/src/Sources/BaseSource.h b/src/Sources/BaseSource.h index fb5e567..5dbc894 100644 --- a/src/Sources/BaseSource.h +++ b/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: diff --git a/src/Sources/FboSource.cpp b/src/Sources/FboSource.cpp new file mode 100644 index 0000000..f64236b --- /dev/null +++ b/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 \ No newline at end of file diff --git a/src/Sources/FboSource.h b/src/Sources/FboSource.h new file mode 100644 index 0000000..2a27ded --- /dev/null +++ b/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 \ No newline at end of file diff --git a/src/Sources/SourceType.h b/src/Sources/SourceType.h index 515e2e4..ad4ebe5 100644 --- a/src/Sources/SourceType.h +++ b/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; diff --git a/src/Surfaces/SurfaceManager.cpp b/src/Surfaces/SurfaceManager.cpp index c2c8c68..929fd1f 100644 --- a/src/Surfaces/SurfaceManager.cpp +++ b/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"); diff --git a/src/UserInterface/SourcesEditor.cpp b/src/UserInterface/SourcesEditor.cpp index d106d67..622fef7 100644 --- a/src/UserInterface/SourcesEditor.cpp +++ b/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 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; - } } } \ No newline at end of file diff --git a/src/UserInterface/SourcesEditor.h b/src/UserInterface/SourcesEditor.h index e0edecc..324d038 100644 --- a/src/UserInterface/SourcesEditor.h +++ b/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); + }; } } \ No newline at end of file diff --git a/src/ofxPiMapper.cpp b/src/ofxPiMapper.cpp index 1e8bce9..546002d 100644 --- a/src/ofxPiMapper.cpp +++ b/src/ofxPiMapper.cpp @@ -3,16 +3,14 @@ ofxPiMapper::ofxPiMapper(): bShowInfo(false), isSetUp(false){ - ofAddListener(ofEvents().setup, this, &ofxPiMapper::setup, OF_EVENT_ORDER_BEFORE_APP); ofAddListener(ofEvents().keyPressed, this, &ofxPiMapper::keyPressed); } ofxPiMapper::~ofxPiMapper() { - ofRemoveListener(ofEvents().setup, this, &ofxPiMapper::setup, OF_EVENT_ORDER_BEFORE_APP); ofRemoveListener(ofEvents().keyPressed, this, &ofxPiMapper::keyPressed); } -void ofxPiMapper::setup(ofEventArgs& args) { +void ofxPiMapper::setup() { ofLogNotice("ofxPiMapper") << "Setting up..."; // Assign media server to other pi mapper components @@ -105,6 +103,10 @@ void ofxPiMapper::keyPressed(ofKeyEventArgs &args) { } } // keyPressed +void ofxPiMapper::addFboSource(ofx::piMapper::FboSource &fboSource) { + mediaServer.addFboSource(fboSource); +} // addFboSource + void ofxPiMapper::addTriangleSurface() { int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE; diff --git a/src/ofxPiMapper.h b/src/ofxPiMapper.h index ff93ab7..0a7db3d 100644 --- a/src/ofxPiMapper.h +++ b/src/ofxPiMapper.h @@ -4,6 +4,7 @@ #include "SurfaceManager.h" #include "SurfaceManagerGui.h" #include "MediaServer.h" +#include "FboSource.h" #define PIMAPPER_DEF_SURFACES_XML_FILE "defaultSurfaces.xml" #define PIMAPPER_USER_SURFACES_XML_FILE "surfaces.xml" @@ -13,11 +14,14 @@ public: ofxPiMapper(); ~ofxPiMapper(); - void setup(ofEventArgs& args); + void setup(); void draw(); // Called manually to make custom layering possible void keyPressed(ofKeyEventArgs& args); - // TODO: Move these methods to SurfaceManager + // Use this to add custom FBO source + void addFboSource(ofx::piMapper::FboSource& fboSource); + + // TODO: Copy/move these methods to SurfaceManager void addTriangleSurface(); void addQuadSurface();