Swiftでシェーダプログラムを読み込む

OpenGLの解説ではなくて、文字列変換に関するメモです。

実践iPad/iPhoneゲームプログラミング」を読みながら、
Obj-CをSwiftに書き直しています。
まだサポートページも存在するのでサンプルコードも手に入るし、
運が良ければ書店で入手できるかも。
GLKViewが存在するとは言え、貴重な情報源には違いないです。

と言う訳で、さくさく文字列を変換したと思います。

1. シェーダプログラムを追加する

これは、適当なテキストファイルを追加するだけですね。
でもって、XcodeでTypeを変更するとコードヒントが出るようになります。
DefaultからOpenGL Shading Language sourceに変更。)

20150910-1

あと、追加したファイルがコンパイル対象ではなく、
リソースとしてコピーされるようにする必要があるみたいだけど、
自分の環境だと何もしなくても良さそうでした。

20150910-2

追加したファイルが、Compile Sourcesに存在するなら、
手動で削除したり、追加したりする必要があるんですかね?

2. シェーダプログラムを読み込む

追加したファイルが、
“shader.vsh”と”shader.fsh”ならこんな感じ。(*1)

import UIKit
import GLKit

class MyGLKViewController: GLKViewController {
    var program: GLuint = 0
    weak var glkView: GLKView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        glkView = self.view as! GLKView

        glkView.context = EAGLContext( API: .OpenGLES2 )
        EAGLContext.setCurrentContext( glkView.context )

        loadShaders()
        
        // ...
    }
    
    deinit {
        glDeleteProgram( program )
    }

    func loadShaders() -> Bool {
        program = glCreateProgram()
        println( "program = \(program)" )
        
        let vshPath = NSBundle.mainBundle().pathForResource( "shader", ofType: "vsh" )
        let fshPath = NSBundle.mainBundle().pathForResource( "shader", ofType: "fsh" )
        println( "vshPath = \(vshPath)" )
        println( "fshPath = \(fshPath)" )

        var vertShader: GLuint = 0
        if !compileShader(&vertShader, file: vshPath!, shaderType: GLenum(GL_VERTEX_SHADER)) {
            return false
        }
        
        glAttachShader( program, vertShader )
        if !linkProgram(program) {
            if vertShader != 0 {
                glDeleteShader( vertShader )
            }
            
            return false
        }

        // ...

        if vertShader != 0 {
            glDeleteShader( vertShader )
        }

        return true
    }

    func compileShader(inout shader: GLuint, file: String, shaderType: GLenum) -> Bool {
        var str = NSString(contentsOfFile: file, encoding: NSUTF8StringEncoding, error: nil )
        if str == nil {
            println( "Failed to load file!" )
            println( "file: \(file)" )
            
            return false
        }

        var source = str!.UTF8String
        shader = glCreateShader( shaderType )
        glShaderSource( shader, 1, &source, nil )
        glCompileShader( shader )

        var logLength: GLint = 0
        glGetShaderiv( shader, GLenum(GL_INFO_LOG_LENGTH), &logLength )
        if 0 < logLength {
            var log = [GLchar]( count: Int(logLength), repeatedValue: 0 )
            glGetShaderInfoLog( shader, logLength, &logLength, &log )
            println( String.fromCString(log) )
        }

        var status: GLint = 0
        glGetShaderiv( shader, GLenum(GL_COMPILE_STATUS), &status )
        if status == 0 {
            glDeleteShader( shader )
            return false
        }
        
        return true
    }

    func linkProgram(prog: GLuint) -> Bool {
        
        glLinkProgram( prog )
        
        var logLength: GLint = 0
        glGetProgramiv( prog, GLenum(GL_INFO_LOG_LENGTH), &logLength )
        if 0 < logLength {
            var log = [GLchar]( count: Int(logLength), repeatedValue: 0 )
            glGetProgramInfoLog( prog, logLength, &logLength, &log )
            println( String.fromCString(log) )
        }

        var status: GLint = 0
        glGetProgramiv( prog, GLenum(GL_LINK_STATUS), &status )
        if status == 0 {
            return false
        }

        return true
    }

    override func glkView(view: GLKView!, drawInRect rect: CGRect) {
        glClear( GLbitfield(GL_COLOR_BUFFER_BIT) )

        // ...
    }
}

見ての通り、”shader.fsh”は読み込んでないです。
まだ本を読みながら、Swiftに書き直してる段階だけど、
そもそも文字列変換でハマっていたので、何かの参考になれば。

ちなみにこれを実行すると、OpenGLからエラーログが取得できます。

Optional("ERROR: OpenGL ES requires exactly one vertex and one fragment shader to validly link.\n")

おしまい。

(*1) 「実践iPad/iPhoneゲームプログラミング」に載ってるサンプルコードをSwiftで書き直したものです。

Leave a Comment