Browse Source

Merge branch 'develop'

Conflicts:
	ofxaddons_thumbnail.png
master
Krisjanis Rijnieks 11 years ago
parent
commit
a00993c6ec
  1. 79
      README.md
  2. 76
      addon_config.mk
  3. 4
      example/addons.make
  4. BIN
      example/bin/data/sources/videos/test.mov
  5. 314
      example/src/ofApp.cpp
  6. 49
      example/src/ofApp.h
  7. BIN
      piMapperLogo.jpg
  8. 46
      src/MediaServer/DirectoryWatcher.cpp
  9. 144
      src/MediaServer/DirectoryWatcher.h
  10. 300
      src/MediaServer/MediaServer.cpp
  11. 91
      src/MediaServer/MediaServer.h
  12. 59
      src/Sources/BaseSource.cpp
  13. 36
      src/Sources/BaseSource.h
  14. 39
      src/Sources/ImageSource.cpp
  15. 18
      src/Sources/ImageSource.h
  16. 46
      src/Sources/SourceType.h
  17. 74
      src/Sources/VideoSource.cpp
  18. 48
      src/Sources/VideoSource.h
  19. 90
      src/Surfaces/BaseSurface.cpp
  20. 47
      src/Surfaces/BaseSurface.h
  21. 248
      src/Surfaces/QuadSurface.cpp
  22. 40
      src/Surfaces/QuadSurface.h
  23. 392
      src/Surfaces/SurfaceManager.cpp
  24. 49
      src/Surfaces/SurfaceManager.h
  25. 250
      src/Surfaces/SurfaceManagerGui.cpp
  26. 48
      src/Surfaces/SurfaceManagerGui.h
  27. 9
      src/Surfaces/SurfaceType.h
  28. 141
      src/Surfaces/TriangleSurface.cpp
  29. 32
      src/Surfaces/TriangleSurface.h
  30. 72
      src/UserInterface/BaseJoint.cpp
  31. 51
      src/UserInterface/BaseJoint.h
  32. 49
      src/UserInterface/CircleJoint.cpp
  33. 22
      src/UserInterface/CircleJoint.h
  34. 9
      src/UserInterface/EditorType.h
  35. 9
      src/UserInterface/GuiMode.h
  36. 263
      src/UserInterface/ProjectionEditor.cpp
  37. 50
      src/UserInterface/ProjectionEditor.h
  38. 183
      src/UserInterface/RadioList.cpp
  39. 53
      src/UserInterface/RadioList.h
  40. 271
      src/UserInterface/SourcesEditor.cpp
  41. 73
      src/UserInterface/SourcesEditor.h
  42. 234
      src/UserInterface/TextureEditor.cpp
  43. 44
      src/UserInterface/TextureEditor.h
  44. 99
      src/ofxBaseJoint.cpp
  45. 48
      src/ofxBaseJoint.h
  46. 72
      src/ofxBaseSurface.cpp
  47. 39
      src/ofxBaseSurface.h
  48. 51
      src/ofxCircleJoint.cpp
  49. 22
      src/ofxCircleJoint.h
  50. 12
      src/ofxEditorType.h
  51. 14
      src/ofxGuiMode.h
  52. 9
      src/ofxPiMapper.h
  53. 266
      src/ofxProjectionEditor.cpp
  54. 50
      src/ofxProjectionEditor.h
  55. 156
      src/ofxQuadSurface.cpp
  56. 34
      src/ofxQuadSurface.h
  57. 153
      src/ofxSourcesEditor.cpp
  58. 43
      src/ofxSourcesEditor.h
  59. 486
      src/ofxSurfaceManager.cpp
  60. 48
      src/ofxSurfaceManager.h
  61. 254
      src/ofxSurfaceManagerGui.cpp
  62. 46
      src/ofxSurfaceManagerGui.h
  63. 12
      src/ofxSurfaceType.h
  64. 191
      src/ofxTextureEditor.cpp
  65. 42
      src/ofxTextureEditor.h
  66. 146
      src/ofxTriangleSurface.cpp
  67. 30
      src/ofxTriangleSurface.h

79
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

76
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 =

4
example/addons.make

@ -1,3 +1,5 @@
ofxPiMapper
ofxUI
ofxIO
ofxXmlSettings
ofxGui
ofxOMXPlayer

BIN
example/bin/data/sources/videos/test.mov

Binary file not shown.

314
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; i<numRects; i++ ) {
rects.push_back( ofRectangle(0, ofRandom(fbo->getHeight()), 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<rects.size(); i++ ) {
rects[i].y += rectSpeeds[i];
if ( rects[i].y > fbo->getHeight() ) {
rects[i].y = -rects[i].getHeight();
}
}
// Fill FBO
fbo->begin();
ofClear(0);
ofBackground(0);
ofSetColor(255);
for ( int i=0; i<rects.size(); i++ ) {
ofRect( rects[i] );
void ofApp::update() {
// Move rects
for (int i = 0; i < rects.size(); i++) {
rects[i].y += rectSpeeds[i];
if (rects[i].y > fbo->getHeight()) {
rects[i].y = -rects[i].getHeight();
}
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 <r> or <n> to add random or normal surface.\n";
ss << "Press <q> to add a new quad surface.\n";
ss << "Press <s> to save the composition.\n";
ss << "Press <f> to toggle fullscreen.\n";
ss << "Press <a> to reassign the fbo texture to the first surface\n";
ss << "Hit <i> to hide this message.";
ofDrawBitmapStringHighlight(ss.str(), 10, 20, ofColor(0,0,0,100), ofColor(255,255,255,200));
}
void ofApp::draw() {
// Draw the piMapper GUI
gui.draw();
if (bShowInfo) {
// Draw instructions
stringstream ss;
ss << "There are 4 modes:\n\n";
ss << " 1. Presentation mode\n";
ss << " 2. Texture mapping mode\n";
ss << " 3. Projection mapping mode\n";
ss << " 4. Source selection mode\n\n";
ss << "You can switch between the modes by using <1>, <2>, <3> and <4> "
"keys on the keyboard.\n\n";
ss << "Press <r> or <n> to add random or normal surface.\n";
ss << "Press <q> to add a new quad surface.\n";
ss << "Press <s> to save the composition.\n";
ss << "Press <f> to toggle fullscreen.\n";
ss << "Press <a> to reassign the fbo texture to the first surface\n";
ss << "Hit <i> to hide this message.";
ofDrawBitmapStringHighlight(ss.str(), 10, 20, ofColor(0, 0, 0, 100),
ofColor(255, 255, 255, 200));
}
}
void ofApp::exit()
{
// Clear FBO from mem
delete fbo;
void ofApp::exit() {
// Clear FBO from mem
delete fbo;
}
void ofApp::keyPressed(int key)
{
cout << "Key pressed: " << static_cast<char>(key) << endl;
switch (key) {
case '1': gui.setMode(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<char>(key) << endl;
switch (key) {
case '1':
gui.setMode(ofx::piMapper::GuiMode::NONE);
break;
case '2':
gui.setMode(ofx::piMapper::GuiMode::TEXTURE_MAPPING);
break;
case '3':
gui.setMode(ofx::piMapper::GuiMode::PROJECTION_MAPPING);
break;
case '4':
gui.setMode(ofx::piMapper::GuiMode::SOURCE_SELECTION);
break;
case 'i':
bShowInfo = !bShowInfo;
break;
case 'r':
addRandomSurface();
break;
case 'q':
addQuadSurface();
break;
case 'n':
addSurface();
break;
case 'f':
ofToggleFullscreen();
break;
case 's':
surfaceManager.saveXmlSettings("surfaces.xml");
break;
case 'a':
setFboAsSource();
break;
case OF_KEY_BACKSPACE:
surfaceManager.removeSelectedSurface();
break;
default:
break;
}
}
void ofApp::addRandomSurface()
{
int surfaceType = ofxSurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) );
vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) );
vertices.push_back( ofVec2f( ofRandomWidth(), ofRandomHeight() ) );
vector<ofVec2f> texCoords;
texCoords.push_back( ofVec2f( ofRandomuf(), ofRandomuf() ) );
texCoords.push_back( ofVec2f( ofRandomuf(), ofRandomuf() ) );
texCoords.push_back( ofVec2f( ofRandomuf(), ofRandomuf() ) );
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size()-1);
void ofApp::addRandomSurface() {
int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vertices.push_back(ofVec2f(ofRandomWidth(), ofRandomHeight()));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
texCoords.push_back(ofVec2f(ofRandomuf(), ofRandomuf()));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::addQuadSurface()
{
int surfaceType = ofxSurfaceType::QUAD_SURFACE;
vector<ofVec2f> 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<ofVec2f> texCoords;
texCoords.push_back( ofVec2f(ofVec2f(0.0f, 0.0f)) );
texCoords.push_back( ofVec2f(ofVec2f(1.0f, 0.0f)) );
texCoords.push_back( ofVec2f(ofVec2f(1.0f, 1.0f)) );
texCoords.push_back( ofVec2f(ofVec2f(0.0f, 1.0f)) );
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size()-1);
void ofApp::addQuadSurface() {
int surfaceType = ofx::piMapper::SurfaceType::QUAD_SURFACE;
vector<ofVec2f> vertices;
int border = 50;
vertices.push_back(ofVec2f(border, border));
vertices.push_back(ofVec2f(ofGetWidth() - border, border));
vertices.push_back(ofVec2f(ofGetWidth() - border, ofGetHeight() - border));
vertices.push_back(ofVec2f(border, ofGetHeight() - border));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 0.0f)));
texCoords.push_back(ofVec2f(ofVec2f(1.0f, 1.0f)));
texCoords.push_back(ofVec2f(ofVec2f(0.0f, 1.0f)));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::addSurface()
{
int surfaceType = ofxSurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back( ofVec2f( (float)ofGetWidth()/2.0f, 0.0f ) );
vertices.push_back( ofVec2f( (float)ofGetWidth(), (float)ofGetHeight() ) );
vertices.push_back( ofVec2f( 0.0f, (float)ofGetHeight() ) );
vector<ofVec2f> texCoords;
texCoords.push_back( ofVec2f( 0.5f, 0.0f ) );
texCoords.push_back( ofVec2f( 1.0f, 1.0f ) );
texCoords.push_back( ofVec2f( 0.0f, 1.0f ) );
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size()-1);
void ofApp::addSurface() {
int surfaceType = ofx::piMapper::SurfaceType::TRIANGLE_SURFACE;
vector<ofVec2f> vertices;
vertices.push_back(ofVec2f((float)ofGetWidth() / 2.0f, 0.0f));
vertices.push_back(ofVec2f((float)ofGetWidth(), (float)ofGetHeight()));
vertices.push_back(ofVec2f(0.0f, (float)ofGetHeight()));
vector<ofVec2f> texCoords;
texCoords.push_back(ofVec2f(0.5f, 0.0f));
texCoords.push_back(ofVec2f(1.0f, 1.0f));
texCoords.push_back(ofVec2f(0.0f, 1.0f));
surfaceManager.addSurface(surfaceType, vertices, texCoords);
// select this surface right away
surfaceManager.selectSurface(surfaceManager.size() - 1);
}
void ofApp::setFboAsTexture()
{
surfaceManager.getSurface(0)->setTexture( &fbo->getTextureReference() );
void ofApp::setFboAsSource() {
surfaceManager.getSurface(0)->setSource(fboSource);
}

49
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<ofRectangle> rects;
vector<float> rectSpeeds;
};
void keyPressed(int key);
#endif
void addRandomSurface();
void addQuadSurface();
void addSurface();
void setFboAsSource();
ofImage image;
ofx::piMapper::MediaServer mediaServer;
ofx::piMapper::SurfaceManager surfaceManager;
ofx::piMapper::SurfaceManagerGui gui;
bool bShowInfo;
ofFbo* fbo;
ofx::piMapper::BaseSource* fboSource;
vector<ofRectangle> rects;
vector<float> rectSpeeds;
};

BIN
piMapperLogo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

46
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<std::string>& DirectoryWatcher::getFilePaths() {
return filePaths;
}
int DirectoryWatcher::getMediaType() {
return mediaType;
}
} // namespace piMapper
} // namespace ofx

144
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<std::string>& getFilePaths();
int getMediaType();
// Custom events
ofEvent<string> onItemAdded;
ofEvent<string> onItemRemoved;
ofEvent<string> onItemModified;
ofEvent<string> onItemMovedFrom;
ofEvent<string> onItemMovedTo;
private:
ofx::IO::DirectoryWatcherManager dirWatcher;
BasePathFilter* filter;
std::vector<std::string> filePaths;
int mediaType;
};
}
}

300
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<std::string>& MediaServer::getImagePaths() {
return imageWatcher.getFilePaths();
}
std::vector<std::string> MediaServer::getImageNames() {
std::vector<std::string> imageNames;
for (int i = 0; i < getNumImages(); i++) {
// Split image path
std::vector<std::string> 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<std::string>& MediaServer::getVideoPaths() {
return videoWatcher.getFilePaths();
}
std::vector<std::string> MediaServer::getVideoNames() {
std::vector<std::string> videoNames;
for (int i = 0; i < getNumVideos(); i++) {
// Split video path
std::vector<std::string> 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<ImageSource*>(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<ImageSource*>(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<std::string, BaseSource*>::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<VideoSource*>(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<VideoSource*>(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<std::string, BaseSource*>::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<std::string, BaseSource*>::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

91
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<std::string>& getVideoPaths();
std::vector<std::string> getVideoNames();
std::vector<std::string>& getImagePaths();
std::vector<std::string> 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<string> onImageAdded;
ofEvent<string> onImageRemoved;
ofEvent<string> onVideoAdded;
ofEvent<string> onVideoRemoved;
ofEvent<string> onImageLoaded;
ofEvent<string> onImageUnloaded;
ofEvent<string> onVideoLoaded;
ofEvent<string> onVideoUnloaded;
private:
// Directory Watchers
ofx::piMapper::DirectoryWatcher videoWatcher;
ofx::piMapper::DirectoryWatcher imageWatcher;
std::map<std::string, BaseSource*> 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

59
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<string> 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];
}
}
}

36
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;
};
}
}

39
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;
}
}
}

18
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;
};
}
}

46
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);
}
}
};
}
}

74
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
}
}

48
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
};
}
}

90
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;
}
}
}

47
src/Surfaces/BaseSurface.h

@ -0,0 +1,47 @@
#pragma once
#include "ofMain.h"
#include <string>
#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<ofVec3f>& getVertices() {};
virtual vector<ofVec2f>& 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();
};
}
}

248
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<ofVec3f>& 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<ofVec2f>& 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<ofVec3f>& QuadSurface::getVertices() {
// return only joint vertices
return mesh.getVertices();
}
vector<ofVec2f>& 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;
}
}
}

40
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<ofVec3f>& getVertices();
vector<ofVec2f>& getTexCoords();
private:
void calculate4dTextureCoords();
GLfloat quadVertices[12];
GLubyte quadIndices[6];
GLfloat quadTexCoordinates[16];
};
}
}

392
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<ofVec2f> vertices,
vector<ofVec2f> 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<ofVec2f> vertices,
vector<ofVec2f> 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<ofVec3f>* 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<ofVec2f>* 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<ofVec2f> 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<ofVec2f> 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<ofVec2f> 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(); }
}
}

49
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<ofVec2f> vertices,
vector<ofVec2f> texCoords);
void addSurface(int surfaceType, BaseSource* newSource,
vector<ofVec2f> vertices, vector<ofVec2f> 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<BaseSurface*> surfaces;
BaseSurface* selectedSurface;
ofxXmlSettings xmlSettings;
MediaServer* mediaServer;
};
}
}

250
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; }
}
}

48
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;
};
}
}

9
src/Surfaces/SurfaceType.h

@ -0,0 +1,9 @@
#pragma once
namespace ofx {
namespace piMapper {
struct SurfaceType {
enum { TRIANGLE_SURFACE, QUAD_SURFACE };
};
}
}

141
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<ofVec3f>& 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<ofVec2f>& 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<ofVec3f>& TriangleSurface::getVertices() {
// return only joint vertices
return mesh.getVertices();
}
vector<ofVec2f>& TriangleSurface::getTexCoords() { return mesh.getTexCoords(); }
}
}

32
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<ofVec3f>& getVertices();
vector<ofVec2f>& getTexCoords();
};
}
}

72
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;
}
}
}

51
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();
};
}
}

49
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;
}
}
}

22
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();
};
}
}

9
src/UserInterface/EditorType.h

@ -0,0 +1,9 @@
#pragma once
namespace ofx {
namespace piMapper {
struct EditorType {
enum { TEXTURE, PROJECTION };
};
}
}

9
src/UserInterface/GuiMode.h

@ -0,0 +1,9 @@
#pragma once
namespace ofx {
namespace piMapper {
struct GuiMode {
enum { NONE, TEXTURE_MAPPING, PROJECTION_MAPPING, SOURCE_SELECTION };
};
}
}

263
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<ofVec3f*> 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<ofVec3f>& 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<ofVec3f>& 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<ofVec3f>& vertices =
surfaceManager->getSelectedSurface()->getVertices();
for (int i=0; i<vertices.size(); i++) {
vertices[i] += by;
}*/
updateJoints();
}
void ProjectionEditor::stopDragJoints() {
for (int i = 0; i < joints.size(); i++) {
joints[i]->stopDrag();
}
}
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();
}
}
}
}

50
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<CircleJoint*> joints;
bool bShiftKeyDown;
float fSnapDistance;
void drawJoints();
};
}
}

183
src/UserInterface/RadioList.cpp

@ -0,0 +1,183 @@
#include "RadioList.h"
namespace ofx {
namespace piMapper {
RadioList::RadioList() {
storedTitle = "";
storedSelectedItem = 0;
}
RadioList::RadioList(vector<string>& labels, vector<string>& values) {
RadioList();
setup(labels, values);
}
RadioList::RadioList(string title, vector<string>& labels, vector<string>& values) {
RadioList();
setup(title, labels, values);
}
RadioList::~RadioList() { clear(); }
void RadioList::setup(vector<string>& labels, vector<string>& 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<string>& labels, vector<string>& 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<ofxToggle*>(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<ofxToggle*>(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<ofxToggle*>(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<ofxToggle*>(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<ofxToggle*>(guiGroup.getControl(i));
ofParameter<bool>* paramPtr =
static_cast<ofParameter<bool>*>(&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<ofxToggle*>(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<ofxToggle*>(guiGroup.getControl(i));
ofParameter<bool>* paramPtr =
static_cast<ofParameter<bool>*>(&toggle->getParameter());
if (&(paramPtr->get()) == &toggleValue) {
selectItem(i);
break;
}
}
}
}
}

53
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<string>& labels, vector<string>& values);
RadioList(string title, vector<string>& labels, vector<string>& values);
~RadioList();
void setup(vector<string> &labels, vector<string>& values);
void setup(string title, vector<string>& labels, vector<string>& 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<string> onRadioSelected;
private:
vector<string> storedLabels;
vector<string> storedValues;
string storedTitle;
ofxGuiGroup guiGroup;
int storedSelectedItem;
void onToggleClicked(bool &toggleValue);
};
}
}

271
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<string> imageNames = mediaServer->getImageNames();
imageSelector->setup("Images", imageNames, mediaServer->getImagePaths());
ofAddListener(imageSelector->onRadioSelected, this, &SourcesEditor::handleImageSelected);
}
if (numVideos) {
vector<string> 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;
}
}
}

73
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);
};
}
}

234
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<ofVec2f>& 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<ofVec2f>& 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;
}
}
}

44
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<CircleJoint*> joints;
bool bShiftKeyDown;
};
}
}

99
src/ofxBaseJoint.cpp

@ -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;
}

48
src/ofxBaseJoint.h

@ -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

72
src/ofxBaseSurface.cpp

@ -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; 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);
// Assign default texture to texture pointer
texture = &defaultTexture;
}
void ofxBaseSurface::drawTexture(ofVec2f position)
{
ofMesh texMesh;
texMesh.addVertex(position);
texMesh.addVertex(position + ofVec2f(texture->getWidth(), 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;
}

39
src/ofxBaseSurface.h

@ -1,39 +0,0 @@
#ifndef H_OFX_BASE_SURFACE
#define H_OFX_BASE_SURFACE
#include "ofMain.h"
#include <string>
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<ofVec3f>& getVertices(){};
virtual vector<ofVec2f>& 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

51
src/ofxCircleJoint.cpp

@ -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;
}

22
src/ofxCircleJoint.h

@ -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

12
src/ofxEditorType.h

@ -1,12 +0,0 @@
#ifndef H_OFX_EDITOR_TYPE
#define H_OFX_EDITOR_TYPE
struct ofxEditorType
{
enum {
TEXTURE,
PROJECTION
};
};
#endif

14
src/ofxGuiMode.h

@ -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

9
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
#include "MediaServer.h"

266
src/ofxProjectionEditor.cpp

@ -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; 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 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<ofVec3f*> allVertices;
for ( int i=0; i<surfaceManager->size(); i++ ) {
ofxBaseSurface* 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 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<ofVec3f>& vertices = surfaceManager->getSelectedSurface()->getVertices();
for ( int i=0; i<vertices.size(); i++ ) {
joints.push_back( new ofxCircleJoint() );
joints.back()->position = ofVec2f(vertices[i].x, vertices[i].y);
}
}
void ofxProjectionEditor::updateJoints()
{
vector<ofVec3f>& vertices = surfaceManager->getSelectedSurface()->getVertices();
for ( int i=0; i<vertices.size(); i++ ) {
joints[i]->position = ofVec2f(vertices[i].x, vertices[i].y);
}
}
void ofxProjectionEditor::unselectAllJoints()
{
for ( int i=0; i<joints.size(); i++ ) {
joints[i]->unselect();
}
}
void ofxProjectionEditor::moveSelectedSurface(ofVec2f by)
{
if ( surfaceManager == NULL ) return;
if ( surfaceManager->getSelectedSurface() == NULL ) return;
vector<ofVec3f>& vertices = surfaceManager->getSelectedSurface()->getVertices();
for (int i=0; i<vertices.size(); i++) {
vertices[i] += by;
}
updateJoints();
}
void ofxProjectionEditor::stopDragJoints()
{
for (int i=0; i<joints.size(); i++){
joints[i]->stopDrag();
}
}
void ofxProjectionEditor::moveSelection(ofVec2f by)
{
// check if joints selected
bool bJointSelected = false;
ofxBaseJoint* 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 ofxProjectionEditor::setSnapDistance(float newSnapDistance)
{
fSnapDistance = newSnapDistance;
}
ofxCircleJoint* ofxProjectionEditor::hitTestJoints(ofVec2f pos)
{
for ( int i=0; i<joints.size(); i++ ) {
if ( joints[i]->hitTest(pos) ){
return joints[i];
}
}
return NULL;
}
void ofxProjectionEditor::drawJoints()
{
for ( int i=0; i<joints.size(); i++ ) {
joints[i]->draw();
}
}

50
src/ofxProjectionEditor.h

@ -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<ofxCircleJoint*> joints;
bool bShiftKeyDown;
float fSnapDistance;
void drawJoints();
};
#endif

156
src/ofxQuadSurface.cpp

@ -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<ofVec2f>& texCoords = mesh.getTexCoords();
ofVec2f textureSize = ofVec2f(texture->getWidth(), texture->getHeight());
for ( int i=0; i<texCoords.size(); i++ ) {
line.addVertex( ofPoint( texCoords[i] * textureSize ) );
}
line.close();
return line;
}
vector<ofVec3f>& ofxQuadSurface::getVertices()
{
// return only joint vertices
return mesh.getVertices();
}
vector<ofVec2f>& ofxQuadSurface::getTexCoords()
{
return mesh.getTexCoords();
}

34
src/ofxQuadSurface.h

@ -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<ofVec3f>& getVertices();
vector<ofVec2f>& getTexCoords();
};
#endif

153
src/ofxSourcesEditor.cpp

@ -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<string> 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<ofxUIWidget*> widgets = gui->getWidgets();
// find radio list item
ofxUIRadio* radio;
for ( int i=0; i<widgets.size(); i++ ) {
int widgetKind = widgets[i]->getKind();
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; i<widgets.size(); i++ ) {
string widgetName = widgets[i]->getName();
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();
}

43
src/ofxSourcesEditor.h

@ -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<ofImage*> images;
vector<string> imageNames;
//ofxPanel imgSrcPanel;
//void onSourceSelect(bool& value);
};
#endif

486
src/ofxSurfaceManager.cpp

@ -1,486 +0,0 @@
#include "ofxSurfaceManager.h"
ofxSurfaceManager::ofxSurfaceManager()
{
}
ofxSurfaceManager::~ofxSurfaceManager()
{
clear();
}
void ofxSurfaceManager::draw()
{
for ( int i=0; i<surfaces.size(); i++ ) {
surfaces[i]->draw();
}
}
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<ofVec2f> vertices, vector<ofVec2f> 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<ofVec2f> vertices, vector<ofVec2f> 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; i<surfaces.size(); i++ ) {
if ( surfaces[i] == selectedSurface ) {
delete surfaces[i];
surfaces.erase(surfaces.begin()+i);
selectedSurface = NULL;
break;
}
}
}
void ofxSurfaceManager::manageMemory()
{
// check if each of the sources is assigned to a surface or not
for ( int i=0; i<loadedImageSources.size(); i++ ) {
bool bAssigned = false;
for ( int j=0; j<surfaces.size(); j++ ) {
if ( surfaces[j]->getTexture() == &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<surfaces.size(); i++ ) {
xmlSettings.addTag("surface");
xmlSettings.pushTag("surface", i);
ofxBaseSurface* surface = surfaces[i];
xmlSettings.addTag("vertices");
xmlSettings.pushTag("vertices");
vector<ofVec3f>* 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<ofVec2f>* 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");
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<numSurfaces; i++ ) {
xmlSettings.pushTag("surface", i);
// attempt to load surface source
xmlSettings.pushTag("source");
string sourceType = xmlSettings.getValue("source-type", "image");
string sourceName = xmlSettings.getValue("source-name", "none");
ofTexture* sourceTexture = NULL;
if ( sourceName != "none" ) {
stringstream ss;
ss << "sources/images/" << sourceName; // TODO: reuse constants here
sourceTexture = loadImageSource(sourceName, ss.str());
}
xmlSettings.popTag(); // source
// // attempt to load surface type
// ofLog(OF_LOG_WARNING, "Attempt to load surface type.");
// xmlSettings.pushTag("type");
// string surfaceType = xmlSettings.getValue("surface-type", "TRIANGLE_SURFACE");
// xmlSettings.popTag(); // type
xmlSettings.pushTag("vertices");
vector<ofVec2f> 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<ofVec2f> 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<ofVec2f> 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; i<loadedImageSourceNames.size(); i++ ) {
if ( loadedImageSourceNames[i] == name ) {
// this image is already loaded
return &loadedImageSources[i]->getTextureReference();
}
}
// 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; i<loadedImageSources.size(); i++ ) {
if (tex == &loadedImageSources[i]->getTextureReference()) {
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();
}

48
src/ofxSurfaceManager.h

@ -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<ofVec2f> vertices, vector<ofVec2f> texCoords);
void addSurface(int surfaceType, ofTexture* texturePtr, vector<ofVec2f> vertices, vector<ofVec2f> 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<ofxBaseSurface*> surfaces;
ofxBaseSurface* selectedSurface;
vector<string> loadedImageSourceNames;
vector<ofImage*> loadedImageSources;
ofxXmlSettings xmlSettings;
};
#endif

254
src/ofxSurfaceManagerGui.cpp

@ -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;
}

46
src/ofxSurfaceManagerGui.h

@ -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

12
src/ofxSurfaceType.h

@ -1,12 +0,0 @@
#ifndef H_OFX_SURFACE_TYPE
#define H_OFX_SURFACE_TYPE
struct ofxSurfaceType
{
enum {
TRIANGLE_SURFACE,
QUAD_SURFACE
};
};
#endif

191
src/ofxTextureEditor.cpp

@ -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; i<joints.size(); i++ ) {
if ( joints[i]->isDragged() || 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; i<joints.size(); i++ ) {
joints[i]->draw();
}
}
void ofxTextureEditor::setSurface(ofxBaseSurface* newSurface)
{
surface = newSurface;
createJoints();
}
void ofxTextureEditor::clear()
{
surface = NULL;
clearJoints();
}
void ofxTextureEditor::createJoints()
{
if ( surface == NULL ) return;
clearJoints();
vector<ofVec2f>& texCoords = surface->getTexCoords();
ofVec2f textureSize = ofVec2f(surface->getTexture()->getWidth(), surface->getTexture()->getHeight());
for ( int i=0; i<texCoords.size(); i++ ) {
joints.push_back(new ofxCircleJoint());
joints.back()->position = texCoords[i] * textureSize;
}
}
void ofxTextureEditor::clearJoints()
{
while ( joints.size() ) {
delete joints.back();
joints.pop_back();
}
}
void ofxTextureEditor::unselectAllJoints()
{
for ( int i=0; i<joints.size(); i++ ) {
joints[i]->unselect();
}
}
void ofxTextureEditor::moveTexCoords(ofVec2f by)
{
if ( surface == NULL ) return;
vector<ofVec2f>& texCoords = surface->getTexCoords();
ofVec2f textureSize = ofVec2f( surface->getTexture()->getWidth(), surface->getTexture()->getHeight() );
for (int i=0; i<texCoords.size(); i++) {
joints[i]->position += by;
texCoords[i] = joints[i]->position / textureSize;
}
}
void ofxTextureEditor::stopDragJoints()
{
for (int i=0; i<joints.size(); i++){
joints[i]->stopDrag();
}
}
void ofxTextureEditor::moveSelection(ofVec2f by)
{
// check if joints selected
bool bJointSelected = false;
ofxBaseJoint* 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);
}
}
ofxCircleJoint* ofxTextureEditor::hitTestJoints(ofVec2f pos)
{
for ( int i=0; i<joints.size(); i++ ) {
if ( joints[i]->hitTest(pos) ){
return joints[i];
}
}
return NULL;
}

42
src/ofxTextureEditor.h

@ -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<ofxCircleJoint*> joints;
bool bShiftKeyDown;
};
#endif

146
src/ofxTriangleSurface.cpp

@ -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<ofVec2f>& texCoords = mesh.getTexCoords();
ofVec2f textureSize = ofVec2f(texture->getWidth(), texture->getHeight());
for ( int i=0; i<texCoords.size(); i++ ) {
line.addVertex( ofPoint( texCoords[i] * textureSize ) );
}
line.close();
return line;
}
vector<ofVec3f>& ofxTriangleSurface::getVertices()
{
// return only joint vertices
return mesh.getVertices();
}
vector<ofVec2f>& ofxTriangleSurface::getTexCoords()
{
return mesh.getTexCoords();
}

30
src/ofxTriangleSurface.h

@ -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<ofVec3f>& getVertices();
vector<ofVec2f>& getTexCoords();
};
#endif
Loading…
Cancel
Save