Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Vala OpenGL ( ValaGL MatrixMath.vala)

ValaGL MatrixMath.vala の演算
Vec4 ( 4次元ベクトル)

Vec4の定義
struct Vec4
*4次元ベクトル
   メンバー
   GLfloat data[4]

  メソッド
  *生成
   Vec4()
       要素が 0 値の Vec4 を生成 (Creates a new vector, zero initialized.)
   Vec4.from_data (GLfloat x, GLfloat y, GLfloat z, GLfloat w)
      要素が {x, y, z, w} の Vec4 を生成
       (Creates a vector whose contents are the copy of the given data.)
   Vec4.from_array (GLfloat[] data)
      要素が配列 data で与えられる Vec4 を生成
      (Creates a vector whose contents are the copy of the given array.)
   Vec4.expand (ref Vec3 vec3, GLfloat w)
      要素が {vec3.x, vec3.y, vec3.z, w} の Vec4 を生成
      (Expands a 3x3 vector plus scalar into a 4x4 vector.)

  *要素間の演算
   void add (ref Vec4 other)
       this(インスタンス)と other ベクトルとの和
      (Adds the given vector, component-wise.)
   void sub (ref Vec4 other)
       this(インスタンス)から other ベクトルを引く
      (Subtracts the given vector, component-wise.)
   void mul_vec (ref Vec4 other)
       this(インスタンス)と other ベクトルとの積
      (Multiplies the given vector, component-wise.)
   void div_vec (ref Vec4 other)
       this(インスタンス)を other ベクトルで割る
     (Divides the given vector, component-wise.)

  *ベクトル演算
   GLfloat dot_product (ref Vec4 other)
       this(インスタンス)と other ベクトルの内積
      (Computes the dot product of this vector and the other vector.)
   void mul (GLfloat factor)
       this(インスタンス)の各要素を factor 倍する
     (Multiplies the vector by the given scalar.)
  void div (GLfloat factor)
       this(インスタンス)の各要素を factor で割る
      (Divides the vector by the given scalar.)
  GLfloat norm ()
       this(インスタンス)ベクトルの大きさを求める
      (Computes the norm of this vector.)
   void normalize ()
       this(インスタンス)ベクトルを規格化する
      (Normalizes this vector, dividing it by its norm.
       If the norm is zero, the result is undefined.)

  *アクセッサー(ゲッター)
   GLfloat x
       data[0] へのアクセッサー
      (Convenience accessor for data[0].)
  GLfloat y
       data[1] へのアクセッサー
     (Convenience accessor for data[1].)
  GLfloat z
      data[2] へのアクセッサー
      (Convenience accessor for data[2].)
  GLfloat w
      data[3] へのアクセッサー
      (Convenience accessor for data[3].)

1 ベクトルの生成
## prog1.vala
using ValaGL.Core;

void main () {
    var a = Vec4.from_data (1.0f, 2.0f, 3.0f, 4.0f);
    // a.x(data[0])= 1.0, a.y(data[1])= 2.0
    // a.z(data[2])= 3.0, a.w(data[3])= 4.0
    stdout.printf ("Vec4 a x:%f y:%f z:%f w:%f\n", a.data[0], a.data[1], a.data[2], a.data[3]);
    stdout.printf ("Vec4 a x:%f y:%f z:%f w:%f\n", a.x, a.y, a.z, a.w);
    stdout.printf("\n");

   var c = Vec3.from_data (5.0f, 6.0f, 7.0f);
    stdout.printf ("Vec3 c x:%f y:%f z:%f\n", c.x, c.y, c.z);
   var b = Vec4.expand (ref c, 8.0f);
    // b.x = 5.0, b.y = 6.0, b.z = 7.0, b.w = 8.0
    stdout.printf ("Vec4 b x:%f y:%f z:%f w:%f\n", b.x, b.y, b.z, b.w);
}

実行結果
Vec4 a x:1.000000 y:2.000000 z:3.000000 w:4.000000
Vec4 a x:1.000000 y:2.000000 z:3.000000 w:4.000000

Vec3 c x:5.000000 y:6.000000 z:7.000000
Vec4 b x:5.000000 y:6.000000 z:7.000000 w:8.000000


2 ベクトル演算
## prog2.vala
using ValaGL.Core;

void main () {
    var a = Vec4.from_data (1.0f, 2.0f, 3.0f, 4.0f);
    stdout.printf ("Vec4 a x:%f y:%f z:%f w:%f\n", a.x, a.y, a.z, a.w);

   var b = Vec4.from_data (8.0f, 7.0f, 6.0f, 5.0f);
    stdout.printf ("Vec4 b x:%f y:%f z:%f w:%f\n", b.x, b.y, b.z, b.w);
    stdout.printf("\n");

   float s = a.dot_product (ref b);
    // s = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    stdout.printf("s: %f\n", s);
    stdout.printf("\n");

   float a_norm = a.norm ();
    // a_norm = SQRT(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w)
    stdout.printf("a_norm: %f\n", a_norm);
    stdout.printf("\n");

   a.normalize ();
    // a.x = a.x/a.norm(), a.y = a.y/a.norm()
    // a.z = a.z/a.norm(), a.w = a.w/a.norm()
    stdout.printf("a x:%f y:%f z:%f w:%f\n", a.x, a.y, a.z, a.w);
    a_norm = a.norm ();
    stdout.printf("a_norm: %f\n", a_norm);
}

実行結果
Vec4 a x:1.000000 y:2.000000 z:3.000000 w:4.000000
Vec4 b x:8.000000 y:7.000000 z:6.000000 w:5.000000

s: 60.000000

a_norm: 5.477226

a x:0.182574 y:0.365148 z:0.547723 w:0.730297
a_norm: 1.000000


ビルド
valac --vapidir=./ --pkg glepoxy -X -lm main.vala MatrixMath.vala

Vala OpenGL ( ValaGL MatrixMath.vala )

ValaGL MatrixMath.vala の演算

前回のブログで使用した、ValaGL MatrixMath.vala の演算について書いています。

 

今回は、Vec3 ( 3次元ベクトル)です。

 

Vec3の定義

struct Vec3

   メンバー
   GLfloat data[3]

   メソッド
  * 生成
   Vec3()
        要素が 0 値の Vec3 を生成
        ( Creates a new vector, zero initialized. )

   Vec3.from_data (GLfloat x, GLfloat y, GLfloat z)
        要素が {x, y, z} Vec3 を生成
       ( Creates a vector whose contents are the copy of the given data. )

   Vec3.from_array (GLfloat data)
        要素が配列 data で与えられる Vec3 を生成
       ( Creates a vector whose contents are the copy of the given array. )

* 要素間の演算
   void add (ref Vec3 other)
       this
インスタンス)と other ベクトルとの和(要素間の和)
       ( Adds the given vector, component-wise. )

   void sub (ref Vec3 other)
       this
インスタンス)から other ベクトルを引く(要素間の差)
       ( Subtracts the given vector, component-wise. )

   void mul_vec (ref Vec3 other)
       this(インスタンス)と other ベクトルの積(要素間の積)
      ( Multiplies the given vector, component-wise. )

   void div_vec (ref Vec3 other)
      this(インスタンス)を other ベクトルで割る(要素間の商) 
      ( Divides the given vector, component-wise. )

   * ベクトル演算
   GLfloat dot_product (ref Vec3 other)
      this(インスタンス)と other ベクトルの内積
      ( Computes the dot product of this vector and the other vector. )

   Vec3 cross_product (ref Vec3 other)
      this(インスタンス)と other ベクトルの外積(thisベクトル ✖️ otherベクトル)
      ( Computes the cross product of this vector and the other vector. )

   void mul (GLfloat factor)
      this(インスタンス)の各要素をfactor倍する 
      ( Multiplies the vector by the given scalar. )

   void div (GLfloat factor)
      this(インスタンス)の各要素をfactorで割る
      ( Divides the vector by the given scalar. )

   GLfloat norm ()
      this(インスタンス)ベクトルの大きさを求める
     ( Computes the norm of this vector. )

   void normalize ()
      this(インスタンス)ベクトルを規格化する
     ( Normalizes this vector, dividing it by its norm.
       If the norm is zero, the result is undefined. )

  *アクセッサー(ゲッター)
  GLfloat x
       data[0]へのアクセッサー
       ( Convenience accessor for data[0]. )

  GLfloat y
       data[1]へのアクセッサー
      ( Convenience accessor for data[1]. )

GLfloat z
       data[2]へのアクセッサー
      ( Convenience accessor for data[2]. )

 

1 ベクトルの生成

## prog1.vala
using ValaGL.Core;

void main () {
    var a = Vec3 ();
    // a.data[0] = 0,  a.data[1] = 0,  a.data[2] = 0
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.data[0], a.data[1], a.data[2]);
    stdout.printf("\n");

    var b = Vec3.from_data (1.0f, 2.0f, 3.0f);
    // b.x(data[0]) = 1.0,  b.y(data[1]) = 2.0,  b.z(data[2]) = 3.0
    stdout.printf ("Vec3 b x:%f y:%f z:%f\n", b.data[0], b.data[1], b.data[2]);
    stdout.printf ("Vec3 b x:%f y:%f z:%f\n", b.x, b.y, b.z);
    stdout.printf("\n");

    float
d = {4.0f, 5.0f, 6.0f};
    var c = Vec3.from_array (d);
    // c.x = 4.0,  c.y = 5.0,  c.z = 6.0
    stdout.printf ("Vec3 c x:%f y:%f z:%f\n", c.x, c.y, c.z);
}

 

実行結果
Vec3 a x:0.000000 y:0.000000 z:0.000000

Vec3 b x:1.000000 y:2.000000 z:3.000000
Vec3 b x:1.000000 y:2.000000 z:3.000000

Vec3 c x:4.000000 y:5.000000 z:6.000000

 

2 要素間の演算

## prog2.vala
using ValaGL.Core;

void main () {
    var a = Vec3.from_data (4.0f, 5.0f, 6.0f);
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    var b = Vec3.from_data (1.0f, 2.0f, 3.0f);
    stdout.printf ("Vec3 b x:%f y:%f z:%f\n", b.x, b.y, b.z);
    stdout.printf("\n");

    a.add (ref b);
    // a.x = a.x + b.x,  a.y = a.y + b.y,  a.z = a.z + b.z
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");

    a.sub (ref b);
    // a.x = a.x - b.x,  a.y = a.y - b.y,  a.z = a.z - b.z
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");

    a.mul_vec (ref b);
    // a.x = a.x * b.x,  a.y = a.y * b.y,  a.z = a.z * b.z
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");


    a.div_vec (ref b);
    // a.x = a.x / b.x,  a.y = a.y / b.y,  a.z = a.z / b.z
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");
}

 

実行結果
Vec3 a x:4.000000 y:5.000000 z:6.000000
Vec3 b x:1.000000 y:2.000000 z:3.000000

Vec3 a x:5.000000 y:7.000000 z:9.000000

Vec3 a x:4.000000 y:5.000000 z:6.000000

Vec3 a x:4.000000 y:10.000000 z:18.000000

Vec3 a x:4.000000 y:5.000000 z:6.000000

 

3 ベクトル演算

## prog3.vala
using ValaGL.Core;

void main () {
    var a = Vec3.from_data (4.0f, 5.0f, 6.0f);
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    var b = Vec3.from_data (1.0f, 2.0f, 3.0f);
    stdout.printf ("Vec3 b x:%f y:%f z:%f\n", b.x, b.y, b.z);
    stdout.printf("\n");

    float s = a.dot_product (ref b);
    // s = a.x*b.x + a.y*b.y + a.z*b.z
    stdout.printf("s: %f\n", s);
    stdout.printf("\n");

    Vec3 c = a.cross_product (ref b);
    // c.x = a.y*b.z - a.z*b.y,  c.y = a.z*b.x - a.x*b.z,  c.z = a.x*b.y - a.y*b.x
    stdout.printf ("Vec3 c x:%f y:%f z:%f\n", c.x, c.y, c.z);
    stdout.printf("\n");

    a.mul (2);
    // a.x = a.x * 2,  a.y = a.y * 2,  a.z = a.z * 2
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");

    a.div (2);
    // a.x = a.x / 2,  a.y = a.y / 2,  a.z = a.z / 2
    stdout.printf ("Vec3 a x:%f y:%f z:%f\n", a.x, a.y, a.z);
    stdout.printf("\n");

    float b_norm = b.norm ();
    // b_norm = SQRT( b.x*b.x + b.y*b.y + b.z*b.z)
    stdout.printf ("norm b : %f\n", b_norm);
    stdout.printf("\n");

    b.normalize ();
    // b.x = b.x / b.norm(),  b.y = b.y / b.norm(),   b.z = b.z / b.norm()
    stdout.printf ("b x:%f y:%f z:%f\n", b.x, b.y, b.z);
    stdout.printf ("b norm = %f\n", b.norm());
    stdout.printf("\n");
}

 

実行結果
Vec3 a x:4.000000 y:5.000000 z:6.000000
Vec3 b x:1.000000 y:2.000000 z:3.000000

s: 32.000000

Vec3 c x:3.000000 y:-6.000000 z:3.000000

Vec3 a x:8.000000 y:10.000000 z:12.000000

Vec3 a x:4.000000 y:5.000000 z:6.000000

norm b : 3.741657

b x:0.267261 y:0.534522 z:0.801784
b norm = 1.000000

 

*ビルド
valac --vapidir=./ --pkg glepoxy -X -lm prog1.vala MatrixMath.vala
( glepoxy.vapi も必要)

ValaGL + Gtk.GLArea ( Vala & OpenGL)

f:id:onagat12:20160619142808g:plain

 

実行結果

(実際の実行では、スペースキーで、cubeが回転、停止します。)

 

下記のサイトで、Vala, SDL, GLEW で記述された、OpenGL 3.x に対応したrotating cubeアプリケーションが紹介されています。

30/03/2013) ValaGL(simple skeletal application)

https://github.com/lucidfox/valagl)

 

lucidfox | Vala and Modern OpenGL

http://lucidfox.dreamwidth.org/11614.html

http://en.lucidfox.org/2013/03/vala-and-modern-opengl/

 

1 GL 3.x APIに対応した vapiの作成

2 vec3vec4に対応したmatrix vector algebra、またprojections(camera)

   model matrix transformationsのVala言語による再実装

がなされています。

 

今回は、これらのプログラムを用いて、Gtk.GLArea上に同じrotating cubeを描画

します。

使用するプログラム

1 vapi

GLAreaでは、GLライブラリとしてepoxyを用いています。これに対応するように、

ここでは、CヘッダーファイルをGL/glew.hからepoxy/gl.hに変更しています。

(glepoxy.vapi)

 

2 ValaGL.Core内のプログラム

GLProgram.valaVBO.valaIBO.valaCoreError.valaCamera.vala

    MatrixMath.valaGeometryUtils.vala

(1) VBO.valaCoreError.valaCamera.valaMatrixMath.valaGeometryUtils.vala

     は変更なしで使用します。

(2) IBO.vala

     1コメントアウトします。

     52行目 //glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);

(3) GLProgram.vala

   変更します。下記参照。

 

3   main.vala (App.valaに相当)

## main.vala

using Gtk;

using Gdk;

 

public class MainWindow : Gtk.Window

{

    private glArea gl_area;

    private float angle = 0.0f;

    private uint tick_id;

    private bool isRunning = false;

 

    public MainWindow ()

    {

        title = "GLArea Test";

        destroy.connect (Gtk.main_quit);

        set_events (EventMask.KEY_PRESS_MASK );

 

        var box = new Box (Orientation.VERTICAL, 0);

 

        gl_area = new glArea ();

 

        this.key_press_event.connect ((evt) => {

            if (evt.keyval == Gdk.Key.space) {

                GLib.message ("Key Pressed");

                if (isRunning == false) {

                    tick_id = gl_area.add_tick_callback (tick);

                } else {

                   gl_area.remove_tick_callback (tick_id);

                }

                isRunning = !isRunning;

           }

           return true;

        });

 

        var button = new Button.with_label ("Quit");

        button.clicked.connect (Gtk.main_quit);

 

        box.pack_start (gl_area, true, true);

        box.pack_start (button, false, false);

        add (box);

    }

 

    private bool tick (Widget widget, FrameClock frame_clock)

    {

        angle = angle + 1.0f;

        stdout.printf("angle: %f\n", angle);

        gl_area.update_scene_data(angle);

        gl_area.queue_render ();

 

        return true;

    }

}

 

int main (string args)

{

    Gtk.init (ref args);

 

    var mainWindow = new MainWindow();

    mainWindow.show_all ();

 

    Gtk.main ();

 

    return 0;

}

 

4   glArea.vala (Canvas.valaに相当)

## glArea.vala

using Gtk;

using Gdk;

using GL;

using ValaGL.Core;

 

public class glArea : Gtk.GLArea

{

    private GLuint vao = {0};

    private GLProgram gl_program;

    private VBO coord_vbo;

    private VBO color_vbo;

    private IBO element_ibo;

    private GLint mvp_location;

    private float rotation_angle;

 

    private GLfloat cube_vertices = {

        // front

        -1, -1, 1,

         1, -1, 1,

         1, 1, 1,

        -1, 1, 1,

        // back

        -1, -1, -1,

         1, -1, -1,

         1, 1, -1,

        -1, 1, -1

    };

 

    private GLfloat cube_colors = {

        // front colors

        1, 0, 0,

        0, 1, 0,

        0, 0, 1,

        1, 1, 1,

        // back colors

        1, 0, 0,

        0, 1, 0,

        0, 0, 1,

        1, 1, 1

    };

 

    private GLushort cube_elements = {

        // front

        0, 1, 2,

        2, 3, 0,

        // top

        1, 5, 6,

        6, 2, 1,

        // back

        7, 6, 5,

        5, 4, 7,

        // bottom

        4, 0, 3,

        3, 7, 4,

        // left

        4, 5, 1,

        1, 0, 4,

        // right

        3, 2, 6,

        6, 7, 3

    };

 

    public glArea ()

    {

        set_size_request (500, 400);

        has_depth_buffer = true;

        render.connect (on_render);

    }

 

    private bool on_render (GLContext contxt)

    {

        stdout.printf ("render\n");

        // realize

 

        glGenVertexArrays(1, vao);

        glBindVertexArray(vao[0]);

 

        try {

            gl_program = new GLProgram();

            coord_vbo = new VBO(cube_vertices);

            color_vbo = new VBO(cube_colors);

            element_ibo = new IBO(cube_elements);

        } catch (CoreError e) {

            stdout.printf("CoreError: %s\n", e.message);

        }

 

        mvp_location = gl_program.get_uniform_location("MVP");

 

        glEnableVertexAttribArray(0);

        coord_vbo.apply_as_vertex_array(0, 3);

        glEnableVertexAttribArray(1);

        color_vbo.apply_as_vertex_array(1, 3);

 

        glBindVertexArray(0);

 

        // render

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

 

        var camera = new Camera ();

        camera.set_perspective_projection (70.0f, 5.0f/4.0f, 0.01f, 100.0f);

 

        var eye = Vec3.from_data (0, 2, 0);

        var center = Vec3.from_data (0, 0, -2);

        var up = Vec3.from_data (0, 1, 0);

        camera.look_at (ref eye, ref center, ref up);

 

        var model_matrix = Mat4.identity ();

        Vec3 translation = Vec3.from_data (0, 0, -4);

        GeometryUtil.translate (ref model_matrix, ref translation);

        Vec3 rotation = Vec3.from_data (0, 1, 0);

        GeometryUtil.rotate (ref model_matrix, rotation_angle, ref rotation);

 

        gl_program.make_current();

        camera.apply (mvp_location, ref model_matrix);

 

        glBindVertexArray(vao[0]);

        glDrawElements((GLenum)GL_TRIANGLES, cube_elements.length,

       GL_UNSIGNED_SHORT, null);

 

        glBindVertexArray (0);

        glUseProgram (0);

 

        glFlush();

 

        return true;

    }

 

    public void update_scene_data (float angle)

    {

        rotation_angle = angle;

    }

}

depth_bufferを有効にするには、GLAreaクラスのプロパティhas_depth_buffer

trueにします。

 

 

5   GLProgram.vala

vertex shaderfragment shaderをここに記述します。これは、前回(2015/11/15

説明したワーニングが出ないようにするためです。各shaderプログラムを直接glShaderSource()に渡します。

(1) shaderプログラムをクラス定義(public class GLProgram)の前に挿入します。

## vertex shader

const string vert_src = {

    "#version 330 core\n" +

    "layout(location = 0) in vec3 coord3d;\n" +

    "layout(location = 1) in vec3 v_color;\n" +

    "out vec3 f_color;\n" +

    "uniform mat4 MVP;\n" +

    "void main() {\n" +

    " f_color = v_color;\n" +

    " gl_Position = MVP * vec4(coord3d, 1.0);\n" +

    "}"};

 

## fragment shader

    const string[] frag_src = {

    "#version 330 core\n" +

    "in vec3 f_color;\n" +

    "void main() {\n" +

    " gl_FragColor = vec4(f_color.x, f_color.y, f_color.z, 1.0);\n" +

    "}"};

 

(2) shaderプログラムが関連する引数を削除し、変更します。

public GLProgram () throws CoreError

vertex_shader = create_shader (GL_VERTEX_SHADER)

  fragment_shaderも同様。

 

(3) shaderプログラムの読込み部分を変更します。

create_shader_from_file メソッドは使用しない。

private static Gluint create_shader (Gluint shader_type) throws CoreErroe

if (shader_type == GL_VERTEX_SHADER) {

        glShaderSource (shader, 1, vert_src, null);

    } else {

        glShaderSource (shader, 1, frag_src, null);

    }

 

* プログラム

ValaGL-GLArea.zip (http://yahoo.jp/box/PhHb1j )

 

* ビルド

valac --vapidir=./ --pkg gtk+-3.0 --pkg gdk-pixbuf-2.0 --pkg glepoxy -X -lepoxy -X -lm

main.vala glArea.vala Camera.vala MatrixMath.vala GeometryUtil.vala GLProgram.vala

VBO.vala IBO.vala CoreError.vala

 

Genie + OpenGL(3)

前回プログラム(Genie + OpenGL)のワーニング

前回使用したプログラム(testglarea.gsglarea.gs)とvapiでは、glShaderSource関数に関して、以下のようなワーニングが出ていました。

** ワーニング **

testglarea.vala.c: 関数 ‘main_window_on_realize’ :

testglarea.vala.c:150:39: 警告: 互換性のないポインタ型から 3 番目の ‘epoxy_glShaderSource’ の引数に渡しています [-Wincompatible-pointer-types]

glShaderSource (_tmp3_, (GLsizei) 1, &vert_src, NULL);

^

testglarea.vala.c:150:39: 備考: expected ‘const GLchar * const* {aka const char * const*}’ but argument is of type ‘GLchar ** {aka char **}’

vertex shaderfragment shaderの両方で出てきます。)

 

関連するプログラムとvapiの部分は以下のようになっています。

プログラム

    vert_src : GLchar* = "#version 330\n \n in vec4 position;\n void main() {\n gl_Position = position;\n }";

    glShaderSource(vert_shader, 1, &vert_src, null);

  (vert_src変数はポインターとして扱っています。)

vapi

    public void glShaderSource (GLuint shader, GLsizei count, GLchar* *source, GLint* length);

 

今回、この部分をワーニングが出ないように修正しました。

プログラム

    const vert_src : array of string = {"#version 330\n \n in vec4 position;\n void main() {\n gl_Position = position;\n }"};

    glShaderSource(vert_shader, 1, vert_src, null);

vapi

    public void glShaderSource (GLuint shader, GLsizei count, string *source, GLint* length);

 

glepoxy.vapi

 

##testglarea.gs

uses

    Gtk

    GL

 

init

    Gtk.init (ref args)

    var mainWindow = new MainWindow()

    mainWindow.show_all ()

    Gtk.main ()

 

const vert_src : array of string = {"#version 330\n \n in vec4 position;\n void main() {\n gl_Position = position;\n }"};

const frag_src : array of string = {"#version 330\n \n out vec4 outputColor;\n void main() {\n outputColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n }"};

 

class MainWindow : Window

     gl_vao : GLuint = 0

     gl_program : GLuint

 

     init

         title = "GLArea Test"

         destroy.connect (Gtk.main_quit)

 

         var box = new Box (Orientation.VERTICAL, 0)

 

         var glarea = new GLArea ()

         glarea.set_size_request (500, 400)

         glarea.render.connect (on_glarea_render)

 

         var button = new Button.with_label ("Quit")

         button.clicked.connect (Gtk.main_quit)

 

         box.pack_start (glarea, true, true)

         box.pack_start (button, false, false)

         add (box)

 

         def on_realize (cntxt:Gdk.GLContext)

         print ("realize")

 

         gl_buffer : GLuint = 0

 

         /// realize

         verts : array of float = { +0.0f, +1.0f, -1.0f, -1.0f, +1.0f, -1.0f}

 

         vert_shader : GLuint

         frag_shader : GLuint

         compileSuccess : GLint = 0

 

         vert_shader = glCreateShader (GL_VERTEX_SHADER);

         frag_shader = glCreateShader (GL_FRAGMENT_SHADER);

 

         glShaderSource(vert_shader, 1, vert_src, null);

         glCompileShader(vert_shader);

         glGetShaderiv (vert_shader, GL_COMPILE_STATUS, out compileSuccess);

         if compileSuccess == GL_FALSE do print ("vert-shader Error")

 

         glShaderSource(frag_shader, 1, frag_src, null);

         glCompileShader(frag_shader);

         glGetShaderiv (frag_shader, GL_COMPILE_STATUS, out compileSuccess);

         if compileSuccess == GL_FALSE do print ("frag-shader Error")

 

         gl_program = glCreateProgram();

         glAttachShader(gl_program, vert_shader);

         glAttachShader(gl_program, frag_shader);

         glLinkProgram(gl_program);

 

         glGenVertexArrays(1, out gl_vao);

         glBindVertexArray(gl_vao);

 

         glGenBuffers(1, out gl_buffer);

         glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);

         glBufferData(GL_ARRAY_BUFFER, sizeof(float)*verts.length, verts, GL_STATIC_DRAW);

 

         glEnableVertexAttribArray(0);

         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

         glBindVertexArray(0);

 

         glDeleteBuffers(1, out gl_buffer);

 

     def on_glarea_render (cntxt:Gdk.GLContext): bool

         print ("render")

         on_realize (cntxt)

         /// render

         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

 

         glUseProgram(gl_program);

         glBindVertexArray(gl_vao);

         glDrawArrays(GL_TRIANGLES, 0, 3);

 

         glBindVertexArray (0);

         glUseProgram (0);

 

         glFlush();

 

         return true

Genie + OpenGL(Gtk.GLArea)2

f:id:onagat12:20151114174806p:plain

gtk3-demoにあるGLAreaデモをGenie言語で書き直しました。

(単独のプログラムは、gtk+-3.16ソース内のtestsにあります。testglarea.c

testglarea.gs(前回のプログラム)と同じglepoxy.vapiを使っています。

 

##glarea.gs

uses

    Gtk

    GL

 

init

    Gtk.init (ref args)

    var mainWindow = new MainWindow()

    mainWindow.show_all ()

    Gtk.main ()

 

class MainWindow : Window

    glarea : GLArea

    scale_x : Scale

    scale_y : Scale

    scale_z : Scale

    phi : float

    theta : float

    psi : float

 

    gl_vao : GLuint = 0

    gl_program : GLuint

    mvp_location : GLint

 

    init

        title = "GLArea Test"

        border_width = 12;

        destroy.connect (Gtk.main_quit)

 

        var box = new Box (Orientation.VERTICAL, 0)

        box.spacing = 6;

 

        glarea = new GLArea ()

        glarea.set_size_request (400, 400)

        glarea.render.connect (on_glarea_render)

 

        var controls = new Box (Orientation.VERTICAL, 0)

        var slider_x = new Box (Orientation.HORIZONTAL, 0)

        var slider_y = new Box (Orientation.HORIZONTAL, 0)

        var slider_z = new Box (Orientation.HORIZONTAL, 0)

 

        var label_x = new Label ("X axis ")

        var label_y = new Label ("Y axis ")

        var label_z = new Label ("Z axis ")

        scale_x = new Scale.with_range (Orientation.HORIZONTAL, 0, 360, 2)

        scale_y = new Scale.with_range (Orientation.HORIZONTAL, 0, 360, 2)

        scale_z = new Scale.with_range (Orientation.HORIZONTAL, 0, 360, 2)

        scale_x.value_changed.connect (on_value_changed)

        scale_y.value_changed.connect (on_value_changed)

        scale_z.value_changed.connect (on_value_changed)

 

        slider_x.pack_start (label_x, false, false, 0)

        slider_x.pack_start (scale_x)

        slider_y.pack_start (label_y, false, false, 0)

        slider_y.pack_start (scale_y)

        slider_z.pack_start (label_z, false, false, 0)

        slider_z.pack_start (scale_z)

 

        controls.pack_start (slider_x, false, false, 0)

        controls.pack_start (slider_y, false, false, 0)

        controls.pack_start (slider_z, false, false, 0)

 

        var button = new Button.with_label ("Quit")

        button.clicked.connect (Gtk.main_quit)

 

        box.pack_start (glarea, true, true)

        box.pack_start (controls, false, false)

        box.pack_start (button, false, false)

        add (box)

 

    def on_value_changed ()

        print("value-changed")

        phi = (float)scale_x.get_value ()

        theta = (float)scale_y.get_value ()

        psi = (float)scale_z.get_value ()

        print("phi: %f", phi)

        print("theta: %f", theta)

        print("psi: %f", psi)

 

        glarea.queue_render ()

 

    def on_realize (cntxt:Gdk.GLContext)

        print ("realize")

 

        gl_buffer : GLuint = 0

 

        vert_src : GLchar* = "#version 330\n \n in vec4 position;\n uniform mat4 mvp;\n void main() {\n gl_Position = mvp * position;\n }";

 

        frag_src : GLchar* = "#version 330\n \n out vec4 outputColor;\n void main() {\n outputColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n }";

 

        /// realize

        verts : array of float = { +0.0f, +1.0f, -1.0f, -1.0f, +1.0f, -1.0f}

 

        vert_shader : GLuint

        frag_shader : GLuint

        compileSuccess : GLint = 0

 

        vert_shader = glCreateShader (GL_VERTEX_SHADER);

        frag_shader = glCreateShader (GL_FRAGMENT_SHADER);

 

        glShaderSource(vert_shader, 1, &vert_src, null);

        glCompileShader(vert_shader);

        glGetShaderiv (vert_shader, GL_COMPILE_STATUS, out compileSuccess);

        if compileSuccess == GL_FALSE do print ("vert-shader Error")

 

        glShaderSource(frag_shader, 1, &frag_src, null);

        glCompileShader(frag_shader);

        glGetShaderiv (frag_shader, GL_COMPILE_STATUS, out compileSuccess);

        if compileSuccess == GL_FALSE do print ("frag-shader Error")

 

        gl_program = glCreateProgram();

        glAttachShader(gl_program, vert_shader);

        glAttachShader(gl_program, frag_shader);

        glLinkProgram(gl_program);

 

        mvp_location = glGetUniformLocation (gl_program, "mvp");

 

        glGenVertexArrays(1, out gl_vao);

        glBindVertexArray(gl_vao);

 

        glGenBuffers(1, out gl_buffer);

        glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);

        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*verts.length, verts, GL_STATIC_DRAW);

 

        glEnableVertexAttribArray(0);

        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

        glBindVertexArray(0);

 

        glDeleteBuffers(1, out gl_buffer);

 

    def on_glarea_render (cntxt:Gdk.GLContext): bool

        print ("render")

        on_realize (cntxt)

        /// render

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

 

        var mvp = new array of float[16]

        compute_mvp (out mvp, phi, theta, psi)

 

        glUseProgram(gl_program);

        glUniformMatrix4fv (mvp_location, 1, GL_FALSE, &mvp[0]);

        glBindVertexArray(gl_vao);

        glDrawArrays(GL_TRIANGLES, 0, 3);

 

        glBindVertexArray (0);

        glUseProgram (0);

 

        glFlush();

 

        return true

 

    def compute_mvp (out res:array of float, phi:float, theta:float, psi:float)

        print "compute mvp"

 

        res = new array of float[16]

        x : float = phi * ((float)Math.PI / 180.0f)

        y : float = theta * ((float)Math.PI / 180.0f)

        z : float = psi * ((float)Math.PI / 180.0f)

        print "x: %f", x

        print "y: %f", y

        print "z: %f", z

        c1:float = Math.cosf(x); s1:float = Math.sinf(x);

        c2:float = Math.cosf(y); s2:float = Math.sinf(y);

        c3:float = Math.cosf(z); s3:float = Math.sinf(z);

        var c3c2 = c3 * c2

        var s3c1 = s3 * c1

        var c3s2s1 = c3 * s2 * s1

        var s3s1 = s3 * s1

        var c3s2c1 = c3 * s2 * c1

        var s3c2 = s3 * c2

        var c3c1 = c3 * c1

        var s3s2s1 = s3 * s2 * s1

        var c3s1 = c3 * s1

        var s3s2c1 = s3 * s2 * c1

        var c2s1 = c2 * s1

        var c2c1 = c2 * c1

 

        res[0] = 1.0f; res[4] = 0.0f; res[8] = 0.0f; res[12] = 0.0f;

        res[1] = 0.0f; res[5] = 1.0f; res[9] = 0.0f; res[13] = 0.0f;

        res[2] = 0.0f; res[6] = 0.0f; res[10] = 1.0f; res[14] = 0.0f;

        res[3] = 0.0f; res[7] = 0.0f; res[11] = 0.0f; res[15] = 1.0f;

 

        res[0] = c3c2;  res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.0f;

        res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.0f;

        res[2] = s2;      res[6] = -c2s1;              res[10] = c2c1;              res[14] = 0.0f;

        res[3] = 0.0f;   res[7] = 0.0f;                  res[11] = 0.0f;               res[15] = 1.0f;

 

 

ビルド

valac --vapidir=vapi --pkg gtk+-3.0 --pkg glepoxy -X -lepoxy -X -lm glarea.gs

Glibの数学ライブラリを使用しているので、 “-X -lm”のオプションを入れています。

Genie + OpenGL(Gtk.GLArea)

f:id:onagat12:20151114135737p:plain

gtk+-3.16から、Gtk.GLArea ウィジェが追加され、GtkWindow内で簡単にOpenGLプログラミングが出来るようになりました。OpenGL context等が自動的に設定されます。

OpenGLライブラリとして、epoxyライブラリを使用しています。

 

Gtk.GLArea ウィジェ とOpenGLを使って、三角形を描画しています。

Genie言語で記述しています。

 

vapigles2.vapiを参考に、epoxyライブラリで使用できるように追加・修正をしています。

glepoxy.vapi

glShaderSource()関数で、シェーダーファイルの指定が上手く処理できていません。

ポインターを使って記述しています。(ワーニングが出ます。)

 

##testglarea.gs

uses

    Gtk

    GL

 

init

    Gtk.init (ref args)

    var mainWindow = new MainWindow()

    mainWindow.show_all ()

    Gtk.main ()

 

class MainWindow : Window

    gl_vao : GLuint = 0

    gl_program : GLuint

 

    init

        title = "GLArea Test"

        destroy.connect (Gtk.main_quit)

 

        var box = new Box (Orientation.VERTICAL, 0)

 

        var glarea = new GLArea ()

        glarea.set_size_request (500, 400)

        glarea.render.connect (on_glarea_render)

 

        var button = new Button.with_label ("Quit")

        button.clicked.connect (Gtk.main_quit)

 

        box.pack_start (glarea, true, true)

        box.pack_start (button, false, false)

        add (box)

 

   def on_realize (cntxt:Gdk.GLContext)

        print ("realize")

 

        gl_buffer : GLuint = 0

 

        vert_src : GLchar* = "#version 330\n \n in vec4 position;\n void main() {\n gl_Position = position;\n }";

 

        frag_src : GLchar* = "#version 330\n \n out vec4 outputColor;\n void main() {\n outputColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n }";

 

        /// realize

        verts : array of float = { +0.0f, +1.0f, -1.0f, -1.0f, +1.0f, -1.0f}

 

        vert_shader : GLuint

        frag_shader : GLuint

        compileSuccess : GLint = 0

 

        vert_shader = glCreateShader (GL_VERTEX_SHADER);

        frag_shader = glCreateShader (GL_FRAGMENT_SHADER);

 

        glShaderSource(vert_shader, 1, &vert_src, null);

        glCompileShader(vert_shader);

        glGetShaderiv (vert_shader, GL_COMPILE_STATUS, out compileSuccess);

        if compileSuccess == GL_FALSE do print ("vert-shader Error")

 

        glShaderSource(frag_shader, 1, &frag_src, null);

        glCompileShader(frag_shader);

        glGetShaderiv (frag_shader, GL_COMPILE_STATUS, out compileSuccess);

        if compileSuccess == GL_FALSE do print ("frag-shader Error")

 

        gl_program = glCreateProgram();

        glAttachShader(gl_program, vert_shader);

        glAttachShader(gl_program, frag_shader);

        glLinkProgram(gl_program);

 

        glGenVertexArrays(1, out gl_vao);

        glBindVertexArray(gl_vao);

 

        glGenBuffers(1, out gl_buffer);

        glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);

        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*verts.length, verts, GL_STATIC_DRAW);

 

        glEnableVertexAttribArray(0);

        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

        glBindVertexArray(0);

 

        glDeleteBuffers(1, out gl_buffer);

 

   def on_glarea_render (cntxt:Gdk.GLContext): bool

        print ("render")

        on_realize (cntxt)

        /// render

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

 

        glUseProgram(gl_program);

        glBindVertexArray(gl_vao);

        glDrawArrays(GL_TRIANGLES, 0, 3);

 

        glBindVertexArray (0);

        glUseProgram (0);

 

        glFlush();

 

        return true

 

 

ビルド

valac --vapidir=../vapi --pkg gtk+-3.0 --pkg glepoxy -X -lepoxy testglarea.gs

Genie Image Viewer 2 (GtkStack)

f:id:onagat12:20150619121114p:plain

プログラムを実行したところ

 

f:id:onagat12:20150619121135p:plain

一覧表示(List)から画像を選択し、拡大表示(Large)ボタンを押すとページが

遷移し拡大画像が表示される。

 

前回のimage-viewerプログラムをGtkStackを使って書き直しました。
clutter-gtkを使用しています。
・ファイルの読み込み、前回と同様。
・ファイルパスリストの作成、前回と同様。
・画像の表示、前回と同様。

## image-viewer-stack-gs.gs
uses
    GtkClutter
    Clutter

init
     if GtkClutter.init(ref args) != InitError.SUCCESS
        print "Clutter init error"

    var win = new MainWindow ()
    win.show_all ()

    Gtk.main ()

class MainWindow : Gtk.Window
    image : Image
    actor2 : Clutter.Actor
    filename : string
    IMAGE_DIR_PATH : string = "../images/"
    STAGE_WIDTH : int = 600
    STAGE_HEIGHT : int = 600
    THUMBNAIL_SIZE : int = 150
    ROW_COUNT : int = 4
    COL_COUNT : int = 3

    init
        title = "ImageViewer"
        window_position = Gtk.WindowPosition.CENTER
        default_width = 620
        default_height = 650
        border_width = 10
        destroy.connect(Gtk.main_quit)

        var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 5)
        add(box)

        var stack = new Gtk.Stack()
        stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT
        stack.transition_duration = 1000
   
        var widget1 = new Embed ()
        var stage1 = widget1.get_stage ()
        stage1.width = stage1.height = STAGE_WIDTH
        var widget2 = new Embed ()
        var stage2 = widget2.get_stage ()
        stage2.width = stage2.height = STAGE_WIDTH

        var img_path_list = new list of string

        try
            var directory = File.new_for_path (IMAGE_DIR_PATH)
            var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME, 0)

            file_info : FileInfo
            while (file_info = enumerator.next_file ()) != null
                filename = file_info.get_name ()
                //stdout.printf ("%s\n", file_info.get_name ());
                //stdout.printf ("%s\n", filename)
                img_path_list.add (filename)
        except e:Error
            print "Message: %s", e.message

        //stdout.printf ("%s\n", filename)
        print " "
        for s in img_path_list
            print s

        for var row = 0 to (ROW_COUNT - 1)
            for var col = 0 to (COL_COUNT - 1)
                var s = img_path_list[row * COL_COUNT + col]

                try
                    var pixbuf = new Gdk.Pixbuf.from_file (IMAGE_DIR_PATH + s)
                    image = new Image ()
                    image.set_data (pixbuf.get_pixels (),
                            pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888,
                            pixbuf.width,
                            pixbuf.height,
                            pixbuf.rowstride)
                except e:Error
                    print "Message: %s", e.message

                var actor = new Clutter.Actor ()
                actor.content = image
                actor.set_size (THUMBNAIL_SIZE, THUMBNAIL_SIZE)
                actor.set_position (row * THUMBNAIL_SIZE, col * THUMBNAIL_SIZE)
                actor.reactive = true
                actor.button_press_event.connect (actor_clicked_cb)
                stage1.add_child (actor);

        stack.add_titled(widget1, "list", "List")

        actor2 = new Clutter.Actor ()
        actor2.set_size (STAGE_WIDTH, STAGE_HEIGHT)
        stage2.add_child (actor2)
        stack.add_titled(widget2, "large", "Large")

        var switcher = new Gtk.StackSwitcher()
        switcher.set_stack(stack)
        box.pack_start(switcher, false, false, 0)
        box.pack_start(stack, true, true, 0)

    def actor_clicked_cb (actor:Clutter.Actor, evt:ButtonEvent) : bool
        print "Clicked"

        var image2  = new Clutter.Image ()
        image2 = (Clutter.Image)actor.content
        actor2.content = image2

        return true

 

ビルド
valac --pkg gtk+-3.0 --pkg clutter-gtk-1.0 --pkg gee-0.8 image-viewer-stack-gs.gs