Hatena::ブログ(Diary)

C++でゲームプログラミング

2014-01-16

[][][]libclang の Python binding を使用する 〜導入編〜

最近 libclang の Python binding を使用をしようた Vim プラグインを作成しているのでその覚書としてポツポツ書いていこうかと思います。

ibclang とは Clang が提供している構文解析ツールになります。

この構文解析器は Clang から提供されている Python binding を使用することで比較的簡単に使用することができます。

諸事情により LLVM 3.3 で動作確認していますが、LLVM 3.4 でも基本的な使い方は変わらないはずです。

あと Python はあまり慣れていないので書き方など間違っている箇所があったらすみません。


[Python binding を導入する]

Python binding は Clang のソースコードに付属しています。

ソースファイルはここsvn などから落としてくるとよいでしょう。

この Python binding を Python から使用したい場合は予め $PYTHONPATH に設定しておく必要があります。

$PYTHONPATH=D:/clang/bindings/python

[使用する]

とりあえず、簡単な使い方をしてみます。


[test.cpp]

struct X{
    int value;

    void
    func(){}
};

int
plus(int a, int b){
    return a + b;
}

namespace hoge{
    int
    minus(int a, int b){
        return a - b;
    }
}

int
main(){
    plus(1, 2);
    hoge::minus(3, 5);
    return 0;
}

[main.py]

import sys

import clang.cindex
from clang.cindex import Index
from clang.cindex import Config


def print_node_tree(node):
    print "%s : %s" % (node.kind.name, node.displayname)
    for child in node.get_children():
        print_node_tree(child)

index = Index.create()
tu = index.parse("test.cpp")
print_node_tree(tu.cursor)

[出力]

TRANSLATION_UNIT : test.cpp
TYPEDEF_DECL : __builtin_va_list
STRUCT_DECL : X
FIELD_DECL : value
CXX_METHOD : func()
COMPOUND_STMT : 
FUNCTION_DECL : plus(int, int)
PARM_DECL : a
PARM_DECL : b
COMPOUND_STMT : 
RETURN_STMT : 
BINARY_OPERATOR : 
UNEXPOSED_EXPR : a
DECL_REF_EXPR : a
UNEXPOSED_EXPR : b
DECL_REF_EXPR : b
NAMESPACE : hoge
FUNCTION_DECL : minus(int, int)
PARM_DECL : a
PARM_DECL : b
COMPOUND_STMT : 
RETURN_STMT : 
BINARY_OPERATOR : 
UNEXPOSED_EXPR : a
DECL_REF_EXPR : a
UNEXPOSED_EXPR : b
DECL_REF_EXPR : b
FUNCTION_DECL : main()
COMPOUND_STMT : 
CALL_EXPR : plus
UNEXPOSED_EXPR : plus
DECL_REF_EXPR : plus
INTEGER_LITERAL : 
INTEGER_LITERAL : 
CALL_EXPR : minus
UNEXPOSED_EXPR : minus
DECL_REF_EXPR : minus
NAMESPACE_REF : hoge
INTEGER_LITERAL : 
INTEGER_LITERAL : 
RETURN_STMT : 
INTEGER_LITERAL : 

とりあえず、こんな感じ。

次は Config 周りについてでも。


[Clang]

  • clang++ (LLVM) 3.3

2011-10-30

[]Shader のコンパイルエラーを取得

OGLplus で Shader のコンパイルに失敗した場合、Comple() 時に例外(CompileError)が飛んできます。


[ソース]

#include <vector>
#include <iostream>

#define GL_VERSION_4_1 1
#include <GL/glew.h>
#include <oglplus/gl.hpp>
#include <oglplus/context.hpp>
#include <oglplus/shader.hpp>
#include <GL/Glut.h>


int
main(int argc, char *argv[]){
    namespace glp = oglplus;
    typedef glp::Context glc;
    
    // Shader を使うために初期化
    glutCreateWindow("");
    auto err = glewInit();
    if (err != GLEW_OK)
    {
        std::cout << "Error:" << glewGetErrorString(err) << std::endl;
    }
    
    glp::VertexShader vs;

    vs.Source(R"delimiter(
        #version 330
        in vec3 Position
        void main(void){
            gl_Position = vec4(Position, 1.0);
        }
    )delimiter");
    
    try{
        // Shader Compile
        vs.Compile();
        std::cout << "SUCCESS" << std::endl;
    }
    catch(glp::CompileError const& error){
        std::cout << error.Log() << std::endl;
    }
    
    return 0;
}

[出力]

0(4) : error C0000: syntax error, unexpected reserved word "void", expecting ',' or ';' at token "void"

CompileError::Log で、コンパイルエラー内容を取得することが出来ます。


[OGLplus]

  • 0.6.0

2011-10-29

[]OGLplus を使ってシェーダで遊んでみた

実行時にシェーダファイルをリロードできるようにして遊んでみました。


[main.cpp]

#include <vector>
#include <GL/glew.h>

#include <oglplus/gl.hpp>
// OGLplus 0.5.0 以降だと near far を undef しておかないと動かない
#undef near
#undef far

//#include <oglplus/all.hpp>
#include <oglplus/context.hpp>
#include <oglplus/buffer.hpp>
#include <oglplus/vertex_attrib.hpp>
#include <oglplus/vertex_array.hpp>
#include <oglplus/shader.hpp>
#include <oglplus/program.hpp>
#include <oglplus/pixel_data.hpp>
#include <oglplus/image.hpp>

#include <GL/Glut.h>

#include <cstdlib>
#include <string>
#include <gl/graphics.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <fstream>
#include <sstream>

namespace glp = oglplus;
typedef glp::Context glc;


template<typename Shader, typename Char>
boost::optional<std::string>
shader_compile(Shader& shader, Char const* source){
    shader.Source(source);
    try{
        shader.Compile();
        return boost::none;
    }
    catch (glp::CompileError const& error) {
        std::cout << error.what() << std::endl;
        return error.Log();
    }
}

template<typename Shader, typename Char>
boost::optional<std::string>
shader_compile(Shader& shader, std::basic_ifstream<Char> const& file){
    std::stringstream buffer;
    buffer << file.rdbuf();
    return shader_compile(shader, buffer.str().c_str());
}


struct triangle : boost::noncopyable{
    
    triangle(std::initializer_list<GLfloat> triangle_verts){
        load_shader();

        // bind the VAO for the triangle
        vertex_array.Bind();

        // bind the VBO for the triangle vertices
        verts.Bind(glp::Buffer::Target::Array);
        // upload the data
        glp::Buffer::Data(glp::Buffer::Target::Array,
            triangle_verts.size(),
            triangle_verts.begin()
        );
        // setup the vertex attribs array for the vertices
        glp::VertexAttribArray vert_attr(prog, "Position");
        vert_attr.Setup(3, glp::DataType::Float);
        vert_attr.Enable();
    }
    
    void
    render() const{
        vertex_array.Bind();
        glc::DrawArrays(glp::PrimitiveType::Triangles, 0, 3);
    }
    void
    reload_shader(std::string name = "basic"){
        prog.DetachShader(vs);
        prog.DetachShader(fs);
        load_shader(name);
        std::cout << "reloaded shader" << std::endl;
    }

private:
    void
    load_shader(std::string name = "basic"){
        if(auto error = shader_compile(vs, std::ifstream(name + ".vert"))){
            std::cout << "==== VertexShader Compile Error ====" << std::endl;
            std::cout << *error << std::endl;
            return;
        }

        if(auto error = shader_compile(fs, std::ifstream(name + ".frag"))){
            std::cout << "==== FragmentShader Compile Error ====" << std::endl;
            std::cout << *error << std::endl;
            return;
        }
        // attach the shaders to the program
        prog.AttachShader(vs);
        prog.AttachShader(fs);
        // link and use it
        prog.Link();
        prog.Use();
    }

    // Vertex shader
    glp::VertexShader vs;

    // Fragment shader
    glp::FragmentShader fs;

    // Program
    glp::Program prog;

    // A vertex array object for the rendered triangle
    glp::VertexArray vertex_array;
    // VBO for the triangle's vertices
    glp::Buffer verts;
};


int
main(int argc, char *argv[]){
    namespace glp = oglplus;
    typedef glp::Context glc;
    
    gl::graphics g(argc, argv, 500, 500, "test");
    
    // glew の初期化
    auto err = glewInit();
    if (err != GLEW_OK)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }
    
    glc::ClearColor(0.5f, 0.7f, 0.9f, 1.0f);
    glc::ClearDepth(1.0f);

    // △ポリゴンの生成
    triangle obj1({
        0.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    });

    triangle obj2({
         0.0f,  0.0f, 0.0f,
        -1.0f,  0.0f, 0.0f,
         0.0f, -1.0f, 0.0f
    });
    //----------------------------------------------------------------------    
    
    gl::displayfunc(g, [&](){
        glc::Clear().ColorBuffer().DepthBuffer();
        obj1.render();
        obj2.render();
    });
    
    gl::reshapefunc(g, [&](int width, int height){
        glc::Viewport(width, height);
    });

    // キー入力イベント
    gl::keyboardfunc(g, [&obj1](unsigned char key, int x, int y){
        if(key == 'q') return exit(0);
        if(key == 'u') return obj1.reload_shader();
    });

    // idle
    gl::idlefunc(g, [&](){
        boost::this_thread::sleep(boost::posix_time::milliseconds(16));
        glutPostRedisplay();
    });

    g.run();
    
    return 0;
}

[basic.vert]

#version 330
in vec3 Position;
out vec4 vertColor;

void main(void){
    gl_Position = vec4(Position, 1.0);
    vec3 color = (Position + 1.0) / 2.0;
    vertColor = vec4(color, 1.0);
}

[basic.frag]

#version 330
in vec4 vertColor;
out vec4 fragColor;

void main(void){
    fragColor = vertColor;
}

[出力]

f:id:osyo-manga:20111029060231p:image


実行時に変更出来るのでシェーダ楽しい。

次は画像か3D辺りを描画させたいですね。

しかし、今だに OGLplus(OpenGL)の描画ロジックがよく分からない…。


[OGLplus]

  • 0.6.0

2011-10-28

[]OGLplus 0.6.0

いつの間にか OGLplus がバージョンアップしていました。

0.6.0 はまだ正式リリースじゃないのかな?

最新版の OGLplus だと gcc 4.6.1 にも対応しているみたいです。

Windows にはまだ対応していないみたいなので、ソースコードに手を加えないと Windows だと動きませんでしたが。

一応手元の gcc 4.7 でもコンパイルすることが出来ました。

リリースノートとかどこかに載っていないのかな?

2011-10-21

[][]OGLplus で複数の△ポリゴンの描画

oglplus/001_triangle.cpp をベースにして複数のポリゴン描画を行ってみました。


[ソース]

#include <vector>

#define GL_VERSION_4_1
#include <GL/glew.h>

#include <oglplus/gl.hpp>
//#include <oglplus/all.hpp>

#include <oglplus/context.hpp>
#include <oglplus/buffer.hpp>
#include <oglplus/vertex_attrib.hpp>
#include <oglplus/vertex_array.hpp>
#include <oglplus/shader.hpp>
#include <oglplus/program.hpp>

#include <GL/Glut.h>

#include <cstdlib>
#include <gl/graphics.hpp>
#include <boost/thread.hpp>

namespace glp = oglplus;
typedef glp::Context glc;

struct triangle : boost::noncopyable{
    
    triangle(std::initializer_list<GLfloat> triangle_verts){
        // Set the vertex shader source
        vs.Source(R"delimiter(
            #version 330
            in vec3 Position;
            void main(void){
                gl_Position = vec4(Position, 1.0);
            }
        )delimiter");
        
        // compile it
        vs.Compile();

        // set the fragment shader source
        fs.Source(R"delimiter(
            #version 330
            out vec4 fragColor;
            void main(void){
                fragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        )delimiter");
        // compile it
        fs.Compile();

        // attach the shaders to the program
        prog.AttachShader(vs);
        prog.AttachShader(fs);
        // link and use it
        prog.Link();
        prog.Use();

        // bind the VAO for the triangle
        vertex_array.Bind();

        // bind the VBO for the triangle vertices
        verts.Bind(glp::Buffer::Target::Array);
        // upload the data
        glp::Buffer::Data(glp::Buffer::Target::Array,
            triangle_verts.size(),
            triangle_verts.begin()
        );
        // setup the vertex attribs array for the vertices
        glp::VertexAttribArray vert_attr(prog, "Position");
        vert_attr.Setup(3, glp::DataType::Float);
        vert_attr.Enable();
    }
    
    void
    render() const{
        vertex_array.Bind();
        glc::DrawArrays(glp::PrimitiveType::Triangles, 0, 3);
    }
private:
    // Vertex shader
    glp::VertexShader vs;

    // Fragment shader
    glp::FragmentShader fs;

    // Program
    glp::Program prog;

    // A vertex array object for the rendered triangle
    glp::VertexArray vertex_array;
    // VBO for the triangle's vertices
    glp::Buffer verts;
};


int
main(int argc, char *argv[]){
    namespace glp = oglplus;
    typedef glp::Context glc;
    
    gl::graphics g(argc, argv, 500, 500, "test");
    
    // glew の初期化
    auto err = glewInit();
    if (err != GLEW_OK)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }
    
    glc::ClearColor(0.5f, 0.7f, 0.9f, 1.0f);
    glc::ClearDepth(1.0f);

    // △ポリゴンの生成
    triangle obj1({
        0.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    });

    triangle obj2({
         0.0f,  0.0f, 0.0f,
        -1.0f,  0.0f, 0.0f,
         0.0f, -1.0f, 0.0f
    });
    //-------------------------------------------------------------------------
    
    gl::displayfunc(g, [&](){
        glc::Clear().ColorBuffer().DepthBuffer();
        obj1.render();
        obj2.render();
    });
    
    gl::reshapefunc(g, [&](int width, int height){
        glc::Viewport(width, height);
    });

    // キー入力イベント
    gl::keyboardfunc(g, [](unsigned char key, int x, int y){
        if(key == 'q') return exit(0);
    });

    // idle
    gl::idlefunc(g, [&](){
        boost::this_thread::sleep(boost::posix_time::milliseconds(16));
        glutPostRedisplay();
    });

    g.run();
    
    return 0;
}

[出力]

f:id:osyo-manga:20111021204411p:image

描画方法はちょっと変えましたが、大まかな処理はそのままです。

glut の描画処理は、以前 Boost.Geometry で使用したライブラリを使っています。

OpenGL 側の描画処理はまだよく分かっていないですね…。

VAO?VBO? なにそれおいしいの。

Bind とかさっぱり分からん…。


あと上記の場合だとシェーダプログラムが重複しているので Boost.Flyweight とか使ってみたいですね。


[OGLplus]

  • 0.4.0