Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Vala OepnGL ( ValaGL MatrixMath.vala )

ValaGL MatrixMath.vala の演算
Mat3(3x3 行列)

Mat3 の定義
struct Mat3
  メンバー
  float data[9]
      Mat3 の各要素
      m11(data[0]), m12(data[3]), m13(data[6])
      m21(data[1]), m22(data[4]), m23(data[7])
      m31(data[2]), m32(data[5]), m33(data[8])

  メソッド
  *生成
  Mat3()
      要素が 0 値の Mat3 を生成
      (Creates a new matrix, zero initialized.)
  Mat3.from_data (GLfloat a11, GLfloat a12, GLfloat a13,
    GLfloat a21, GLfloat a22, GLfloat a23,
    GLfloat a31, GLfloat a32, GLfloat a33)
      要素が、以下のようになる Mat3 を生成
      m11 = a11, m12 = a12, m13 = a13
      m21 = a21, m22 = a22, m23 = a23
      m31 = a31, m32 = a32, m33 = a33
      (Creates a matrix whose contents are the copy of the given data.
       Warning: the data are specified in column-first-index order,
       which is different from the internal storage format
       (row-first-index).)

  Mat3.from_vec_mul (ref Vec3 a, ref Vec3 b)
      2つの Vec3 a, b から Mat3 を生成(a * bT の計算、bT は b の
      転置ベクトル)
      m11 = a.x * b.x, m12 = a.x * b.y, m13 = a.x * b.z
      m21 = a.y * b.x, m22 = a.y * b.y, m23 = a.y * b.z
      m31 = a.z * b.x, m32 = a.z * b.y, m33 = a.z * b.z
      (Given two vectors a and b, computes a matrix equal to a * bT.)
  Mat3.from_array (GLfloat data)
      要素が配列 data で与えられる Mat3 を生成
      m11 = data[0], m12 = data[3], m13 = data[6]
      m21 = data[1], m22 = data[4], m23 = data[7]
      m31 = data[2], m32 = data[5], m33 = data[8]
      (Creates a matrix whose contents are the copy of the given
       array,assumed to have at least 9 elements.)
  Mat3.identity ()
      単位行列を生成
      m11 = 1, m12 = 0, m13 = 0
      m21 = 0, m22 = 1, m23 = 0
      m31 = 0, m32 = 0, m33 = 1
      (Creates an identity matrix.)

  *ベクトル演算
  void add (ref Mat3 other)
      this(インスタンス)と other 行列との和(要素間の和)
      (Adds the given matrix, component-wise.)
  void sub (ref Mat3 other)
      this(インスタンス)と other 行列との差(要素間の差)
      this から other 行列を引く
      (Subtracts the given matrix, component-wise.)

  void mul (GLfloat factor)
      this(インスタンス)の各要素をfactor倍する
      (Multiplies the matrix by the given scalar, component-wise.)
  void div (GLfloat factor)
      this(インスタンス)の各要素をfactorで割る
      (Divides the matrix by the given scalar, component-wise.)

      void mul_mat (ref Mat3 other)
      this(インスタンス、Mat3)と other 行列(Mat3)の積
     ( this × other )
      m11 = m11*other11 + m12*other21 + m13*other31
      m12 = m11*other12 + m12*other22 + m13*other32
      m13 = m11*other13 + m12*other23 + m13*other33
      m21 = m21*other11 + m22*other21 + m23*other31
      m22 = m21*other12 + m22*other22 + m23*other32
      m23 = m21*other13 + m22*other23 + m23*other33
      m31 = m31*other11 + m32*other21 + m33*other31
      m32 = m31*other12 + m32*other22 + m33*other32
      m33 = m31*other13 + m32*other23 + m33*other33
      (Multiplies the given matrix using the linear algebra definition
       of matrix multiplication.)
  Vec3 mul_vec (ref Vec3 vec)
      this(インスタンス, Mat3)と vec ベクトル(Vec3) の積
      ( this × vec )
      生成されるベクトル(Vec3): v
      v.x = m11*vec.x + m12*vec.y + m13*vec.z
      v.y = m21*vec.x + m22*vec.y + m23*vec.z
      v.z = m31*vec.x + m32*vec.y + m33*vec.z
      (Multiplies this matrix by the given vector and returns the result
       as a new vector.)
  Mat3 transposed ()
      this(インスタンス, Mat3)の転置行列を生成
      生成される転置行列(Mat3): A
      a11 = m11, a12 = m21, a13 = m31
      a21 = m12, a22 = m22, a23 = m32
      a31 = m13, a32 = m23, a33 = m33
      Returns a new matrix that is the transposition of this matrix.
  GLfloat det ()
      this(インスタンス, Mat3)の行列式を計算
      行列式の値: D
      D = m11*(m22*m31 - m32*m23) - m12*(m21*m33 - m31*m23)
         + m13*(m21*m32 - m31*m22)
      Computes the determinant of this matrix.
  Mat3 inverted (out bool success)
      this(インスタンス, Mat3)の逆行列を生成
      this(インスタンス)の行列式の値: D
      生成される逆行列(Mat3): A
      逆行列が存在しない場合(D = 0)、success に "false" が設定
         される。
      逆行列が存在する場合(D ≠ 0)、success に "true" が設定され、
         逆行列が生成される。
      a11 = (m22*m33 - m32*m23) / D
      a12 = -(m12*m33 - m32*m13) / D
      a13 = (m12*m23 - m22*m13) / D
      a21 = -(m21*m33 - m31*m23) / D
      a22 = (m11*m33 - m31*m13) / D
      a23 = -(m11*m23 - m21*m13) / D
      a31 = (m21*m32 - m31*m22) / D
      a32 = -(m11*m32 - m31*m12) / D
      a33 = (m11*m22 - m21*m12) / D
      Returns a new matrix that is the inversion of this matrix.
      @param success Set to ``false`` if the matrix cannot be inverted
       (its determinant is zero) and ``true`` otherwise.
      @return The inverted matrix if the matrix was successfully
       inverted, otherwise the return value is undefined.


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

void main () {
    var a = Mat3 ();
    // a11(data[0])= 0, a12(data[3])= 0, a13(data[6])= 0
    // a21(data[1])= 0, a22(data[4])= 0, a23(data[7])= 0
    // a31(data[2])= 0, a32(data[5])= 0, a33(data[8])= 0
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a = Mat3.from_data (1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
       7.0f, 8.0f, 9.0f);
    // a11(data[0])= 1, a12(data[3])= 2, a13(data[6])= 3
    // a21(data[1])= 4, a22(data[4])= 5, a23(data[7])= 6
    // a31(data[2])= 7, a32(data[5])= 8, a33(data[8])= 9
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    var va = Vec3.from_data (1.0f, 2.0f, 3.0f);
    var vb = Vec3.from_data (4.0f, 5.0f, 6.0f);
    a = Mat3.from_vec_mul (ref va, ref vb);
    // a11(data[0])= 4, a12(data[3])= 5, a13(data[6])= 6
    // a21(data[1])= 8, a22(data[4])= 10, a23(data[7])= 12
    // a31(data[2])= 12, a32(data[5])= 15, a33(data[8])= 18
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    float d_array = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
    a = Mat3.from_array (d_array);
    // a11(data[0])= 1, a12(data[3])= 4, a13(data[6])= 7
    // a21(data[1])= 2, a22(data[4])= 5, a23(data[7])= 8
    // a31(data[2])= 3, a32(data[5])= 6, a33(data[8])= 9
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a = Mat3.identity ();
    // a11(data[0])= 1, a12(data[3])= 0, a13(data[6])= 0
    // a21(data[1])= 0, a22(data[4])= 1, a23(data[7])= 0
    // a31(data[2])= 0, a32(data[5])= 0, a33(data[8])= 1
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");
}

実行結果
Mat3 A
a11=0.000000 a12=0.000000 a13=0.000000
a21=0.000000 a22=0.000000 a23=0.000000
a31=0.000000 a32=0.000000 a33=0.000000

Mat3 A
a11=1.000000 a12=2.000000 a13=3.000000
a21=4.000000 a22=5.000000 a23=6.000000
a31=7.000000 a32=8.000000 a33=9.000000

Mat3 A
a11=4.000000 a12=5.000000 a13=6.000000
a21=8.000000 a22=10.000000 a23=12.000000
a31=12.000000 a32=15.000000 a33=18.000000

Mat3 A
a11=1.000000 a12=4.000000 a13=7.000000
a21=2.000000 a22=5.000000 a23=8.000000
a31=3.000000 a32=6.000000 a33=9.000000

Mat3 A
a11=1.000000 a12=0.000000 a13=0.000000
a21=0.000000 a22=1.000000 a23=0.000000
a31=0.000000 a32=0.000000 a33=1.000000


2 ベクトル演算
## prog2
## main.vala
// Mat3 ベクトル演算 1
using ValaGL.Core;

void main () {
    var a = Mat3.from_data (1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
       7.0f, 8.0f, 9.0f);
    var b = Mat3.from_data (9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f,
       3.0f, 2.0f, 1.0f);
    a.add (ref b);
    // a11(data[0])= 10, a12(data[3])= 10, a13(data[6])= 10
    // a21(data[1])= 10, a22(data[4])= 10, a23(data[7])= 10
    // a31(data[2])= 10, a32(data[5])= 10, a33(data[8])= 10
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a.sub (ref b);
    // a11(data[0])= 1, a12(data[3])= 2, a13(data[6])= 3
    // a21(data[1])= 4, a22(data[4])= 5, a23(data[7])= 6
    // a31(data[2])= 7, a32(data[5])= 8, a33(data[8])= 9
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a.mul (2.0f);
    // a11(data[0])= 2, a12(data[3])= 4, a13(data[6])= 6
    // a21(data[1])= 8, a22(data[4])= 10, a23(data[7])= 12
    // a31(data[2])= 14, a32(data[5])= 16, a33(data[8])= 18
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a.div (2.0f);
    // a11(data[0])= 1, a12(data[3])= 2, a13(data[6])= 3
    // a21(data[1])= 4, a22(data[4])= 5, a23(data[7])= 6
    // a31(data[2])= 7, a32(data[5])= 8, a33(data[8])= 9
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");

    a.mul_mat (ref b);
    // a11(data[0])= 30, a12(data[3])= 24, a13(data[6])= 18
    // a21(data[1])= 84, a22(data[4])= 69, a23(data[7])= 54
    // a31(data[2])= 138, a32(data[5])= 114, a33(data[8])= 90
    stdout.printf ("Mat3 A\n");
    stdout.printf ("a11=%f a12=%f a13=%f \n", a.data[0], a.data[3],
       a.data[6]);
    stdout.printf ("a21=%f a22=%f a23=%f \n", a.data[1], a.data[4],
       a.data[7]);
    stdout.printf ("a31=%f a32=%f a33=%f \n", a.data[2], a.data[5],
       a.data[8]);
    stdout.printf ("\n");
}

実行結果
Mat3 A
a11=10.000000 a12=10.000000 a13=10.000000
a21=10.000000 a22=10.000000 a23=10.000000
a31=10.000000 a32=10.000000 a33=10.000000

Mat3 A
a11=1.000000 a12=2.000000 a13=3.000000
a21=4.000000 a22=5.000000 a23=6.000000
a31=7.000000 a32=8.000000 a33=9.000000

Mat3 A
a11=2.000000 a12=4.000000 a13=6.000000
a21=8.000000 a22=10.000000 a23=12.000000
a31=14.000000 a32=16.000000 a33=18.000000

Mat3 A
a11=1.000000 a12=2.000000 a13=3.000000
a21=4.000000 a22=5.000000 a23=6.000000
a31=7.000000 a32=8.000000 a33=9.000000

Mat3 A
a11=30.000000 a12=24.000000 a13=18.000000
a21=84.000000 a22=69.000000 a23=54.000000
a31=138.000000 a32=114.000000 a33=90.000000


3 ベクトル演算2
## prog3
## main.vala
// Mat3 ベクトル演算 2
using ValaGL.Core;

void main () {
    var a = Mat3.from_data (2.0f, -2.0f, 3.0f, 1.0f, 1.0f, 1.0f,
       1.0f, 3.0f, -1.0f);
    var va = Vec3.from_data (1.0f, 2.0f, 3.0f);

    //Vec3 mul_vec (ref Vec3 vec)
    Vec3 vb = a.mul_vec (ref va);
    // vb.x = 7, vb.y = 6, vb.z = 4
    stdout.printf ("Vec3 vb\n");
    stdout.printf ("vb.x=%f vb.y=%f vb.z=%f \n", vb.x, vb.y, vb.z);
    stdout.printf ("\n");

    //Mat3 transposed ()
    Mat3 b = a.transposed ();
    // b11(data[0])= 2, b12(data[3])= 1, b13(data[6])= 1
    // b21(data[1])= -2, b22(data[4])= 1, b23(data[7])= 3
    // b31(data[2])= 3, b32(data[5])= 1, b33(data[8])= -1
    stdout.printf ("Mat3 B\n");
    stdout.printf ("b11=%f b12=%f b13=%f \n", b.data[0], b.data[3],
       b.data[6]);
    stdout.printf ("b21=%f b22=%f b23=%f \n", b.data[1], b.data[4],
       b.data[7]);
    stdout.printf ("b31=%f b32=%f b33=%f \n", b.data[2], b.data[5],
       b.data[8]);
    stdout.printf ("\n");

    //GLfloat det ()
    float det = a.det ();
    // det = -6
    stdout.printf ("float Det\n");
    stdout.printf ("det =%f\n", det);
    stdout.printf ("\n");

    //Mat3 inverted (out bool success)
    bool success;
    b = a.inverted (out success);
    // success
    // b11(data[0])= 4/6, b12(data[3])= -7/6, b13(data[6])= 5/6
    // b21(data[1])= -2/6, b22(data[4])= 5/6, b23(data[7])= -1/6
    // b31(data[2])= -2/6, b32(data[5])= 8/6, b33(data[8])= -4/6
    // not success
    // b11(data[0])= 0, b12(data[3])= 0, b13(data[6])= 0
    // b21(data[1])= 0, b22(data[4])= 0, b23(data[7])= 0
    // b31(data[2])= 0, b32(data[5])= 0, b33(data[8])= 0
    stdout.printf ("Mat3 B\n");
    if (success == false) {stdout.printf ("not success\n");}
    else {stdout.printf ("success\n");}
    stdout.printf ("b11=%f b12=%f b13=%f \n", b.data[0], b.data[3],
       b.data[6]);
    stdout.printf ("b21=%f b22=%f b23=%f \n", b.data[1], b.data[4],
       b.data[7]);
    stdout.printf ("b31=%f b32=%f b33=%f \n", b.data[2], b.data[5],
       b.data[8]);
}

実行結果
Vec3 vb
vb.x=7.000000 vb.y=6.000000 vb.z=4.000000

Mat3 B
b11=2.000000 b12=1.000000 b13=1.000000
b21=-2.000000 b22=1.000000 b23=3.000000
b31=3.000000 b32=1.000000 b33=-1.000000

float Det
det =-6.000000

Mat3 B
success
b11=0.666667 b12=-1.166667 b13=0.833333
b21=-0.333333 b22=0.833333 b23=-0.166667
b31=-0.333333 b32=1.333333 b33=-0.666667


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

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