[work 120] Character ‘A’

[work 120] Character ‘A’

Movie

Source code

about

  • ‘A’をモチーフにしたスケッチ
  • フォントをロードして文字を描画する頂点群を取得
  • 頂点と頂点を等間隔に分割した点を追加する
  • ある点を起点に指定した数分の頂点を描画する
  • 起点となる点をずらす

file

  • 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
  • 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h"
#include "ofApp.h"

//================================
int main( ){

    // 4K:4096x2160
    // 2K:2048x1080
    // FullHD:1920x1080
    // HD:1440x1080
    // HD720p:1280x720
    // DVD:720x480
    // setup the GL context
//    ofSetupOpenGL(1280,720, OF_WINDOW);
    ofSetupOpenGL(1024,1024, OF_WINDOW);

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once

#include "ofMain.h"

#include "Character.hpp"



class ofApp : public ofBaseApp{
public:
    ofApp();
    ~ofApp();
    
    void setup();
    void update();
    void draw();
    
    void keyPressed(int key);
    void keyReleased(int key);
    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 gotMessage(ofMessage msg);
    
private:
    std::shared_ptr<Character> ch;
};
#include "ofApp.h"
#include <chrono>


ofApp::ofApp(){
    
}

ofApp::~ofApp(){
    
}

//--------------------------------------------------------------
void ofApp::setup(){
    double fps = 30;
    
    ofSetFrameRate(fps);
    ofBackground(ofColor::white);
    ofSetBackgroundAuto(true);
    ofSetVerticalSync(true);
    
    ch = make_shared<Character>();
    ch->setup();
}

//--------------------------------------------------------------
void ofApp::update(){
    auto t0 = std::chrono::high_resolution_clock::now();
    
    ch->update();
    
    auto t1 = std::chrono::high_resolution_clock::now();
    cout << "update(): " << std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() / 1000.0 << " sec" << endl;
}


//--------------------------------------------------------------
void ofApp::draw(){
    auto t0 = std::chrono::high_resolution_clock::now();
    
    ch->display();
    
    std::cout << "fps: " << ofGetFrameRate() << std::endl;
    
    auto t1 = std::chrono::high_resolution_clock::now();
    cout << "draw(): " << std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0).count() / 1000.0 << " sec" << endl;
}
#ifndef Character_hpp
#define Character_hpp

#include <stdio.h>
#include "ofMain.h"

class Character {
public:
    Character(){};
    ~Character(){};
    void setup();
    void update();
    void display();
    
private:
    ofTrueTypeFont font;
    std::vector<std::vector<glm::vec3>> pointList;
    std::vector<int> indexList;
};

#endif /* Character_hpp */
#include "Character.hpp"


void Character::setup()
{
    ofTrueTypeFontSettings settings("font/Helvetica.ttc", 32);
    settings.addRange(ofUnicode::Latin);
    settings.addRanges(ofAlphabet::Japanese);
    settings.contours = true;
    font.load(settings);
    
    float dist = 1.5;
    std::vector<ofPath> paths = font.getStringAsPoints("A", true, false);
    
    std::cout << "PATH:" << paths.size() << std::endl;
    for (ofPath path : paths) {
        std::vector<ofPolyline> lines = path.getOutline();
        
        std::cout << "LINE:" << lines.size() << std::endl;
        
        for (ofPolyline pl : lines) {
            std::vector<glm::vec3> points;
            
            for (int i = 0; i < pl.getVertices().size(); i++) {
                int next = (i + 1) % pl.getVertices().size();
                float d = glm::distance(pl.getVertices().at(i), pl.getVertices().at(next));
                int num = (int)(d / dist);
                
                for (int m = 1; m <= num; m++) {
                    int n = (num + 1) - m;
                    glm::vec3 p = (pl.getVertices().at(i) * n / (m + n)) + (pl.getVertices().at(next) * m / (m + n));
                    points.push_back(p);
                }
                points.push_back(pl.getVertices().at(next));
            }
            pointList.push_back(points);
            
            indexList.push_back(0);

            std::cout << "POINTS:" << pointList.back().size() << std::endl;
        }
    }
}


void Character::update()
{
    for (int i = 0; i < indexList.size(); i++) {
        indexList.at(i) = (indexList.at(i) + 1) % pointList.at(i).size();
    }
}


void Character::display()
{
    for (int i = 0; i < indexList.size(); i++) {
        int startIdx = indexList.at(i);
        int size = pointList.at(i).size();
        int max = (size * 5) / 10;
        
        ofPushMatrix();
        ofTranslate(150, ofGetHeight() - 150);
        ofFill();
        ofSetColor(ofColor::black);
        ofBeginShape();
        for (int j = 0; j < max; j++) {
            int idx = (startIdx + j) % size;
            glm::vec3 p = pointList.at(i).at(idx) * 25;
            ofDrawCircle(p, 4);
        }
        ofEndShape();
        ofPopMatrix();
        
    }
}

Link to the reference page

ソースコードで使用したAPIの中から要点になりそうなものをいくつか選んでリストアップしました。

categoryAPI/Lib
openframeworksofTrueTypeFont
openframeworksglm::vec3
openframeworksglm::distance
c++std::vector

Development environment

  • openframeworks 0.10.1
  • c++
  • macOS
  • Xcode