diff options
Diffstat (limited to 'FESgui/src')
| -rw-r--r-- | FESgui/src/PerlinPhasingFilter.cpp | 151 | ||||
| -rw-r--r-- | FESgui/src/PerlinPhasingFilter.h | 23 | ||||
| -rw-r--r-- | FESgui/src/audiobuffer.h | 42 | ||||
| -rw-r--r-- | FESgui/src/lineSegmenter.cpp | 109 | ||||
| -rw-r--r-- | FESgui/src/lineSegmenter.h | 48 | ||||
| -rw-r--r-- | FESgui/src/lineTransformer.cpp | 135 | ||||
| -rw-r--r-- | FESgui/src/lineTransformer.h | 22 | ||||
| -rw-r--r-- | FESgui/src/main.cpp | 46 | ||||
| -rw-r--r-- | FESgui/src/ofApp.cpp | 1064 | ||||
| -rw-r--r-- | FESgui/src/ofApp.h | 273 | ||||
| -rw-r--r-- | FESgui/src/selectpanel.h | 53 | ||||
| -rw-r--r-- | FESgui/src/vectortext.h | 366 |
12 files changed, 2332 insertions, 0 deletions
diff --git a/FESgui/src/PerlinPhasingFilter.cpp b/FESgui/src/PerlinPhasingFilter.cpp new file mode 100644 index 0000000..897a776 --- /dev/null +++ b/FESgui/src/PerlinPhasingFilter.cpp @@ -0,0 +1,151 @@ +// +// PerlinPhasingFilter.cpp +// filterSandbox +// +// Created by Matthew Fargo on 2014/06/24. +// +// + +#include "PerlinPhasingFilter.h" + +PerlinPhasingFilter::PerlinPhasingFilter(float width, float height, float scale) : AbstractFilter(width, height) { + _name = "Perlin Pixellation"; + _scale = scale; + _addParameter(new ParameterF("fractionalWidthOfPixel", 0.05)); + _addParameter(new ParameterF("scale", _scale)); + _addParameter(new ParameterF("phase", 0.0)); + _setupShader(); +} +PerlinPhasingFilter::~PerlinPhasingFilter() {} + + +string PerlinPhasingFilter::_getFragSrc() { + return GLSL_STRING(120, + //precision highp float; + uniform sampler2D inputImageTexture; + + uniform float fractionalWidthOfPixel; + uniform float scale; + uniform float phase; + // + // GLSL textureless classic 3D noise "cnoise", + // with an RSL-style periodic variant "pnoise". + // Author: Stefan Gustavson (stefan.gustavson@liu.se) + // Version: 2011-10-11 + // + // Many thanks to Ian McEwan of Ashima Arts for the + // ideas for permutation and gradient selection. + // + // Copyright (c) 2011 Stefan Gustavson. All rights reserved. + // Distributed under the MIT license. See LICENSE file. + // https://github.com/stegu/webgl-noise + // + + vec3 mod289(vec3 x) + { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec4 mod289(vec4 x) + { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec4 permute(vec4 x) + { + return mod289(((x*34.0)+10.0)*x); + } + + vec4 taylorInvSqrt(vec4 r) + { + return 1.79284291400159 - 0.85373472095314 * r; + } + + vec3 fade(vec3 t) { + return t*t*t*(t*(t*6.0-15.0)+10.0); + } + + // Classic Perlin noise + float cnoise(vec3 P) + { + vec3 Pi0 = floor(P); // Integer part for indexing + vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 + Pi0 = mod289(Pi0); + Pi1 = mod289(Pi1); + vec3 Pf0 = fract(P); // Fractional part for interpolation + vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 + vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); + vec4 iy = vec4(Pi0.yy, Pi1.yy); + vec4 iz0 = Pi0.zzzz; + vec4 iz1 = Pi1.zzzz; + + vec4 ixy = permute(permute(ix) + iy); + vec4 ixy0 = permute(ixy + iz0); + vec4 ixy1 = permute(ixy + iz1); + + vec4 gx0 = ixy0 * (1.0 / 7.0); + vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; + gx0 = fract(gx0); + vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); + vec4 sz0 = step(gz0, vec4(0.0)); + gx0 -= sz0 * (step(0.0, gx0) - 0.5); + gy0 -= sz0 * (step(0.0, gy0) - 0.5); + + vec4 gx1 = ixy1 * (1.0 / 7.0); + vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; + gx1 = fract(gx1); + vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); + vec4 sz1 = step(gz1, vec4(0.0)); + gx1 -= sz1 * (step(0.0, gx1) - 0.5); + gy1 -= sz1 * (step(0.0, gy1) - 0.5); + + vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); + vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); + vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); + vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); + vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); + vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); + vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); + vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); + + vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); + g000 *= norm0.x; + g010 *= norm0.y; + g100 *= norm0.z; + g110 *= norm0.w; + vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); + g001 *= norm1.x; + g011 *= norm1.y; + g101 *= norm1.z; + g111 *= norm1.w; + + float n000 = dot(g000, Pf0); + float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); + float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); + float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); + float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); + float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); + float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); + float n111 = dot(g111, Pf1); + + vec3 fade_xyz = fade(Pf0); + vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); + vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); + float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); + return 2.2 * n_xyz; + } + + void main() { + vec2 uv = (gl_TexCoord[0].xy); + + float n = cnoise( vec3(uv,phase) *scale)+ + cnoise( vec3(uv,phase) *scale*3.71098f)+ + cnoise( vec3(uv,phase) *scale*11.56476f); + vec2 sampleDivisor = vec2((((n + 1.0) / 2.0) + 0.5) * fractionalWidthOfPixel); + + vec2 samplePos = uv - mod(uv, sampleDivisor); + gl_FragColor = texture2D(inputImageTexture, samplePos ); + } + + ); +} diff --git a/FESgui/src/PerlinPhasingFilter.h b/FESgui/src/PerlinPhasingFilter.h new file mode 100644 index 0000000..0c4ba36 --- /dev/null +++ b/FESgui/src/PerlinPhasingFilter.h @@ -0,0 +1,23 @@ +// +// PerlinPhasingFilter.h +// filterSandbox +// +// Created by Matthew Fargo on 2014/06/24. +// +// + +#pragma once + +#include "AbstractFilter.h" + +class PerlinPhasingFilter : public AbstractFilter { +public: + PerlinPhasingFilter(float width, float height, float scale=8.f); + virtual ~PerlinPhasingFilter(); + + +protected: + virtual string _getFragSrc(); + float _scale; +}; + diff --git a/FESgui/src/audiobuffer.h b/FESgui/src/audiobuffer.h new file mode 100644 index 0000000..a56dd4b --- /dev/null +++ b/FESgui/src/audiobuffer.h @@ -0,0 +1,42 @@ +#pragma once + + +#define min(a,b) (a<b?a:b) +#define max(a,b) (a>b?a:b) + +class Buffer{ +public: + Buffer(size_t sz=0){ + if (sz){ + data =new float[sz]; + memset(data,0,sz*sizeof(float)); + size=sz; + } + else data=NULL; + } + ~Buffer(){ + if (data){ + delete[] data; //why is this throwing an error + } + } + void add(float * input, int num){ + //this assumes that num < size + memcpy(&data[writePoint],input,min(num,size-writePoint)*sizeof(float)); + if (size-writePoint<num){ //we have to wrap + //copy the remaining chunk to the start and set the new writePoint + memcpy(data,&input[size-writePoint],(num-(size-writePoint))*sizeof(float)); + writePoint=num-(size-writePoint); + } + else writePoint+=num; + } + float operator [] (int i) const { + return data[(writePoint>i?writePoint-i:size-(i-writePoint))-1]; + } + float& operator [] (int i) { + return data[(writePoint>i?writePoint-i:size-(i-writePoint))-1]; + } +private: + size_t size; + float *data; + int writePoint; +};
\ No newline at end of file diff --git a/FESgui/src/lineSegmenter.cpp b/FESgui/src/lineSegmenter.cpp new file mode 100644 index 0000000..3f434b1 --- /dev/null +++ b/FESgui/src/lineSegmenter.cpp @@ -0,0 +1,109 @@ + #include "lineSegmenter.h" + +const vector <ofPolyline> & lineSegmenter::getSegments(int num,float coverage, float phase){ + //num - number of segments + //coverage - amount that each segment fills it's slot from 0-1 + //phase - from 0-1 + + //if the path is closed, we can make a segment that crosses the end/beginning + //however we want to be able to deal with open paths + +/* + +segments 0...n - 1 +phase 0...1 + +phase 0 + +segment 0 is (0 -> coverage) / n +segment n - 1 is ((0 -> coverage) + (n-1)) /n + +phase 1: has to be the loop target, it has to look identical + +segment 0 is (1 -> coverage) / n +segment n - 1 is (1 - > coverage) + (n-1) + +*/ + + + segments.clear(); + + for (int i=0;i<num;i++){ + float startIndex=line.getIndexAtPercent((phase+i)/num); //always <1 + float endPoint=(phase+i+coverage)/num; //can be >1 + float endIndex=line.getIndexAtPercent(endPoint>1.0f?endPoint-1.0f:endPoint); + ofPolyline segment; + segment.addVertex(line.getPointAtIndexInterpolated(startIndex)); + for (int j=(int)ceil(startIndex);j<(endPoint>1?line.size():(int)ceil(endIndex));j++){ + segment.addVertex(line[j]); + } + if (endPoint>1){ + segments.push_back(segment); + segment.clear(); + for (int j=0;j<(int)ceil(endIndex);j++){ + segment.addVertex(line[j]); + } + segment.addVertex(line.getPointAtIndexInterpolated(endIndex)); + } + else { + segment.addVertex(line.getPointAtIndexInterpolated(endIndex)); + } + segments.push_back(segment); + } + + return segments; +} + +void lineSegmenter::draw(){ + line.draw(); + return; +} +int lineSegmenter::size(){ + return line.size(); +} + +const vector <colourPolyline> & colourLineSegmenter::getSegments(int num,float coverage, float phase){ + + segments.clear(); + + for (int i=0;i<num;i++){ + float startIndex=line.getIndexAtPercent((phase+i)/num); //always <1 + float endPoint=(phase+i+coverage)/num; //can be >1 + float endIndex=line.getIndexAtPercent(endPoint>1.0f?endPoint-1.0f:endPoint); + colourPolyline segment; + segment.addVertex(line.getPointAtIndexInterpolated(startIndex),line.getColourAtIndexInterpolated(startIndex)); + for (int j=(int)ceil(startIndex);j<(endPoint>1?line.size():(int)ceil(endIndex));j++){ + segment.addVertex(line[j],line.getColourAt(j)); + } + if (endPoint>1){ + segments.push_back(segment); + segment.clear(); + for (int j=0;j<(int)ceil(endIndex);j++){ + segment.addVertex(line[j],line.getColourAt(j)); + } + segment.addVertex(line.getPointAtIndexInterpolated(endIndex),line.getColourAtIndexInterpolated(endIndex)); + } + else { + segment.addVertex(line.getPointAtIndexInterpolated(endIndex),line.getColourAtIndexInterpolated(endIndex) ); + } + segments.push_back(segment); + } + + return segments; +} + +void colourLineSegmenter::draw(){ + line.draw(); + return; +} +int colourLineSegmenter::size(){ + return line.size(); +} + + +/* + + + + +*/
\ No newline at end of file diff --git a/FESgui/src/lineSegmenter.h b/FESgui/src/lineSegmenter.h new file mode 100644 index 0000000..2467c6a --- /dev/null +++ b/FESgui/src/lineSegmenter.h @@ -0,0 +1,48 @@ +#pragma once + +#include "ofMain.h" +#include "colourPolyline.h" + +class lineSegmenter{ + public: + lineSegmenter(ofPolyline &_line){ + line=_line; + if (line.isClosed()){ + line.addVertex(line[0]); + } + } + const vector <ofPolyline> &getSegments(int num,float coverage, float phase); + ofPolyline getPoly(){ + return line; + } + void draw(); + int size(); + private: + ofPolyline line; + vector <ofPolyline> segments; +}; + +class colourLineSegmenter{ + public: + colourLineSegmenter(colourPolyline &_line){ + line=_line; + //if (line.isClosed()){ + // line.addVertex(line[0]); + //} + } + colourLineSegmenter(ofPolyline &_line,const ofColor color=ofColor(255,255,255)){ + line=colourPolyline(_line,color); + if (_line.isClosed()){ + line.addVertex(line[0],line.getColourAt(0)); + } + } + const vector <colourPolyline> &getSegments(int num,float coverage, float phase); + colourPolyline getPoly(){ + return line; + } + void draw(); + int size(); + private: + colourPolyline line; + vector <colourPolyline> segments; +};
\ No newline at end of file diff --git a/FESgui/src/lineTransformer.cpp b/FESgui/src/lineTransformer.cpp new file mode 100644 index 0000000..e138ff4 --- /dev/null +++ b/FESgui/src/lineTransformer.cpp @@ -0,0 +1,135 @@ +#include "lineTransformer.h" + + +void lineTransformer::drawWarpFrame(glm::vec2 warpframe[4]){ + ofSetColor(255,255,255); + ofNoFill(); + for (int i=0;i<4;i++){ + ofDrawCircle(warpframe[i],25); + ofDrawLine(warpframe[i],warpframe[(i+1)%4]); + } +} + +void lineTransformer::drawWarpFrame(glm::vec3 warpframe[4]){ + ofSetColor(255,255,255); + ofNoFill(); + for (int i=0;i<4;i++){ + ofDrawCircle(warpframe[i],25); + ofDrawLine(warpframe[i],warpframe[(i+1)%4]); + } +} + +void lineTransformer::gaussianElimination(float * input, int n) +{ + auto i = 0; + auto j = 0; + auto m = n - 1; + + while (i < m && j < n) + { + auto iMax = i; + for (auto k = i + 1; k < m; ++k) + { + if (fabs(input[k * n + j]) > fabs(input[iMax * n + j])) + { + iMax = k; + } + } + + if (input[iMax * n + j] != 0) + { + if (i != iMax) + { + for (auto k = 0; k < n; ++k) + { + auto ikIn = input[i * n + k]; + input[i * n + k] = input[iMax * n + k]; + input[iMax * n + k] = ikIn; + } + } + + float ijIn = input[i * n + j]; + for (auto k = 0; k < n; ++k) + { + input[i * n + k] /= ijIn; + } + + for (auto u = i + 1; u < m; ++u) + { + auto ujIn = input[u * n + j]; + for (auto k = 0; k < n; ++k) + { + input[u * n + k] -= ujIn * input[i * n + k]; + } + } + + ++i; + } + ++j; + } + + for (auto i = m - 2; i >= 0; --i) + { + for (auto j = i + 1; j < n - 1; ++j) + { + input[i * n + m] -= input[i * n + j] * input[j * n + m]; + } + } +} + +glm::mat4 lineTransformer::getPerspectiveTransformMatrix(const glm::vec2 src[4], const glm::vec2 dst[4]) +{ + float p[8][9] = + { + { -src[0][0], -src[0][1], -1, 0, 0, 0, src[0][0] * dst[0][0], src[0][1] * dst[0][0], -dst[0][0] }, // h11 + { 0, 0, 0, -src[0][0], -src[0][1], -1, src[0][0] * dst[0][1], src[0][1] * dst[0][1], -dst[0][1] }, // h12 + { -src[1][0], -src[1][1], -1, 0, 0, 0, src[1][0] * dst[1][0], src[1][1] * dst[1][0], -dst[1][0] }, // h13 + { 0, 0, 0, -src[1][0], -src[1][1], -1, src[1][0] * dst[1][1], src[1][1] * dst[1][1], -dst[1][1] }, // h21 + { -src[2][0], -src[2][1], -1, 0, 0, 0, src[2][0] * dst[2][0], src[2][1] * dst[2][0], -dst[2][0] }, // h22 + { 0, 0, 0, -src[2][0], -src[2][1], -1, src[2][0] * dst[2][1], src[2][1] * dst[2][1], -dst[2][1] }, // h23 + { -src[3][0], -src[3][1], -1, 0, 0, 0, src[3][0] * dst[3][0], src[3][1] * dst[3][0], -dst[3][0] }, // h31 + { 0, 0, 0, -src[3][0], -src[3][1], -1, src[3][0] * dst[3][1], src[3][1] * dst[3][1], -dst[3][1] }, // h32 + }; + + gaussianElimination(&p[0][0], 9); + + return glm::mat4(p[0][8], p[3][8], 0, p[6][8], + p[1][8], p[4][8], 0, p[7][8], + 0, 0, 1, 0, + p[2][8], p[5][8], 0, 1); +} + +ofPolyline lineTransformer::polyLineTransform(const ofMatrix4x4 xform, const ofPolyline& poly){ + ofPolyline tempPoly; + for (auto& p:poly){ + tempPoly.addVertex(ofVec3f(p)*xform); + } + return tempPoly; +} + +colourPolyline lineTransformer::polyLineTransform(const ofMatrix4x4 xform,colourPolyline& poly,float colourFade){ + colourPolyline tempPoly; + for (int i=0;i<poly.size();i++){ + tempPoly.addVertex(ofVec3f(poly[i])*xform,poly.getColourAt(i)*colourFade); + } + return tempPoly; +} + +ofPolyline lineTransformer::makePolygon(int num,float diam){ + ofPolyline poly; + float step=PI*2/num; + for (int i=0;i<=num;i++){ + poly.addVertex(cos(step*i)*diam,sin(step*i)*diam); + } + return poly; +} + +void lineTransformer::drawPoly(ofPolyline poly,float x,float y){ + glPushMatrix(); + ofTranslate(x,y); + poly.draw(); + for (int i=0;i<poly.size();i++){ + ofDrawBitmapString(poly.getDegreesAtIndex(i),poly[i].x+10,poly[i].y+10,0); + } + glPopMatrix(); +} diff --git a/FESgui/src/lineTransformer.h b/FESgui/src/lineTransformer.h new file mode 100644 index 0000000..23b2b0a --- /dev/null +++ b/FESgui/src/lineTransformer.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ofMain.h" +#include "colourPolyline.h" + +class lineTransformer { + + public: + lineTransformer(){ + } + void static drawWarpFrame(glm::vec2 warpframe[4]); + void static drawWarpFrame(glm::vec3 warpframe[4]); + void static gaussianElimination(float * input, int n); + glm::mat4 static getPerspectiveTransformMatrix(const glm::vec2 src[4], const glm::vec2 dst[4]); + ofPolyline static polyLineTransform(const ofMatrix4x4 xform,const ofPolyline& poly); + ofPolyline static polyLineTransform(ofPoint (*transferFunction)(const ofPoint),const ofPolyline& poly); + colourPolyline static polyLineTransform(const ofMatrix4x4 xform,colourPolyline& poly,float colourFade=1.0f); + colourPolyline static polyLineTransform(ofPoint (*transferFunction)(const ofPoint),colourPolyline& poly,float colourFade=1.0f); + ofPolyline static makePolygon(int num,float diam); + void static drawPoly(ofPolyline poly,float x,float y); + +};
\ No newline at end of file diff --git a/FESgui/src/main.cpp b/FESgui/src/main.cpp new file mode 100644 index 0000000..226ae24 --- /dev/null +++ b/FESgui/src/main.cpp @@ -0,0 +1,46 @@ +#include "ofMain.h" +#include "ofApp.h" + + +//======================================================================== +int main(int argc, char *argv[]){ + + + ofGLFWWindowSettings settings; + + //settings.setGLVersion(3,2); if using kinect + + settings.decorated = true; + settings.setSize(outputWindowSize.x,outputWindowSize.y); + settings.setPosition(ofVec2f(1700,0)); + settings.resizable = false; + + shared_ptr<ofAppBaseWindow> mainWindow = ofCreateWindow(settings); + mainWindow->setVerticalSync(false); + + settings.setSize(1200,1100); + settings.setPosition(ofVec2f(0,20)); + settings.resizable = false; + + // share OpenGL resources with other windows + settings.shareContextWith = mainWindow; + + settings.decorated = true; //doesn't suppress FS title bar + shared_ptr<ofAppBaseWindow> guiWindow = ofCreateWindow(settings); + guiWindow->setVerticalSync(false); + + shared_ptr<ofApp> mainApp(new ofApp); + + ofAddListener(mainWindow->events().update,mainApp.get(),&ofApp::updateOutput); + ofAddListener(mainWindow->events().draw,mainApp.get(),&ofApp::drawOutput); + ofAddListener(mainWindow->events().windowResized,mainApp.get(),&ofApp::outputWindowResized); + ofAddListener(mainWindow->events().keyPressed,mainApp.get(),&ofApp::outputKeyPressed); + ofAddListener(mainWindow->events().keyReleased,mainApp.get(),&ofApp::outputKeyReleased); + ofAddListener(mainWindow->events().mouseDragged,mainApp.get(),&ofApp::outputMouseDragged); + ofAddListener(mainWindow->events().mousePressed,mainApp.get(),&ofApp::outputMousePressed); + ofAddListener(mainWindow->events().mouseReleased,mainApp.get(),&ofApp::outputMouseReleased); + + ofRunApp(guiWindow, mainApp); + ofRunMainLoop(); +} +
\ No newline at end of file diff --git a/FESgui/src/ofApp.cpp b/FESgui/src/ofApp.cpp new file mode 100644 index 0000000..a1c49be --- /dev/null +++ b/FESgui/src/ofApp.cpp @@ -0,0 +1,1064 @@ +#include "ofApp.h" + + + +//====================== settings + +void ofApp::default_settings(){ + warpframe[0]=glm::vec3(0,0,0); + warpframe[1]=glm::vec3(outputWindowSize.x,0,0); + warpframe[2]=glm::vec3(outputWindowSize.x,outputWindowSize.y,0); + warpframe[3]=glm::vec3(0,outputWindowSize.y,0); + outputPosition=ofPoint(0,0,0); + outputScale=1.0f; +} + +void ofApp::save_settings(){ + XML.setValue("WARP:p0:X", warpframe[0].x); + XML.setValue("WARP:p0:Y", warpframe[0].y); + XML.setValue("WARP:p1:X", warpframe[1].x); + XML.setValue("WARP:p1:Y", warpframe[1].y); + XML.setValue("WARP:p2:X", warpframe[2].x); + XML.setValue("WARP:p2:Y", warpframe[2].y); + XML.setValue("WARP:p3:X", warpframe[3].x); + XML.setValue("WARP:p3:Y", warpframe[3].y); + + XML.setValue("SAFETY:p0:X", safety_frame[0].x); + XML.setValue("SAFETY:p0:Y", safety_frame[0].y); + XML.setValue("SAFETY:p1:X", safety_frame[1].x); + XML.setValue("SAFETY:p1:Y", safety_frame[1].y); + XML.setValue("SAFETY:p2:X", safety_frame[2].x); + XML.setValue("SAFETY:p2:Y", safety_frame[2].y); + XML.setValue("SAFETY:p3:X", safety_frame[3].x); + XML.setValue("SAFETY:p3:Y", safety_frame[3].y); + + XML.setValue("POSITION:X", outputPosition.x); + XML.setValue("POSITION:Y", outputPosition.y); + + XML.setValue("SCALE", outputScale); + + if (XML.saveFile("settings.xml")){ + cout << "settings.xml saved!" <<std::endl; + } + else { + cout << "could not save settings.xml!" <<std::endl; + } +} + +void ofApp::setup_lasergui(int x, int y){ + + laser.setup(x,y); + + bShowPositionInterface=false; + bOutputSelected=false; + + outputOffsetScale=1.0f; + commandPressed=false; + + + select_warpframe=-1; + bDrawFrame=false; + + select_safetyframe=-1; + + if( XML.loadFile("settings.xml") ){ + cout << "settings.xml loaded!" <<std::endl; + + } + else{ + cout << "unable to load settings.xml"<<std::endl; + } + + warpframe[0]=glm::vec2( + XML.getValue("WARP:p0:X", 0), + XML.getValue("WARP:p0:Y", 0) + ); + warpframe[1]=glm::vec2( + XML.getValue("WARP:p1:X", outputWindowSize.x), + XML.getValue("WARP:p1:Y", 0) + ); + warpframe[2]=glm::vec2( + XML.getValue("WARP:p2:X", outputWindowSize.x), + XML.getValue("WARP:p2:Y", outputWindowSize.y) + ); + warpframe[3]=glm::vec2( + XML.getValue("WARP:p3:X", 0), + XML.getValue("WARP:p3:Y", outputWindowSize.y) + ); + + safety_frame[0]=glm::vec3( + XML.getValue("SAFETY:p0:X", 0), + XML.getValue("SAFETY:p0:Y", 0), + 0 + ); + safety_frame[1]=glm::vec3( + XML.getValue("SAFETY:p1:X", outputWindowSize.x), + XML.getValue("SAFETY:p1:Y", 0), + 0 + ); + safety_frame[2]=glm::vec3( + XML.getValue("SAFETY:p2:X", outputWindowSize.x), + XML.getValue("SAFETY:p2:Y", outputWindowSize.y), + 0 + ); + safety_frame[3]=glm::vec3( + XML.getValue("SAFETY:p3:X", 0), + XML.getValue("SAFETY:p3:Y", outputWindowSize.y), + 0 + ); + + outputPosition=ofPoint( + XML.getValue("POSITION:X", 0), + XML.getValue("POSITION:Y", 0), + 0 + ); + + laser.set_centre(outputPosition); + + outputScale=XML.getValue("SCALE", 1.0f); +} + +void ofApp::setup(){ + + int frameRate=60; + + ofSetFrameRate(frameRate); + ofBackground(0); + + ofDisableArbTex(); //this is required for perlin filter + ofEnableSmoothing(); + ofEnableAlphaBlending(); + ofSetVerticalSync(true); + + blockSize = SAMPLERATE / (frameRate*10); //80 + + ofSoundStreamListDevices(); + + soundStream.setup(this,0, 1, SAMPLERATE, blockSize, 1); + + buffer=Buffer(SAMPLERATE); + + //vScale=3.0f; + //hScale=8.0f; + + //lineWidth=2.0f; + + //panels are 210 wide + + videoSourcePanel.setup("video sources","",5,5); + videoSourcePanel.add(captPreview.set("camera preview",true)); + videoSourcePanel.add(captEnable.set("camera",false)); + videoSourcePanel.add(videoOscEnable.set("oscilloscope",false)); + videoSourcePanel.add(playerEnable.set("player",false)); + videoSourcePanel.add(contoursVideoDraw.set("contours",false)); + videoSourcePanel.add(SVGVideoDraw.set("SVG",false)); + videoSourcePanel.add(textVideoDraw.set("text",false)); + videoSourcePanel.add(video_speed.set("playback speed",1.0,0.0,3.0)); + + vectorSourcePanel.setup("vector sources","",5,370); + vectorSourcePanel.add(edit_safety.set("edit safety",false)); + vectorSourcePanel.add(use_safety.set("use safety",true)); + vectorSourcePanel.add(vectorOscEnable.set("oscilloscope",false)); + vectorSourcePanel.add(contoursLaserDraw.set("contours",false)); + vectorSourcePanel.add(SVGLaserDraw.set("SVG",false)); + vectorSourcePanel.add(textLaserDraw.set("text",false)); + + setup_lasergui(970,500); + + audiopanel.setup("oscilloscope","",5,220); + audiopanel.add(vScale.set("vertical",3.0,0.0,20.0)); //scaling + audiopanel.add(hScale.set("horizontal",1.0,0.1,10.0)); //ms + audiopanel.add(onset_threshold.set("onset threshold", 0.05f, 0.0f, 1.0f )); + audiopanel.add(use_onset.set("trigger onset",false)); + audiopanel.add(onset_duration.set("duration", 10, 1, 100)); + + svggui.setup("SVG","",5,500); + svggui.add(shapes_randomise.set("randomise shapes", true)); + svggui.add(shapes_amount.set("shapes amount", 0.2, 0.0, 1.0)); + svggui.add(shapes_duration.set("shape duration", 5.0, 0, 10.0)); + svggui.add(use_mask.set("use mask", true)); + svggui.add(invert_mask.set("invert mask", false)); + + //segmenter + svggui.add(use_segmenter.set("use segmenter", false)); + svggui.add(colour_segmenter.set("colour", false)); + svggui.add(segmenter_speed.set("segmenter speed", 0.2, -1.0, 1.0)); + svggui.add(segmenter_length.set("segmenter length", 0.2, 0.0, 1.0)); + svggui.add(segmenter_number.set("segmenter number", 1, 1, 8)); + + text.setup(5,750); + + drawingpanel.setup("drawing","",550,500); + drawingpanel.add(lineWidth.set("width",2.0,0.1,10.0)); + + useKinect=true; + + if (useKinect) { + std::vector <ofxKinectV2::KinectDeviceInfo> deviceList = kinect.getDeviceList(); + if (deviceList.size()){ + useKinect=kinect.open(deviceList[0].serial); + } + else useKinect=false; + } + + if (!useKinect) { + _video.initGrabber(1280, 720); + } + + contourgui.setup("video contours","",550,550); + contourgui.add(video_outlines.set("enable",false)); + contourgui.add(contour_adaptive.set("adaptive",false)); + contourgui.add(contour_threshold.set("threshold", 140, 0, 255)); + contourgui.add(contour_adaptive_window.set("window", 0.5, 0, 1.0)); + contourgui.add(contour_simplify.set("simplify", 0.8, 0.0, 10.0)); + //contourgui.add(contour_useColour.set("use colour",false)); //TODO + + vectorTransforms.setup("vector transform","",550,750); + vectorTransforms.add(use_rotate.set("rotation",false)); + vectorTransforms.add(xf_rotate.set("rotate speed", 0.0, -1.0, 1.0)); + vectorTransforms.add(use_scale.set("scaling",false)); + vectorTransforms.add(xf_scale_speed.set("scale speed", 1.0, 0.0, 10.0)); + vectorTransforms.add(xf_scale_min.set("scale min", 1.0, 0.0, 3.0)); + vectorTransforms.add(xf_scale_max.set("scale maz", 1.0, 0.0, 3.0)); + + perlin = new PerlinPhasingFilter( + outputWindowSize.x, + outputWindowSize.y, + 8.f + ); + + perlinpanel.setup("PerlinPhasingFilter","",760,500); + perlinpanel.add(perlinEnable.set("enable",false)); + perlinpanel.add(perlinScale.set("scale",0.0,-1.0,1.0)); + perlinpanel.add(perlinSpeed.set("speed",0.0,-1.0,1.0)); + perlinpanel.add(perlinPixelWidth.set("pixel width",0.0,0.0,1.0)); + perlinpanel.add(perlinPixelWidthSpeed.set("pixel speed",1.0,0.0,10.0)); + + preview.allocate(outputWindowSize.x,outputWindowSize.y); + + gist.setUseForOnsetDetection(GIST_PEAK_ENERGY); + gist.setThreshold(GIST_PEAK_ENERGY, .05);// + + ofAddListener(GistEvent::ON,this,&ofApp::onNoteOn); + ofAddListener(GistEvent::OFF,this,&ofApp::onNoteOff); + + onset_frame=0; +} + +//-------------------------------------------------------------- +void ofApp::updateOutput(ofEventArgs & args){ + _player.setSpeed(video_speed); +} + +void ofApp::update(){ + laser.update(); + text.update(onset_frame); + + if (_player.isLoaded()){ + _player.update(); + } + + if (captPreview||captEnable){ + if (useKinect){ + kinect.update(); + if (kinect.isFrameNew()){ + texRGB.setFromPixels(kinect.getPixels()); + } + } + else { + _video.update(); + texRGB.setFromPixels(_video.getPixels()); + } + int tw=texRGB.getHeight()*1.333f; + int sl=(texRGB.getWidth()-tw)/2; + texRGB.crop(sl, 0, tw, texRGB.getHeight()); + } + + float interval=ofGetElapsedTimef()-prev_time; + rotate_amt+=interval*xf_rotate*5; + + phase=fmod(phase+(interval*segmenter_speed),1); //for segmenter + prev_time=ofGetElapsedTimef(); + + while (phase<0.0f) { + phase+=1.0f; + } + + scale_phase+=(interval*xf_scale_speed); + + scale_amt=(((sin(scale_phase)*0.5)+0.5)*(xf_scale_max-xf_scale_min))+xf_scale_min; + + gist.setThreshold(GIST_PEAK_ENERGY,onset_threshold); + + onset_frame++; +} + +//-------------------------------------------------------------- GUI +void ofApp::draw(){ + //draw the workspace window. + // 5 - 240 - panels + // 250 - 570 - sources (320x240) + // 580 - 1220 - preview (640x480) + + + + ofBackground(0); + + ofSetColor(255); + + + if (bShowPositionInterface){ + + glPushMatrix(); + + ofNoFill(); + + glTranslatef(20,20,0); + + ofDrawRectangle(0,0,560,560); + + glTranslatef(outputOffset.x,outputOffset.y,0); + + glScalef(guiScale,guiScale,guiScale ); + + glTranslatef(2048.0f+outputPosition.x,2048.0f+outputPosition.y,0); + + if (bOutputSelected) { + if (commandPressed) { + ofSetColor(0,255,0); + } + else { + ofSetColor(255,0,0); + } + } + + ofDrawRectangle( + (-outputWindowSize.x/2)*outputScale*outputOffsetScale, + (-outputWindowSize.y/2)*outputScale*outputOffsetScale, + outputWindowSize.x*outputScale*outputOffsetScale, + outputWindowSize.y*outputScale*outputOffsetScale); + + ofFill(); + + glPopMatrix(); + } + else { + //draw gui, sources and preview + + videoSourcePanel.draw(); + vectorSourcePanel.draw(); + audiopanel.draw(); + drawingpanel.draw(); + perlinpanel.draw(); + contourgui.draw(); + vectorTransforms.draw(); + svggui.draw(); + laser.drawgui(); + text.drawgui(); + + float sourcescale=sourceframesize.x/outputWindowSize.x; + + for (int i=0;i<4;i++){ + glPushMatrix(); + glTranslatef(210,249*i,0); + ofNoFill(); + ofDrawRectangle(5,5,sourceframesize.x+4,sourceframesize.y+4); + ofFill(); + + glTranslatef(7,7,0); + + //draw video sources within case statement + switch(i){ + case 0:{ + if (captPreview){ + if (useKinect){ + if (texRGB.isAllocated()){ + texRGB.draw(0,0,sourceframesize.x,sourceframesize.y); + } + } + else { + texRGB.draw(0,0,sourceframesize.x,sourceframesize.y); + } + } + break; + } + case 1:{ + if (_player.isLoaded()){ + if (ofGetElapsedTimef()-videostart<2.54f){ + int amt=(ofGetElapsedTimef()-videostart)*100; + ofSetColor(amt); + } + _player.draw(0,0,sourceframesize.x,sourceframesize.y); + ofSetColor(255); + } + break; + } + case 2:{ + glPushMatrix(); + glScalef(sourcescale,sourcescale,sourcescale); + for (auto shape=segmenters.begin();shape!=segmenters.end();shape++){ + shape->getPoly().draw(); + } + glPopMatrix(); + ofSetColor(255); + break; + } + } + + + + //draw vectors within case statement + + glPopMatrix(); + } + + glPushMatrix(); + glTranslatef(550,5,0); + ofNoFill(); + ofDrawRectangle(0,0,previewframesize.x+4,previewframesize.y+4); + ofFill(); + + if (perlinEnable) perlin->begin(); + preview.draw(2,2,previewframesize.x,previewframesize.y); + if (perlinEnable) perlin->end(); + + glPopMatrix(); + + } + + ofSetWindowTitle(ofToString(phase, 3)+" "+ofToString(ofGetFrameRate(), 2)+" fps laser points: "+ofToString(laser.get_numpts())); +} + +static float phase=0.0f; +static float lastframetime=0.0f; +static float scale=10.0f; +static float pixelWidth=0.05f; + +static int num=0; + +void ofApp::drawOutput(ofEventArgs & args){ +/* + if (perlinScale!=ps){ + perlin->updateParameter("scale", perlinScale); + ps=perlinScale; + //ofLog()<<"set perlin scale to "<<perlinScale; + } + */ + //this is mental, phase will update but scale will not + //it's not related to name, or order - generating a change per interval like this works differently + float interval=ofGetElapsedTimef()-lastframetime; + lastframetime=ofGetElapsedTimef(); + phase+=interval*perlinSpeed; + scale+=interval*perlinScale; + pixelWidth+=interval*perlinPixelWidth; + perlin->updateParameter("phase", phase); + perlin->updateParameter("scale", scale); + perlin->updateParameter("fractionalWidthOfPixel",0.05f+(sin(ofGetElapsedTimef()*perlinPixelWidthSpeed)*perlinPixelWidth)); + + //prepare vectors + + float vpos=ofGetHeight()/2; + + float scale=ofGetHeight()*vScale; + + ofPolyline osc; + + osc.addVertex(0,vpos+(buffer[0]*scale)); + + float i=0.0f; + float step=ofGetWidth()/(hScale*48); + + while (i<(ofGetWidth()+step)){ + i+=max(1.0f,(float)step); + osc.lineTo(i,vpos+(buffer[(int)i]*scale)); + } + + //render output to fbo and output + + preview.begin(); + + ofBackground(0); + ofSetColor(255,255,255); + + + ofClear(0,0,0,0); + + vector<colourPolyline> contouroutput; + + if (captEnable||(_player.isLoaded()&&playerEnable)){ + if (video_outlines){ + //use capture or player to generate outlines + if (captEnable){ + colorImg.setFromPixels(texRGB.getPixels()); + } + else if (_player.isLoaded()&&playerEnable){ + colorImg.setFromPixels(_player.getPixels()); + } + ofPoint scale=ofPoint(outputWindowSize.x/colorImg.getWidth(),outputWindowSize.y/colorImg.getHeight()); + if (grayImage.getWidth()!=colorImg.getWidth()||grayImage.getHeight()!=colorImg.getHeight()){ + grayImage.clear(); + } + grayImage=colorImg; + if(contour_adaptive){ + grayImage.adaptiveThreshold(grayImage.getWidth()*contour_adaptive_window, contour_threshold,false,true); + } + else { + grayImage.threshold(contour_threshold); + } + contourFinder.findContours(grayImage, 20, (grayImage.getWidth()*grayImage.getHeight())/3, 10, true); + for (int i = 0; i < contourFinder.nBlobs; i++){ + colourPolyline shape; + for (auto& point:contourFinder.blobs[i].pts){ + ofVec3f p=point*scale; + ofColor c=colorImg.getPixels().getColor(point.x,point.y); + shape.addVertex(p,c); //contour_useColour?c:ofColor(laser_R,laser_G,laser_B)); + } + shape.simplify(contour_simplify); + contouroutput.push_back(shape); + } + } + } + + vector<colourPolyline> svgoutput; + + if (SVGLaserDraw||SVGVideoDraw){ + if (!use_onset||onset_frame<onset_duration||shapes_randomise){ + if (shapes_randomise){ + //if (framecounter==0){ + // select_random_shapes(); + // framecounter=shapes_duration; + //} + select_random_shapes(shapes_duration,!use_onset||onset_frame<onset_duration); + for (auto s:shape_selection){ + if (use_segmenter){ + auto segments=segmenters[s].getSegments(segmenter_number,segmenter_length,phase); + for (auto segment=segments.begin();segment!=segments.end();segment++){ + //polyOutput.push_back(colourPolyline(*segment,ofColor(laser_R,laser_G,laser_B))); + svgoutput.push_back(*segment); + } + } + else { + //polyOutput.push_back(colourPolyline(segmenters[s].getPoly(),ofColor(laser_R,laser_G,laser_B))); + svgoutput.push_back(segmenters[s].getPoly()); + } + } + framecounter--; + } + else { + for (auto shape=segmenters.begin();shape!=segmenters.end();shape++){ + if (use_segmenter){ + auto segments=shape->getSegments(segmenter_number,segmenter_length,phase); + for (auto segment=segments.begin();segment!=segments.end();segment++){ + //polyOutput.push_back(colourPolyline(*segment,ofColor(laser_R,laser_G,laser_B))); + svgoutput.push_back(*segment); + } + } + else { + //polyOutput.push_back(colourPolyline(shape->getPoly(),ofColor(laser_R,laser_G,laser_B))); + svgoutput.push_back(shape->getPoly()); + } + } + } + if (contour_useColour){ + vector<colourPolyline> newPolys; + for (auto p: svgoutput){ + newPolys.push_back(colourPolyline((ofPolyline)p,ofColor(255,255,255))); //laser_R,laser_G,laser_B))) ; + } + svgoutput=newPolys; + } + } + } + + vector<colourPolyline> textoutput; + + if (textVideoDraw||textLaserDraw){ + textoutput = text.getOutlines(ofGetWidth()/2,ofGetHeight()/2); + /* + if (textoutput.size()!=num) { + ofLog()<<textoutput.size()<<" text shapes"; + num=textoutput.size(); + } + */ + + } + + ofSetLineWidth(lineWidth); + + if (contoursVideoDraw) { + for (auto c:contouroutput) c.draw(); + } + else if (SVGVideoDraw) { + for (auto s:svgoutput) s.draw(); + } + else if (textVideoDraw){ + for (auto i:textoutput) i.draw(); + } + else if (captEnable){ + texRGB.draw(0,0,outputWindowSize.x,outputWindowSize.y); + } + else if (_player.isLoaded()&&playerEnable){ + if (ofGetElapsedTimef()-videostart<2.54f){ + int amt=(ofGetElapsedTimef()-videostart)*100; + ofSetColor(amt); + } + _player.draw(0,0,outputWindowSize.x,outputWindowSize.y); + } + + if (videoOscEnable) osc.draw(); + + preview.end(); + + if (perlinEnable) perlin->begin(); + //shader.begin(); + preview.draw(0,0); + //shader.end(); + if (perlinEnable) perlin->end(); + + vector<colourPolyline> output; + + if (vectorOscEnable) output.push_back(osc); + else if (contoursLaserDraw) output=contouroutput; + else if (SVGLaserDraw) output=svgoutput; + else if (textLaserDraw) output=textoutput; + + //laser transformation comes here + + vector <colourPolyline> transformedOutput; + + if (use_rotate||use_scale){ + ofMatrix4x4 rm = ofMatrix4x4::newIdentityMatrix(); + rm.translate(-outputWindowSize.x/2,-outputWindowSize.y/2,0); + if (use_rotate){ + rm.rotateRad(rotate_amt,0,0,1); + } + if (use_scale){ + rm.scale(scale_amt,scale_amt,scale_amt); + } + rm.translate(outputWindowSize.x/2,outputWindowSize.y/2,0); + for (auto& shape:output){ + transformedOutput.push_back(lineTransformer::polyLineTransform(rm,shape)); + } + } + else { + transformedOutput=output; + } + + //laser warping comes here + + glm::vec2 src[]={ + glm::vec2(0,0), + glm::vec2(ofGetWidth(),0), + glm::vec2(ofGetWidth(),ofGetHeight()), + glm::vec2(0,ofGetHeight()) + }; + + glm::vec2 mp=glm::vec2(outputWindowSize.x/2,outputWindowSize.y/2); + + glm::vec2 scaled_dest[]={ + ((warpframe[0]-mp)*outputScale*outputOffsetScale)+mp, + ((warpframe[1]-mp)*outputScale*outputOffsetScale)+mp, + ((warpframe[2]-mp)*outputScale*outputOffsetScale)+mp, + ((warpframe[3]-mp)*outputScale*outputOffsetScale)+mp + }; + + ofMatrix4x4 scaled_warp =lineTransformer::getPerspectiveTransformMatrix(src,scaled_dest); + ofMatrix4x4 warp =lineTransformer::getPerspectiveTransformMatrix(src,warpframe); + + vector <colourPolyline> warpedOutput; + vector <colourPolyline> scaledWarpedOutput; + + for (auto s:transformedOutput){ + warpedOutput.push_back(lineTransformer::polyLineTransform(warp,s)); + scaledWarpedOutput.push_back(lineTransformer::polyLineTransform(scaled_warp,s)); + } + + ofPolyline safety; + safety.addVertex(safety_frame[0]); + safety.addVertex(safety_frame[1]); + safety.addVertex(safety_frame[2]); + safety.addVertex(safety_frame[3]); + //safety.close(); //addVertex(safety_frame[0]); + + ofPolyline warpedScaledSafety=lineTransformer::polyLineTransform(scaled_warp,safety); + + warpedScaledSafety.close(); + + vector <colourPolyline> clippedOutput; + + if (use_safety){ + vector <ofPolyline> masks; + masks.push_back(warpedScaledSafety); //create polyline + + for (auto& poly: scaledWarpedOutput) + { + clipper.Clear(); + clipper.addPolylines(masks, ClipperLib::ptClip); + vector <ofPolyline> shapes; //TODO make clipper clip colourpolylines + shapes.push_back(poly); + clipper.addPolylines(shapes,ClipperLib::ptSubject); + vector <ofPolyline> clipped; + //if (invert_mask){ + // clipped = clipper.getClippedLines(ClipperLib::ctDifference); + //}else { + clipped = clipper.getClippedLines(ClipperLib::ctIntersection); + //} + for (auto& clip: clipped) + { + clip.simplify(contour_simplify); + clippedOutput.push_back(colourPolyline(clip,poly.getColourAt(0))); + } + } + } + else { + clippedOutput=scaledWarpedOutput; + } + + //laser sorting comes here + + if (edit_safety){ + lineTransformer::drawWarpFrame(safety_frame); + laser.draw(warpedScaledSafety); + } + else if (clippedOutput.size()) { + laser.draw(clippedOutput); + } + else { + colourPolyline blank; + for (int i=0;i<100;i++){ + blank.addVertex(ofGetWidth()/2,ofGetHeight()/2,0,0,0); + } + laser.draw(blank); + } + + if (bDrawFrame){ + lineTransformer::drawWarpFrame(warpframe); + } +} + +void ofApp::onNoteOn(GistEvent &e){ + //ofLog() << "<<NOTE ON>>"; + onset_frame=0; + onset_number++; + //noteOnRadius = 100; +}; + + +void ofApp::onNoteOff(GistEvent &e){ + //ofLog() << "<<NOTE OFF>>"; + //turn off? + //noteOnRadius = 0; +}; + +void ofApp::audioIn(float * input, int blockSize, int nChannels){ + buffer.add(input,blockSize); + + vector<float>buf; + buf.assign(&input[0],&input[blockSize-1]); + gist.processAudio(buf, blockSize, nChannels,SAMPLERATE); +} + + +void ofApp::select_random_shapes(float duration,bool generate){ + float timedelta=ofGetElapsedTimef()-last_frame_time; + last_frame_time=ofGetElapsedTimef(); + //track how long each shape has been selected + for (int i=0;i<shape_selection_durations.size();i++){ + if (shape_selection_durations[i]>0.0f){ + shape_selection_durations[i]=shape_selection_durations[i]-timedelta; + } + } + + shape_selection.clear(); + + for (int i=0;i<shape_selection_durations.size();i++){ + if (shape_selection_durations[i]>0.0f){ + shape_selection.insert(i); + } + } + std::stringstream strom; + for (auto& s:shape_selection){ + strom << s <<":"<<shape_selection_durations[s]<<" "; + } + + //cout << timedelta <<": decay selection: "<<shape_selection.size()<<" shapes (" << strom.str() <<") \n"; + if (generate){ + + while (shape_selection.size()<(segmenters.size()*shapes_amount)){ + int selection=rand()%segmenters.size(); + if (shape_selection.find(selection)==shape_selection.end()){ + shape_selection_durations[selection]=duration+ofRandom(1.0f); + shape_selection.insert(selection); + } + } + std::stringstream strm; + for (auto& s:shape_selection){ + strm << s <<":"<<shape_selection_durations[s]<<" "; + } + } + //cout << "random selection: "<<shape_selection.size()<<" shapes (" << strm.str() <<") \n"; +} + + +//-------------------------------------------------------------- +void ofApp::exit() { + + +} + + + +//-------------------------------------------------------------- +void ofApp::outputKeyPressed(ofKeyEventArgs &args){ + + if (args.key=='f') { + ofToggleFullscreen(); + preview.allocate(ofGetWidth(),ofGetHeight()); + } + + keyPressed(args); + + +} + +void ofApp::keyPressed(ofKeyEventArgs &args){ + if (args.key==OF_KEY_COMMAND){ + commandPressed=true; + } + + switch(args.key){ + case '`':{ + bShowPositionInterface=!bShowPositionInterface; + break; + } + case 'w':{ + bDrawFrame=!bDrawFrame; + break; + } + case 'd':{ + default_settings(); + break; + } + case 's':{ + save_settings(); + break; + } + case '1':{ + scale=1.0f; + break; + } + case '2':{ + scale=2.0f; + break; + } + case '3':{ + scale=3.0f; + break; + } + case '4':{ + scale=4.0f; + break; + } + case '5':{ + scale=5.0f; + break; + } + case '6':{ + scale=6.0f; + break; + } + case '7':{ + scale=7.0f; + break; + } + case '8':{ + scale=8.0f; + break; + } + case '9':{ + scale=9.0f; + break; + } + } +} + +//-------------------------------------------------------------- +void ofApp::outputKeyReleased(ofKeyEventArgs &args){ + keyReleased(args); +} + +void ofApp::keyReleased(ofKeyEventArgs &args){ + if (args.key==OF_KEY_COMMAND){ + commandPressed=false; + } +} + + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y ){ +} + +//-------------------------------------------------------------- +void ofApp::outputMouseDragged(ofMouseEventArgs & args){ + if (select_warpframe>-1){ + warpframe[select_warpframe]=glm::vec2(args.x,args.y); + } + if (select_safetyframe>-1){ + safety_frame[select_safetyframe]=glm::vec3(args.x,args.y,0); + } + +} + +void ofApp::mouseDragged(int x, int y, int button){ + if (bOutputSelected){ + if (commandPressed){ + float startDistance=((outputPosition*guiScale)+ofPoint(300,300)).distance(outputSelectionPoint); + float currentDistance=((outputPosition*guiScale)+ofPoint(300,300)).distance(ofPoint(x,y)); + outputOffsetScale=currentDistance/startDistance; + } + else { + outputOffset=ofPoint(x,y)-outputSelectionPoint; + laser.set_centre(ofPoint( + outputPosition.x+(outputOffset.x/guiScale), + outputPosition.y+(outputOffset.y/guiScale) + )); + } + } +} + +//-------------------------------------------------------------- +void ofApp::outputMousePressed(ofMouseEventArgs & args){ + for (int i=0;i<4;i++){ + if (ofPoint(args.x,args.y).distance(warpframe[i])<25){ + select_warpframe=i; + } + } + if (edit_safety){ + for (int i=0;i<4;i++){ + if (ofPoint(args.x,args.y).distance(safety_frame[i])<25){ + select_safetyframe=i; + } + } + } +} + +void ofApp::mousePressed(int x, int y, int button){ + if (bShowPositionInterface){ + if (x>(300+((outputPosition.x-((outputWindowSize.x/2)*outputScale))*guiScale))&& + x<(300+((outputPosition.x+((outputWindowSize.x/2)*outputScale))*guiScale))&& + y>(300+((outputPosition.y-((outputWindowSize.y/2)*outputScale))*guiScale))&& + y<(300+((outputPosition.y+((outputWindowSize.y/2)*outputScale))*guiScale)) + ){ + outputSelectionPoint=ofPoint(x,y); + bOutputSelected=true; + } + } + +} + +//-------------------------------------------------------------- +void ofApp::outputMouseReleased(ofMouseEventArgs & args){ + select_warpframe=-1; + select_safetyframe=-1; +} + +void ofApp::mouseReleased(int x, int y, int button){ + if (bOutputSelected){ + if (commandPressed){ + outputScale*=outputOffsetScale; + } + else { + outputPosition+=outputOffset/guiScale; + } + bOutputSelected=false; + outputOffset=ofPoint(0,0); + outputOffsetScale=1.0f; + } + +} + +//-------------------------------------------------------------- +void ofApp::mouseEntered(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseExited(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::outputWindowResized(ofResizeEventArgs &resizeargs){ + +} + +void ofApp::windowResized(int w, int h){ + +} + + + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + std::string filename=dragInfo.files[0]; + for (int i=0;i<4;i++){ + if (dragInfo.position.x>215&&dragInfo.position.x<540 + &&dragInfo.position.y>249*i+5&&dragInfo.position.y<249*i+249){ + ofLog()<<"slot "<<i<<" received "<<filename<<" : "<<dragInfo.position.x; + + if (i==1) { + if (_player.load(filename)){ + videostart=ofGetElapsedTimef(); + } + } + + if (i==2) { + svg.load(filename); + vector <ofPath> imagepaths= svg.getPaths(); + + std::stringstream strm; + + if (imagepaths.size()){ + segmenters.clear(); + shape_selection_durations.clear(); + for (auto& path:imagepaths){ + path.setPolyWindingMode(OF_POLY_WINDING_ODD); + + vector <ofPolyline> outlines= path.getOutline(); + for (auto& outline:outlines){ + strm << outline.size() << "->"; + outline.simplify(contour_simplify); + strm << outline.size() << " "; + segmenters.push_back(colourLineSegmenter(outline,path.getStrokeColor())); + shape_selection_durations.push_back(0.0f); + } + + strm << " , "; + } + + std::stringstream strom; + + shape_selection.clear(); + while (shape_selection.size()<(segmenters.size()*shapes_amount)){ + int selection=(int)ofRandom(0,segmenters.size()); + shape_selection.insert(selection); + } + for (auto s:shape_selection){ + float spawn=(ofRandom(0,(float)shapes_duration)); + shape_selection_durations[s]=spawn; + strom << s << ":"<<spawn<<" "; + } + last_frame_time=ofGetElapsedTimef(); + //cout << "SVG: selected paths [ "<<strom.str() << " ]" <<std::endl; + //cout << "SVG: found " << imagepaths.size() << " paths with " << segmenters.size() << " shapes [ " << strm.str() << " ]" <<std::endl; + //select_random_shapes(shapes_duration); + } + } + + if (i==3) { + text.loadfile(filename); + } + } + + } + +}
\ No newline at end of file diff --git a/FESgui/src/ofApp.h b/FESgui/src/ofApp.h new file mode 100644 index 0000000..8519f01 --- /dev/null +++ b/FESgui/src/ofApp.h @@ -0,0 +1,273 @@ +#pragma once + +#include "ofMain.h" +#include "ofxGui.h" +#include "ofxXmlSettings.h" +#include "ofxKinectV2.h" +#include "ofxOpenCv.h" +#include "ofxClipper.h" +#include "ofxSVG.h" +#include "ofxGist.h" +#include "ofxOpenALSoundPlayer.h" + +#include "PerlinPhasingFilter.h" +#include "lasergui.h" +#include "audiobuffer.h" +#include "linetransformer.h" +#include "linesegmenter.h" +#include "selectpanel.h" +#include "vectortext.h" + +#define SAMPLERATE 48000 + +const ofPoint outputWindowSize=ofPoint(1024,768); +const float guiScale=560.0f/4096.0f; +const ofPoint sourceframesize=ofPoint(320,240); +const ofPoint previewframesize=ofPoint(640,480); + +class textgui : public ofxPanel{ + public: + ofParameter<bool> use_beat; + ofParameter<float> beat_duration; + ofParameter<float> text_speed; + ofParameter<float> text_scale; + ofParameter<bool> enable_anim; + ofParameter<bool> anim_rev; + ofParameter<float> vert_pos; + ofParameter<float> vert_spread; + glyphbanner text; + int onset_frame; + void loadfile(const string & f){ + if (!strcmp(strchr(f.c_str(), '\0') - 4, ".plt")){ + text.loadPalette(f); + } + else { + text.load(f); + } + } + void setup(int x, int y){ + //text.loadFont("fonts/EMSSpaceRocks.svg"); + text.loadFont("fonts/EMSOsmotron.svg"); + + ofxPanel::setup("text","",x,y); + ofxPanel::add(use_beat.set("use beat", false)); + ofxPanel::add(beat_duration.set("duration factor", 0.5f, 0.0f, 1.0f)); + ofxPanel::add(text_speed.set("speed", 5.0f, 0.0f, 25.0f)); + ofxPanel::add(text_scale.set("scale", 0.1f, 0.0f, 0.5f)); + ofxPanel::add(enable_anim.set("animate", false)); + ofxPanel::add(anim_rev.set("reverse", false)); + ofxPanel::add(vert_pos.set("vert_pos", 0.0f, -0.3f, 0.3f)); + ofxPanel::add(vert_spread.set("vert_spread", 0.0f, -0.3f, 0.3f)); + + } + void update(int oframe=0){ + onset_frame=oframe; + text.update(text_speed,true); + } + void drawgui(int oframe=0){ + onset_frame=oframe; + ofxPanel::draw(); + } + void createWords(string t){ + text.createWords(t); + } + vector<colourPolyline>& getOutlines(float x=0, float y=0){ + return text.getOutlines(text_scale,STYLE_OVERLAPPING,x,y+(ofGetHeight()*vert_pos),enable_anim,anim_rev,vert_spread,use_beat,beat_duration); + } + +}; + +class ofApp: public ofBaseApp { + + public: + void setup(); + void update(); + void draw(); + void exit(); + + void keyPressed(ofKeyEventArgs &keyargs); + void keyReleased(ofKeyEventArgs & args); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void mouseEntered(int x, int y); + void mouseExited(int x, int y); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + + void updateOutput(ofEventArgs & args); + void drawOutput(ofEventArgs & args); + void outputKeyPressed(ofKeyEventArgs & args); + void outputKeyReleased(ofKeyEventArgs & args); + void outputMouseDragged(ofMouseEventArgs & args); + void outputMousePressed(ofMouseEventArgs & args); + void outputMouseReleased(ofMouseEventArgs & args); + void outputWindowResized(ofResizeEventArgs &resizeargs); +//--laser interface and settings------------------------------------------------ + lasergui laser; + + ofxXmlSettings XML; + void default_settings(); + void save_settings(); + + void setup_lasergui(int x, int y); + + void select_random_shapes(float duration,bool generate); + + bool commandPressed; + + glm::vec2 warpframe[4]; + int select_warpframe; + bool bDrawFrame; + + bool bShowPositionInterface; + bool bOutputSelected; + ofPoint outputSelectionPoint; + ofPoint outputPosition; + ofPoint outputOffset; + float outputScale; + float outputOffsetScale; + + glm::vec3 safety_frame[4]; + int select_safetyframe; +//--audio------------------------------------------------ + + ofSoundStream soundStream; + int blockSize; + + void audioIn(float * input, int blockSize, int nChannels); + + ofxGist gist; + void onNoteOn(GistEvent &e); + void onNoteOff(GistEvent &e); + + ofxPanel audiopanel; + ofParameter<float> vScale; + ofParameter<float> hScale; + ofParameter<float> onset_threshold; + ofParameter<bool> use_onset; + ofParameter<int> onset_duration; + + int onset_frame; + int onset_number; + + Buffer buffer; + +//--vector drawing------------------------------------- + + ofxPanel drawingpanel; + ofParameter<float> lineWidth; + +//--perlin filter + + PerlinPhasingFilter *perlin; + ofxPanel perlinpanel; + ofParameter<bool> perlinEnable; + ofParameter<float> perlinScale; + ofParameter<float> perlinSpeed; + ofParameter<float> perlinPixelWidth; + ofParameter<float> perlinPixelWidthSpeed; + +//--video capture (automatic) + + bool useKinect; + ofxKinectV2 kinect; + ofImage texRGB; + ofVideoGrabber _video; + +//--preview and sources + + ofFbo preview; + + ofxPanel videoSourcePanel; + ofParameter<bool> captPreview; + ofParameter<bool> captEnable; + ofParameter<bool> videoOscEnable; + ofParameter<bool> playerEnable; + ofParameter<bool> contoursVideoDraw; + ofParameter<bool> SVGVideoDraw; + ofParameter<bool> textVideoDraw; + ofParameter<float> video_speed; //move this + + + ofxPanel vectorSourcePanel; + ofParameter<bool> edit_safety; + ofParameter<bool> use_safety; + ofParameter<bool> vectorOscEnable; + ofParameter<bool> contoursLaserDraw; + ofParameter<bool> SVGLaserDraw; + ofParameter<bool> textLaserDraw; + + ofxPanel vectorTransforms; + ofParameter<bool> use_rotate; + ofParameter<float> xf_rotate; + ofParameter<bool> use_scale; + ofParameter<float> xf_scale_speed; + ofParameter<float> xf_scale_min; + ofParameter<float> xf_scale_max; + + int framecounter; + float phase,prev_time; //to calculate phase + float rotate_amt; + float scale_phase,scale_amt; + +//--video player + + ofVideoPlayer _player; + float videostart; + +//--contours + + ofxCvColorImage colorImg; + ofxCvGrayscaleImage grayImage; + ofxCvContourFinder contourFinder; + + ofxPanel contourgui; + ofParameter<bool> video_outlines; + ofParameter<bool> contour_adaptive; + ofParameter<int> contour_threshold; + ofParameter<float> contour_adaptive_window; + ofParameter<float> contour_simplify; + ofParameter<bool> contour_useColour; + +//get colour somewhere else +// ofxIntSlider laser_R; +// ofxIntSlider laser_G; +// ofxIntSlider laser_B; + +//==//SVG player=================================== + + ofxSVG svg; + vector <colourLineSegmenter> segmenters; + vector <float> shape_selection_durations; + + set <int> shape_selection; + float last_frame_time; + + //svg gui + ofxPanel svggui; + ofParameter<bool> shapes_randomise; + ofParameter<float> shapes_amount; + ofParameter<float> shapes_duration; + ofParameter<bool> use_mask; + ofParameter<bool> invert_mask; + + //segmenter + ofParameter<bool> use_segmenter; + ofParameter<bool> colour_segmenter; + ofParameter<float> segmenter_speed; + ofParameter<float> segmenter_length; + ofParameter<int> segmenter_number; + + +//==/Mask clipping=================================== / + + + ofx::Clipper clipper; + +//==/text=================================== / + + textgui text; + +};
\ No newline at end of file diff --git a/FESgui/src/selectpanel.h b/FESgui/src/selectpanel.h new file mode 100644 index 0000000..a6811bc --- /dev/null +++ b/FESgui/src/selectpanel.h @@ -0,0 +1,53 @@ +#pragma once + +#include "ofMain.h" +#include "ofxGui.h" + +/* a gui panel that receives key and drag events. */ + +class selectPanel : public ofxPanel { + public: + selectPanel(string _name=""){ + name=_name; + ofRegisterKeyEvents(this, defaultEventsPriority); + ofRegisterDragEvents(this, defaultEventsPriority); + } + bool mouseMoved(ofMouseEventArgs & args){ + if (args.x>getPosition().x&& + args.x-getPosition().x<getWidth()&& + args.y>getPosition().y&& + args.y-getPosition().y<getHeight()){ + isSelected=true; + setHeaderBackgroundColor(ofColor(255,128,0)); + } + else { + isSelected=false; + setHeaderBackgroundColor(ofColor(80,80,80)); + } + } + bool keyPressed(ofKeyEventArgs & args){ + if (isSelected){ + ofLog()<<name<<" KEY> "<<args.key; + switch(args.key){ + default: + break; + } + } + } + bool keyReleased(ofKeyEventArgs & args){ + //required in order to call ofRegisterKeyEvents + } + virtual void loadfile(const string & f){}; + bool dragEvent(ofDragInfo & dragInfo){ + if (dragInfo.position.x>getPosition().x&& + dragInfo.position.x-getPosition().x<getWidth()&& + dragInfo.position.y>getPosition().y&& + dragInfo.position.y-getPosition().y<getHeight()){ + ofLog()<<name<<" DRAG> "<<dragInfo.files[0]; + loadfile(dragInfo.files[0]); + } + } +private: + bool isSelected; + string name; +};
\ No newline at end of file diff --git a/FESgui/src/vectortext.h b/FESgui/src/vectortext.h new file mode 100644 index 0000000..4625989 --- /dev/null +++ b/FESgui/src/vectortext.h @@ -0,0 +1,366 @@ +#pragma once + +#include "ofMain.h" +#include "ofxSvg.h" +#include "lineTransformer.h" +#include "colourPolyline.h" +#include "ofxXmlSettings.h" + +class glyph{ +public: + glyph(char c,float w,vector<ofPolyline> lines){ + glyph(c,w,lines,ofColor(0,0,0)); + } + glyph(char c,float w,vector<ofPolyline> lines,ofColor col){ + code=c; + width=w; + outline=lines; + colour=col; + } + void draw(float x, float y){ + ofSetColor(colour); + ofPushMatrix(); + ofTranslate(x,y); + for (auto& v:outline) v.draw(); + ofPopMatrix(); + } + void randomiseColour(){ + colour=ofColor::fromHsb(ofRandom(255.0),225,255); + } + char code; + float width; + vector<ofPolyline> outline; + ofColor colour; +}; + +class glyphWord{ +public: + glyphWord(){ + amount=1.0f; + val=ofRandom(1.0f); + val2=ofRandom(1.0f); + width=0; + } + vector<glyph> glyphs; + float amount; + float val; //a random float used for word parameters + float val2; + float width; +}; + +#define STYLE_SENTENCE 1 +#define STYLE_OVERLAPPING 2 + +class glyphbanner{ + ofXml SVGFont; + vector<glyphWord> words; + vector<colourPolyline> outlines; + ofVec2f centre; + float lastUpdateTime; + float playhead; + float enspace; + float last_beat; + float last_beat_duration; + vector<ofColor> palette; + struct { + vector<ofColor> balanced={ + ofColor::fromHex(0xE27D60), + ofColor::fromHex(0x085DCB), + ofColor::fromHex(0xE8A87C), + ofColor::fromHex(0xC38D9E), + ofColor::fromHex(0x41B3A3) + }; + vector<ofColor> uneasy={ + ofColor::fromHex(0x2154B9), + ofColor::fromHex(0xC45A62), + ofColor::fromHex(0x95A28A), + ofColor::fromHex(0x98546D), + ofColor::fromHex(0xE9DADA), + ofColor::fromHex(0x9FF3E9), + ofColor::fromHex(0xD07B37), + ofColor::fromHex(0x741710), + ofColor::fromHex(0x102ADC), + ofColor::fromHex(0x9FA1AC) + }; + vector<ofColor> stark={ + ofColor::fromHex(0xFFFFFF), + ofColor::fromHex(0x000000), + ofColor::fromHex(0x000000), + ofColor::fromHex(0x000000) + }; + }palettes; + vector<string> split(string s) { + size_t pos_start = 0, pos_end; + string token; + vector<string> res; + + while ((pos_end = s.find (" ", pos_start)) != string::npos) { + token = s.substr (pos_start, pos_end - pos_start); + pos_start = pos_end + 1; + res.push_back (token); + } + + res.push_back (s.substr (pos_start)); + return res; + } + float segment; //the fraction that the word has displayed +public: + glyphbanner(){ + palette=palettes.stark; + }; + void init(string message){ + createWords(message); + lastUpdateTime=ofGetElapsedTimef(); + playhead=0.0f; + } + int length(){ + int l=0; + for (auto& w:words) { + l+=w.glyphs.size(); + } + return l+max(0,(int)words.size()-1); + } + float width(){ + float _w=0.0f; + for (auto& w:words) { + for (auto& g:w.glyphs) _w+=g.width; + } + return _w+max((float)(words.size()-1)*enspace,0.0f); + } + int glyphCount(){ + int c=0; + for (auto& w:words){ + c+=w.glyphs.size(); + } + return c; + } + string text(){ + string s; + for (auto& w:words) { + for (auto& g:w.glyphs) s+=ofToString(g.code); + } + return s; + } + void loadFont(filesystem::path path){ + if( SVGFont.load(path) ){ + vector<glyphWord> w=words; + clear(); + createWords(w); + enspace=getGlyph(' ').width; + ofLog()<<"loaded "<<path.stem().string(); + }else{ + ofLog()<<"unable to load "<<path<<" check data/ folder"; + } + + } + void load(string path){ + ofFile file; + file.open(path, ofFile::ReadWrite, false); + ofBuffer buff = file.readToBuffer(); + string s=buff.getText(); + if (s.size()){ + createWords(s); + } + } + void loadPalette(vector<ofColor> p){ + palette=p; + } + void loadPalette(string path){ + ofxXmlSettings xml; + if (xml.load(path)){ + ofLog()<<path<<": found palette, "<<xml.getNumTags("colour")<<" colours"; + vector<ofColor> palette; + for (int i=0;i<xml.getNumTags("colour");i++){ + string s=xml.getValue("colour","", i); + try { + int c=std::stoul(s, nullptr, 16); + palette.push_back(ofColor::fromHex(c)); + } + catch (const std::exception& e) { + ofLog()<<"palette loader: could not convert "<<s; + } + } + if (palette.size()) loadPalette(palette); + } + else { + ofLog()<<"could not load palette "<<path; + } + } + void createWords(string message,bool usePalette=false){ + clear(); + vector<string> m=split(message); + for (auto& word: m){ + glyphWord w; + for (auto& c: word){ + glyph g=getGlyph(c, + usePalette? + palette[ofRandom(palette.size())]: + //112->231 hue sat 0->255 brightness 255 + ofColor::fromHsb(ofRandom(119)+112,ofRandom(255),255) + ); + w.width+=g.width; + w.glyphs.push_back(g); + } + words.push_back(w); + } + ofLog()<<"glyphbanner created "<<words.size()<<" words"; + } + void createWords(vector<glyphWord> _words){ + clear(); + for (auto& _w:_words) { + glyphWord w; + for (auto& g: _w.glyphs){ + w.glyphs.push_back(getGlyph(g.code,g.colour)); + } + words.push_back(w); + } + } + glyph getGlyph(char c,ofColor col=ofColor(255,255,255)){ + vector<ofPolyline> shapes; + ofPolyline shape; + string elementPath = "/svg/defs/font/glyph[@unicode='"+ofToString(c)+"']"; + + if(SVGFont.findFirst(elementPath) == 0 ){ + elementPath = "/svg/defs/font/glyph[@unicode='?']"; + } + + ofXml xmlElement = SVGFont.findFirst(elementPath); + + float charWidth = ofToFloat(xmlElement.getAttribute("horiz-adv-x").getValue()); + + vector<string> splitGlyphPath = ofSplitString(xmlElement.getAttribute("d").getValue(), " ");//glyph path data in SVG looks like this: "M 139 -9.45 L 230 18.9 L 299 22.1 L 227 25.2" + + for(int i=0; i<splitGlyphPath.size(); i+=3){ + if(splitGlyphPath[i] == "M"){ + if (shape.size()) { + shapes.push_back(shape); + shape.clear(); + } + shape.addVertex(ofToFloat(splitGlyphPath[i+1]), ofToFloat(splitGlyphPath[i+2])); + }else if(splitGlyphPath[i] == "L"){ + shape.lineTo(ofToFloat(splitGlyphPath[i+1]), ofToFloat(splitGlyphPath[i+2])); + } + } + if (shape.size()) shapes.push_back(shape); + return glyph(c,charWidth,shapes,col); + } + void addGlyph(char g,bool usePalette=false){ + if (g==' ') words.push_back(glyphWord()); + else { + words[words.size()-1].glyphs.push_back(getGlyph(g, + usePalette? + palette[ofRandom(palette.size())]: + ofColor::fromHsb(ofRandom(119)+112,ofRandom(255),255) + )); + } + } + void removeGlyph(){ + if (words.size()){ + glyphWord lw=words[words.size()-1]; + lw.glyphs.pop_back(); + if (!lw.glyphs.size()){ + words.pop_back(); + } + } + } + void clear(){words.clear();} + void update(float speed=1.0f,bool usePalette=false,bool use_beat=false,int onset_frame=0){ + + if (!words.size()) return; + + float delta=ofGetElapsedTimef()-lastUpdateTime; + lastUpdateTime=ofGetElapsedTimef(); + playhead+=delta*speed; + + int theword=0; + if (false){ //1 word per second + theword=int(playhead)%words.size(); + segment=playhead-int(playhead); + } + + if (use_beat){ //change on the beat + if (!onset_frame){ + theword=(theword+1)%words.size(); + segment=0.0f; + last_beat_duration=ofGetElapsedTimef()-last_beat; + last_beat=ofGetElapsedTimef(); + } + else { + segment=(ofGetElapsedTimef()-last_beat)/last_beat_duration; + } + } + else { //proportional to #of letters + int theletter=int(playhead)%glyphCount(); + theword=0; + while(theletter>words[theword].glyphs.size()){ + theletter-=words[theword].glyphs.size(); + theword++; + } + float playfraction=playhead-int(playhead); + + //segment=(((float)theletter+words[theword].glyphs.size()+playhead-int(playhead))/words[theword].glyphs.size()); + segment=(((float)theletter+playfraction-1)/words[theword].glyphs.size()); + } + //calculate params for word/letter anim + for (int i=0;i<words.size();i++){ + words[i].amount=(i==theword?sin(segment*3.14):0); + for (auto& g:words[i].glyphs){ + if (ofRandom(100)<speed) { + g.colour= + usePalette? + palette[ofRandom(palette.size())]: + ofColor::fromHsb(ofRandom(119)+112,ofRandom(255),255); + } + } + } + } + vector<colourPolyline>& getOutlines(float s=1.0f,int style=STYLE_SENTENCE,float x=0,float y=0,bool anim=false,bool reverse=false, float vert_spread=0.0f, bool use_beat=false, float beat_duration=0.0f){ + outlines.clear(); + + if (beat_duration>segment){ //I don't think this is what segment is + return outlines; + } + switch (style){ + case STYLE_SENTENCE:{ + float p=((-width())/2); + for (auto& w:words){ + for (auto& g:w.glyphs){ + if (w.amount>0.0f&&g.colour.getBrightness()>0){ + for (auto& o:g.outline){ + auto q=o; + q.scale(s,-s); + q.translate(glm::vec3((p*s)+x,y,0)); + outlines.push_back(colourPolyline(q,g.colour*w.amount)); + } + } + p+=g.width; + } + p+=enspace; + } + break; + } + case STYLE_OVERLAPPING:{ + for (auto& w:words){ + float p=(w.val*(ofGetWidth()-w.width)); + float v=y+(vert_spread*w.val*(ofGetHeight())); + for (auto& g:w.glyphs){ + if (w.amount>0.0f&&g.colour.getBrightness()>0){ + for (auto& o:g.outline){ + auto q=o; + float a=anim?reverse?1.0f-segment:segment:1.0; + q.scale(s*a,-s*a); + q.translate(glm::vec3((p*s*a)+x,v,0)); + outlines.push_back(colourPolyline(q,g.colour*w.amount)); + } + } + p+=g.width*(anim?reverse?1.0f-segment:segment:1.0); + } + } + } + default:{ + break; + } + } + return outlines; + } +};
\ No newline at end of file |
