diff --git a/README.md b/README.md index ffe8880..759632e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![Pi Mapper Logo](piMapperLogo.jpg) + ofxPiMapper =========== @@ -14,9 +16,11 @@ Development As the projects gets a bit more popular, I see that people want to add missing features. I have a whole bunch of features that I want to add in future releases, but right now I'm trying to understand how to keep it more or less organized. -Currently I have decided to use [A successful Git branching model](http://nvie.com/posts/a-successful-git) by [Vincent Driessen](https://twitter.com/nvie), so read this article and I do not doubt that it will help you with other Git related projects. +Currently I have decided to use [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) by [Vincent Driessen](https://twitter.com/nvie), so read this article and I do not doubt that it will help you with other Git related projects. + +I'm trying to organize the project by adding future release version milestones and assigning specific issues as TODO items to them. If you notice something strange or see that there is something that can be done in a better way, don't hesitate and add an issue. -I'm still working on boosting my understanding about the issue tracking system on GitHub, I believe that it would be the best way how to keep new feature requests and bugfixes organized. +As of Release 0.2.0 some refractoring has been done (thanks [aspeteRakete](https://github.com/aspeteRakete)), namespaces have been added and we are thinking about introducing a code style for this project. Still improving on the overal structure. Licence ------- @@ -35,6 +39,8 @@ cd ~/openFrameworks/addons git clone https://github.com/kr15h/ofxPiMapper.git ``` +Before moving on, make sure that you have all the dependencies installed. Refer to the **Dependencies** section to see what you need. + To test the addon, you will have to compile and run it: ```bash @@ -42,11 +48,7 @@ cd ~/openFrameworks/addons/ofxPiMapper/example make ``` -After it compiles, run it by executing it directly instead of using `make run`: - -``` -./bin/example -``` +After it compiles, run it with either `make run` or `./bin/example` It will take a while first, but once it runs, press 1, 2, 3 and 4 keys to switch between modes of the software. Switch to mode 3 at first to select a surface. Afterwards you will be able to edit the texture mapping of it in mode 2 and choose a source in mode 4. Mode 1 is the presentation mode. It is activated on start by default. @@ -98,19 +100,74 @@ BACKSPACE | Delete surface Dependencies ------------ -[ofxUI](https://github.com/rezaali/ofxUI) - will be replaced with custom solution as it consumes a lot of processing power. -ofxXmlSettings + - ofxGui + - ofxXmlSettings + - [ofxIO](https://github.com/bakercp/ofxIO) + - [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) + +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 +``` + +And you are good to go! Compatibility ------------ -Tested with 0.8.0, 0.8.1 (OS X and Raspbian) +Tested with 0.8.1 - 0.8.4 (OS X and Raspbian) Known issues ------------ -When launching the example with `make run` keyboard and mouse input is being lost sometimes. Executing the example directly by using `./bin/example` might solve the problem. Not sure how and why. +Keyboard and mouse input is being lost sometimes on the Raspberry Pi. Not sure how and why. Probably because of bad drivers and it seems that Raspberry Pi keyboard and mouse code in openFrameworks is not quite ready yet. Some claim that the following commands solves the issue: + +``` +sudo apt-get update && sudo apt-get dist-upgrade +sudo rpi-update +``` + +[ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer) has an issue, it throws an error when compiling: + +``` +fatal error: libavcodec/opt.h: No such file or directory +``` + +To fix that, create a file `opt.h` in `addons/ofxOMXPlayer/libs/ffmpeg/libavcodec/` with the following contents: + +**opt.h** + +``` +#ifndef AVCODEC_OPT_H +#define AVCODEC_OPT_H +#include "libavcodec/version.h" +#if FF_API_OPT_H +#include "libavutil/opt.h" +#endif +#endif // AVCODEC_OPT_H +``` + +More about this issue [here](https://github.com/jvcleave/ofxOMXPlayer/issues/34). Version history --------------- +###TODO +A short wishlist for the next releases: + + - Refined directoryWatcher mechanism, source lists should react on added and removed files + - OSC remote control module + - Even better structure + +### Version 0.2.0 (2014-10-18): + - Added logo (thanks [Irina Spicaka](http://irina.spicaka.info/)) + - Added perspective warping for quad surfaces (thanks [aspeteRakete](https://github.com/aspeteRakete)) + - Added namespaces + - Replaced ofxUI with ofxGui + - Added media server (thanks [aspeteRakete](https://github.com/aspeteRakete)) + - Added source types and reworked all relevant classes to support them instead of ofTexture directly + - Added video source (based on [ofxOMXPlayer](https://github.com/jvcleave/ofxOMXPlayer)) ### Version 0.1.4 (2014-07-10): - Added fbo texture example diff --git a/addon_config.mk b/addon_config.mk new file mode 100644 index 0000000..8529e37 --- /dev/null +++ b/addon_config.mk @@ -0,0 +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 optimized for the Raspberry Pi +ADDON_AUTHOR = kr15h aspeteRakete +ADDON_TAGS = "Raspberry Pi" "Projection 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 = ofxIO 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/addons.make b/example/addons.make index 802cd29..6546213 100644 --- a/example/addons.make +++ b/example/addons.make @@ -1,3 +1,5 @@ ofxPiMapper -ofxUI +ofxIO ofxXmlSettings +ofxGui +ofxOMXPlayer diff --git a/example/bin/data/sources/videos/test.mov b/example/bin/data/sources/videos/test.mov new file mode 100644 index 0000000..48a307b Binary files /dev/null and b/example/bin/data/sources/videos/test.mov differ diff --git a/example/src/ofApp.cpp b/example/src/ofApp.cpp index 7012632..101e14e 100755 --- a/example/src/ofApp.cpp +++ b/example/src/ofApp.cpp @@ -1,164 +1,190 @@ #include "ofApp.h" -void ofApp::setup() -{ - bShowInfo = false; - - // 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 ); - setFboAsTexture(); - - // Genereate rects - int numRects = 20; // change this to add more or less rects - for ( int i=0; igetHeight()), fbo->getWidth(), ofRandom(20)) ); - rectSpeeds.push_back( (1.0f + ofRandom(5)) ); - } +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 fbo->getHeight() ) { - rects[i].y = -rects[i].getHeight(); - } - } - - // Fill FBO - fbo->begin(); - ofClear(0); - ofBackground(0); - ofSetColor(255); - for ( int i=0; i fbo->getHeight()) { + rects[i].y = -rects[i].getHeight(); } - fbo->end(); + } + + // Fill FBO + fbo->begin(); + ofClear(0); + ofBackground(0); + ofSetColor(255); + for (int i = 0; i < rects.size(); i++) { + ofRect(rects[i]); + } + fbo->end(); } -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 or to add random or normal surface.\n"; - ss << "Press to add a new quad surface.\n"; - ss << "Press to save the composition.\n"; - ss << "Press to toggle fullscreen.\n"; - ss << "Press to reassign the fbo texture to the first surface\n"; - ss << "Hit to hide this message."; - - ofDrawBitmapStringHighlight(ss.str(), 10, 20, ofColor(0,0,0,100), ofColor(255,255,255,200)); - } +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 or to add random or normal surface.\n"; + ss << "Press to add a new quad surface.\n"; + ss << "Press to save the composition.\n"; + ss << "Press to toggle fullscreen.\n"; + ss << "Press to reassign the fbo texture to the first surface\n"; + ss << "Hit 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::exit() { + // Clear FBO from mem + delete fbo; } -void ofApp::keyPressed(int key) -{ - cout << "Key pressed: " << static_cast(key) << endl; - - switch (key) { - case '1': gui.setMode(ofxGuiMode::NONE); break; - case '2': gui.setMode(ofxGuiMode::TEXTURE_MAPPING); break; - case '3': gui.setMode(ofxGuiMode::PROJECTION_MAPPING); break; - case '4': gui.setMode(ofxGuiMode::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': setFboAsTexture(); break; - case OF_KEY_BACKSPACE: surfaceManager.removeSelectedSurface(); break; - default: break; - } +void ofApp::keyPressed(int key) { + cout << "Key pressed: " << static_cast(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 = ofxSurfaceType::TRIANGLE_SURFACE; - vector vertices; - vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) ); - vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) ); - vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) ); - vector 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::addRandomSurface() { + int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE; + vector vertices; + vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight())); + vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight())); + vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight())); + vector 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 = ofxSurfaceType::QUAD_SURFACE; - vector vertices; - - int border = 50; - vertices.push_back( ofVec2f(border, border) ); - vertices.push_back( ofVec2f(border, ofGetHeight() - border) ); - vertices.push_back( ofVec2f(ofGetWidth() - border, ofGetHeight() - border) ); - vertices.push_back( ofVec2f(ofGetWidth() - border, border) ); - - vector 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::addQuadSurface() { + int surfaceType = ofx::piMapper::SurfaceType::QUAD_SURFACE; + vector 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 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 = ofxSurfaceType::TRIANGLE_SURFACE; - vector 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 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::addSurface() { + int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE; + vector 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 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::setFboAsTexture() -{ - surfaceManager.getSurface(0)->setTexture( &fbo->getTextureReference() ); +void ofApp::setFboAsSource() { + surfaceManager.getSurface(0)->setSource(fboSource); } \ No newline at end of file diff --git a/example/src/ofApp.h b/example/src/ofApp.h index 05d7a8f..b3455a3 100755 --- a/example/src/ofApp.h +++ b/example/src/ofApp.h @@ -1,31 +1,30 @@ -#ifndef H_OF_APP -#define H_OF_APP +#pragma once #include "ofMain.h" #include "ofxPiMapper.h" +#include "BaseSource.h" -class ofApp : public ofBaseApp -{ -public: - void setup(); - void update(); - void draw(); - void exit(); +class ofApp : public ofBaseApp { + public: + void setup(); + void update(); + void draw(); + void exit(); - void keyPressed(int key); - - void addRandomSurface(); - void addQuadSurface(); - void addSurface(); - void setFboAsTexture(); - - ofImage image; - ofxSurfaceManager surfaceManager; - ofxSurfaceManagerGui gui; - bool bShowInfo; - ofFbo* fbo; - vector rects; - vector rectSpeeds; -}; + void keyPressed(int key); -#endif \ No newline at end of file + 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 rects; + vector rectSpeeds; +}; \ No newline at end of file diff --git a/piMapperLogo.jpg b/piMapperLogo.jpg new file mode 100644 index 0000000..824fa32 Binary files /dev/null and b/piMapperLogo.jpg differ diff --git a/src/MediaServer/DirectoryWatcher.cpp b/src/MediaServer/DirectoryWatcher.cpp new file mode 100644 index 0000000..e55fa79 --- /dev/null +++ b/src/MediaServer/DirectoryWatcher.cpp @@ -0,0 +1,46 @@ +// +// DirectoryWatcher.cpp +// example +// +// Created by felix on 23.09.14. +// +// + +#include "DirectoryWatcher.h" + +namespace ofx { + namespace piMapper { + DirectoryWatcher::DirectoryWatcher(std::string path, int watcherMediaType) { + mediaType = watcherMediaType; + // Decide what filter we need depending on media type + if (mediaType == SourceType::SOURCE_TYPE_VIDEO) { + filter = new VideoPathFilter(); + } else if (mediaType == SourceType::SOURCE_TYPE_IMAGE) { + filter = new ImagePathFilter(); + } else { + ofLogFatalError("DirectoryWatcher::DirectoryWatcher", "Unkonwn media type"); + std::exit(EXIT_FAILURE); + } + dirWatcher.registerAllEvents(this); + // For some reason the filters are not working, + // we leave just the path here and do the filter logic in the listeners + dirWatcher.addPath(path); + // Initial directory listing. Fill the file paths vector. + IO::DirectoryUtils::list(path, filePaths, true, filter); + } + + DirectoryWatcher::~DirectoryWatcher() { + delete filter; + filter = NULL; + } + + std::vector& DirectoryWatcher::getFilePaths() { + return filePaths; + } + + int DirectoryWatcher::getMediaType() { + return mediaType; + } + + } // namespace piMapper +} // namespace ofx \ No newline at end of file diff --git a/src/MediaServer/DirectoryWatcher.h b/src/MediaServer/DirectoryWatcher.h new file mode 100644 index 0000000..40f0bf4 --- /dev/null +++ b/src/MediaServer/DirectoryWatcher.h @@ -0,0 +1,144 @@ +// +// DirectoryWatcher.h +// example +// +// Created by felix on 23.09.14. +// +// + +#pragma once + +#include "ofMain.h" +#include "ofxIO.h" +#include "SourceType.h" + +namespace ofx { +namespace piMapper { + + class BasePathFilter : public ofx::IO::AbstractPathFilter { + public: + BasePathFilter() {}; + virtual ~BasePathFilter() {}; + virtual bool accept(const Poco::Path& path) const {}; + }; + +class VideoPathFilter : public BasePathFilter { + public: + VideoPathFilter() {}; + virtual ~VideoPathFilter() {}; + + bool accept(const Poco::Path& path) const { + return !Poco::File(path).isHidden() && + (ofIsStringInString(path.toString(), ".mp4") || + ofIsStringInString(path.toString(), ".h264")|| + ofIsStringInString(path.toString(), ".mov") || + ofIsStringInString(path.toString(), ".avi") || + ofIsStringInString(path.toString(), ".mpeg")); + } +}; + +class ImagePathFilter : public BasePathFilter { + public: + ImagePathFilter() {}; + virtual ~ImagePathFilter() {}; + + bool accept(const Poco::Path& path) const { + return !Poco::File(path).isHidden() && + (ofIsStringInString(path.toString(), ".png") || + ofIsStringInString(path.toString(), ".jpg") || + ofIsStringInString(path.toString(), ".jpeg")); + } +}; + +class DirectoryWatcher { + public: + DirectoryWatcher(std::string path, int watcherMediaType); + ~DirectoryWatcher(); + + // TODO make useful stuff with onDirectoryWatcher* + void onDirectoryWatcherItemAdded( + const ofx::IO::DirectoryWatcherManager::DirectoryEvent& evt) { + string path = evt.item.path(); + Poco::Path pocoPath = Poco::Path(path); + if (!filter->accept(pocoPath)) { + return; + } + filePaths.push_back(path); + ofNotifyEvent(onItemAdded, path, this); + } + + void onDirectoryWatcherItemRemoved( + const ofx::IO::DirectoryWatcherManager::DirectoryEvent& evt) { + string path = evt.item.path(); + Poco::Path pocoPath = Poco::Path(path); + if (!filter->accept(pocoPath)) { + return; + } + // Remove path from vector + for (int i = 0; i < filePaths.size(); i++) { + if (path == filePaths[i]) { + filePaths.erase(filePaths.begin() + i); + break; + } + } + ofNotifyEvent(onItemRemoved, path, this); + } + + void onDirectoryWatcherItemModified( + const ofx::IO::DirectoryWatcherManager::DirectoryEvent& evt) { + string path = evt.item.path(); + Poco::Path pocoPath = Poco::Path(path); + if (!filter->accept(pocoPath)) { + return; + } + ofNotifyEvent(onItemModified, path, this); + } + + void onDirectoryWatcherItemMovedFrom( + const ofx::IO::DirectoryWatcherManager::DirectoryEvent& evt) { + string path = evt.item.path(); + Poco::Path pocoPath = Poco::Path(path); + if (!filter->accept(pocoPath)) { + return; + } + ofLogNotice("ofApp::onDirectoryWatcherItemMovedFrom") + << "Moved From: " << path; + ofNotifyEvent(onItemMovedFrom, path, this); + } + + void onDirectoryWatcherItemMovedTo( + const ofx::IO::DirectoryWatcherManager::DirectoryEvent& evt) { + string path = evt.item.path(); + Poco::Path pocoPath = Poco::Path(path); + if (!filter->accept(pocoPath)) { + return; + } + ofLogNotice("ofApp::onDirectoryWatcherItemMovedTo") + << "Moved To: " << path; + ofNotifyEvent(onItemMovedTo, path, this); + } + + void onDirectoryWatcherError(const Poco::Exception& exc) { + ofLogError("ofApp::onDirectoryWatcherError") + << "Error: " << exc.displayText(); + } + + // Getters + std::vector& getFilePaths(); + int getMediaType(); + + // Custom events + ofEvent onItemAdded; + ofEvent onItemRemoved; + ofEvent onItemModified; + ofEvent onItemMovedFrom; + ofEvent onItemMovedTo; + + private: + ofx::IO::DirectoryWatcherManager dirWatcher; + BasePathFilter* filter; + std::vector filePaths; + int mediaType; +}; +} +} \ No newline at end of file diff --git a/src/MediaServer/MediaServer.cpp b/src/MediaServer/MediaServer.cpp new file mode 100644 index 0000000..f8539bc --- /dev/null +++ b/src/MediaServer/MediaServer.cpp @@ -0,0 +1,300 @@ +// +// MediaServer.cpp +// example +// +// Created by felix on 13.09.14. +// +// + +#include "MediaServer.h" + +namespace ofx { +namespace piMapper { + + MediaServer::MediaServer(): + videoWatcher(ofToDataPath(DEFAULT_VIDEOS_DIR, true), SourceType::SOURCE_TYPE_VIDEO), + imageWatcher(ofToDataPath(DEFAULT_IMAGES_DIR, true), SourceType::SOURCE_TYPE_IMAGE) { + addWatcherListeners(); + } + + MediaServer::~MediaServer() { + removeWatcherListeners(); + }; + + int MediaServer::getNumImages() { return imageWatcher.getFilePaths().size(); } + int MediaServer::getNumVideos() { return videoWatcher.getFilePaths().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::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(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 { + std::stringstream ss; + ss << "Can not load media of unknown type: " << mediaType; + ofLogFatalError("MediaServer") << ss.str(); + std::exit(EXIT_FAILURE); + } + return NULL; + } + + BaseSource* MediaServer::loadImage(string& path) { + ImageSource* imageSource = NULL; + // 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(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() << endl; + loadedSources[path]->clear(); + std::map::iterator it = loadedSources.find(path); + delete it->second; + loadedSources.erase(it); + ofLogNotice("MediaServer") << "Source count AFTER image removal: " << loadedSources.size() << 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(string& path) { + VideoSource* videoSource = NULL; + // 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(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() << endl; + videoSource->clear(); + std::map::iterator it = loadedSources.find(path); + delete it->second; + loadedSources.erase(it); + ofLogNotice("MediaServer") << "Source count after video removal: " << loadedSources.size() << 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(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 { + // 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); + } + } + + // Clear all loaded media + void MediaServer::clear() { + typedef std::map::iterator it_type; + for (it_type i = loadedSources.begin(); i != loadedSources.end(); i++) { + delete i->second; + } + loadedSources.clear(); + } + + 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::handleImageAdded(string& path) { + ofNotifyEvent(onImageAdded, path, this); + } + void MediaServer::handleImageRemoved(string& path) { + ofNotifyEvent(onImageRemoved, path, this); + } + + void MediaServer::handleVideoAdded(string& path) { + ofNotifyEvent(onVideoAdded, path, this); + } + void MediaServer::handleVideoRemoved(string& path) { + ofNotifyEvent(onVideoRemoved, path, this); + } + + void MediaServer::addWatcherListeners() { + ofAddListener(imageWatcher.onItemAdded, this, &MediaServer::handleImageAdded); + ofAddListener(imageWatcher.onItemRemoved, this, &MediaServer::handleImageRemoved); + ofAddListener(videoWatcher.onItemAdded, this, &MediaServer::handleVideoAdded); + ofAddListener(videoWatcher.onItemRemoved, this, &MediaServer::handleVideoRemoved); + } + + void MediaServer::removeWatcherListeners() { + ofRemoveListener(imageWatcher.onItemAdded, this, &MediaServer::handleImageAdded); + ofRemoveListener(imageWatcher.onItemRemoved, this, &MediaServer::handleImageRemoved); + ofRemoveListener(videoWatcher.onItemAdded, this, &MediaServer::handleVideoAdded); + ofRemoveListener(videoWatcher.onItemRemoved, this, &MediaServer::handleVideoRemoved); + } + +} // namespace piMapper +} // namespace ofx \ No newline at end of file diff --git a/src/MediaServer/MediaServer.h b/src/MediaServer/MediaServer.h new file mode 100644 index 0000000..3e700e1 --- /dev/null +++ b/src/MediaServer/MediaServer.h @@ -0,0 +1,91 @@ +// +// MediaServer.h +// example +// +// Created by felix on 13.09.14. +// +// + +#pragma once + +#include "ofMain.h" +#include "DirectoryWatcher.h" +#include "BaseSource.h" +#include "ImageSource.h" +#include "VideoSource.h" +#include "SourceType.h" + +#define DEFAULT_IMAGES_DIR "sources/images/" +#define DEFAULT_VIDEOS_DIR "sources/videos/" + +namespace ofx { +namespace piMapper { + +class MediaServer { + public: + MediaServer(); + virtual ~MediaServer(); + + int getNumVideos(); + int getNumImages(); + std::vector& getVideoPaths(); + std::vector getVideoNames(); + std::vector& getImagePaths(); + std::vector getImageNames(); + + BaseSource* loadMedia(string& path, int mediaType); + BaseSource* loadImage(string& path); + void unloadImage(string& path); + BaseSource* loadVideo(string& path); + void unloadVideo(string& path); + void unloadMedia(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); + + // Custom events + ofEvent onImageAdded; + ofEvent onImageRemoved; + ofEvent onVideoAdded; + ofEvent onVideoRemoved; + ofEvent onImageLoaded; + ofEvent onImageUnloaded; + ofEvent onVideoLoaded; + ofEvent onVideoUnloaded; + + private: + // Directory Watchers + ofx::piMapper::DirectoryWatcher videoWatcher; + ofx::piMapper::DirectoryWatcher imageWatcher; + std::map loadedSources; + // imageWatcher event listeners + void handleImageAdded(string& path); + void handleImageRemoved(string& path); + // TODO rest of listeners + /* + void onImageModified(); + void onImageMovedFrom(); + void onImageMovedTo(); + */ + + // videoWatcher event listeners + void handleVideoAdded(string& path); + void handleVideoRemoved(string& path); + // TODO rest of listeners + /* + void onVideoModified(); + void onVideoMovedFrom(); + void onVideoMovedTo(); + */ + + // Add/remove event listeners. + // Add event listeners to image and video watcher events. + void addWatcherListeners(); + + // Remove event listeners to image and video watcher events + void removeWatcherListeners(); +}; +} // namespace piMapper +} // namespace ofx diff --git a/src/Sources/BaseSource.cpp b/src/Sources/BaseSource.cpp new file mode 100644 index 0000000..d984b72 --- /dev/null +++ b/src/Sources/BaseSource.cpp @@ -0,0 +1,59 @@ +#include "BaseSource.h" + +namespace ofx { + namespace piMapper { + BaseSource::BaseSource() { + //cout << "BaseSource" << endl; + init(); + } + + 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; + } + + int BaseSource::getType() { + return type; + } + + std::string& BaseSource::getPath() { + return path; + } + + void BaseSource::init() { + texture = NULL; + name = ""; + path = ""; + loadable = false; + loaded = false; + type = SourceType::SOURCE_TYPE_NONE; + referenceCount = 1; // We have one instance on init + } + + void BaseSource::setNameFromPath(std::string& fullPath) { + std::vector pathParts; + //cout << "fullPath: " << fullPath << endl; + pathParts = ofSplitString(fullPath, "/"); // Maybe on win "/" is "\", have to test + //cout << "lastPathPart: " << pathParts[pathParts.size() - 1] << endl; + name = pathParts[pathParts.size() - 1]; + } + } +} \ No newline at end of file diff --git a/src/Sources/BaseSource.h b/src/Sources/BaseSource.h new file mode 100644 index 0000000..fb5e567 --- /dev/null +++ b/src/Sources/BaseSource.h @@ -0,0 +1,36 @@ +#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 + int getType(); + std::string& getPath(); + virtual void clear() {}; + 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? + int type; + }; + } +} diff --git a/src/Sources/ImageSource.cpp b/src/Sources/ImageSource.cpp new file mode 100644 index 0000000..0cf8dde --- /dev/null +++ b/src/Sources/ImageSource.cpp @@ -0,0 +1,39 @@ +#include "ImageSource.h" + +namespace ofx { + namespace piMapper { + ImageSource::ImageSource() { + //cout << "ImageSource" << endl; + loadable = true; + loaded = false; + type = SourceType::SOURCE_TYPE_IMAGE; + } + + ImageSource::~ImageSource() {} + + void ImageSource::loadImage(std::string& filePath) { + path = filePath; + //cout << "loading image: " << filePath << endl; + setNameFromPath(filePath); + //cout << "path: " << path << endl; + image = new ofImage(); + if (!image->loadImage(filePath)) { + ofLogWarning("ImageSource") << "Could not load image"; + //std::exit(EXIT_FAILURE); + } + texture = &image->getTextureReference(); + loaded = true; + } + + void ImageSource::clear() { + texture = NULL; + image->clear(); + delete image; + image = NULL; + //path = ""; + //name = ""; + loaded = false; + } + + } +} \ No newline at end of file diff --git a/src/Sources/ImageSource.h b/src/Sources/ImageSource.h new file mode 100644 index 0000000..29a5d79 --- /dev/null +++ b/src/Sources/ImageSource.h @@ -0,0 +1,18 @@ +#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; + }; + } +} \ No newline at end of file diff --git a/src/Sources/SourceType.h b/src/Sources/SourceType.h new file mode 100644 index 0000000..515e2e4 --- /dev/null +++ b/src/Sources/SourceType.h @@ -0,0 +1,46 @@ +#pragma once + +#include "ofLog.h" + +#define SOURCE_TYPE_NAME_NONE "none" +#define SOURCE_TYPE_NAME_IMAGE "image" +#define SOURCE_TYPE_NAME_VIDEO "video" + +namespace ofx { + namespace piMapper { + class SourceType { + public: + enum { SOURCE_TYPE_NONE, SOURCE_TYPE_IMAGE, SOURCE_TYPE_VIDEO }; + + static std::string GetSourceTypeName(int 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 { + std::stringstream ss; + ss << "Invalid source type: " << sourceTypeEnum; + ofLogFatalError("SourceType") << ss.str(); + std::exit(EXIT_FAILURE); + } + }; + + static int GetSourceTypeEnum(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 { + std::stringstream ss; + ss << "Invalid source type name: " << sourceTypeName; + ofLogFatalError("SourceType") << ss.str(); + std::exit(EXIT_FAILURE); + } + } + }; + } +} \ No newline at end of file diff --git a/src/Sources/VideoSource.cpp b/src/Sources/VideoSource.cpp new file mode 100644 index 0000000..4ccbdb4 --- /dev/null +++ b/src/Sources/VideoSource.cpp @@ -0,0 +1,74 @@ +#include "VideoSource.h" + +namespace ofx { + namespace piMapper { + VideoSource::VideoSource() { + //cout << "VideoSource constr" << endl; + loadable = true; + loaded = false; + type = SourceType::SOURCE_TYPE_VIDEO; +#ifdef TARGET_RASPBERRY_PI + omxPlayer = NULL; +#else + videoPlayer = NULL; + +#endif + } + + VideoSource::~VideoSource() {} + + void VideoSource::loadVideo(std::string& filePath) { + path = filePath; + //cout << "loading video: " << filePath << endl; + setNameFromPath(filePath); +#ifdef TARGET_RASPBERRY_PI + // Do things with the OMX player + ofxOMXPlayerSettings settings; + settings.videoPath = filePath; + settings.useHDMIForAudio = true; //default true + settings.enableTexture = true; //default true + settings.enableLooping = true; //default true + settings.enableAudio = false; //default true, save resources by disabling + //settings.doFlipTexture = true; //default false + omxPlayer = new ofxOMXPlayer(); + omxPlayer->setup(settings); + texture = &(omxPlayer->getTextureReference()); +#else + // regular ofVideoPlayer + videoPlayer = new ofVideoPlayer(); + videoPlayer->loadMovie(filePath); + videoPlayer->setLoopState(OF_LOOP_NORMAL); + videoPlayer->play(); + texture = &(videoPlayer->getTextureReference()); + ofAddListener(ofEvents().update, this, &VideoSource::update); +#endif + loaded = true; + } + + void VideoSource::clear() { + texture = NULL; +#ifdef TARGET_RASPBERRY_PI + omxPlayer->close(); + delete omxPlayer; + omxPlayer = NULL; +#else + ofRemoveListener(ofEvents().update, this, &VideoSource::update); + videoPlayer->stop(); + videoPlayer->close(); + delete videoPlayer; + videoPlayer = NULL; +#endif + //path = ""; + //name = ""; + loaded = false; + } + +#ifndef TARGET_RASPBERRY_PI + void VideoSource::update(ofEventArgs &args) { + if (videoPlayer != NULL) { + videoPlayer->update(); + } + } +#endif + } +} \ No newline at end of file diff --git a/src/Sources/VideoSource.h b/src/Sources/VideoSource.h new file mode 100644 index 0000000..9ab8a97 --- /dev/null +++ b/src/Sources/VideoSource.h @@ -0,0 +1,48 @@ +#pragma once + +#include "ofMain.h" +#include "BaseSource.h" +#ifdef TARGET_RASPBERRY_PI + /* + Notice that if you get an error like this: + fatal error: libavcodec/opt.h: No such file or directory + Create a file opt.h in addons/ofxOMXPlayer/libs/ffmpeg/libavcodec/ + with the following contents: + + #ifndef AVCODEC_OPT_H + #define AVCODEC_OPT_H + #include "libavcodec/version.h" + #if FF_API_OPT_H + #include "libavutil/opt.h" + #endif + #endif // AVCODEC_OPT_H + + More here: https://github.com/jvcleave/ofxOMXPlayer/issues/34 + */ + #include "ofxOMXPlayer.h" +#endif + +namespace ofx { + namespace piMapper { + class VideoSource : public BaseSource { + public: + VideoSource(); + ~VideoSource(); + std::string& getPath(); + void loadVideo(std::string& path); + void clear(); +#ifndef TARGET_RASPBERRY_PI + void update(ofEventArgs& args); +#endif + + private: +#ifdef TARGET_RASPBERRY_PI + ofxOMXPlayer* omxPlayer; // Naming different for less confusion +#else + // Go with ofVideoPlayer or + // TODO: High Performance Video player on newer Macs + ofVideoPlayer* videoPlayer; +#endif + }; + } +} \ No newline at end of file diff --git a/src/Surfaces/BaseSurface.cpp b/src/Surfaces/BaseSurface.cpp new file mode 100644 index 0000000..d6a1ce5 --- /dev/null +++ b/src/Surfaces/BaseSurface.cpp @@ -0,0 +1,90 @@ +#include "BaseSurface.h" + +namespace ofx { +namespace piMapper { + +BaseSurface::BaseSurface() { + ofEnableNormalizedTexCoords(); + createDefaultTexture(); +} + + BaseSurface::~BaseSurface() { + delete defaultSource; + defaultSource = NULL; + defaultTexture.clear(); + } + +void BaseSurface::createDefaultTexture() { + ofPixels pixels; + pixels.allocate(500, 500, 1); + for (int i = 0; i < pixels.size(); i++) { + pixels[i] = 255; + } + int squareSize = 10; // size of each test pattern square + 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(ofVec2f position) { + if (source->getTexture() == NULL) { + ofLogWarning("BaseSurface") << "Source texture empty. Not drawing."; + return; + } + + ofMesh texMesh; + texMesh.addVertex(position); + texMesh.addVertex(position + ofVec2f(source->getTexture()->getWidth(), 0.0f)); + texMesh.addVertex(position + + ofVec2f(source->getTexture()->getWidth(), source->getTexture()->getHeight())); + texMesh.addVertex(position + ofVec2f(0.0f, source->getTexture()->getHeight())); + texMesh.addTriangle(0, 2, 3); + texMesh.addTriangle(0, 1, 2); + texMesh.addTexCoord(ofVec2f(0.0f, 0.0f)); + texMesh.addTexCoord(ofVec2f(1.0f, 0.0f)); + texMesh.addTexCoord(ofVec2f(1.0f, 1.0f)); + texMesh.addTexCoord(ofVec2f(0.0f, 1.0f)); + source->getTexture()->bind(); + texMesh.draw(); + source->getTexture()->unbind(); +} + + //void BaseSurface::setTexture(ofTexture* texturePtr) { texture = texturePtr; } + void BaseSurface::setSource(BaseSource* newSource) { + source = newSource; + } + + //ofTexture* BaseSurface::getTexture() { return texture; } + BaseSource* BaseSurface::getSource() { + return source; + } + + //ofTexture* BaseSurface::getDefaultTexture() { return &defaultTexture; } + BaseSource* BaseSurface::getDefaultSource() { + return defaultSource; + } +} +} \ No newline at end of file diff --git a/src/Surfaces/BaseSurface.h b/src/Surfaces/BaseSurface.h new file mode 100644 index 0000000..28b8b52 --- /dev/null +++ b/src/Surfaces/BaseSurface.h @@ -0,0 +1,47 @@ +#pragma once + +#include "ofMain.h" +#include +#include "BaseSource.h" + +using namespace std; + +namespace ofx { +namespace piMapper { +class BaseSurface { + public: + BaseSurface(); + ~BaseSurface(); + virtual void setup() {}; + virtual void draw() {}; + virtual void setVertex(int index, ofVec2f p) {}; + virtual void setTexCoord(int index, ofVec2f t) {}; + virtual void moveBy(ofVec2f v) {}; + virtual int getType() {}; + virtual bool hitTest(ofVec2f p) {}; + virtual ofPolyline getHitArea() {}; + virtual ofPolyline getTextureHitArea() {}; + virtual vector& getVertices() {}; + virtual vector& getTexCoords() {}; + + // Draws a texture using ofMesh + void drawTexture(ofVec2f position); + //void setTexture(ofTexture* texturePtr); + void setSource(BaseSource* newSource); + + //ofTexture* getTexture(); + //ofTexture* getDefaultTexture(); + BaseSource* getSource(); + BaseSource* getDefaultSource(); + + protected: + ofMesh mesh; + //ofTexture* texture; + ofTexture defaultTexture; + BaseSource* source; + BaseSource* defaultSource; + + void createDefaultTexture(); +}; +} +} \ No newline at end of file diff --git a/src/Surfaces/QuadSurface.cpp b/src/Surfaces/QuadSurface.cpp new file mode 100644 index 0000000..cffd145 --- /dev/null +++ b/src/Surfaces/QuadSurface.cpp @@ -0,0 +1,248 @@ +#include "QuadSurface.h" + +namespace ofx { +namespace piMapper { +QuadSurface::QuadSurface() { + cout << "QuadSurface constructor." << endl; + setup(); +} + +QuadSurface::~QuadSurface() { cout << "QuadSurface destructor." << endl; } + +void QuadSurface::setup() { + // Create 4 points for the 2 triangles + ofVec2f p1 = ofVec2f(0, 0); + ofVec2f p2 = ofVec2f(0, ofGetHeight()); + ofVec2f p3 = ofVec2f(ofGetWidth(), ofGetHeight()); + ofVec2f p4 = ofVec2f(ofGetWidth(), 0); + + // Create 4 point for the texture coordinates + ofVec2f t1 = ofVec2f(ofVec2f(0.0f, 0.0f)); + ofVec2f t2 = ofVec2f(ofVec2f(1.0f, 0.0f)); + ofVec2f t3 = ofVec2f(ofVec2f(1.0f, 1.0f)); + ofVec2f t4 = ofVec2f(ofVec2f(0.0f, 1.0f)); + + setup(p1, p2, p3, p4, t1, t2, t3, t4, source); +} + +void QuadSurface::setup(ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f p4, + ofVec2f t1, ofVec2f t2, ofVec2f t3, ofVec2f t4, + BaseSource* newSource) { + // Assign texture + source = newSource; + + // Clear mesh + mesh.clear(); + + // Create a surface with the points + mesh.addVertex(p1); + mesh.addVertex(p2); + mesh.addVertex(p3); + mesh.addVertex(p4); + + // Add 2 triangles + mesh.addTriangle(0, 2, 3); + mesh.addTriangle(0, 1, 2); + + // Add texture coordinates + mesh.addTexCoord(t1); + mesh.addTexCoord(t2); + mesh.addTexCoord(t3); + mesh.addTexCoord(t4); + + // Pure GL setup + // indices + quadIndices[0] = 0; + quadIndices[1] = 1; + quadIndices[2] = 2; + quadIndices[3] = 0; + quadIndices[4] = 2; + quadIndices[5] = 3; + // tex coords (those are alway 0) + quadTexCoordinates[2] = 0; + quadTexCoordinates[6] = 0; + quadTexCoordinates[10] = 0; + quadTexCoordinates[14] = 0; + + calculate4dTextureCoords(); +} + +void QuadSurface::draw() { + if (source->getTexture() == NULL) { + ofLogWarning("QuadSurface") << "Source texture empty. Not drawing."; + return; + } + + /*if(mesh.haveVertsChanged() || mesh.haveTexCoordsChanged()){ + calculate4dTextureCoords(); + }*/ + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(4, GL_FLOAT, 0, quadTexCoordinates); + glVertexPointer(3, GL_FLOAT, 0, quadVertices); + + source->getTexture()->bind(); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, quadIndices); + source->getTexture()->unbind(); +} + +void QuadSurface::setVertex(int index, ofVec2f p) { + if (index > 3) { + ofLog() << "Vertex with this index does not exist: " << index << endl; + return; + } + + mesh.setVertex(index, p); + calculate4dTextureCoords(); +} + +void QuadSurface::setTexCoord(int index, ofVec2f t) { + if (index > 3) { + ofLog() << "Texture coordinate with this index does not exist: " << index + << endl; + return; + } + + mesh.setTexCoord(index, t); + calculate4dTextureCoords(); +} + +void QuadSurface::moveBy(ofVec2f v) { + vector& vertices = getVertices(); + for (int i = 0; i < vertices.size(); i++) { + vertices[i] += v; + } + calculate4dTextureCoords(); +} + +int QuadSurface::getType() { return SurfaceType::QUAD_SURFACE; } + +bool QuadSurface::hitTest(ofVec2f p) { + // Construct ofPolyline from vertices + ofPolyline line = getHitArea(); + + if (line.inside(p.x, p.y)) { + return true; + } else { + return false; + } +} + +ofVec2f QuadSurface::getVertex(int index) { + if (index > 3) { + ofLog() << "Vertex with this index does not exist: " << index << endl; + throw std::runtime_error("Vertex index out of bounds."); + } + + ofVec3f vert = mesh.getVertex(index); + return ofVec2f(vert.x, vert.y); +} + +ofVec2f QuadSurface::getTexCoord(int index) { + if (index > 3) { + throw std::runtime_error("Texture coordinate index out of bounds."); + } + + return mesh.getTexCoord(index); +} + +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; + vector& texCoords = mesh.getTexCoords(); + ofVec2f textureSize = ofVec2f(source->getTexture()->getWidth(), source->getTexture()->getHeight()); + for (int i = 0; i < texCoords.size(); i++) { + line.addVertex(ofPoint(texCoords[i] * textureSize)); + } + line.close(); + + return line; +} + +vector& QuadSurface::getVertices() { + // return only joint vertices + return mesh.getVertices(); +} + +vector& QuadSurface::getTexCoords() { return mesh.getTexCoords(); } + +void QuadSurface::calculate4dTextureCoords() { + // Perspective Warping with OpenGL Fixed Pipeline and q coordinates + // see: + // http://www.reedbeta.com/blog/2012/05/26/quadrilateral-interpolation-part-1/ + // for information on the technique + // Pue OpenGL is used because the ofMesh sadly doesn't support ofVec4f as + // texture coordinates. + // calculate intersection point + ofVec3f p0 = mesh.getVertex(0); + ofVec3f p1 = mesh.getVertex(1); + ofVec3f p2 = mesh.getVertex(2); + ofVec3f p3 = mesh.getVertex(3); + + ofVec3f t0 = mesh.getTexCoord(0); + ofVec3f t1 = mesh.getTexCoord(1); + ofVec3f t2 = mesh.getTexCoord(2); + ofVec3f t3 = mesh.getTexCoord(3); + + ofPoint interSect; + ofLineSegmentIntersection(ofPoint(p0.x, p0.y), ofPoint(p2.x, p2.y), + ofPoint(p1.x, p1.y), ofPoint(p3.x, p3.y), + interSect); + ofVec3f interSecVec = ofVec3f(interSect.x, interSect.y, 0); + + // calculate distances to intersection point + float d0 = interSecVec.distance(p0); + float d1 = interSecVec.distance(p1); + float d2 = interSecVec.distance(p2); + float d3 = interSecVec.distance(p3); + + // vertices + // top left corner + quadVertices[0] = p0.x; + quadVertices[1] = p0.y; + quadVertices[2] = 0; + // top right corner + quadVertices[3] = p1.x; + quadVertices[4] = p1.y; + quadVertices[5] = 0; + // bottom right corner + quadVertices[6] = p2.x; + quadVertices[7] = p2.y; + quadVertices[8] = 0; + // bottom left corner + quadVertices[9] = p3.x; + quadVertices[10] = p3.y; + quadVertices[11] = 0; + + float q0 = (d0 + d2) / (d2); + float q1 = (d1 + d3) / (d3); + float q2 = (d2 + d0) / (d0); + float q3 = (d3 + d1) / (d1); + + quadTexCoordinates[0] = t0.x; + quadTexCoordinates[1] = t0.y; + quadTexCoordinates[3] = q0; + + quadTexCoordinates[4] = t1.x * q1; + quadTexCoordinates[5] = t1.y; + quadTexCoordinates[7] = q1; + + quadTexCoordinates[8] = t2.x * q2; + quadTexCoordinates[9] = t2.y * q2; + quadTexCoordinates[11] = q2; + + quadTexCoordinates[12] = t3.x; + quadTexCoordinates[13] = t3.y * q3; + quadTexCoordinates[15] = q3; +} +} +} \ No newline at end of file diff --git a/src/Surfaces/QuadSurface.h b/src/Surfaces/QuadSurface.h new file mode 100755 index 0000000..6422a6f --- /dev/null +++ b/src/Surfaces/QuadSurface.h @@ -0,0 +1,40 @@ +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" + +namespace ofx { +namespace piMapper { +class QuadSurface : public BaseSurface { + public: + QuadSurface(); + ~QuadSurface(); + + void setup(); + + void setup(ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f p4, ofVec2f t1, + ofVec2f t2, ofVec2f t3, ofVec2f t4, BaseSource* newSource); + + void draw(); + void setVertex(int index, ofVec2f p); + void setTexCoord(int index, ofVec2f t); + void moveBy(ofVec2f v); + + int getType(); + bool hitTest(ofVec2f p); + ofVec2f getVertex(int index); + ofVec2f getTexCoord(int index); + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + vector& getVertices(); + vector& getTexCoords(); + + private: + void calculate4dTextureCoords(); + GLfloat quadVertices[12]; + GLubyte quadIndices[6]; + GLfloat quadTexCoordinates[16]; +}; +} +} \ No newline at end of file diff --git a/src/Surfaces/SurfaceManager.cpp b/src/Surfaces/SurfaceManager.cpp new file mode 100644 index 0000000..c2c8c68 --- /dev/null +++ b/src/Surfaces/SurfaceManager.cpp @@ -0,0 +1,392 @@ +#include "SurfaceManager.h" + +namespace ofx { +namespace piMapper { + SurfaceManager::SurfaceManager() { + // Init variables + mediaServer = NULL; + } + +SurfaceManager::~SurfaceManager() { clear(); } + +void SurfaceManager::draw() { + for (int i = 0; i < surfaces.size(); i++) { + surfaces[i]->draw(); + } +} + +void SurfaceManager::addSurface(int surfaceType) { + if (surfaceType == SurfaceType::TRIANGLE_SURFACE) { + surfaces.push_back(new TriangleSurface()); + } else if (surfaceType == SurfaceType::QUAD_SURFACE) { + surfaces.push_back(new QuadSurface()); + } else { + ofLogFatalError("SurfaceManager") << "Attempt to add non-existing surface type"; + std::exit(EXIT_FAILURE); + } +} + +void SurfaceManager::addSurface(int surfaceType, BaseSource* newSource) { + if (surfaceType == SurfaceType::TRIANGLE_SURFACE) { + surfaces.push_back(new TriangleSurface()); + surfaces.back()->setSource(newSource); + } else if (surfaceType == SurfaceType::QUAD_SURFACE) { + surfaces.push_back(new QuadSurface()); + surfaces.back()->setSource(newSource); + } else { + ofLogFatalError("SurfaceManager") << "Attempt to add non-existing surface type"; + std::exit(EXIT_FAILURE); + } +} + +void SurfaceManager::addSurface(int surfaceType, vector vertices, + vector texCoords) { + if (surfaceType == SurfaceType::TRIANGLE_SURFACE) { + if (vertices.size() < 3) { + throw std::runtime_error( + "There must be 3 vertices for a triangle surface."); + } else if (texCoords.size() < 3) { + throw std::runtime_error( + "There must be 3 texture coordinates for a triangle surface."); + } + + surfaces.push_back(new TriangleSurface()); + + for (int i = 0; i < 3; i++) { + surfaces.back()->setVertex(i, vertices[i]); + surfaces.back()->setTexCoord(i, texCoords[i]); + } + + } else if (surfaceType == SurfaceType::QUAD_SURFACE) { + if (vertices.size() < 4) { + throw std::runtime_error("There must be 4 vertices for a quad surface."); + } else if (texCoords.size() < 4) { + throw std::runtime_error( + "There must be 4 texture coordinates for a quad surface."); + } + + surfaces.push_back(new QuadSurface()); + + for (int i = 0; i < 4; i++) { + surfaces.back()->setVertex(i, vertices[i]); + surfaces.back()->setTexCoord(i, texCoords[i]); + } + } else { + ofLogFatalError("SurfaceManager") << "Attempt to add non-existing surface type"; + std::exit(EXIT_FAILURE); + } +} + +void SurfaceManager::addSurface(int surfaceType, BaseSource* newSource, + vector vertices, + vector texCoords) { + if (surfaceType == SurfaceType::TRIANGLE_SURFACE) { + if (vertices.size() < 3) { + throw std::runtime_error( + "There must be 3 vertices for a triangle surface."); + } else if (texCoords.size() < 3) { + throw std::runtime_error( + "Thre must be 3 texture coordinates for a triangle surface."); + } + + surfaces.push_back(new TriangleSurface()); + surfaces.back()->setSource(newSource); + + for (int i = 0; i < 3; i++) { + surfaces.back()->setVertex(i, vertices[i]); + surfaces.back()->setTexCoord(i, texCoords[i]); + } + + } else if (surfaceType == SurfaceType::QUAD_SURFACE) { + if (vertices.size() < 4) { + throw std::runtime_error("There must be 4 vertices for a quad surface."); + } else if (texCoords.size() < 4) { + throw std::runtime_error( + "Thre must be 4 texture coordinates for a quad surface."); + } + + surfaces.push_back(new QuadSurface()); + surfaces.back()->setSource(newSource); + + for (int i = 0; i < 4; i++) { + surfaces.back()->setVertex(i, vertices[i]); + surfaces.back()->setTexCoord(i, texCoords[i]); + } + } else { + ofLogFatalError("SurfaceManager") << "Attempt to add non-existing surface type"; + std::exit(EXIT_FAILURE); + } +} + +void SurfaceManager::removeSelectedSurface() { + if (selectedSurface == NULL) { + return; + } + for (int i = 0; i < surfaces.size(); i++) { + if (surfaces[i] == selectedSurface) { + delete surfaces[i]; + surfaces.erase(surfaces.begin() + i); + selectedSurface = NULL; + break; + } + } +} + +void SurfaceManager::clear() { + // delete all extra allocations from the heap + while (surfaces.size()) { + delete surfaces.back(); + surfaces.pop_back(); + } +} + +void SurfaceManager::saveXmlSettings(string fileName) { + // Exit if mediaServer not set + if (mediaServer == NULL) { + ofLogFatalError("SurfaceManager") << "Media server not set"; + std::exit(EXIT_FAILURE); + } + // We need a fresh copy of the xml settings object + xmlSettings.clear(); + // Save surfaces + xmlSettings.addTag("surfaces"); + xmlSettings.pushTag("surfaces"); + for (int i = 0; i < surfaces.size(); i++) { + xmlSettings.addTag("surface"); + xmlSettings.pushTag("surface", i); + BaseSurface* surface = surfaces[i]; + + xmlSettings.addTag("vertices"); + xmlSettings.pushTag("vertices"); + vector* vertices = &surface->getVertices(); + for (int j = 0; j < vertices->size(); j++) { + xmlSettings.addTag("vertex"); + xmlSettings.pushTag("vertex", j); + ofVec3f* 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"); + vector* texCoords = &surface->getTexCoords(); + for (int j = 0; j < texCoords->size(); j++) { + xmlSettings.addTag("texCoord"); + xmlSettings.pushTag("texCoord", j); + ofVec2f* 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"); + string sourceTypeName = SourceType::GetSourceTypeName(surface->getSource()->getType()); + cout << "sourceTypeName: " << sourceTypeName << endl; + xmlSettings.addValue("source-type", sourceTypeName); + xmlSettings.addValue("source-name", surface->getSource()->getName()); + xmlSettings.popTag(); // source + xmlSettings.popTag(); // surface + } + xmlSettings.popTag(); // surfaces + xmlSettings.save(fileName); +} + +void SurfaceManager::loadXmlSettings(string fileName) { + // Exit if there is no media server + if (mediaServer == NULL) { + ofLogFatalError("SurfaceManager") << "Media server not set"; + std::exit(EXIT_FAILURE); + } + if (!xmlSettings.loadFile(fileName)) { + ofLogWarning("SurfaceManager") << "Could not load XML settings"; + return; + } + if (!xmlSettings.tagExists("surfaces")) { + ofLogWarning("SurfaceManager") << "XML settings is empty or has wrong markup"; + return; + } + + xmlSettings.pushTag("surfaces"); + + int numSurfaces = xmlSettings.getNumTags("surface"); + for (int i = 0; i < numSurfaces; i++) { + xmlSettings.pushTag("surface", i); + // attempt to load surface source + xmlSettings.pushTag("source"); + string sourceType = xmlSettings.getValue("source-type", ""); + string sourceName = xmlSettings.getValue("source-name", ""); + BaseSource* source = NULL; + 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); + } + xmlSettings.popTag(); // source + xmlSettings.pushTag("vertices"); + vector vertices; + int vertexCount = xmlSettings.getNumTags("vertex"); + // it's a triangle ? + if (vertexCount == 3) { + //ofLog(OF_LOG_NOTICE, "create Triangle"); + xmlSettings.pushTag("vertex", 0); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("vertex", 1); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 100.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("vertex", 2); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 100.0f))); + xmlSettings.popTag(); + + xmlSettings.popTag(); // vertices + + xmlSettings.pushTag("texCoords"); + + vector texCoords; + + xmlSettings.pushTag("texCoord", 0); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("texCoord", 1); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 1.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("texCoord", 2); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 1.0f))); + xmlSettings.popTag(); + + xmlSettings.popTag(); // texCoords + + // now we have variables sourceName and sourceTexture + // by checking those we can use one or another addSurface method + if (sourceName != "none" && source != NULL) { + addSurface(SurfaceType::TRIANGLE_SURFACE, source, vertices, + texCoords); + } else { + addSurface(SurfaceType::TRIANGLE_SURFACE, vertices, texCoords); + } + } + // it's a quad ? + else if (vertexCount == 4) + // if (surface-type == QUAD_SURFACE) + { + xmlSettings.pushTag("vertex", 0); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("vertex", 1); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 100.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("vertex", 2); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 100.0f), + xmlSettings.getValue("y", 100.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("vertex", 3); + vertices.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 100.0f))); + xmlSettings.popTag(); + + xmlSettings.popTag(); // vertices + + xmlSettings.pushTag("texCoords"); + + vector texCoords; + + xmlSettings.pushTag("texCoord", 0); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("texCoord", 1); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 1.0f), + xmlSettings.getValue("y", 0.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("texCoord", 2); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 1.0f), + xmlSettings.getValue("y", 1.0f))); + xmlSettings.popTag(); + + xmlSettings.pushTag("texCoord", 3); + texCoords.push_back(ofVec2f(xmlSettings.getValue("x", 0.0f), + xmlSettings.getValue("y", 1.0f))); + xmlSettings.popTag(); + + xmlSettings.popTag(); // texCoords + + // now we have variables sourceName and sourceTexture + // by checking those we can use one or another addSurface method + if (sourceName != "none" && source != NULL) { + addSurface(SurfaceType::QUAD_SURFACE, source, vertices, + texCoords); + } else { + addSurface(SurfaceType::QUAD_SURFACE, vertices, texCoords); + } + } + + xmlSettings.popTag(); // surface + } + + xmlSettings.popTag(); // surfaces +} + + void SurfaceManager::setMediaServer(MediaServer* newMediaServer) { + mediaServer = newMediaServer; + } + +BaseSurface* SurfaceManager::selectSurface(int index) { + if (index >= surfaces.size()) { + throw std::runtime_error("Surface index out of bounds."); + } + + selectedSurface = surfaces[index]; + + // notify that a new surface has been selected + ofSendMessage("surfaceSelected"); +} + +BaseSurface* SurfaceManager::getSelectedSurface() { + return selectedSurface; +} + +void SurfaceManager::deselectSurface() { + selectedSurface = NULL; +} + +BaseSurface* SurfaceManager::getSurface(int index) { + if (index >= surfaces.size()) { + throw std::runtime_error("Surface index out of bounds."); + return NULL; + } + + return surfaces[index]; +} + +int SurfaceManager::size() { return surfaces.size(); } +} +} diff --git a/src/Surfaces/SurfaceManager.h b/src/Surfaces/SurfaceManager.h new file mode 100755 index 0000000..2e6eb6f --- /dev/null +++ b/src/Surfaces/SurfaceManager.h @@ -0,0 +1,49 @@ +#pragma once + +#include "BaseSurface.h" +#include "TriangleSurface.h" +#include "QuadSurface.h" +#include "SurfaceType.h" +#include "MediaServer.h" +#include "BaseSource.h" +#include "SourceType.h" + +#include "ofEvents.h" +#include "ofxXmlSettings.h" + +using namespace std; + +namespace ofx { +namespace piMapper { +class SurfaceManager { + public: + SurfaceManager(); + ~SurfaceManager(); + + void draw(); + void addSurface(int surfaceType); + void addSurface(int surfaceType, BaseSource* newSource); + void addSurface(int surfaceType, vector vertices, + vector texCoords); + void addSurface(int surfaceType, BaseSource* newSource, + vector vertices, vector texCoords); + void removeSelectedSurface(); + void clear(); + void saveXmlSettings(string fileName); + void loadXmlSettings(string fileName); + void setMediaServer(MediaServer* newMediaServer); + + BaseSurface* getSurface(int index); + int size(); + BaseSurface* selectSurface(int index); + BaseSurface* getSelectedSurface(); + void deselectSurface(); + + private: + std::vector surfaces; + BaseSurface* selectedSurface; + ofxXmlSettings xmlSettings; + MediaServer* mediaServer; +}; +} +} \ No newline at end of file diff --git a/src/Surfaces/SurfaceManagerGui.cpp b/src/Surfaces/SurfaceManagerGui.cpp new file mode 100644 index 0000000..dee1584 --- /dev/null +++ b/src/Surfaces/SurfaceManagerGui.cpp @@ -0,0 +1,250 @@ +#include "SurfaceManagerGui.h" + +namespace ofx { +namespace piMapper { +SurfaceManagerGui::SurfaceManagerGui() { + surfaceManager = NULL; + guiMode = GuiMode::NONE; + bDrag = false; + registerMouseEvents(); + ofHideCursor(); +} + +SurfaceManagerGui::~SurfaceManagerGui() { + unregisterMouseEvents(); + surfaceManager = NULL; +} + +void SurfaceManagerGui::registerMouseEvents() { + ofAddListener(ofEvents().mousePressed, this, + &SurfaceManagerGui::mousePressed); + ofAddListener(ofEvents().mouseReleased, this, + &SurfaceManagerGui::mouseReleased); + ofAddListener(ofEvents().mouseDragged, this, + &SurfaceManagerGui::mouseDragged); +} + +void SurfaceManagerGui::unregisterMouseEvents() { + ofRemoveListener(ofEvents().mousePressed, this, + &SurfaceManagerGui::mousePressed); + ofRemoveListener(ofEvents().mouseReleased, this, + &SurfaceManagerGui::mouseReleased); + ofRemoveListener(ofEvents().mouseDragged, this, + &SurfaceManagerGui::mouseDragged); +} + +void SurfaceManagerGui::draw() { + if (surfaceManager == NULL) return; + + if (guiMode == GuiMode::NONE) { + surfaceManager->draw(); + } else if (guiMode == GuiMode::TEXTURE_MAPPING) { + // draw the texture of the selected surface + if (surfaceManager->getSelectedSurface() != NULL) { + surfaceManager->getSelectedSurface()->drawTexture(ofVec2f(0, 0)); + } + + // draw surfaces with opacity + ofPushStyle(); + ofSetColor(255, 255, 255, 200); + surfaceManager->draw(); + ofPopStyle(); + + // highlight selected surface + drawSelectedSurfaceHighlight(); + + // hilight selected surface texture + drawSelectedSurfaceTextureHighlight(); + + // draw texture editing GUI on top + textureEditor.draw(); + + } else if (guiMode == GuiMode::PROJECTION_MAPPING) { + // draw projection surfaces first + surfaceManager->draw(); + + // highlight selected surface + drawSelectedSurfaceHighlight(); + + // draw projection mapping editing gui + projectionEditor.draw(); + + } else if (guiMode == GuiMode::SOURCE_SELECTION) { + // draw projection surfaces first + surfaceManager->draw(); + + // highlight selected surface + drawSelectedSurfaceHighlight(); + + sourcesEditor.draw(); + } +} + +void SurfaceManagerGui::mousePressed(ofMouseEventArgs& args) { + if (guiMode == GuiMode::NONE) { + return; + } else if (guiMode == GuiMode::TEXTURE_MAPPING) { + bool bSurfaceSelected = false; + + CircleJoint* hitJoint = + textureEditor.hitTestJoints(ofVec2f(args.x, args.y)); + if (hitJoint != NULL) { + textureEditor.unselectAllJoints(); + hitJoint->select(); + hitJoint->startDrag(); + bSurfaceSelected = true; + } else { + textureEditor.unselectAllJoints(); + } + + if (surfaceManager->getSelectedSurface() != NULL && !bSurfaceSelected) { + // hittest texture area to see if we are hitting the texture surface + if (surfaceManager->getSelectedSurface()->getTextureHitArea().inside( + args.x, args.y)) { + clickPosition = ofVec2f(args.x, args.y); + startDrag(); + } + } + + } else if (guiMode == GuiMode::PROJECTION_MAPPING) { + bool bSurfaceSelected = false; + + CircleJoint* hitJoint = + projectionEditor.hitTestJoints(ofVec2f(args.x, args.y)); + if (hitJoint != NULL) { + projectionEditor.unselectAllJoints(); + hitJoint->select(); + hitJoint->startDrag(); + bSurfaceSelected = true; + } + + // attempt to select surface, loop from end to beginning + if (!bSurfaceSelected) { + for (int i = surfaceManager->size() - 1; i >= 0; i--) { + if (surfaceManager->getSurface(i)->hitTest(ofVec2f(args.x, args.y))) { + projectionEditor.clearJoints(); + surfaceManager->selectSurface(i); + projectionEditor.createJoints(); + bSurfaceSelected = true; + break; + } + } + } + + if (bSurfaceSelected && hitJoint == NULL) { + // if not hitting the joints, start drag only if we have a selected + // surface + clickPosition = ofVec2f(args.x, args.y); + startDrag(); + } + + if (!bSurfaceSelected) { + // unselect if no surface selected + projectionEditor.clearJoints(); + surfaceManager->deselectSurface(); + } + } else if (guiMode == GuiMode::SOURCE_SELECTION) { + } +} + +void SurfaceManagerGui::mouseReleased(ofMouseEventArgs& args) { + stopDrag(); + projectionEditor.stopDragJoints(); + textureEditor.stopDragJoints(); +} + +void SurfaceManagerGui::mouseDragged(ofMouseEventArgs& args) { + if (bDrag) { + ofVec2f mousePosition = ofVec2f(args.x, args.y); + ofVec2f distance = mousePosition - clickPosition; + + if (guiMode == GuiMode::PROJECTION_MAPPING) { + // add this distance to all vertices in surface + projectionEditor.moveSelectedSurface(distance); + } else if (guiMode == GuiMode::TEXTURE_MAPPING) { + textureEditor.moveTexCoords(distance); + } + clickPosition = mousePosition; + } +} + +void SurfaceManagerGui::setSurfaceManager(SurfaceManager* newSurfaceManager) { + surfaceManager = newSurfaceManager; + projectionEditor.setSurfaceManager(surfaceManager); + sourcesEditor.setSurfaceManager(surfaceManager); +} + + // Set external media server so we can access it from wherever we need + void SurfaceManagerGui::setMediaServer(MediaServer* newMediaServer) { + mediaServer = newMediaServer; + // Set the media server of the sources editor here + sourcesEditor.setMediaServer(mediaServer); + } + +void SurfaceManagerGui::setMode(int newGuiMode) { + if (newGuiMode != GuiMode::NONE && newGuiMode != GuiMode::TEXTURE_MAPPING && + newGuiMode != GuiMode::PROJECTION_MAPPING && + newGuiMode != GuiMode::SOURCE_SELECTION) { + throw std::runtime_error("Trying to set invalid mode."); + } + + if (newGuiMode == GuiMode::NONE) { + ofHideCursor(); + } else { + ofShowCursor(); + } + + guiMode = newGuiMode; + + if (guiMode == GuiMode::SOURCE_SELECTION) { + sourcesEditor.enable(); + //string sourceName = surfaceManager->getSelectedSurfaceSourceName(); + //sourcesEditor.selectImageSourceRadioButton(sourceName); + } else { + sourcesEditor.disable(); + } + + if (guiMode == GuiMode::TEXTURE_MAPPING) { + textureEditor.enable(); + // refresh texture editor surface reference + textureEditor.setSurface(surfaceManager->getSelectedSurface()); + } else { + textureEditor.disable(); + } + + if (guiMode == GuiMode::PROJECTION_MAPPING) { + projectionEditor.enable(); + } else { + projectionEditor.disable(); + } +} + +void SurfaceManagerGui::drawSelectedSurfaceHighlight() { + if (surfaceManager->getSelectedSurface() == NULL) return; + + ofPolyline line = surfaceManager->getSelectedSurface()->getHitArea(); + + ofPushStyle(); + ofSetLineWidth(1); + ofSetColor(255, 255, 255, 255); + line.draw(); + ofPopStyle(); +} + +void SurfaceManagerGui::drawSelectedSurfaceTextureHighlight() { + if (surfaceManager->getSelectedSurface() == NULL) return; + + ofPolyline line = surfaceManager->getSelectedSurface()->getTextureHitArea(); + + ofPushStyle(); + ofSetLineWidth(1); + ofSetColor(255, 255, 0, 255); + line.draw(); + ofPopStyle(); +} + +void SurfaceManagerGui::startDrag() { bDrag = true; } + +void SurfaceManagerGui::stopDrag() { bDrag = false; } +} +} \ No newline at end of file diff --git a/src/Surfaces/SurfaceManagerGui.h b/src/Surfaces/SurfaceManagerGui.h new file mode 100644 index 0000000..7e998a8 --- /dev/null +++ b/src/Surfaces/SurfaceManagerGui.h @@ -0,0 +1,48 @@ +#pragma once + +// I'm starting to think, maybe we should use ofxStateMachine here. +// Would make sense. TODO later. + +#include "ofEvents.h" +#include "ofGraphics.h" + +#include "SurfaceManager.h" +#include "TextureEditor.h" +#include "ProjectionEditor.h" +#include "SourcesEditor.h" +#include "GuiMode.h" + +namespace ofx { +namespace piMapper { +class SurfaceManagerGui { + public: + SurfaceManagerGui(); + ~SurfaceManagerGui(); + + void registerMouseEvents(); + void unregisterMouseEvents(); + + void draw(); + void mousePressed(ofMouseEventArgs& args); + void mouseReleased(ofMouseEventArgs& args); + void mouseDragged(ofMouseEventArgs& args); + void setSurfaceManager(SurfaceManager* newSurfaceManager); + void setMediaServer(MediaServer* newMediaServer); + void setMode(int newGuiMode); + void drawSelectedSurfaceHighlight(); + void drawSelectedSurfaceTextureHighlight(); + void startDrag(); + void stopDrag(); + + private: + SurfaceManager* surfaceManager; + MediaServer* mediaServer; + TextureEditor textureEditor; + ProjectionEditor projectionEditor; + SourcesEditor sourcesEditor; + int guiMode; + bool bDrag; + ofVec2f clickPosition; +}; +} +} \ No newline at end of file diff --git a/src/Surfaces/SurfaceType.h b/src/Surfaces/SurfaceType.h new file mode 100755 index 0000000..e00e875 --- /dev/null +++ b/src/Surfaces/SurfaceType.h @@ -0,0 +1,9 @@ +#pragma once + +namespace ofx { + namespace piMapper { + struct SurfaceType { + enum { TRIANGLE_SURFACE, QUAD_SURFACE }; + }; + } +} \ No newline at end of file diff --git a/src/Surfaces/TriangleSurface.cpp b/src/Surfaces/TriangleSurface.cpp new file mode 100644 index 0000000..f370080 --- /dev/null +++ b/src/Surfaces/TriangleSurface.cpp @@ -0,0 +1,141 @@ +#include "TriangleSurface.h" + +namespace ofx { +namespace piMapper { +TriangleSurface::TriangleSurface() { + setup(); +} + +TriangleSurface::~TriangleSurface() {} + +void TriangleSurface::setup() { + // Create 3 points for the triangle + ofVec2f p1 = ofVec2f(ofGetWidth() / 2.0f, 0); + ofVec2f p2 = ofVec2f(ofVec2f(0, ofGetHeight())); + ofVec2f p3 = ofVec2f(ofGetWidth(), ofGetHeight()); + + // Create 3 point for the texture coordinates + ofVec2f t1 = ofVec2f(0.5f, 0); + ofVec2f t2 = ofVec2f(0, 1.0f); + ofVec2f t3 = ofVec2f(1, 1.0f); + + setup(p1, p2, p3, t1, t2, t3, source); +} + +void TriangleSurface::setup(ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f t1, + ofVec2f t2, ofVec2f t3, BaseSource* newSource) { + // Assign texture + source = newSource; + + // Clear mesh + mesh.clear(); + + // Create a surface with the points + mesh.addVertex(p1); + mesh.addVertex(p2); + mesh.addVertex(p3); + + // Add texture coordinates + mesh.addTexCoord(t1); + mesh.addTexCoord(t2); + mesh.addTexCoord(t3); +} + +void TriangleSurface::draw() { + if (source->getTexture() == NULL) { + ofLogWarning("TriangleSurface") << "Source texture is empty. Not drawing."; + return; + } + + source->getTexture()->bind(); + mesh.draw(); + source->getTexture()->unbind(); +} + +void TriangleSurface::setVertex(int index, ofVec2f p) { + if (index > 2) { + ofLog() << "Vertex with this index does not exist: " << index << endl; + return; + } + + mesh.setVertex(index, p); +} + +void TriangleSurface::setTexCoord(int index, ofVec2f t) { + if (index > 2) { + ofLog() << "Texture coordinate with this index does not exist: " << index + << endl; + return; + } + + mesh.setTexCoord(index, t); +} + +void TriangleSurface::moveBy(ofVec2f v) { + vector& vertices = getVertices(); + for (int i = 0; i < vertices.size(); i++) { + vertices[i] += v; + } +} + +int TriangleSurface::getType() { return SurfaceType::TRIANGLE_SURFACE; } + +bool TriangleSurface::hitTest(ofVec2f p) { + // Construct ofPolyline from vertices + ofPolyline line = getHitArea(); + + if (line.inside(p.x, p.y)) { + return true; + } else { + return false; + } +} + +ofVec2f TriangleSurface::getVertex(int index) { + if (index > 2) { + ofLog() << "Vertex with this index does not exist: " << index << endl; + throw std::runtime_error("Vertex index out of bounds."); + } + + ofVec3f vert = mesh.getVertex(index); + return ofVec2f(vert.x, vert.y); +} + +ofVec2f TriangleSurface::getTexCoord(int index) { + if (index > 2) { + throw std::runtime_error("Texture coordinate index out of bounds."); + } + + return mesh.getTexCoord(index); +} + +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; + vector& texCoords = mesh.getTexCoords(); + ofVec2f textureSize = ofVec2f(source->getTexture()->getWidth(), source->getTexture()->getHeight()); + for (int i = 0; i < texCoords.size(); i++) { + line.addVertex(ofPoint(texCoords[i] * textureSize)); + } + line.close(); + + return line; +} + +vector& TriangleSurface::getVertices() { + // return only joint vertices + return mesh.getVertices(); +} + +vector& TriangleSurface::getTexCoords() { return mesh.getTexCoords(); } +} +} \ No newline at end of file diff --git a/src/Surfaces/TriangleSurface.h b/src/Surfaces/TriangleSurface.h new file mode 100644 index 0000000..073719b --- /dev/null +++ b/src/Surfaces/TriangleSurface.h @@ -0,0 +1,32 @@ +#pragma once + +#include "ofMain.h" +#include "BaseSurface.h" +#include "SurfaceType.h" + +namespace ofx { +namespace piMapper { +class TriangleSurface : public BaseSurface { + public: + TriangleSurface(); + ~TriangleSurface(); + + void setup(); + void setup(ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f t1, ofVec2f t2, + ofVec2f t3, BaseSource* newSource); + void draw(); + void setVertex(int index, ofVec2f p); + void setTexCoord(int index, ofVec2f t); + void moveBy(ofVec2f v); + + int getType(); + bool hitTest(ofVec2f p); + ofVec2f getVertex(int index); + ofVec2f getTexCoord(int index); + ofPolyline getHitArea(); + ofPolyline getTextureHitArea(); + vector& getVertices(); + vector& getTexCoords(); +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/BaseJoint.cpp b/src/UserInterface/BaseJoint.cpp new file mode 100644 index 0000000..37b96b2 --- /dev/null +++ b/src/UserInterface/BaseJoint.cpp @@ -0,0 +1,72 @@ +#include "BaseJoint.h" + +namespace ofx { +namespace piMapper { + +BaseJoint::BaseJoint() { + setDefaultColors(); + setDefaultProperties(); + registerMouseEvents(); +} + +BaseJoint::~BaseJoint() { unregisterMouseEvents(); } + +void BaseJoint::registerMouseEvents() { + ofAddListener(ofEvents().mousePressed, this, &BaseJoint::mousePressed); + ofAddListener(ofEvents().mouseDragged, this, &BaseJoint::mouseDragged); +} + +void BaseJoint::unregisterMouseEvents() { + ofRemoveListener(ofEvents().mousePressed, this, &BaseJoint::mousePressed); + ofRemoveListener(ofEvents().mouseDragged, this, &BaseJoint::mouseDragged); +} + +void BaseJoint::mousePressed(ofMouseEventArgs& args) { + if (hitTest(ofVec2f(args.x, args.y))) { + // selected = true; + clickDistance = position - ofVec2f(args.x, args.y); + // startDrag(); + } +} + +void BaseJoint::mouseReleased(int x, int y, int button) { stopDrag(); } + +void BaseJoint::mouseDragged(ofMouseEventArgs& args) { + if (!bDrag) return; + position = ofVec2f(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(ofVec2f 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 = ofVec2f(20.0f, 20.0f); + clickDistance = ofVec2f(0.0f, 0.0f); + bDrag = false; + selected = false; + strokeWidth = 1.5f; +} +} +} \ No newline at end of file diff --git a/src/UserInterface/BaseJoint.h b/src/UserInterface/BaseJoint.h new file mode 100644 index 0000000..d2fdcf0 --- /dev/null +++ b/src/UserInterface/BaseJoint.h @@ -0,0 +1,51 @@ +#pragma once + +#include "ofMain.h" + +namespace ofx { +namespace piMapper { + +class BaseJoint { + public: + BaseJoint(); + ~BaseJoint(); + + void registerMouseEvents(); + void unregisterMouseEvents(); + + ofVec2f 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(ofVec2f newClickDistance); + bool isDragged(); + bool isSelected(); + + virtual void update() {}; + virtual void draw() {}; + virtual bool hitTest(ofVec2f position) {}; + + protected: + ofColor fillColor; + ofColor strokeColor; + ofColor fillColorSelected; + ofColor strokeColorSelected; + float strokeWidth; + ofVec2f clickDistance; // How far from the center of the joint the user has + // clicked? + bool bDrag; + + private: + void setDefaultColors(); + void setDefaultProperties(); +}; +} +} diff --git a/src/UserInterface/CircleJoint.cpp b/src/UserInterface/CircleJoint.cpp new file mode 100644 index 0000000..1e3bb3d --- /dev/null +++ b/src/UserInterface/CircleJoint.cpp @@ -0,0 +1,49 @@ +#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; + + ofPushStyle(); + ofFill(); + + if (selected) { + ofSetColor(fillColorSelected); + } else { + ofSetColor(fillColor); + } + + ofCircle(position.x, position.y, radius); + ofNoFill(); + + if (selected) { + ofSetColor(strokeColorSelected); + } else { + ofSetColor(strokeColor); + } + + ofSetLineWidth(strokeWidth); + ofCircle(position.x, position.y, radius); + ofPopStyle(); +} + +void CircleJoint::setDefaultProperties() { radius = 10.0f; } + +bool CircleJoint::hitTest(ofVec2f pos) { + float distance = position.distance(pos); + if (distance < radius) + return true; + else + return false; +} +} +} \ No newline at end of file diff --git a/src/UserInterface/CircleJoint.h b/src/UserInterface/CircleJoint.h new file mode 100644 index 0000000..ade616f --- /dev/null +++ b/src/UserInterface/CircleJoint.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ofMain.h" +#include "BaseJoint.h" + +namespace ofx { +namespace piMapper { +class CircleJoint : public BaseJoint { + public: + CircleJoint(); + + void update(); + void draw(); + bool hitTest(ofVec2f position); + + private: + float radius; + + void setDefaultProperties(); +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/EditorType.h b/src/UserInterface/EditorType.h new file mode 100644 index 0000000..b7fdc14 --- /dev/null +++ b/src/UserInterface/EditorType.h @@ -0,0 +1,9 @@ +#pragma once + +namespace ofx { +namespace piMapper { +struct EditorType { + enum { TEXTURE, PROJECTION }; +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/GuiMode.h b/src/UserInterface/GuiMode.h new file mode 100644 index 0000000..f6b1ac4 --- /dev/null +++ b/src/UserInterface/GuiMode.h @@ -0,0 +1,9 @@ +#pragma once + +namespace ofx { +namespace piMapper { +struct GuiMode { + enum { NONE, TEXTURE_MAPPING, PROJECTION_MAPPING, SOURCE_SELECTION }; +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/ProjectionEditor.cpp b/src/UserInterface/ProjectionEditor.cpp new file mode 100644 index 0000000..1851cd2 --- /dev/null +++ b/src/UserInterface/ProjectionEditor.cpp @@ -0,0 +1,263 @@ +#include "ProjectionEditor.h" + +namespace ofx { +namespace piMapper { +ProjectionEditor::ProjectionEditor() { + surfaceManager = NULL; + bShiftKeyDown = false; + fSnapDistance = 10.0f; + enable(); +} + +ProjectionEditor::~ProjectionEditor() { + clearJoints(); + surfaceManager = NULL; + disable(); +} + +void ProjectionEditor::registerAppEvents() { + ofAddListener(ofEvents().update, this, &ProjectionEditor::update); + ofAddListener(ofEvents().messageEvent, this, &ProjectionEditor::gotMessage); +} + +void ProjectionEditor::unregisterAppEvents() { + ofRemoveListener(ofEvents().update, this, &ProjectionEditor::update); + ofRemoveListener(ofEvents().messageEvent, this, + &ProjectionEditor::gotMessage); +} + +void ProjectionEditor::registerMouseEvents() { + ofAddListener(ofEvents().mouseDragged, this, &ProjectionEditor::mouseDragged); +} + +void ProjectionEditor::unregisterMouseEvents() { + ofRemoveListener(ofEvents().mouseDragged, this, + &ProjectionEditor::mouseDragged); +} + +void ProjectionEditor::registerKeyEvents() { + ofAddListener(ofEvents().keyPressed, this, &ProjectionEditor::keyPressed); + ofAddListener(ofEvents().keyReleased, this, &ProjectionEditor::keyReleased); +} + +void ProjectionEditor::unregisterKeyEvents() { + ofRemoveListener(ofEvents().keyPressed, this, &ProjectionEditor::keyPressed); + ofRemoveListener(ofEvents().keyReleased, this, + &ProjectionEditor::keyReleased); +} + +void ProjectionEditor::enable() { + registerAppEvents(); + registerMouseEvents(); + registerKeyEvents(); +} + +void ProjectionEditor::disable() { + unregisterAppEvents(); + unregisterMouseEvents(); + unregisterKeyEvents(); +} + +void ProjectionEditor::update(ofEventArgs& args) { + // 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() != NULL) { + // update vertex to new location + surfaceManager->getSelectedSurface()->setVertex(i, joints[i]->position); + } 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 ProjectionEditor::draw() { + if (surfaceManager == NULL) return; + if (surfaceManager->getSelectedSurface() == NULL) return; + if (joints.size() <= 0) createJoints(); + drawJoints(); +} + +void ProjectionEditor::mouseDragged(ofMouseEventArgs& args) { + ofVec2f mousePosition = ofVec2f(args.x, args.y); + + // Collect all vertices of the projection surfaces + 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 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()) { + // Snap it! + for (int j = 0; j < allVertices.size(); j++) { + float distance = mousePosition.distance(*allVertices[j]); + // cout << "distance: " << distance << endl; + if (distance < fSnapDistance) { + joints[i]->position = *allVertices[j]; + ofVec2f clickDistance = joints[i]->position - ofVec2f(args.x, args.y); + joints[i]->setClickDistance(clickDistance); + break; + } + } + } + } +} + +void ProjectionEditor::keyPressed(ofKeyEventArgs& args) { + int key = args.key; + float moveStep; + + if (bShiftKeyDown) + moveStep = 10.0f; + else + moveStep = 0.5f; + + switch (key) { + case OF_KEY_LEFT: + moveSelection(ofVec2f(-moveStep, 0.0f)); + break; + case OF_KEY_RIGHT: + moveSelection(ofVec2f(moveStep, 0.0f)); + break; + case OF_KEY_UP: + moveSelection(ofVec2f(0.0f, -moveStep)); + break; + case OF_KEY_DOWN: + moveSelection(ofVec2f(0.0f, moveStep)); + break; + case OF_KEY_SHIFT: + bShiftKeyDown = true; + break; + } +} + +void ProjectionEditor::keyReleased(ofKeyEventArgs& args) { + int key = args.key; + switch (key) { + case OF_KEY_SHIFT: + bShiftKeyDown = false; + break; + } +} + +void ProjectionEditor::gotMessage(ofMessage& msg) { + if (msg.message == "surfaceSelected") { + // refresh gui + clearJoints(); + createJoints(); + } +} + +void ProjectionEditor::setSurfaceManager(SurfaceManager* newSurfaceManager) { + surfaceManager = newSurfaceManager; +} + +void ProjectionEditor::clearJoints() { + while (joints.size()) { + delete joints.back(); + joints.pop_back(); + } +} + +void ProjectionEditor::createJoints() { + if (surfaceManager == NULL) return; + clearJoints(); + + if (surfaceManager->getSelectedSurface() == NULL) { + ofLog(OF_LOG_WARNING, "Trying to create joints while no surface selected."); + return; + } + + vector& vertices = + surfaceManager->getSelectedSurface()->getVertices(); + + for (int i = 0; i < vertices.size(); i++) { + joints.push_back(new CircleJoint()); + joints.back()->position = ofVec2f(vertices[i].x, vertices[i].y); + } +} + +void ProjectionEditor::updateJoints() { + vector& vertices = + surfaceManager->getSelectedSurface()->getVertices(); + for (int i = 0; i < vertices.size(); i++) { + joints[i]->position = ofVec2f(vertices[i].x, vertices[i].y); + } +} + +void ProjectionEditor::unselectAllJoints() { + for (int i = 0; i < joints.size(); i++) { + joints[i]->unselect(); + } +} + +void ProjectionEditor::moveSelectedSurface(ofVec2f by) { + if (surfaceManager == NULL) return; + if (surfaceManager->getSelectedSurface() == NULL) return; + surfaceManager->getSelectedSurface()->moveBy(by); + /*vector& vertices = + surfaceManager->getSelectedSurface()->getVertices(); + for (int i=0; istopDrag(); + } +} + +void ProjectionEditor::moveSelection(ofVec2f 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 { + moveSelectedSurface(by); + } +} + +void ProjectionEditor::setSnapDistance(float newSnapDistance) { + fSnapDistance = newSnapDistance; +} + +CircleJoint* ProjectionEditor::hitTestJoints(ofVec2f pos) { + for (int i = 0; i < joints.size(); i++) { + if (joints[i]->hitTest(pos)) { + return joints[i]; + } + } + return NULL; +} + +void ProjectionEditor::drawJoints() { + for (int i = 0; i < joints.size(); i++) { + joints[i]->draw(); + } +} +} +} \ No newline at end of file diff --git a/src/UserInterface/ProjectionEditor.h b/src/UserInterface/ProjectionEditor.h new file mode 100755 index 0000000..50b8582 --- /dev/null +++ b/src/UserInterface/ProjectionEditor.h @@ -0,0 +1,50 @@ +#pragma once + +#include "SurfaceManager.h" +#include "CircleJoint.h" + +namespace ofx { +namespace piMapper { +class ProjectionEditor { + public: + ProjectionEditor(); + ~ProjectionEditor(); + + void registerAppEvents(); + void unregisterAppEvents(); + void registerMouseEvents(); + void unregisterMouseEvents(); + void registerKeyEvents(); + void unregisterKeyEvents(); + + void enable(); + void disable(); + + void update(ofEventArgs& args); + void draw(); + void mouseDragged(ofMouseEventArgs& args); + void keyPressed(ofKeyEventArgs& args); + void keyReleased(ofKeyEventArgs& args); + void gotMessage(ofMessage& msg); + void setSurfaceManager(SurfaceManager* newSurfaceManager); + void clearJoints(); + void createJoints(); + void updateJoints(); + void unselectAllJoints(); + void moveSelectedSurface(ofVec2f by); + void stopDragJoints(); + void updateVertices(); + void moveSelection(ofVec2f by); + void setSnapDistance(float newSnapDistance); + CircleJoint* hitTestJoints(ofVec2f pos); + + private: + SurfaceManager* surfaceManager; + vector joints; + bool bShiftKeyDown; + float fSnapDistance; + + void drawJoints(); +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/RadioList.cpp b/src/UserInterface/RadioList.cpp new file mode 100644 index 0000000..3ccc71f --- /dev/null +++ b/src/UserInterface/RadioList.cpp @@ -0,0 +1,183 @@ +#include "RadioList.h" + +namespace ofx { +namespace piMapper { +RadioList::RadioList() { + storedTitle = ""; + storedSelectedItem = 0; +} + +RadioList::RadioList(vector& labels, vector& values) { + RadioList(); + setup(labels, values); +} + +RadioList::RadioList(string title, vector& labels, vector& values) { + RadioList(); + setup(title, labels, values); +} + +RadioList::~RadioList() { clear(); } + +void RadioList::setup(vector& labels, 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 + toggle->registerMouseEvents(); +#endif + } +} + +void RadioList::setup(string title, vector& labels, vector& values) { + // Store title for later use + storedTitle = title; + guiGroup.setName(title); + setup(labels, values); +} + +void RadioList::draw() { guiGroup.draw(); } + +void RadioList::setTitle(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); + //string name = toggle->getName(); + // Throw event with value that is image path instead of name + 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); + + cout << "num items after enable: " << guiGroup.getNumControls() << 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)); + ofParameter* paramPtr = + static_cast*>(&toggle->getParameter()); + 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(); } + +string RadioList::getTitle() { return guiGroup.getName(); } + +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; + } + } +} +} +} diff --git a/src/UserInterface/RadioList.h b/src/UserInterface/RadioList.h new file mode 100644 index 0000000..c0e1daf --- /dev/null +++ b/src/UserInterface/RadioList.h @@ -0,0 +1,53 @@ +#pragma once + +#include "ofGraphics.h" +#include "ofxGuiGroup.h" +#include "ofxToggle.h" +#include "ofxLabel.h" + +namespace ofx { +namespace piMapper { +class RadioList { + public: + RadioList(); + RadioList(vector& labels, vector& values); + RadioList(string title, vector& labels, vector& values); + ~RadioList(); + + void setup(vector &labels, vector& values); + void setup(string title, vector& labels, vector& values); + void draw(); + void setTitle(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(); + string getTitle(); + 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(string & radioName) + ofEvent onRadioSelected; + + private: + vector storedLabels; + vector storedValues; + string storedTitle; + ofxGuiGroup guiGroup; + int storedSelectedItem; + + void onToggleClicked(bool &toggleValue); +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/SourcesEditor.cpp b/src/UserInterface/SourcesEditor.cpp new file mode 100644 index 0000000..d106d67 --- /dev/null +++ b/src/UserInterface/SourcesEditor.cpp @@ -0,0 +1,271 @@ +#include "SourcesEditor.h" + +namespace ofx { +namespace piMapper { + SourcesEditor::SourcesEditor() { + init(); + // Create new MediaServer instance, + // we will need to clear this in the deconstr + mediaServer = new MediaServer(); + isMediaServerExternal = false; + addMediaServerListeners(); + } + + SourcesEditor::SourcesEditor(MediaServer* externalMediaServer) { + init(); + // Assign external MediaServer instance pointer + mediaServer = externalMediaServer; + isMediaServerExternal = true; + addMediaServerListeners(); + } + + SourcesEditor::~SourcesEditor() { + unregisterAppEvents(); + delete imageSelector; + delete videoSelector; + removeMediaServerListeners(); + clearMediaServer(); + } + + void SourcesEditor::registerAppEvents() { + ofAddListener(ofEvents().setup, this, &SourcesEditor::setup); + } + + void SourcesEditor::unregisterAppEvents() { + ofRemoveListener(ofEvents().setup, this, &SourcesEditor::setup); + } + + void SourcesEditor::setup(ofEventArgs& args) { + imageSelector = new RadioList(); + videoSelector = new RadioList(); + + // Get media count + int numImages = mediaServer->getNumImages(); + int numVideos = mediaServer->getNumVideos(); + + // Depending on media count, decide what to load and initialize + if (numImages) { + // Get image names from media server + vector imageNames = mediaServer->getImageNames(); + imageSelector->setup("Images", imageNames, mediaServer->getImagePaths()); + ofAddListener(imageSelector->onRadioSelected, this, &SourcesEditor::handleImageSelected); + } + if (numVideos) { + vector videoNames = mediaServer->getVideoNames(); + videoSelector->setup("Videos", videoNames, mediaServer->getVideoPaths()); + ofAddListener(videoSelector->onRadioSelected, this, &SourcesEditor::handleVideoSelected); + } + + if (numImages) { + imageSelector->setPosition(20, 20); + if (numVideos) { + videoSelector->setPosition(250, 20); + } + } else { + if (numVideos) { + videoSelector->setPosition(20, 20); + } + } + + } + + void SourcesEditor::draw() { + // Don't draw if there is no source selected + if (surfaceManager->getSelectedSurface() == NULL) { + ofLogNotice("SourcesEditor") << "No surface selected"; + return; + } + if (imageSelector->size()) { + imageSelector->draw(); + } + if (videoSelector->size()) { + videoSelector->draw(); + } + + } + + void SourcesEditor::disable() { + if (imageSelector->size()) { + imageSelector->disable(); + } + if (videoSelector->size()) { + videoSelector->disable(); + } + } + + void SourcesEditor::enable() { + // Don't enable if there is no surface selected + if (surfaceManager->getSelectedSurface() == NULL) { + ofLogNotice("SourcesEditor") << "No surface selected. Not enabling and not showing source list."; + return; + } + if (imageSelector->size()) { + imageSelector->enable(); + } + if (videoSelector->size()) { + videoSelector->enable(); + } + BaseSource* source = surfaceManager->getSelectedSurface()->getSource(); + selectSourceRadioButton(source->getPath()); + } + + void SourcesEditor::setSurfaceManager(SurfaceManager* newSurfaceManager) { + surfaceManager = newSurfaceManager; + } + + void SourcesEditor::setMediaServer(MediaServer* newMediaServer) { + // If the new media server is not valid + if (newMediaServer == NULL) { + // Log an error and return from the routine + ofLogFatalError("SourcesEditor") << "New media server is NULL"; + std::exit(EXIT_FAILURE); + } + // Attempt to clear existing media server and assign new one + clearMediaServer(); + //cout << "old ms addr: " << mediaServer << endl; + //cout << "new ms addr: " << newMediaServer << endl; + mediaServer = newMediaServer; + isMediaServerExternal = true; + } + + void SourcesEditor::selectSourceRadioButton(std::string& sourcePath) { + if (sourcePath == "") { + ofLogNotice("SourcesEditor") << "Path is empty"; + if (imageSelector->size()) { + imageSelector->unselectAll(); + } + if (videoSelector->size()) { + videoSelector->unselectAll(); + } + return; + } else { + // Check image selector first + bool imageRadioSelected = false; + bool videoRadioSelected = false; + if (imageSelector->size()) { + imageRadioSelected = imageSelector->selectItemByValue(sourcePath); + } + if (videoSelector->size()) { + videoRadioSelected = videoSelector->selectItemByValue(sourcePath); + } + if (imageRadioSelected || videoRadioSelected) { + return; + } + // Log warning if we are still here + ofLogWarning("SourcesEditor") << "Could not find option in any of the source lists"; + } + } + + 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) { + ofLogError("SourcesEditor::addMediaServerListeners", "Media server not set"); + return; + } + // Add listeners to custom events of the media server + ofAddListener(mediaServer->onImageAdded, this, &SourcesEditor::handleImageAdded); + ofAddListener(mediaServer->onImageRemoved, this, &SourcesEditor::handleImageRemoved); + ofAddListener(mediaServer->onVideoAdded, this, &SourcesEditor::handleVideoAdded); + ofAddListener(mediaServer->onVideoRemoved, this, &SourcesEditor::handleVideoRemoved); + ofAddListener(mediaServer->onImageLoaded, this, &SourcesEditor::handleImageLoaded); + ofAddListener(mediaServer->onImageUnloaded, this, &SourcesEditor::handleImageUnloaded); + + } + + void SourcesEditor::removeMediaServerListeners() { + // Check if the media server is valid + if (mediaServer == NULL) { + ofLogError("SourcesEditor::addMediaServerListeners", "Media server not set"); + return; + } + // Remove listeners to custom events of the media server + ofRemoveListener(mediaServer->onImageAdded, this, &SourcesEditor::handleImageAdded); + ofRemoveListener(mediaServer->onImageRemoved, this, &SourcesEditor::handleImageRemoved); + ofRemoveListener(mediaServer->onVideoAdded, this, &SourcesEditor::handleVideoAdded); + ofRemoveListener(mediaServer->onVideoRemoved, this, &SourcesEditor::handleVideoRemoved); + ofRemoveListener(mediaServer->onImageLoaded, this, &SourcesEditor::handleImageLoaded); + ofRemoveListener(mediaServer->onImageUnloaded, this, &SourcesEditor::handleImageUnloaded); + } + + void SourcesEditor::handleImageSelected(string& imagePath) { + // Unselect video item if any selected + videoSelector->unselectAll(); + BaseSurface* surface = surfaceManager->getSelectedSurface(); + if (surface == NULL) { + ofLogNotice("SourcesEditor") << "No surface selected"; + return; + } + // Unload old media + BaseSource* source = surface->getSource(); + if (source->isLoadable()) { + mediaServer->unloadMedia(source->getPath()); + } + // Load new image + surface->setSource(mediaServer->loadImage(imagePath)); + } + + void SourcesEditor::handleVideoSelected(string& videoPath) { + // Unselect image item if any selected + imageSelector->unselectAll(); + BaseSurface* surface = surfaceManager->getSelectedSurface(); + if (surface == NULL) { + ofLogNotice("SourcesEditor") << "No surface selected"; + return; + } + // Unload old media + BaseSource* source = surface->getSource(); + if (source->isLoadable()) { + mediaServer->unloadMedia(source->getPath()); + } + // Load new video + surface->setSource(mediaServer->loadVideo(videoPath)); + } + + void SourcesEditor::clearMediaServer() { + // If mediaServer is local, clear it + if (!isMediaServerExternal) { + // Clear all loaded sources + mediaServer->clear(); + // Destroy the pointer and set it to NULL pointer + delete mediaServer; + mediaServer = NULL; + } + } + + 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::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 new file mode 100644 index 0000000..e0edecc --- /dev/null +++ b/src/UserInterface/SourcesEditor.h @@ -0,0 +1,73 @@ +#pragma once + +#include "ofGraphics.h" +#include "ofEvents.h" +#include "SurfaceManager.h" +#include "RadioList.h" +#include "MediaServer.h" + +namespace ofx { +namespace piMapper { +class SourcesEditor { + public: + // Default contructor that initializes media server locally, + // thus requiring to delete the media server from memory on deconstr + SourcesEditor(); + + // Alternative constructor that allows to assign external media server + SourcesEditor(MediaServer* externalMediaServer); + ~SourcesEditor(); + + void registerAppEvents(); + void unregisterAppEvents(); + + void setup(ofEventArgs& args); + void draw(); + void loadImage(string name, string path); + void disable(); + void enable(); + void setSurfaceManager(SurfaceManager* newSurfaceManager); + + // Sets external MediaServer + void setMediaServer(MediaServer* newMediaServer); + //void selectImageSourceRadioButton(string name); + void selectSourceRadioButton(std::string& sourcePath); + + int getLoadedTexCount(); + ofTexture* getTexture(int index); + + private: + MediaServer* mediaServer; + SurfaceManager* surfaceManager; + RadioList* imageSelector; + RadioList* videoSelector; + + // Is the media server pointer local or from somewhere else? + // We use this to determine if we are allowed to clear media server locally. + bool isMediaServerExternal; + + // Init handles variable initialization in all constructors + void init(); + + // 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(string& imagePath); + void handleVideoSelected(string& videoPath); + + // 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); +}; +} +} \ No newline at end of file diff --git a/src/UserInterface/TextureEditor.cpp b/src/UserInterface/TextureEditor.cpp new file mode 100755 index 0000000..f7be105 --- /dev/null +++ b/src/UserInterface/TextureEditor.cpp @@ -0,0 +1,234 @@ +#include "TextureEditor.h" + +namespace ofx { +namespace piMapper { +TextureEditor::TextureEditor() { + clear(); + enable(); +} + +TextureEditor::~TextureEditor() { + clear(); + disable(); +} + +void TextureEditor::registerAppEvents() { + ofAddListener(ofEvents().update, this, &TextureEditor::update); +} + +void TextureEditor::unregisterAppEvents() { + ofRemoveListener(ofEvents().update, this, &TextureEditor::update); +} + +void TextureEditor::registerKeyEvents() { + ofAddListener(ofEvents().keyPressed, this, &TextureEditor::keyPressed); + ofAddListener(ofEvents().keyReleased, this, &TextureEditor::keyReleased); +} + +void TextureEditor::unregisterKeyEvents() { + ofRemoveListener(ofEvents().keyPressed, this, &TextureEditor::keyPressed); + ofRemoveListener(ofEvents().keyReleased, this, &TextureEditor::keyReleased); +} + +void TextureEditor::enable() { + registerAppEvents(); + registerKeyEvents(); + bShiftKeyDown = false; +} + +void TextureEditor::disable() { + unregisterAppEvents(); + unregisterKeyEvents(); +} + +void TextureEditor::update(ofEventArgs& args) { + if (surface == NULL) return; + + // update surface if one of the joints is being dragged + ofVec2f textureSize = ofVec2f(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); + + 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 TextureEditor::keyPressed(ofKeyEventArgs& args) { + int key = args.key; + float moveStep; + + if (bShiftKeyDown) + moveStep = 10.0f; + else + moveStep = 0.5f; + + switch (key) { + case OF_KEY_LEFT: + moveSelection(ofVec2f(-moveStep, 0.0f)); + break; + case OF_KEY_RIGHT: + moveSelection(ofVec2f(moveStep, 0.0f)); + break; + case OF_KEY_UP: + moveSelection(ofVec2f(0.0f, -moveStep)); + break; + case OF_KEY_DOWN: + moveSelection(ofVec2f(0.0f, moveStep)); + break; + case OF_KEY_SHIFT: + bShiftKeyDown = true; + break; + } +} + +void TextureEditor::keyReleased(ofKeyEventArgs& args) { + int key = args.key; + switch (key) { + case OF_KEY_SHIFT: + bShiftKeyDown = false; + break; + } +} + +void TextureEditor::draw() { + if (surface == NULL) return; + + drawJoints(); +} + +void TextureEditor::drawJoints() { + for (int i = 0; i < joints.size(); i++) { + joints[i]->draw(); + } +} + +void TextureEditor::setSurface(BaseSurface* newSurface) { + surface = newSurface; + createJoints(); +} + +void TextureEditor::clear() { + surface = NULL; + clearJoints(); +} + +void TextureEditor::createJoints() { + if (surface == NULL) return; + clearJoints(); + vector& texCoords = surface->getTexCoords(); + ofVec2f textureSize = ofVec2f(surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + + for (int i = 0; i < texCoords.size(); i++) { + joints.push_back(new CircleJoint()); + joints.back()->position = texCoords[i] * textureSize; + } +} + +void TextureEditor::clearJoints() { + while (joints.size()) { + delete joints.back(); + joints.pop_back(); + } +} + +void TextureEditor::unselectAllJoints() { + for (int i = 0; i < joints.size(); i++) { + joints[i]->unselect(); + } +} + +void TextureEditor::moveTexCoords(ofVec2f by) { + if (surface == NULL) return; + vector& texCoords = surface->getTexCoords(); + ofVec2f textureSize = ofVec2f(surface->getSource()->getTexture()->getWidth(), + surface->getSource()->getTexture()->getHeight()); + for (int i = 0; i < texCoords.size(); i++) { + joints[i]->position += by; + texCoords[i] = joints[i]->position / textureSize; + } +} + +void TextureEditor::stopDragJoints() { + for (int i = 0; i < joints.size(); i++) { + joints[i]->stopDrag(); + } +} + +void TextureEditor::moveSelection(ofVec2f 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 TextureEditor::constrainJointsToQuad(int selectedJointIndex) +{ + switch (selectedJointIndex) { + case 0: + joints[1]->position = ofVec2f(joints[1]->position.x, joints[0]->position.y); + joints[2]->position = ofVec2f(joints[1]->position.x, joints[3]->position.y); + joints[3]->position = ofVec2f(joints[0]->position.x, joints[3]->position.y); + break; + case 1: + joints[0]->position = ofVec2f(joints[0]->position.x, joints[1]->position.y); + joints[2]->position = ofVec2f(joints[1]->position.x, joints[2]->position.y); + joints[3]->position = ofVec2f(joints[0]->position.x, joints[2]->position.y); + break; + case 2: + joints[1]->position = ofVec2f(joints[2]->position.x, joints[1]->position.y); + joints[3]->position = ofVec2f(joints[3]->position.x, joints[2]->position.y); + joints[0]->position = ofVec2f(joints[3]->position.x, joints[1]->position.y); + break; + case 3: + joints[0]->position = ofVec2f(joints[3]->position.x, joints[0]->position.y); + joints[2]->position = ofVec2f(joints[2]->position.x, joints[3]->position.y); + joints[1]->position = ofVec2f(joints[2]->position.x, joints[0]->position.y); + break; + } // switch +} + +CircleJoint* TextureEditor::hitTestJoints(ofVec2f pos) { + for (int i = 0; i < joints.size(); i++) { + if (joints[i]->hitTest(pos)) { + return joints[i]; + } + } + return NULL; +} +} +} \ No newline at end of file diff --git a/src/UserInterface/TextureEditor.h b/src/UserInterface/TextureEditor.h new file mode 100644 index 0000000..5e49a12 --- /dev/null +++ b/src/UserInterface/TextureEditor.h @@ -0,0 +1,44 @@ +#pragma once + +#include "ofEvents.h" + +#include "BaseSurface.h" +#include "CircleJoint.h" + +namespace ofx { +namespace piMapper { +class TextureEditor { + public: + TextureEditor(); + ~TextureEditor(); + + void registerAppEvents(); + void unregisterAppEvents(); + void registerKeyEvents(); + void unregisterKeyEvents(); + void enable(); + void disable(); + + void update(ofEventArgs& args); + void keyPressed(ofKeyEventArgs& args); + void keyReleased(ofKeyEventArgs& args); + void draw(); + void drawJoints(); + void setSurface(BaseSurface* newSurface); + void clear(); + void createJoints(); + void clearJoints(); + void unselectAllJoints(); + void moveTexCoords(ofVec2f by); + void stopDragJoints(); + void moveSelection(ofVec2f by); + void constrainJointsToQuad(int selectedJointIndex); + CircleJoint* hitTestJoints(ofVec2f pos); + + private: + BaseSurface* surface; + vector joints; + bool bShiftKeyDown; +}; +} +} \ No newline at end of file diff --git a/src/ofxBaseJoint.cpp b/src/ofxBaseJoint.cpp deleted file mode 100644 index 22d147d..0000000 --- a/src/ofxBaseJoint.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "ofxBaseJoint.h" - -ofxBaseJoint::ofxBaseJoint() -{ - setDefaultColors(); - setDefaultProperties(); - registerMouseEvents(); -} - -ofxBaseJoint::~ofxBaseJoint() -{ - unregisterMouseEvents(); -} - -void ofxBaseJoint::registerMouseEvents() -{ - ofAddListener(ofEvents().mousePressed, this, &ofxBaseJoint::mousePressed); - ofAddListener(ofEvents().mouseDragged, this, &ofxBaseJoint::mouseDragged); -} - -void ofxBaseJoint::unregisterMouseEvents() -{ - ofRemoveListener(ofEvents().mousePressed, this, &ofxBaseJoint::mousePressed); - ofRemoveListener(ofEvents().mouseDragged, this, &ofxBaseJoint::mouseDragged); -} - -void ofxBaseJoint::mousePressed(ofMouseEventArgs& args) -{ - if ( hitTest(ofVec2f(args.x, args.y)) ) { - //selected = true; - clickDistance = position - ofVec2f(args.x, args.y); - //startDrag(); - } -} - -void ofxBaseJoint::mouseReleased(int x, int y, int button) -{ - stopDrag(); -} - -void ofxBaseJoint::mouseDragged(ofMouseEventArgs& args) -{ - if ( !bDrag ) return; - position = ofVec2f(args.x, args.y) + clickDistance; -} - -void ofxBaseJoint::startDrag() -{ - bDrag = true; -} - -void ofxBaseJoint::stopDrag() -{ - bDrag = false; -} - -void ofxBaseJoint::select() -{ - selected = true; -} - -void ofxBaseJoint::unselect() -{ - selected = false; -} - -void ofxBaseJoint::setClickDistance(ofVec2f newClickDistance) -{ - clickDistance = newClickDistance; -} - -bool ofxBaseJoint::isDragged() -{ - return bDrag; -} - -bool ofxBaseJoint::isSelected() -{ - return selected; -} - -void ofxBaseJoint::setDefaultColors() -{ - fillColor = ofColor(0, 255, 255, 0); - strokeColor = ofColor(255, 255, 255); - fillColorSelected = ofColor(255, 255, 0, 0); - strokeColorSelected = ofColor(255, 0, 0); -} - -void ofxBaseJoint::setDefaultProperties() -{ - enabled = true; - visible = true; - position = ofVec2f(20.0f, 20.0f); - clickDistance = ofVec2f(0.0f, 0.0f); - bDrag = false; - selected = false; - strokeWidth = 1.5f; -} \ No newline at end of file diff --git a/src/ofxBaseJoint.h b/src/ofxBaseJoint.h deleted file mode 100644 index d3decb7..0000000 --- a/src/ofxBaseJoint.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef H_OFX_BASE_JOINT -#define H_OFX_BASE_JOINT - -#include "ofMain.h" - -class ofxBaseJoint { -public: - ofxBaseJoint(); - ~ofxBaseJoint(); - - void registerMouseEvents(); - void unregisterMouseEvents(); - - ofVec2f 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(ofVec2f newClickDistance); - bool isDragged(); - bool isSelected(); - - virtual void update(){}; - virtual void draw(){}; - virtual bool hitTest(ofVec2f position){}; - -protected: - ofColor fillColor; - ofColor strokeColor; - ofColor fillColorSelected; - ofColor strokeColorSelected; - float strokeWidth; - ofVec2f clickDistance; // How far from the center of the joint the user has clicked? - bool bDrag; - -private: - void setDefaultColors(); - void setDefaultProperties(); -}; - -#endif diff --git a/src/ofxBaseSurface.cpp b/src/ofxBaseSurface.cpp deleted file mode 100644 index 67db7ef..0000000 --- a/src/ofxBaseSurface.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "ofxBaseSurface.h" - -ofxBaseSurface::ofxBaseSurface() -{ - ofEnableNormalizedTexCoords(); - createDefaultTexture(); -} - -void ofxBaseSurface::createDefaultTexture() -{ - ofPixels pixels; - pixels.allocate(500, 500, 1); - for ( int i=0; igetWidth(), 0.0f)); - texMesh.addVertex(position + ofVec2f(texture->getWidth(), texture->getHeight())); - texMesh.addVertex(position + ofVec2f(0.0f, texture->getHeight())); - texMesh.addTriangle(0, 2, 3); - texMesh.addTriangle(0, 1, 2); - texMesh.addTexCoord(ofVec2f(0.0f, 0.0f)); - texMesh.addTexCoord(ofVec2f(1.0f, 0.0f)); - texMesh.addTexCoord(ofVec2f(1.0f, 1.0f)); - texMesh.addTexCoord(ofVec2f(0.0f, 1.0f)); - texture->bind(); - texMesh.draw(); - texture->unbind(); -} - -void ofxBaseSurface::setTexture(ofTexture *texturePtr) -{ - texture = texturePtr; -} - -ofTexture* ofxBaseSurface::getTexture() -{ - return texture; -} - -ofTexture* ofxBaseSurface::getDefaultTexture() -{ - return &defaultTexture; -} \ No newline at end of file diff --git a/src/ofxBaseSurface.h b/src/ofxBaseSurface.h deleted file mode 100644 index 300df97..0000000 --- a/src/ofxBaseSurface.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef H_OFX_BASE_SURFACE -#define H_OFX_BASE_SURFACE - -#include "ofMain.h" -#include - -using namespace std; - -class ofxBaseSurface -{ -public: - ofxBaseSurface(); - virtual void setup(){}; - virtual void draw(){}; - virtual void setVertex(int index, ofVec2f p){}; - virtual void setTexCoord(int index, ofVec2f t){}; - virtual int getType(){}; - virtual bool hitTest(ofVec2f p){}; - virtual ofPolyline getHitArea(){}; - virtual ofPolyline getTextureHitArea(){}; - virtual vector& getVertices(){}; - virtual vector& getTexCoords(){}; - - // Draws a texture using ofMesh - void drawTexture(ofVec2f position); - void setTexture(ofTexture* texturePtr); - - ofTexture* getTexture(); - ofTexture* getDefaultTexture(); - -protected: - ofMesh mesh; - ofTexture* texture; - ofTexture defaultTexture; - - void createDefaultTexture(); -}; - -#endif \ No newline at end of file diff --git a/src/ofxCircleJoint.cpp b/src/ofxCircleJoint.cpp deleted file mode 100644 index 4abbc5c..0000000 --- a/src/ofxCircleJoint.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "ofxCircleJoint.h" - -ofxCircleJoint::ofxCircleJoint() -{ - setDefaultProperties(); -} - -void ofxCircleJoint::update() -{ - if (!enabled) return; -} - -void ofxCircleJoint::draw() -{ - if (!visible) return; - if (!enabled) return; - - ofPushStyle(); - ofFill(); - - if ( selected ) { - ofSetColor(fillColorSelected); - } else { - ofSetColor(fillColor); - } - - ofCircle(position.x, position.y, radius); - ofNoFill(); - - if ( selected ) { - ofSetColor(strokeColorSelected); - } else { - ofSetColor(strokeColor); - } - - ofSetLineWidth(strokeWidth); - ofCircle(position.x, position.y, radius); - ofPopStyle(); -} - -void ofxCircleJoint::setDefaultProperties() -{ - radius = 10.0f; -} - -bool ofxCircleJoint::hitTest(ofVec2f pos) -{ - float distance = position.distance(pos); - if ( distance < radius ) return true; - else return false; -} \ No newline at end of file diff --git a/src/ofxCircleJoint.h b/src/ofxCircleJoint.h deleted file mode 100644 index f3016e9..0000000 --- a/src/ofxCircleJoint.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef H_OFX_CIRCLE_JOINT -#define H_OFX_CIRCLE_JOINT - -#include "ofMain.h" -#include "ofxBaseJoint.h" - -class ofxCircleJoint : public ofxBaseJoint -{ -public: - ofxCircleJoint(); - - void update(); - void draw(); - bool hitTest(ofVec2f position); - -private: - float radius; - - void setDefaultProperties(); -}; - -#endif \ No newline at end of file diff --git a/src/ofxEditorType.h b/src/ofxEditorType.h deleted file mode 100644 index cc0c1c8..0000000 --- a/src/ofxEditorType.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef H_OFX_EDITOR_TYPE -#define H_OFX_EDITOR_TYPE - -struct ofxEditorType -{ - enum { - TEXTURE, - PROJECTION - }; -}; - -#endif \ No newline at end of file diff --git a/src/ofxGuiMode.h b/src/ofxGuiMode.h deleted file mode 100644 index c60fe71..0000000 --- a/src/ofxGuiMode.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef H_OFX_GUI_MODE -#define H_OFX_GUI_MODE - -struct ofxGuiMode -{ - enum { - NONE, - TEXTURE_MAPPING, - PROJECTION_MAPPING, - SOURCE_SELECTION - }; -}; - -#endif \ No newline at end of file diff --git a/src/ofxPiMapper.h b/src/ofxPiMapper.h index 4f65bd2..975b9f6 100644 --- a/src/ofxPiMapper.h +++ b/src/ofxPiMapper.h @@ -1,7 +1,6 @@ -#ifndef H_OFX_PI_MAPPER -#define H_OFX_PI_MAPPER +#pragma once -#include "ofxSurfaceManager.h" -#include "ofxSurfaceManagerGui.h" +#include "SurfaceManager.h" +#include "SurfaceManagerGui.h" -#endif \ No newline at end of file +#include "MediaServer.h" \ No newline at end of file diff --git a/src/ofxProjectionEditor.cpp b/src/ofxProjectionEditor.cpp deleted file mode 100644 index 2762f82..0000000 --- a/src/ofxProjectionEditor.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "ofxProjectionEditor.h" - -ofxProjectionEditor::ofxProjectionEditor() -{ - surfaceManager = NULL; - bShiftKeyDown = false; - fSnapDistance = 10.0f; - enable(); -} - -ofxProjectionEditor::~ofxProjectionEditor() -{ - clearJoints(); - surfaceManager = NULL; - disable(); -} - -void ofxProjectionEditor::registerAppEvents() -{ - ofAddListener(ofEvents().update, this, &ofxProjectionEditor::update); - ofAddListener(ofEvents().messageEvent, this, &ofxProjectionEditor::gotMessage); -} - -void ofxProjectionEditor::unregisterAppEvents() -{ - ofRemoveListener(ofEvents().update, this, &ofxProjectionEditor::update); - ofRemoveListener(ofEvents().messageEvent, this, &ofxProjectionEditor::gotMessage); -} - -void ofxProjectionEditor::registerMouseEvents() -{ - ofAddListener(ofEvents().mouseDragged, this, &ofxProjectionEditor::mouseDragged); -} - -void ofxProjectionEditor::unregisterMouseEvents() -{ - ofRemoveListener(ofEvents().mouseDragged, this, &ofxProjectionEditor::mouseDragged); -} - -void ofxProjectionEditor::registerKeyEvents() -{ - ofAddListener(ofEvents().keyPressed, this, &ofxProjectionEditor::keyPressed); - ofAddListener(ofEvents().keyReleased, this, &ofxProjectionEditor::keyReleased); -} - -void ofxProjectionEditor::unregisterKeyEvents() -{ - ofRemoveListener(ofEvents().keyPressed, this, &ofxProjectionEditor::keyPressed); - ofRemoveListener(ofEvents().keyReleased, this, &ofxProjectionEditor::keyReleased); -} - -void ofxProjectionEditor::enable() -{ - registerAppEvents(); - registerMouseEvents(); - registerKeyEvents(); -} - -void ofxProjectionEditor::disable() -{ - unregisterAppEvents(); - unregisterMouseEvents(); - unregisterKeyEvents(); -} - -void ofxProjectionEditor::update(ofEventArgs &args) -{ - // update surface if one of the joints is being dragged - for ( int i=0; iisDragged() || joints[i]->isSelected() ) { - - if ( surfaceManager->getSelectedSurface() != NULL ) { - // update vertex to new location - surfaceManager->getSelectedSurface()->setVertex(i, joints[i]->position); - } 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 ofxProjectionEditor::draw() -{ - if ( surfaceManager == NULL ) return; - if ( surfaceManager->getSelectedSurface() == NULL ) return; - if ( joints.size() <= 0 ) createJoints(); - drawJoints(); -} - -void ofxProjectionEditor::mouseDragged(ofMouseEventArgs &args) -{ - ofVec2f mousePosition = ofVec2f(args.x, args.y); - - // Collect all vertices of the projection surfaces - vector allVertices; - for ( int i=0; isize(); i++ ) { - ofxBaseSurface* surface = surfaceManager->getSurface(i); - if ( surface == surfaceManager->getSelectedSurface() ) { - continue; // Don't add vertices of selected surface - } - for ( int j=0; jgetVertices().size(); j++ ) { - allVertices.push_back(&surface->getVertices()[j]); - } - } - - // Snap currently dragged joint to nearest vertex - for ( int i=0; iisDragged() ) { - // Snap it! - for ( int j=0; jposition = *allVertices[j]; - ofVec2f clickDistance = joints[i]->position - ofVec2f(args.x, args.y); - joints[i]->setClickDistance(clickDistance); - break; - } - } - } - } -} - -void ofxProjectionEditor::keyPressed(ofKeyEventArgs &args) -{ - int key = args.key; - float moveStep; - - if (bShiftKeyDown) moveStep = 10.0f; - else moveStep = 0.5f; - - switch (key) { - case OF_KEY_LEFT: moveSelection(ofVec2f(-moveStep,0.0f)); break; - case OF_KEY_RIGHT: moveSelection(ofVec2f(moveStep,0.0f)); break; - case OF_KEY_UP: moveSelection(ofVec2f(0.0f,-moveStep)); break; - case OF_KEY_DOWN: moveSelection(ofVec2f(0.0f,moveStep)); break; - case OF_KEY_SHIFT: bShiftKeyDown = true; break; - } -} - -void ofxProjectionEditor::keyReleased(ofKeyEventArgs &args) -{ - int key = args.key; - switch (key) { - case OF_KEY_SHIFT: bShiftKeyDown = false; break; - } -} - -void ofxProjectionEditor::gotMessage(ofMessage& msg) -{ - if (msg.message == "surfaceSelected") { - // refresh gui - clearJoints(); - createJoints(); - } -} - -void ofxProjectionEditor::setSurfaceManager(ofxSurfaceManager *newSurfaceManager) -{ - surfaceManager = newSurfaceManager; -} - -void ofxProjectionEditor::clearJoints() -{ - while ( joints.size() ) { - delete joints.back(); - joints.pop_back(); - } -} - -void ofxProjectionEditor::createJoints() -{ - if ( surfaceManager == NULL ) return; - clearJoints(); - - if ( surfaceManager->getSelectedSurface() == NULL ) { - ofLog(OF_LOG_WARNING, "Trying to create joints while no surface selected."); - return; - } - - vector& vertices = surfaceManager->getSelectedSurface()->getVertices(); - - for ( int i=0; iposition = ofVec2f(vertices[i].x, vertices[i].y); - } -} - -void ofxProjectionEditor::updateJoints() -{ - vector& vertices = surfaceManager->getSelectedSurface()->getVertices(); - for ( int i=0; iposition = ofVec2f(vertices[i].x, vertices[i].y); - } -} - -void ofxProjectionEditor::unselectAllJoints() -{ - for ( int i=0; iunselect(); - } -} - -void ofxProjectionEditor::moveSelectedSurface(ofVec2f by) -{ - if ( surfaceManager == NULL ) return; - if ( surfaceManager->getSelectedSurface() == NULL ) return; - vector& vertices = surfaceManager->getSelectedSurface()->getVertices(); - for (int i=0; istopDrag(); - } -} - -void ofxProjectionEditor::moveSelection(ofVec2f by) -{ - // check if joints selected - bool bJointSelected = false; - ofxBaseJoint* selectedJoint; - for ( int i=0; iisSelected()) { - bJointSelected = true; - selectedJoint = joints[i]; - break; - } - } - - if ( bJointSelected ) { - selectedJoint->position += by; - } else { - moveSelectedSurface(by); - } -} - -void ofxProjectionEditor::setSnapDistance(float newSnapDistance) -{ - fSnapDistance = newSnapDistance; -} - -ofxCircleJoint* ofxProjectionEditor::hitTestJoints(ofVec2f pos) -{ - for ( int i=0; ihitTest(pos) ){ - return joints[i]; - } - } - return NULL; -} - -void ofxProjectionEditor::drawJoints() -{ - for ( int i=0; idraw(); - } -} \ No newline at end of file diff --git a/src/ofxProjectionEditor.h b/src/ofxProjectionEditor.h deleted file mode 100755 index c4b95ec..0000000 --- a/src/ofxProjectionEditor.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef H_OFX_PROJECTION_EDITOR -#define H_OFX_PROJECTION_EDITOR - -#include "ofxSurfaceManager.h" -#include "ofxCircleJoint.h" - -class ofxProjectionEditor -{ -public: - ofxProjectionEditor(); - ~ofxProjectionEditor(); - - void registerAppEvents(); - void unregisterAppEvents(); - void registerMouseEvents(); - void unregisterMouseEvents(); - void registerKeyEvents(); - void unregisterKeyEvents(); - - void enable(); - void disable(); - - void update(ofEventArgs& args); - void draw(); - void mouseDragged(ofMouseEventArgs& args); - void keyPressed(ofKeyEventArgs& args); - void keyReleased(ofKeyEventArgs& args); - void gotMessage(ofMessage& msg); - void setSurfaceManager(ofxSurfaceManager* newSurfaceManager); - void clearJoints(); - void createJoints(); - void updateJoints(); - void unselectAllJoints(); - void moveSelectedSurface(ofVec2f by); - void stopDragJoints(); - void updateVertices(); - void moveSelection(ofVec2f by); - void setSnapDistance(float newSnapDistance); - ofxCircleJoint* hitTestJoints(ofVec2f pos); - -private: - ofxSurfaceManager* surfaceManager; - vector joints; - bool bShiftKeyDown; - float fSnapDistance; - - void drawJoints(); -}; - -#endif \ No newline at end of file diff --git a/src/ofxQuadSurface.cpp b/src/ofxQuadSurface.cpp deleted file mode 100644 index 68f8c7e..0000000 --- a/src/ofxQuadSurface.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "ofxQuadSurface.h" - -ofxQuadSurface::ofxQuadSurface() -{ - cout << "ofxQuadSurface constructor." << endl; - setup(); -} - -ofxQuadSurface::~ofxQuadSurface() -{ - cout << "ofxQuadSurface destructor." << endl; -} - -void ofxQuadSurface::setup() -{ - // Create 4 points for the 2 triangles - ofVec2f p1 = ofVec2f(0, 0); - ofVec2f p2 = ofVec2f(0, ofGetHeight()); - ofVec2f p3 = ofVec2f(ofGetWidth(), ofGetHeight()); - ofVec2f p4 = ofVec2f(ofGetWidth(), 0); - - // Create 4 point for the texture coordinates - ofVec2f t1 = ofVec2f(ofVec2f(0.0f, 0.0f)); - ofVec2f t2 = ofVec2f(ofVec2f(1.0f, 0.0f)); - ofVec2f t3 = ofVec2f(ofVec2f(1.0f, 1.0f)); - ofVec2f t4 = ofVec2f(ofVec2f(0.0f, 1.0f)); - - setup( p1, p2, p3, p4, t1, t2, t3, t4, texture ); -} - -void ofxQuadSurface::setup( ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f p4, - ofVec2f t1, ofVec2f t2, ofVec2f t3, ofVec2f t4, ofTexture* texturePtr ) -{ - // Assign texture - texture = texturePtr; - - // Clear mesh - mesh.clear(); - - // Create a surface with the points - mesh.addVertex( p1 ); - mesh.addVertex( p2 ); - mesh.addVertex( p3 ); - mesh.addVertex( p4 ); - - // Add 2 triangles - mesh.addTriangle(0, 2, 3); - mesh.addTriangle(0, 1, 2); - - // Add texture coordinates - mesh.addTexCoord(t1); - mesh.addTexCoord(t2); - mesh.addTexCoord(t3); - mesh.addTexCoord(t4); -} - -void ofxQuadSurface::draw() -{ - texture->bind(); - mesh.draw(); - texture->unbind(); -} - -void ofxQuadSurface::setVertex(int index, ofVec2f p) -{ - if ( index > 3 ) { - ofLog() << "Vertex with this index does not exist: " << index << endl; - return; - } - - mesh.setVertex(index, p); -} - -void ofxQuadSurface::setTexCoord(int index, ofVec2f t) -{ - if ( index > 3 ) { - ofLog() << "Texture coordinate with this index does not exist: " << index << endl; - return; - } - - mesh.setTexCoord(index, t); -} - -int ofxQuadSurface::getType() -{ - return ofxSurfaceType::QUAD_SURFACE; -} - -bool ofxQuadSurface::hitTest(ofVec2f p) -{ - // Construct ofPolyline from vertices - ofPolyline line = getHitArea(); - - if ( line.inside(p.x, p.y) ) { - return true; - } else { - return false; - } -} - -ofVec2f ofxQuadSurface::getVertex(int index) -{ - if ( index > 3 ) { - ofLog() << "Vertex with this index does not exist: " << index << endl; - throw std::runtime_error("Vertex index out of bounds."); - } - - ofVec3f vert = mesh.getVertex(index); - return ofVec2f(vert.x, vert.y); -} - -ofVec2f ofxQuadSurface::getTexCoord(int index) -{ - if (index > 3) { - throw std::runtime_error("Texture coordinate index out of bounds."); - } - - return mesh.getTexCoord(index); -} - -ofPolyline ofxQuadSurface::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 ofxQuadSurface::getTextureHitArea() -{ - ofPolyline line; - vector& texCoords = mesh.getTexCoords(); - ofVec2f textureSize = ofVec2f(texture->getWidth(), texture->getHeight()); - for ( int i=0; i& ofxQuadSurface::getVertices() -{ - // return only joint vertices - return mesh.getVertices(); -} - -vector& ofxQuadSurface::getTexCoords() -{ - - return mesh.getTexCoords(); -} \ No newline at end of file diff --git a/src/ofxQuadSurface.h b/src/ofxQuadSurface.h deleted file mode 100755 index f2b8164..0000000 --- a/src/ofxQuadSurface.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef H_OFX_QUAD_SURFACE -#define H_OFX_QUAD_SURFACE - -#include "ofMain.h" -#include "ofxBaseSurface.h" -#include "ofxSurfaceType.h" - -class ofxQuadSurface : public ofxBaseSurface -{ -public: - ofxQuadSurface(); - ~ofxQuadSurface(); - - void setup(); - - void setup( ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f p4, - ofVec2f t1, ofVec2f t2, ofVec2f t3, ofVec2f t4, - ofTexture* texturePtr ); - - void draw(); - void setVertex( int index, ofVec2f p ); - void setTexCoord( int index, ofVec2f t ); - - int getType(); - bool hitTest(ofVec2f p); - ofVec2f getVertex(int index); - ofVec2f getTexCoord(int index); - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - vector& getVertices(); - vector& getTexCoords(); -}; - -#endif \ No newline at end of file diff --git a/src/ofxSourcesEditor.cpp b/src/ofxSourcesEditor.cpp deleted file mode 100644 index 372f13d..0000000 --- a/src/ofxSourcesEditor.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "ofxSourcesEditor.h" - -ofxSourcesEditor::ofxSourcesEditor() -{ - defImgDir = DEFAULT_IMAGES_DIR; - registerAppEvents(); -} - -ofxSourcesEditor::~ofxSourcesEditor() -{ - unregisterAppEvents(); - delete gui; - while ( images.size() ) { - delete images.back(); - images.pop_back(); - } -} - -void ofxSourcesEditor::registerAppEvents() -{ - ofAddListener(ofEvents().setup, this, &ofxSourcesEditor::setup); -} - -void ofxSourcesEditor::unregisterAppEvents() -{ - ofRemoveListener(ofEvents().setup, this, &ofxSourcesEditor::setup); -} - -void ofxSourcesEditor::setup(ofEventArgs& args) -{ - gui = new ofxUICanvas(); - gui->disable(); - gui->disableAppDrawCallback(); - - // read directory contents - ofDirectory imgDir; - imgDir.listDir(defImgDir); - imgDir.sort(); - - vector vnames; - - for(int i = 0; i < (int)imgDir.size(); i++){ - //images[i].loadImage(imgDir.getPath(i)); - vnames.push_back(imgDir.getName(i)); - } - - gui->addLabel(defImgDir, OFX_UI_FONT_SMALL); - ofxUIRadio *radio = gui->addRadio("images", vnames, OFX_UI_ORIENTATION_VERTICAL); - radio->activateToggle("image0.png"); - - ofAddListener(gui->newGUIEvent,this,&ofxSourcesEditor::guiEvent); -} - -void ofxSourcesEditor::draw() -{ - gui->draw(); -} - -void ofxSourcesEditor::loadImage( string name, string path ) -{ - images.push_back(new ofImage()); - images.back()->loadImage(path); - - imageNames.push_back(name); - - ofSendMessage("imageLoaded"); -} - -void ofxSourcesEditor::disable() -{ - gui->disable(); -} - -void ofxSourcesEditor::enable() -{ - gui->enable(); -} - -void ofxSourcesEditor::setSurfaceManager(ofxSurfaceManager *newSurfaceManager) -{ - surfaceManager = newSurfaceManager; -} - -void ofxSourcesEditor::selectImageSourceRadioButton(string name) -{ - vector widgets = gui->getWidgets(); - - // find radio list item - ofxUIRadio* radio; - for ( int i=0; igetKind(); - if ( widgetKind == OFX_UI_WIDGET_RADIO ){ - radio = (ofxUIRadio*)widgets[i]; - break; - } - } - - if (name == "none") { - ofxUIToggle* toggle = (ofxUIToggle*)radio->getActive(); - if ( toggle != NULL ) { - toggle->setValue(false); - } - return; - } else { - for ( int i=0; igetName(); - if ( name == widgetName ) { - radio->activateToggle(name); - return; - } - } - } -} - -int ofxSourcesEditor::getLoadedTexCount() -{ - return images.size(); -} - -ofTexture* ofxSourcesEditor::getTexture(int index) -{ - if (index >= images.size()){ - throw std::runtime_error("Texture index out of bounds."); - } - - return &images[index]->getTextureReference(); -} - -void ofxSourcesEditor::guiEvent(ofxUIEventArgs &e) -{ - string name = e.widget->getName(); - int kind = e.widget->getKind(); - - if(kind == OFX_UI_WIDGET_TOGGLE){ - ofxUIToggle *toggle = (ofxUIToggle *) e.widget; - cout << name << "\t value: " << toggle->getValue() << endl; - } - - if ( surfaceManager->getSelectedSurface() == NULL ) { - return; - } - - if (name == "images") { - return; - } - - stringstream ss; - ss << defImgDir << name; - cout << "attempt to load image: " << ss.str() << endl; - ofTexture* texture = surfaceManager->loadImageSource(name, ss.str()); - surfaceManager->getSelectedSurface()->setTexture(texture); - surfaceManager->manageMemory(); -} \ No newline at end of file diff --git a/src/ofxSourcesEditor.h b/src/ofxSourcesEditor.h deleted file mode 100644 index 7344e33..0000000 --- a/src/ofxSourcesEditor.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef H_OFX_SOURCES_EDITOR -#define H_OFX_SOURCES_EDITOR - -#include "ofGraphics.h" -#include "ofEvents.h" -#include "ofxUI.h" -#include "ofxSurfaceManager.h" - -#define DEFAULT_IMAGES_DIR "sources/images/"; - -class ofxSourcesEditor -{ -public: - ofxSourcesEditor(); - ~ofxSourcesEditor(); - - void registerAppEvents(); - void unregisterAppEvents(); - - void setup(ofEventArgs& args); - void draw(); - void loadImage( string name, string path ); - void disable(); - void enable(); - void setSurfaceManager(ofxSurfaceManager* newSurfaceManager); - void selectImageSourceRadioButton(string name); - - int getLoadedTexCount(); - ofTexture* getTexture(int index); - -private: - ofxSurfaceManager* surfaceManager; - string defImgDir; - ofxUICanvas *gui; - void guiEvent(ofxUIEventArgs &e); - vector images; - vector imageNames; - //ofxPanel imgSrcPanel; - - //void onSourceSelect(bool& value); -}; - -#endif \ No newline at end of file diff --git a/src/ofxSurfaceManager.cpp b/src/ofxSurfaceManager.cpp deleted file mode 100644 index e7df328..0000000 --- a/src/ofxSurfaceManager.cpp +++ /dev/null @@ -1,486 +0,0 @@ -#include "ofxSurfaceManager.h" - -ofxSurfaceManager::ofxSurfaceManager() -{ - -} - -ofxSurfaceManager::~ofxSurfaceManager() -{ - clear(); -} - -void ofxSurfaceManager::draw() -{ - for ( int i=0; idraw(); - } -} - -void ofxSurfaceManager::addSurface(int surfaceType) -{ - if ( surfaceType == ofxSurfaceType::TRIANGLE_SURFACE ) { - surfaces.push_back( new ofxTriangleSurface() ); - } - else if (surfaceType == ofxSurfaceType::QUAD_SURFACE ) { - surfaces.push_back( new ofxQuadSurface() ); - } - else { - throw std::runtime_error("Attempt to add non-existing surface type."); - } -} - -void ofxSurfaceManager::addSurface(int surfaceType, ofTexture* texturePtr) -{ - if ( surfaceType == ofxSurfaceType::TRIANGLE_SURFACE ) { - surfaces.push_back( new ofxTriangleSurface() ); - surfaces.back()->setTexture(texturePtr); - } - else if (surfaceType == ofxSurfaceType::QUAD_SURFACE ) { - surfaces.push_back( new ofxQuadSurface() ); - surfaces.back()->setTexture(texturePtr); - } - else { - throw std::runtime_error("Attempt to add non-existing surface type."); - } -} - -void ofxSurfaceManager::addSurface(int surfaceType, vector vertices, vector texCoords) -{ - if ( surfaceType == ofxSurfaceType::TRIANGLE_SURFACE ) { - - if ( vertices.size() < 3 ) { - throw std::runtime_error("There must be 3 vertices for a triangle surface."); - } else if (texCoords.size() < 3) { - throw std::runtime_error("There must be 3 texture coordinates for a triangle surface."); - } - - surfaces.push_back( new ofxTriangleSurface() ); - - for ( int i=0; i<3; i++ ) { - surfaces.back()->setVertex(i, vertices[i]); - surfaces.back()->setTexCoord(i, texCoords[i]); - } - - } - else if (surfaceType == ofxSurfaceType::QUAD_SURFACE ) { - if ( vertices.size() < 4 ) { - throw std::runtime_error("There must be 4 vertices for a quad surface."); - } else if (texCoords.size() < 4) { - throw std::runtime_error("There must be 4 texture coordinates for a quad surface."); - } - - surfaces.push_back( new ofxQuadSurface() ); - - for ( int i=0; i<4; i++ ) { - surfaces.back()->setVertex(i, vertices[i]); - surfaces.back()->setTexCoord(i, texCoords[i]); - } - } - else { - throw std::runtime_error("Attempt to add non-existing surface type."); - } - -} - -void ofxSurfaceManager::addSurface(int surfaceType, ofTexture* texturePtr, vector vertices, vector texCoords) -{ - if ( surfaceType == ofxSurfaceType::TRIANGLE_SURFACE ) { - - if ( vertices.size() < 3 ) { - throw std::runtime_error("There must be 3 vertices for a triangle surface."); - } else if (texCoords.size() < 3) { - throw std::runtime_error("Thre must be 3 texture coordinates for a triangle surface."); - } - - surfaces.push_back( new ofxTriangleSurface() ); - surfaces.back()->setTexture(texturePtr); - - for ( int i=0; i<3; i++ ) { - surfaces.back()->setVertex(i, vertices[i]); - surfaces.back()->setTexCoord(i, texCoords[i]); - } - - } - else if (surfaceType == ofxSurfaceType::QUAD_SURFACE ) { - if ( vertices.size() < 4 ) { - throw std::runtime_error("There must be 4 vertices for a quad surface."); - } else if (texCoords.size() < 4) { - throw std::runtime_error("Thre must be 4 texture coordinates for a quad surface."); - } - - surfaces.push_back( new ofxQuadSurface() ); - surfaces.back()->setTexture(texturePtr); - - for ( int i=0; i<4; i++ ) { - surfaces.back()->setVertex(i, vertices[i]); - surfaces.back()->setTexCoord(i, texCoords[i]); - } - } - else { - throw std::runtime_error("Attempt to add non-existing surface type."); - } -} - -void ofxSurfaceManager::removeSelectedSurface() -{ - if ( selectedSurface == NULL ) return; - - for ( int i=0; igetTexture() == &loadedImageSources[i]->getTextureReference() ) { - bAssigned = true; - break; - } - } - - if ( !bAssigned ) { - // purge the image source from memory - delete loadedImageSources[i]; - loadedImageSources.erase(loadedImageSources.begin()+i); - cout << "Deleting image source: " << loadedImageSourceNames[i] << endl; - loadedImageSourceNames.erase(loadedImageSourceNames.begin()+i); - i--; - } - } -} - -void ofxSurfaceManager::clear() -{ - // delete all extra allocations from the heap - while ( surfaces.size() ) { - delete surfaces.back(); - surfaces.pop_back(); - } - - while ( loadedImageSources.size() ) { - delete loadedImageSources.back(); - loadedImageSources.pop_back(); - } - - while ( loadedImageSourceNames.size() ) { - loadedImageSourceNames.pop_back(); - } -} - -// String getTypeString(ofxSurfaceType e) -// { -// switch e -// { -// case TRINAGLE_SURFACE: return "TRINAGLE_SURFACE"; -// case QUAD_SURFACE: return "QUAD_SURFACE"; -// default: throw Exception("Bad MyEnum"); -// } -// } - -void ofxSurfaceManager::saveXmlSettings(string fileName) -{ - xmlSettings.clear(); - - // save surfaces - xmlSettings.addTag("surfaces"); - xmlSettings.pushTag("surfaces"); - for ( int i=0; i* vertices = &surface->getVertices(); - for ( int j=0; jsize(); j++ ) { - xmlSettings.addTag("vertex"); - xmlSettings.pushTag("vertex", j); - ofVec3f* 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"); - vector* texCoords = &surface->getTexCoords(); - for ( int j=0; jsize(); j++ ) { - xmlSettings.addTag("texCoord"); - xmlSettings.pushTag("texCoord", j); - ofVec2f* 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"); - - xmlSettings.addValue("source-type", "image"); - xmlSettings.addValue("source-name", getSurfaceSourceName(surface)); - //xmlSettings.addValue("source-path", "/root/etc/image.jpg"); - xmlSettings.popTag(); // source - - - // xmlSettings.addTag("type"); - // xmlSettings.pushTag("type"); - // // surfaceType == ofxSurfaceType::TRIANGLE_SURFACE - // ofxSurfaceType surfaceType = &surface->getType(); - // xmlSettings.addValue("surface-type", surfaceType); - // xmlSettings.popTag(); // type - - xmlSettings.popTag(); // surface - } - xmlSettings.popTag(); // surfaces - - xmlSettings.save(fileName); -} - -void ofxSurfaceManager::loadXmlSettings(string fileName) -{ - - - if (!xmlSettings.loadFile(fileName)){ - ofLog(OF_LOG_WARNING, "Could not load XML settings."); - return; - } - - if (!xmlSettings.tagExists("surfaces")){ - ofLog(OF_LOG_WARNING, "XML settings is empty or has wrong markup."); - return; - } - - xmlSettings.pushTag("surfaces"); - - int numSurfaces = xmlSettings.getNumTags("surface"); - for ( int i=0; i vertices; - - int vertexCount = xmlSettings.getNumTags("vertex"); - - - //it's a triangle ? - if (vertexCount == 3) - { - ofLog(OF_LOG_NOTICE, "create Triangle"); - xmlSettings.pushTag("vertex", 0); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("vertex", 1); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 100.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("vertex", 2); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 100.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.popTag(); // vertices - - xmlSettings.pushTag("texCoords"); - - vector texCoords; - - xmlSettings.pushTag("texCoord", 0); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("texCoord", 1); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 1.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("texCoord", 2); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 1.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.popTag(); // texCoords - - - // now we have variables sourceName and sourceTexture - // by checking those we can use one or another addSurface method - if ( sourceName != "none" && sourceTexture != NULL ) { - addSurface(ofxSurfaceType::TRIANGLE_SURFACE, sourceTexture, vertices, texCoords); - } else { - addSurface(ofxSurfaceType::TRIANGLE_SURFACE, vertices, texCoords); - } - } - // it's a quad ? - else if (vertexCount == 4) - // if (surface-type == QUAD_SURFACE) - { - xmlSettings.pushTag("vertex", 0); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("vertex", 1); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 100.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("vertex", 2); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 100.0f), xmlSettings.getValue("y", 100.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("vertex", 3); - vertices.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 100.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.popTag(); // vertices - - xmlSettings.pushTag("texCoords"); - - vector texCoords; - - xmlSettings.pushTag("texCoord", 0); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("texCoord", 1); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 1.0f), xmlSettings.getValue("y", 0.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("texCoord", 2); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 1.0f), xmlSettings.getValue("y", 1.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.pushTag("texCoord", 3); - texCoords.push_back( ofVec2f( xmlSettings.getValue("x", 0.0f), xmlSettings.getValue("y", 1.0f) ) ); - xmlSettings.popTag(); - - xmlSettings.popTag(); // texCoords - - - // now we have variables sourceName and sourceTexture - // by checking those we can use one or another addSurface method - if ( sourceName != "none" && sourceTexture != NULL ) { - addSurface(ofxSurfaceType::QUAD_SURFACE, sourceTexture, vertices, texCoords); - } else { - addSurface(ofxSurfaceType::QUAD_SURFACE, vertices, texCoords); - } - - - } - - xmlSettings.popTag(); // surface - } - - xmlSettings.popTag(); // surfaces -} - -ofxBaseSurface* ofxSurfaceManager::selectSurface(int index) -{ - if ( index >= surfaces.size() ) { - throw std::runtime_error("Surface index out of bounds."); - } - - selectedSurface = surfaces[index]; - - // notify that a new surface has been selected - ofSendMessage("surfaceSelected"); -} - -ofxBaseSurface* ofxSurfaceManager::getSelectedSurface() -{ - return selectedSurface; -} - -void ofxSurfaceManager::deselectSurface() -{ - selectedSurface = NULL; -} - -ofTexture* ofxSurfaceManager::loadImageSource(string name, string path) -{ - // check if it is loaded - for ( int i=0; igetTextureReference(); - } - } - - // not loaded - load - ofImage* image = new ofImage(); - if ( !image->loadImage(path) ){ - return NULL; - } - loadedImageSources.push_back(image); - loadedImageSourceNames.push_back(name); - return &image->getTextureReference(); -} - -string ofxSurfaceManager::getSelectedSurfaceSourceName() -{ - if ( selectedSurface == NULL ) { - return "none"; - } - - return getSurfaceSourceName( selectedSurface ); -} - -string ofxSurfaceManager::getSurfaceSourceName(ofxBaseSurface *surface) -{ - ofTexture* tex = surface->getTexture(); - for ( int i=0; igetTextureReference()) { - return loadedImageSourceNames[i]; - } - } - - return "none"; -} - -ofxBaseSurface* ofxSurfaceManager::getSurface(int index) -{ - if ( index >= surfaces.size() ) { - throw std::runtime_error("Surface index out of bounds."); - return NULL; - } - - return surfaces[index]; -} - -int ofxSurfaceManager::size() -{ - return surfaces.size(); -} - - - diff --git a/src/ofxSurfaceManager.h b/src/ofxSurfaceManager.h deleted file mode 100755 index 90e8bb1..0000000 --- a/src/ofxSurfaceManager.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef H_OFX_SURFACE_MANAGER -#define H_OFX_SURFACE_MANAGER - -#include "ofxBaseSurface.h" -#include "ofxTriangleSurface.h" -#include "ofxQuadSurface.h" -#include "ofxSurfaceType.h" -#include "ofEvents.h" -#include "ofxXmlSettings.h" - -using namespace std; - -class ofxSurfaceManager -{ -public: - ofxSurfaceManager(); - ~ofxSurfaceManager(); - - void draw(); - void addSurface(int surfaceType); - void addSurface(int surfaceType, ofTexture* texturePtr); - void addSurface(int surfaceType, vector vertices, vector texCoords); - void addSurface(int surfaceType, ofTexture* texturePtr, vector vertices, vector texCoords); - void removeSelectedSurface(); - void manageMemory(); // deletes unasigned sources - void clear(); - void saveXmlSettings(string fileName); - void loadXmlSettings(string fileName); - - ofxBaseSurface* getSurface(int index); - int size(); - ofxBaseSurface* selectSurface(int index); - ofxBaseSurface* getSelectedSurface(); - void deselectSurface(); - ofTexture* loadImageSource(string name, string path); - string getSelectedSurfaceSourceName(); - string getSurfaceSourceName( ofxBaseSurface* surface ); - -private: - vector surfaces; - ofxBaseSurface* selectedSurface; - vector loadedImageSourceNames; - vector loadedImageSources; - ofxXmlSettings xmlSettings; - -}; - -#endif \ No newline at end of file diff --git a/src/ofxSurfaceManagerGui.cpp b/src/ofxSurfaceManagerGui.cpp deleted file mode 100644 index 49d5a1e..0000000 --- a/src/ofxSurfaceManagerGui.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "ofxSurfaceManagerGui.h" - -ofxSurfaceManagerGui::ofxSurfaceManagerGui() -{ - surfaceManager = NULL; - guiMode = ofxGuiMode::NONE; - bDrag = false; - registerMouseEvents(); - ofHideCursor(); -} - -ofxSurfaceManagerGui::~ofxSurfaceManagerGui() -{ - unregisterMouseEvents(); - surfaceManager = NULL; -} - -void ofxSurfaceManagerGui::registerMouseEvents() -{ - ofAddListener(ofEvents().mousePressed, this, &ofxSurfaceManagerGui::mousePressed); - ofAddListener(ofEvents().mouseReleased, this, &ofxSurfaceManagerGui::mouseReleased); - ofAddListener(ofEvents().mouseDragged, this, &ofxSurfaceManagerGui::mouseDragged); -} - -void ofxSurfaceManagerGui::unregisterMouseEvents() -{ - ofRemoveListener(ofEvents().mousePressed, this, &ofxSurfaceManagerGui::mousePressed); - ofRemoveListener(ofEvents().mouseReleased, this, &ofxSurfaceManagerGui::mouseReleased); - ofRemoveListener(ofEvents().mouseDragged, this, &ofxSurfaceManagerGui::mouseDragged); -} - -void ofxSurfaceManagerGui::draw() -{ - if ( surfaceManager == NULL ) return; - - if ( guiMode == ofxGuiMode::NONE ) { - surfaceManager->draw(); - } else if ( guiMode == ofxGuiMode::TEXTURE_MAPPING ) { - - // draw the texture of the selected surface - if ( surfaceManager->getSelectedSurface() != NULL ) { - surfaceManager->getSelectedSurface()->drawTexture( ofVec2f(0,0) ); - } - - // draw surfaces with opacity - ofPushStyle(); - ofSetColor(255, 255, 255, 200); - surfaceManager->draw(); - ofPopStyle(); - - // highlight selected surface - drawSelectedSurfaceHighlight(); - - // hilight selected surface texture - drawSelectedSurfaceTextureHighlight(); - - // draw texture editing GUI on top - textureEditor.draw(); - - } else if ( guiMode == ofxGuiMode::PROJECTION_MAPPING ) { - - // draw projection surfaces first - surfaceManager->draw(); - - // highlight selected surface - drawSelectedSurfaceHighlight(); - - // draw projection mapping editing gui - projectionEditor.draw(); - - } else if ( guiMode == ofxGuiMode::SOURCE_SELECTION ) { - // draw projection surfaces first - surfaceManager->draw(); - - // highlight selected surface - drawSelectedSurfaceHighlight(); - - sourcesEditor.draw(); - } -} - -void ofxSurfaceManagerGui::mousePressed(ofMouseEventArgs &args) -{ - if ( guiMode == ofxGuiMode::NONE ) { - return; - } else if ( guiMode == ofxGuiMode::TEXTURE_MAPPING ) { - - bool bSurfaceSelected = false; - - ofxCircleJoint* hitJoint = textureEditor.hitTestJoints(ofVec2f(args.x, args.y)); - if ( hitJoint != NULL ) { - textureEditor.unselectAllJoints(); - hitJoint->select(); - hitJoint->startDrag(); - bSurfaceSelected = true; - } else { - textureEditor.unselectAllJoints(); - } - - if ( surfaceManager->getSelectedSurface() != NULL && !bSurfaceSelected ) { - // hittest texture area to see if we are hitting the texture surface - if ( surfaceManager->getSelectedSurface()->getTextureHitArea().inside(args.x, args.y) ) { - clickPosition = ofVec2f(args.x, args.y); - startDrag(); - } - } - - } else if ( guiMode == ofxGuiMode::PROJECTION_MAPPING ) { - - bool bSurfaceSelected = false; - - ofxCircleJoint* hitJoint = projectionEditor.hitTestJoints(ofVec2f(args.x, args.y)); - if ( hitJoint != NULL ) { - projectionEditor.unselectAllJoints(); - hitJoint->select(); - hitJoint->startDrag(); - bSurfaceSelected = true; - } - - // attempt to select surface, loop from end to beginning - if ( !bSurfaceSelected ){ - for ( int i=surfaceManager->size()-1; i>=0; i-- ) { - if ( surfaceManager->getSurface(i)->hitTest( ofVec2f(args.x, args.y) ) ) { - projectionEditor.clearJoints(); - surfaceManager->selectSurface(i); - projectionEditor.createJoints(); - bSurfaceSelected = true; - break; - } - } - } - - if ( bSurfaceSelected && hitJoint == NULL ) { - // if not hitting the joints, start drag only if we have a selected surface - clickPosition = ofVec2f(args.x, args.y); - startDrag(); - } - - if ( !bSurfaceSelected ) { - // unselect if no surface selected - projectionEditor.clearJoints(); - surfaceManager->deselectSurface(); - } - } else if ( guiMode == ofxGuiMode::SOURCE_SELECTION ) { - - } -} - -void ofxSurfaceManagerGui::mouseReleased(ofMouseEventArgs &args) -{ - stopDrag(); - projectionEditor.stopDragJoints(); - textureEditor.stopDragJoints(); -} - -void ofxSurfaceManagerGui::mouseDragged(ofMouseEventArgs &args) -{ - if (bDrag) { - ofVec2f mousePosition = ofVec2f(args.x, args.y); - ofVec2f distance = mousePosition - clickPosition; - - if ( guiMode == ofxGuiMode::PROJECTION_MAPPING ) { - // add this distance to all vertices in surface - projectionEditor.moveSelectedSurface(distance); - } else if ( guiMode == ofxGuiMode::TEXTURE_MAPPING ) { - textureEditor.moveTexCoords(distance); - } - clickPosition = mousePosition; - } -} - -void ofxSurfaceManagerGui::setSurfaceManager(ofxSurfaceManager* newSurfaceManager) -{ - surfaceManager = newSurfaceManager; - projectionEditor.setSurfaceManager( surfaceManager ); - sourcesEditor.setSurfaceManager( surfaceManager ); -} - -void ofxSurfaceManagerGui::setMode(int newGuiMode) -{ - if (newGuiMode != ofxGuiMode::NONE && - newGuiMode != ofxGuiMode::TEXTURE_MAPPING && - newGuiMode != ofxGuiMode::PROJECTION_MAPPING && - newGuiMode != ofxGuiMode::SOURCE_SELECTION) { - throw std::runtime_error("Trying to set invalid mode."); - } - - if ( newGuiMode == ofxGuiMode::NONE ) { - ofHideCursor(); - } else { - ofShowCursor(); - } - - guiMode = newGuiMode; - - if ( guiMode == ofxGuiMode::SOURCE_SELECTION ) { - sourcesEditor.enable(); - string sourceName = surfaceManager->getSelectedSurfaceSourceName(); - sourcesEditor.selectImageSourceRadioButton(sourceName); - } else { - sourcesEditor.disable(); - } - - if ( guiMode == ofxGuiMode::TEXTURE_MAPPING ) { - textureEditor.enable(); - // refresh texture editor surface reference - textureEditor.setSurface(surfaceManager->getSelectedSurface()); - } else { - textureEditor.disable(); - } - - if (guiMode == ofxGuiMode::PROJECTION_MAPPING) { - projectionEditor.enable(); - } else { - projectionEditor.disable(); - } -} - -void ofxSurfaceManagerGui::drawSelectedSurfaceHighlight() -{ - if ( surfaceManager->getSelectedSurface() == NULL ) return; - - ofPolyline line = surfaceManager->getSelectedSurface()->getHitArea(); - - ofPushStyle(); - ofSetLineWidth(1); - ofSetColor(255, 255, 255, 255); - line.draw(); - ofPopStyle(); -} - -void ofxSurfaceManagerGui::drawSelectedSurfaceTextureHighlight() -{ - if ( surfaceManager->getSelectedSurface() == NULL ) return; - - ofPolyline line = surfaceManager->getSelectedSurface()->getTextureHitArea(); - - ofPushStyle(); - ofSetLineWidth(1); - ofSetColor(255, 255, 0, 255); - line.draw(); - ofPopStyle(); - -} - -void ofxSurfaceManagerGui::startDrag() -{ - bDrag = true; -} - -void ofxSurfaceManagerGui::stopDrag() -{ - bDrag = false; -} \ No newline at end of file diff --git a/src/ofxSurfaceManagerGui.h b/src/ofxSurfaceManagerGui.h deleted file mode 100644 index 605d8a1..0000000 --- a/src/ofxSurfaceManagerGui.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef H_OFX_SURFACE_MANAGER_GUI -#define H_OFX_SURFACE_MANAGER_GUI - -// I'm starting to think, maybe we should use ofxStateMachine here. -// Would make sense. TODO later. - -#include "ofEvents.h" -#include "ofxSurfaceManager.h" -#include "ofxTextureEditor.h" -#include "ofxProjectionEditor.h" -#include "ofxSourcesEditor.h" -#include "ofxGuiMode.h" -#include "ofGraphics.h" - -class ofxSurfaceManagerGui -{ -public: - ofxSurfaceManagerGui(); - ~ofxSurfaceManagerGui(); - - void registerMouseEvents(); - void unregisterMouseEvents(); - - void draw(); - void mousePressed(ofMouseEventArgs& args); - void mouseReleased(ofMouseEventArgs& args); - void mouseDragged(ofMouseEventArgs& args); - void setSurfaceManager(ofxSurfaceManager* newSurfaceManager); - void setMode(int newGuiMode); - void drawSelectedSurfaceHighlight(); - void drawSelectedSurfaceTextureHighlight(); - void startDrag(); - void stopDrag(); - -private: - ofxSurfaceManager* surfaceManager; - ofxTextureEditor textureEditor; - ofxProjectionEditor projectionEditor; - ofxSourcesEditor sourcesEditor; - int guiMode; - bool bDrag; - ofVec2f clickPosition; - -}; - -#endif \ No newline at end of file diff --git a/src/ofxSurfaceType.h b/src/ofxSurfaceType.h deleted file mode 100755 index cbda131..0000000 --- a/src/ofxSurfaceType.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef H_OFX_SURFACE_TYPE -#define H_OFX_SURFACE_TYPE - -struct ofxSurfaceType -{ - enum { - TRIANGLE_SURFACE, - QUAD_SURFACE - }; -}; - -#endif \ No newline at end of file diff --git a/src/ofxTextureEditor.cpp b/src/ofxTextureEditor.cpp deleted file mode 100755 index 0a1aa41..0000000 --- a/src/ofxTextureEditor.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "ofxTextureEditor.h" - -ofxTextureEditor::ofxTextureEditor() -{ - clear(); - enable(); -} - -ofxTextureEditor::~ofxTextureEditor() -{ - clear(); - disable(); -} - -void ofxTextureEditor::registerAppEvents() -{ - ofAddListener(ofEvents().update, this, &ofxTextureEditor::update); -} - -void ofxTextureEditor::unregisterAppEvents() -{ - ofRemoveListener(ofEvents().update, this, &ofxTextureEditor::update); -} - -void ofxTextureEditor::registerKeyEvents() -{ - ofAddListener(ofEvents().keyPressed, this, &ofxTextureEditor::keyPressed); - ofAddListener(ofEvents().keyReleased, this, &ofxTextureEditor::keyReleased); -} - -void ofxTextureEditor::unregisterKeyEvents() -{ - ofRemoveListener(ofEvents().keyPressed, this, &ofxTextureEditor::keyPressed); - ofRemoveListener(ofEvents().keyReleased, this, &ofxTextureEditor::keyReleased); -} - -void ofxTextureEditor::enable() -{ - registerAppEvents(); - registerKeyEvents(); - bShiftKeyDown = false; -} - -void ofxTextureEditor::disable() -{ - unregisterAppEvents(); - unregisterKeyEvents(); -} - -void ofxTextureEditor::update(ofEventArgs &args) -{ - if ( surface == NULL ) return; - - // update surface if one of the joints is being dragged - ofVec2f textureSize = ofVec2f( surface->getTexture()->getWidth(), surface->getTexture()->getHeight() ); - for ( int i=0; iisDragged() || joints[i]->isSelected() ) { - // update vertex to new location - surface->setTexCoord(i, joints[i]->position / textureSize); - break; - } - } -} - -void ofxTextureEditor::keyPressed(ofKeyEventArgs &args) -{ - int key = args.key; - float moveStep; - - if (bShiftKeyDown) moveStep = 10.0f; - else moveStep = 0.5f; - - switch (key) { - case OF_KEY_LEFT: moveSelection(ofVec2f(-moveStep,0.0f)); break; - case OF_KEY_RIGHT: moveSelection(ofVec2f(moveStep,0.0f)); break; - case OF_KEY_UP: moveSelection(ofVec2f(0.0f,-moveStep)); break; - case OF_KEY_DOWN: moveSelection(ofVec2f(0.0f,moveStep)); break; - case OF_KEY_SHIFT: bShiftKeyDown = true; break; - } -} - -void ofxTextureEditor::keyReleased(ofKeyEventArgs &args) -{ - int key = args.key; - switch (key) { - case OF_KEY_SHIFT: bShiftKeyDown = false; break; - } -} - - -void ofxTextureEditor::draw() -{ - if (surface == NULL) return; - - drawJoints(); -} - -void ofxTextureEditor::drawJoints() -{ - for ( int i=0; idraw(); - } -} - -void ofxTextureEditor::setSurface(ofxBaseSurface* newSurface) -{ - surface = newSurface; - createJoints(); -} - -void ofxTextureEditor::clear() -{ - surface = NULL; - clearJoints(); -} - -void ofxTextureEditor::createJoints() -{ - if ( surface == NULL ) return; - clearJoints(); - vector& texCoords = surface->getTexCoords(); - ofVec2f textureSize = ofVec2f(surface->getTexture()->getWidth(), surface->getTexture()->getHeight()); - - for ( int i=0; iposition = texCoords[i] * textureSize; - } -} - -void ofxTextureEditor::clearJoints() -{ - while ( joints.size() ) { - delete joints.back(); - joints.pop_back(); - } -} - -void ofxTextureEditor::unselectAllJoints() -{ - for ( int i=0; iunselect(); - } -} - -void ofxTextureEditor::moveTexCoords(ofVec2f by) -{ - if ( surface == NULL ) return; - vector& texCoords = surface->getTexCoords(); - ofVec2f textureSize = ofVec2f( surface->getTexture()->getWidth(), surface->getTexture()->getHeight() ); - for (int i=0; iposition += by; - texCoords[i] = joints[i]->position / textureSize; - } -} - -void ofxTextureEditor::stopDragJoints() -{ - for (int i=0; istopDrag(); - } -} - -void ofxTextureEditor::moveSelection(ofVec2f by) -{ - // check if joints selected - bool bJointSelected = false; - ofxBaseJoint* selectedJoint; - for ( int i=0; iisSelected()) { - bJointSelected = true; - selectedJoint = joints[i]; - break; - } - } - - if ( bJointSelected ) { - selectedJoint->position += by; - } else { - moveTexCoords(by); - } -} - -ofxCircleJoint* ofxTextureEditor::hitTestJoints(ofVec2f pos) -{ - for ( int i=0; ihitTest(pos) ){ - return joints[i]; - } - } - return NULL; -} \ No newline at end of file diff --git a/src/ofxTextureEditor.h b/src/ofxTextureEditor.h deleted file mode 100644 index 18f30ef..0000000 --- a/src/ofxTextureEditor.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef H_OFX_TEXTURE_EDITOR -#define H_OFX_TEXTURE_EDITOR - -#include "ofEvents.h" -#include "ofxBaseSurface.h" -#include "ofxCircleJoint.h" - -class ofxTextureEditor -{ -public: - ofxTextureEditor(); - ~ofxTextureEditor(); - - void registerAppEvents(); - void unregisterAppEvents(); - void registerKeyEvents(); - void unregisterKeyEvents(); - void enable(); - void disable(); - - void update(ofEventArgs& args); - void keyPressed(ofKeyEventArgs& args); - void keyReleased(ofKeyEventArgs& args); - void draw(); - void drawJoints(); - void setSurface(ofxBaseSurface* newSurface); - void clear(); - void createJoints(); - void clearJoints(); - void unselectAllJoints(); - void moveTexCoords(ofVec2f by); - void stopDragJoints(); - void moveSelection(ofVec2f by); - ofxCircleJoint* hitTestJoints(ofVec2f pos); - -private: - ofxBaseSurface* surface; - vector joints; - bool bShiftKeyDown; -}; - -#endif \ No newline at end of file diff --git a/src/ofxTriangleSurface.cpp b/src/ofxTriangleSurface.cpp deleted file mode 100644 index 2eacf94..0000000 --- a/src/ofxTriangleSurface.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "ofxTriangleSurface.h" - -ofxTriangleSurface::ofxTriangleSurface() -{ - cout << "ofxTriangleSurface constructor." << endl; - setup(); -} - -ofxTriangleSurface::~ofxTriangleSurface() -{ - cout << "ofxTriangleSurface destructor." << endl; -} - -void ofxTriangleSurface::setup() -{ - // Create 3 points for the triangle - ofVec2f p1 = ofVec2f(ofGetWidth()/2.0f, 0); - ofVec2f p2 = ofVec2f(ofVec2f(0, ofGetHeight())); - ofVec2f p3 = ofVec2f(ofGetWidth(), ofGetHeight()); - - // Create 3 point for the texture coordinates - ofVec2f t1 = ofVec2f(0.5f, 0); - ofVec2f t2 = ofVec2f(0, 1.0f); - ofVec2f t3 = ofVec2f(1, 1.0f); - - setup( p1, p2, p3, t1, t2, t3, texture ); -} - -void ofxTriangleSurface::setup( ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f t1, ofVec2f t2, ofVec2f t3, ofTexture* texturePtr ) -{ - // Assign texture - texture = texturePtr; - - // Clear mesh - mesh.clear(); - - // Create a surface with the points - mesh.addVertex( p1 ); - mesh.addVertex( p2 ); - mesh.addVertex( p3 ); - - // Add texture coordinates - mesh.addTexCoord(t1); - mesh.addTexCoord(t2); - mesh.addTexCoord(t3); -} - -void ofxTriangleSurface::draw() -{ - texture->bind(); - mesh.draw(); - texture->unbind(); -} - -void ofxTriangleSurface::setVertex(int index, ofVec2f p) -{ - if ( index > 2 ) { - ofLog() << "Vertex with this index does not exist: " << index << endl; - return; - } - - mesh.setVertex(index, p); -} - -void ofxTriangleSurface::setTexCoord(int index, ofVec2f t) -{ - if ( index > 2 ) { - ofLog() << "Texture coordinate with this index does not exist: " << index << endl; - return; - } - - mesh.setTexCoord(index, t); -} - -int ofxTriangleSurface::getType() -{ - return ofxSurfaceType::TRIANGLE_SURFACE; -} - -bool ofxTriangleSurface::hitTest(ofVec2f p) -{ - // Construct ofPolyline from vertices - ofPolyline line = getHitArea(); - - if ( line.inside(p.x, p.y) ) { - return true; - } else { - return false; - } -} - -ofVec2f ofxTriangleSurface::getVertex(int index) -{ - if ( index > 2 ) { - ofLog() << "Vertex with this index does not exist: " << index << endl; - throw std::runtime_error("Vertex index out of bounds."); - } - - ofVec3f vert = mesh.getVertex(index); - return ofVec2f(vert.x, vert.y); -} - -ofVec2f ofxTriangleSurface::getTexCoord(int index) -{ - if (index > 2) { - throw std::runtime_error("Texture coordinate index out of bounds."); - } - - return mesh.getTexCoord(index); -} - -ofPolyline ofxTriangleSurface::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 ofxTriangleSurface::getTextureHitArea() -{ - ofPolyline line; - vector& texCoords = mesh.getTexCoords(); - ofVec2f textureSize = ofVec2f(texture->getWidth(), texture->getHeight()); - for ( int i=0; i& ofxTriangleSurface::getVertices() -{ - // return only joint vertices - return mesh.getVertices(); -} - -vector& ofxTriangleSurface::getTexCoords() -{ - - return mesh.getTexCoords(); -} \ No newline at end of file diff --git a/src/ofxTriangleSurface.h b/src/ofxTriangleSurface.h deleted file mode 100644 index bed128c..0000000 --- a/src/ofxTriangleSurface.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef H_OFX_TRIANGLE_SURFACE -#define H_OFX_TRIANGLE_SURFACE - -#include "ofMain.h" -#include "ofxBaseSurface.h" -#include "ofxSurfaceType.h" - -class ofxTriangleSurface : public ofxBaseSurface -{ -public: - ofxTriangleSurface(); - ~ofxTriangleSurface(); - - void setup(); - void setup( ofVec2f p1, ofVec2f p2, ofVec2f p3, ofVec2f t1, ofVec2f t2, ofVec2f t3, ofTexture* texturePtr ); - void draw(); - void setVertex( int index, ofVec2f p ); - void setTexCoord( int index, ofVec2f t ); - - int getType(); - bool hitTest(ofVec2f p); - ofVec2f getVertex(int index); - ofVec2f getTexCoord(int index); - ofPolyline getHitArea(); - ofPolyline getTextureHitArea(); - vector& getVertices(); - vector& getTexCoords(); -}; - -#endif \ No newline at end of file