For openFrameworks Users
oFが好きなあなたなら、TrussCも気に入るはず。
同じ楽しさを、現代の技術で。
oFユーザーなら、違和感なく書き始められます
クリエイティブコーディングの基本リズム。この構造は不変です。
ofApp
→
tcApp
使い心地を極力変えないように、手に馴染んだメソッド名を踏襲しています。
ofDrawCircle(x, y, r)
→
drawCircle(x, y, r)
今となっては標準ですよね。Cursor派ですか?もちろん大丈夫です。
長年のペインポイントに対するTrussCの回答
ofSetLineWidth() はOpenGLの制限で太さ1px以上が保証されない。
macOS / Metal環境では完全に無視される。太い線を描くには自前でメッシュを生成するしかなかった。
oFでは太い線を描くと角や終端がプッツリ切れた見た目になっていました。
StrokeMesh を使えば美しいエッジを持った幅のある線を描画できます。
// StrokeMesh で任意の太さの線が描ける
StrokeMesh stroke;
stroke.setStrokeWidth(5.0f); // 5px の太線
stroke.moveTo(0, 0);
stroke.lineTo(100, 100);
stroke.draw();
// Polyline からも生成可能
Polyline line;
line.addVertex(0, 0);
line.addVertex(100, 50);
StrokeMesh stroke2(line, 3.0f);
stroke2.draw();
ofNode はあるが、親子関係の管理が手動。
子ノードの追加・削除でメモリ管理が複雑。
親が消えても子が残ってしまう問題も。
// shared_ptr ベースで自動管理
auto parent = Node::create();
auto child = Node::create();
parent->addChild(child);
// 親を破棄すれば子も自動的に解放される
// 循環参照も weak_ptr で安全に回避
マウス座標は常にスクリーン座標(左上原点)。
回転・スケールしたオブジェクト上のクリック判定は複雑な計算が必要。
ofNode を使っても座標変換は自分で計算するしかなかった。
// RectNode は自動的にローカル座標に変換
class MyButton : public RectNode {
void onMousePressed(const Vec2& localPos, int button) override {
// localPos は「このノードにとっての」座標
// 親が回転していても、自分のローカル座標で届く!
if (localPos.x < width/2) {
// 左半分をクリック
}
}
};
複数のオブジェクトが重なっているときの判定が面倒。
Zオーダー(描画順)を考慮した判定は自前実装するしかなかった。
// RectNode は自動的に Z オーダーを考慮
// 手前のノードが優先的にイベントを受け取る
void onMousePressed(const Vec2& pos, int button) override {
// このノードで処理したら、後ろのノードには届かない
consumeEvent();
}
ofThread はデータ競合を起こしやすい。
「3秒後に実行」を安全にやる標準的な方法がなく、
update内で時間計測してif文を書くとコードが汚くなる。
// メインスレッドで安全に遅延実行
node->callAfter(3.0f, []() {
// 3秒後にメインスレッドで実行
// Mutex 不要、データ競合の心配なし
});
// 繰り返し実行も簡単
node->callEvery(1.0f, []() {
// 1秒ごとに実行
});
AppleがOpenGLを非推奨にし、Metalへ移行。
将来的な動作保証やパフォーマンス最適化が困難に。
いつサポートが切れるかわからない不安。
Metal / DirectX 12 / Vulkan / WebGPU に対応。
OSが推奨する最新のネイティブAPI上で動作するため、高速かつ省電力。
WebAssembly + WebGPU でブラウザへの移植性も高い。
oF本体はMITだが、依存ライブラリにGPLが混在。
FFmpegやFreeTypeなど、ライセンスを確認するのが大変。
クライアントワークで使うときに不安が残る。
GPL汚染ゼロを徹底。
すべての依存ライブラリが商用利用フレンドリー。
安心してクライアントワークに使える。
ofSetFrameRate() はDrawとUpdateが常に連動。
物理シミュレーションを固定タイムステップで回したいときに困る。
イベント駆動型アプリ(ボタンを押したときだけ再描画)も作りにくかった。
デフォルトでは今まで通りupdate, drawを交互に呼び出すこともできますが、イベント駆動型のUIアプリを作るときに無駄なdrawを避けるためにupdateとは別のタイミング(クリック時など)で実行できます。
また、描画負荷が重いアプリでもupdateを固定周期にすることも可能です。
// Draw と Update を独立制御
setDrawVsync(true); // 描画は VSync (60Hz)
setUpdateFps(120); // 物理更新は 120Hz
// イベント駆動型(省電力モード)
setDrawFps(0); // 自動描画を停止
// mousePressed 等で redraw() を呼ぶと描画される
oFの関数、TrussCではこう書く
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofApp : public ofBaseApp | tcApp : public App | |
ofRunApp(new ofApp()) | runApp<tcApp>() | テンプレート形式 |
setup() | setup() | 同じ |
update() | update() | 同じ |
draw() | draw() | 同じ |
keyPressed(int key) | keyPressed(int key) | 同じ |
mousePressed(x, y, button) | mousePressed(x, y, button) | 同じ |
windowResized(w, h) | windowResized(w, h) | 同じ |
dragEvent(ofDragInfo) | filesDropped(paths) | |
ofSetFrameRate(60) | setFps(60) | |
ofSetVerticalSync(true) | setVsync(true) | |
| - | setDrawFps(fps) | 描画レート個別設定 |
| - | setUpdateFps(fps) | 更新レート個別設定 |
ofGetElapsedTimef() | getElapsedTime() | |
ofGetFrameRate() | getFrameRate() | |
ofGetFrameNum() | getFrameCount() | |
ofGetWidth() | getWindowWidth() | |
ofGetHeight() | getWindowHeight() | |
OF_EXIT_APP() | exitApp() | アプリ終了 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofBackground(r, g, b) | clear(r, g, b) | 0.0-1.0 |
ofSetColor(r, g, b, a) | setColor(r, g, b, a) | 0.0-1.0 |
ofSetColor(ofColor::red) | setColor(colors::red) | |
ofDrawRectangle(x, y, w, h) | drawRect(x, y, w, h) | |
ofDrawCircle(x, y, r) | drawCircle(x, y, r) | |
ofDrawEllipse(x, y, w, h) | drawEllipse(x, y, w, h) | |
ofDrawLine(x1, y1, x2, y2) | drawLine(x1, y1, x2, y2) | |
ofDrawTriangle(...) | drawTriangle(...) | |
ofNoFill() | noFill() | |
ofFill() | fill() | |
ofSetLineWidth(w) | setLineWidth(w) | |
ofDrawBitmapString(s, x, y) | drawBitmapString(s, x, y) | |
ofPolyline | Path | |
| - | StrokeMesh | 太線描画 |
ofEnableBlendMode() | setBlendMode() | |
ofScissor() | setScissor() |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofPushMatrix() | pushMatrix() | |
ofPopMatrix() | popMatrix() | |
ofTranslate(x, y, z) | translate(x, y, z) | |
ofRotateDeg(deg) | rotateDeg(deg) | |
ofRotateRad(rad) | rotateRad(rad) | |
ofScale(x, y, z) | scale(x, y, z) |
| openFrameworks | TrussC | 備考 |
|---|---|---|
glm::vec2 / ofVec2f | Vec2 | |
glm::vec3 / ofVec3f | Vec3 | |
glm::vec4 / ofVec4f | Vec4 | |
glm::mat4 / ofMatrix4x4 | Mat4 | |
ofMap(v, a, b, c, d) | map(v, a, b, c, d) | |
ofClamp(v, min, max) | clamp(v, min, max) | |
ofLerp(a, b, t) | lerp(a, b, t) | |
ofNoise(x) | noise(x) | Perlin noise |
ofSignedNoise(x) | signedNoise(x) | |
ofRandom(min, max) | random(min, max) | |
ofDegToRad(deg) | radians(deg) | |
ofRadToDeg(rad) | degrees(rad) | |
PI | PI | |
TWO_PI | TAU | τ = 2π |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofColor(r, g, b, a) | Color(r, g, b, a) | 0.0-1.0 |
ofColor::fromHsb(h, s, b) | Color::fromHSB(h, s, b) | 0.0-1.0 |
| - | Color::fromOKLab(L, a, b) | OKLab色空間 |
| - | Color::fromOKLCH(L, C, h) | OKLCH色空間 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofImage | Image | |
img.load("path") | img.load("path") | 同じ |
img.draw(x, y) | img.draw(x, y) | 同じ |
img.draw(x, y, w, h) | img.draw(x, y, w, h) | 同じ |
img.save("path") | img.save("path") | 同じ |
img.getWidth() | img.getWidth() | 同じ |
img.getHeight() | img.getHeight() | 同じ |
img.setColor(x, y, c) | img.setColor(x, y, c) | 同じ |
img.getColor(x, y) | img.getColor(x, y) | 同じ |
| - | img.setFilter(Nearest/Linear) | テクスチャフィルター |
| - | img.setWrap(Repeat/Clamp/...) | テクスチャラップ |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofTrueTypeFont | TrueTypeFont | |
font.load("font.ttf", size) | font.load("font.ttf", size) | |
font.drawString(s, x, y) | font.drawString(s, x, y) | |
| - | drawBitmapString(s, x, y) | 組み込みフォント |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofPlanePrimitive | createPlane(w, h) | Meshを返す |
ofBoxPrimitive | createBox(size) | |
ofSpherePrimitive | createSphere(r, res) | |
ofIcoSpherePrimitive | createIcoSphere(r, res) | |
ofCylinderPrimitive | createCylinder(r, h, res) | |
ofConePrimitive | createCone(r, h, res) |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofEasyCam | EasyCam | |
cam.begin() | cam.begin() | 同じ |
cam.end() | cam.end() | 同じ |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofEnableLighting() | enableLighting() | |
ofDisableLighting() | disableLighting() | |
ofLight | Light | |
light.setDirectional(dir) | light.setDirectional(dir) | |
light.setPointLight() | light.setPoint(pos) | |
light.setAmbientColor(c) | light.setAmbient(c) | |
light.setDiffuseColor(c) | light.setDiffuse(c) | |
light.setSpecularColor(c) | light.setSpecular(c) | |
ofMaterial | Material | |
| - | Material::gold() | プリセット |
| - | Material::silver() | プリセット |
| - | Material::plastic(color) | プリセット |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofMesh | Mesh | |
mesh.addVertex(v) | mesh.addVertex(v) | |
mesh.addColor(c) | mesh.addColor(c) | |
mesh.addNormal(n) | mesh.addNormal(n) | |
mesh.addIndex(i) | mesh.addIndex(i) | |
mesh.draw() | mesh.draw() | |
mesh.drawWireframe() | mesh.drawWireframe() |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofFbo | Fbo | |
fbo.allocate(w, h) | fbo.allocate(w, h) | |
fbo.begin() | fbo.begin() | |
fbo.end() | fbo.end() | |
fbo.draw(x, y) | fbo.draw(x, y) |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofShader | Shader | |
shader.load(vert, frag) | shader.load(vert, frag) | |
shader.begin() | shader.begin() | |
shader.end() | shader.end() | |
shader.setUniform*() | shader.setUniform*() |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofSoundPlayer | Sound | |
sound.load("file.wav") | sound.load("file.wav") | |
sound.play() | sound.play() | |
sound.stop() | sound.stop() | |
sound.setVolume(v) | sound.setVolume(v) | |
sound.setLoop(true) | sound.setLoop(true) | |
ofSoundStream | SoundStream | マイク入力 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofVideoGrabber | VideoGrabber | |
grabber.setup(w, h) | grabber.setup(w, h) | |
grabber.update() | grabber.update() | |
grabber.draw(x, y) | grabber.draw(x, y) | |
grabber.isFrameNew() | grabber.isFrameNew() |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofSystemLoadDialog() | systemLoadDialog() | |
ofSystemSaveDialog() | systemSaveDialog() | |
ofToDataPath("file") | getDataPath() + "file" | |
ofLoadJson(path) | loadJson(path) | nlohmann/json |
ofSaveJson(path, json) | saveJson(path, json) | |
| - | loadXml(path) | pugixml |
| - | saveXml(path, xml) |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofxTCPClient | TcpClient | |
ofxTCPServer | TcpServer | |
ofxUDPManager | UdpSocket |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofxGui / ofxImGui | Dear ImGui(組み込み) | imgui::Begin() 等 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofNode | Node | shared_ptrベース |
node.setPosition(x, y, z) | node->setPosition(x, y, z) | |
node.setParent(parent) | parent->addChild(child) | |
| - | RectNode | 2D UI用、ヒットテスト対応 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofEvent<T> | Event<T> | |
ofAddListener(...) | EventListener | RAII形式 |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofLog() | tcLogNotice() | |
ofLogVerbose() | tcLogVerbose() | |
ofLogWarning() | tcLogWarning() | |
ofLogError() | tcLogError() |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofThread | Thread | |
| - | ThreadChannel | スレッドセーフなキュー |
| openFrameworks | TrussC | 備考 |
|---|---|---|
ofSerial | Serial |
| openFrameworks | TrussC | 備考 |
|---|---|---|
| - | node->callAfter(sec, func) | 遅延実行 |
| - | node->callEvery(sec, func) | 繰り返し実行 |
oFで培った経験は、そのまま活きる。