トップ 最新 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|

2022-12-01 [macOS][OpenGL]OpenGLに再挑戦(其の参)

前回の続き。

エラーの原因がわかった。glVertexPointer()渡している列挙子が間違えていた。GL_FLATではなくGL_FLOATだ。

#import <iostream>
#import <sstream>
#import <Foundation/Foundation.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>
#import <GLUT/glut.h>
 
int gWidth = 600;
int gHeight = 500;
const int QUIT_VALUE(99);
GLuint  gListID; /* ディスプレイリストID */
 
void display(void)
{
    /* カラーバッファの初期化 */
    glClear(GL_COLOR_BUFFER_BIT);
    
    /* モデリング変換、z軸の負の方向に幾何形状を4単位移動する。 */
    glLoadIdentity();   /* 単位行列 */
    glTranslatef(0.0f, 0.0f, -4.0f);
    
    /* 幾何形状を描画する。 */
    glCallList(gListID);
    
    /* バッファの入れ替え */
    glutSwapBuffers();
    
    assert(glGetError() == GL_NO_ERROR);
}
 
void resize(int w, int h)
{
    /* ウィンドウ・サイズとOpenGLの座標を対応づける */
    glViewport(0, 0, w, h);
    
    /* 投影行列とアスペクト比を更新する */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50.0, (GLdouble)w / (GLdouble)h, 1.0, 10.0);
    
    /* 表示ルーチン用にモデルビューモードに設定する */
    glMatrixMode(GL_MODELVIEW);
    
    assert(glGetError() == GL_NO_ERROR);
    
    gWidth = w;
    gHeight = h;
}
 
void keyboard(unsigned char key, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void special(int key, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void mouse(int button, int state, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void motion(int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void idle(void)
{
    glutPostRedisplay();
}
 
void main_menu_callback(int value)
{
    if (value == QUIT_VALUE)
        exit(EXIT_SUCCESS);
}
 
void init(void)
{
    DBGMSG(@"%s", __func__);
 
    /* ディザ処理を無効にする */
    glDisable(GL_DITHER);
    
    std::string ver((const char*)glGetString(GL_VERSION));
    assert(! ver.empty());
    std::istringstream verStream(ver);
    
    int major, minor;
    char dummySep;
    verStream >> major >> dummySep >> minor;
    const bool useVertexArrays = ((major >= 1) && (minor >= 1));
    
    const GLfloat data[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };
    
    if (useVertexArrays) {
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, data);
    }
    
    /* ディスプレイリストを作成する。 */
    gListID = glGenLists(1);
    glNewList(gListID, GL_COMPILE);
 
    if (useVertexArrays) {
        glDrawArrays(GL_TRIANGLES, 0, 3);
        //glDisableClientState(GL_VERTEX_ARRAY);
    }
    else {
        glBegin(GL_TRIANGLES);
        glVertex3fv(&data[0]);
        glVertex3fv(&data[3]);
        glVertex3fv(&data[6]);
        glEnd();
    }
    
    glEndList();
    
    assert(glGetError() == GL_NO_ERROR);
    
    /* 描画 */
    glutDisplayFunc(display);
 
    /* リサイズ処理 */
    glutReshapeFunc(resize);
    
    /* キーボード */
    glutKeyboardFunc(keyboard);
    
    /* 特殊キー */
    glutSpecialFunc(special);
    
    /* マウス */
    glutMouseFunc(mouse);
    
    /* ドラッグ */
    glutMotionFunc(motion);
    
    /* バックグランド処理 */
    glutIdleFunc(idle);
    
    /* コンテキスト・メニュー */
    glutCreateMenu(main_menu_callback);
    glutAddMenuEntry("Quit", QUIT_VALUE);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
}
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        
        glutInit(&argc, (char **)argv);
        
        /* RGBカラーモード ダブルバッファ */
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
        
        /* 初期ウィンドウ・サイズ */
        glutInitWindowSize(gWidth, gHeight);
        
        /* 初期ウィンドウ位置 */
        glutInitWindowPosition(500, 100);
        
        /* タイトルバー */
        glutCreateWindow("IRIS GL");
        
        /* 初期化 */
        init();
        
        /* 主ループ(イベント駆動) */
        glutMainLoop();
        
    }
    return 0;
}

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/mac/IRIS - GitHub

2022-12-02 [Swift]Combine

Combineはイベント処理演算子を組み合わせて、非同期でイベントを処理するSwiftのAPIだ。
既存のNotificationCenterやAppKitとUIKitのUI部品はCombineに対応しているので、Combineのイベント処理演算子の使ったイベント処理が行える。

例えば、テキスト入力フィールドとデバッグ出力用テキスト・ビューがあるNSViewControllerの派生クラスがあるとする。

import Cocoa
import Combine
 
class ViewController: NSViewController {
    @IBOutlet var inputField: NSTextField!
    @IBOutlet var debugMessageTextView: NSTextView!
    var sub: AnyCancellable? = nil
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
 
    override var representedObject: Any? {
        didSet {
            // Update the view, if already loaded.
        }
    }
}

inputFieldにテキストが入力されたら、そのイベントを受け取りたい場合は、以下のコードとなる。

    override func viewDidLoad() {
        super.viewDidLoad()
 
        sub = NotificationCenter.default
            .publisher(for: NSControl.textDidChangeNotification, object: inputField)
            .sink(receiveCompletion: { print ($0) },
                  receiveValue: { print ($0) })
    }

sink() はイベントを受け取るもので、こんな感じでイベント処理演算子をつなげていることになる。

    override func viewDidLoad() {
        super.viewDidLoad()
 
        sub = NotificationCenter.default
            .publisher(for: NSControl.textDidChangeNotification, object: inputField)
            .map( { ($0.object as! NSTextField).stringValue } )
            .filter( { $0.unicodeScalars.allSatisfy({CharacterSet.alphanumerics.contains($0)}) } )
            .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
            .receive(on: RunLoop.main)
            .assign(to:\NSTextView.string, on: debugMessageTextView)
    }

上の例のコードを説明する。
map() で文字列に変換している。
filter() で英数字のみとしている。
debounce() でイベント発行の頻度を調整している。
receive() でメイン・スレッドで受け取るようにしている。
assign() で入力内容をデバッグ出力用テキスト・ビューに設定している。


トップ 最新 追記