summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Redfern <tim@getdrop.com>2022-11-18 23:26:38 +0000
committerTim Redfern <tim@getdrop.com>2022-11-18 23:26:38 +0000
commit4ceddea7412d683d8b828ad1027529d7167520d4 (patch)
treec2db42b71bad55deab9d49ea639f19c02b3c0ac6
parent2fdf59251151805e217427d6d792077acd1acd59 (diff)
refactor out vector text
-rw-r--r--lasertext/src/ofApp.h262
-rw-r--r--lasertext/src/vectortext.h269
2 files changed, 270 insertions, 261 deletions
diff --git a/lasertext/src/ofApp.h b/lasertext/src/ofApp.h
index a099cf6..621b729 100644
--- a/lasertext/src/ofApp.h
+++ b/lasertext/src/ofApp.h
@@ -8,6 +8,7 @@
#include "ofxHelios.h"
#include "lineTransformer.h"
#include "colourPolyline.h"
+#include "vectortext.h"
class scannableColourPolyline: public colourPolyline{
public:
@@ -109,268 +110,7 @@ public:
}
};
-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;}
- vector<glyph> glyphs;
- float amount;
-};
-
-class glyphbanner{
- ofXml SVGFont;
- vector<glyphWord> words;
- vector<colourPolyline> outlines;
- ofVec2f centre;
- float lastUpdateTime;
- float playhead;
- float enspace;
- 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)
- };
- }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;
- }
-public:
- glyphbanner(){
- palette=palettes.uneasy;
- };
- 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 createWords(string message,bool usePalette=false){
- clear();
- vector<string> m=split(message);
- for (auto& word: m){
- glyphWord w;
- for (auto& c: word){
- w.glyphs.push_back(getGlyph(c,
- usePalette?
- palette[ofRandom(palette.size())]:
- //112->231 hue sat 0->255 brightness 255
- ofColor::fromHsb(ofRandom(119)+112,ofRandom(255),255)
- ));
- }
- words.push_back(w);
- }
- //ofLog()<<"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,float usePalette=false){
-
- float delta=ofGetElapsedTimef()-lastUpdateTime;
- lastUpdateTime=ofGetElapsedTimef();
- playhead+=delta*speed;
-
- int theword=0;
- float segment=0.0f;
- if (false){ //1 word per second
- theword=int(playhead)%words.size();
- segment=playhead-int(playhead);
- }
- 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){
- outlines.clear();
- float p=(-width())/2;
- for (auto& w:words){
- for (auto& g:w.glyphs){
- if (w.amount>0.0f){
- for (auto& o:g.outline){
- auto q=o;
- q.scale(s,-s);
- q.translate(glm::vec3(p*s,-ofGetHeight()/3,0));
- outlines.push_back(colourPolyline(q,g.colour*w.amount));
- }
- }
- p+=g.width;
- }
- p+=enspace;
- }
- return outlines;
- }
-};
class ofApp : public ofBaseApp{
diff --git a/lasertext/src/vectortext.h b/lasertext/src/vectortext.h
new file mode 100644
index 0000000..088ee96
--- /dev/null
+++ b/lasertext/src/vectortext.h
@@ -0,0 +1,269 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxSvg.h"
+#include "lineTransformer.h"
+#include "colourPolyline.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;}
+ vector<glyph> glyphs;
+ float amount;
+};
+
+class glyphbanner{
+ ofXml SVGFont;
+ vector<glyphWord> words;
+ vector<colourPolyline> outlines;
+ ofVec2f centre;
+ float lastUpdateTime;
+ float playhead;
+ float enspace;
+ 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)
+ };
+ }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;
+ }
+public:
+ glyphbanner(){
+ palette=palettes.uneasy;
+ };
+ 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 createWords(string message,bool usePalette=false){
+ clear();
+ vector<string> m=split(message);
+ for (auto& word: m){
+ glyphWord w;
+ for (auto& c: word){
+ w.glyphs.push_back(getGlyph(c,
+ usePalette?
+ palette[ofRandom(palette.size())]:
+ //112->231 hue sat 0->255 brightness 255
+ ofColor::fromHsb(ofRandom(119)+112,ofRandom(255),255)
+ ));
+ }
+ words.push_back(w);
+ }
+ //ofLog()<<"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,float usePalette=false){
+
+ float delta=ofGetElapsedTimef()-lastUpdateTime;
+ lastUpdateTime=ofGetElapsedTimef();
+ playhead+=delta*speed;
+
+ int theword=0;
+ float segment=0.0f;
+ if (false){ //1 word per second
+ theword=int(playhead)%words.size();
+ segment=playhead-int(playhead);
+ }
+ 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){
+ outlines.clear();
+ float p=(-width())/2;
+ for (auto& w:words){
+ for (auto& g:w.glyphs){
+ if (w.amount>0.0f){
+ for (auto& o:g.outline){
+ auto q=o;
+ q.scale(s,-s);
+ q.translate(glm::vec3(p*s,-ofGetHeight()/3,0));
+ outlines.push_back(colourPolyline(q,g.colour*w.amount));
+ }
+ }
+ p+=g.width;
+ }
+ p+=enspace;
+ }
+ return outlines;
+ }
+}; \ No newline at end of file