くまりゅう日記

もっと過去の日記
[.NET | BeOS | Blender | COLLADA | fossil | mono | monotone | NPR | OpenGL | PeerCastStation | Riko | Ruby | Silverlight | TRPG | XNA | ゲーム | ゲーム作り | プログラム | | 模型]

2014-11-10

日記

片付け頑張ってるってこと以外は特に書くこともない。

引っ越し先でネット使えるまでに間があくんじゃないかという気がしてたが、既にフレッツの線が入ってるところだから即日使えるとのことで安心した。週末引っ越しだから片付け頑張るぞ(体調崩して寝込みながら)。

[PeerCastStation] monoで上手く動かん続き

例外トラップを切ってみたら動くようになったんだけど、だからって何か例外が出てるわけでもない。 何故動くようになったのか謎である。

他に報告もないし、うちの環境が調子悪かっただけなんだろうか。それならそれでいいんだけど……。

[OpenGL][Ruby] ハードウェアテッセレーションで文字を描く

ソースを整理したので貼っておきまする。(Gistに貼ったのでRSSでは見れないかも)

#coding: utf-8
# IronRubyで実行してください(http://ironruby.net/)
# OpenTKが必要です(http://www.opentk.com/)
# OpenTK.dllとOpenTK.dll.configを読み込めるディレクトリに置いて実行してください
# OpenGL4.0以降が使えるGPUが必要です
#
# ESCで終了
# 上下キーで長さごとの分割数を増減
# 左右キーで曲がり具合による分割数を増減
#
require 'OpenTK.dll'
OpenGL4 = OpenTK::Graphics::OpenGL4
GL4 = OpenTK::Graphics::OpenGL4::GL
def GL4.uniform2f(location, v0, v1)
@uniform2f ||= self.method(:uniform2).overload(System::Int32, System::Single, System::Single)
@uniform2f.call(location, v0, v1)
end
def GL4.uniform3f(location, v0, v1, v2)
@uniform3f ||= self.method(:uniform3).overload(System::Int32, System::Single, System::Single, System::Single)
@uniform3f.call(location, v0, v1, v2)
end
VertexShaderMask = <<SRC
#version 400
layout (location=0) in vec2 inPosition;
layout (location=1) in vec4 inColor;
out vec4 vColor;
void main()
{
gl_Position = vec4(inPosition, 0.0, 1.0);
vColor = inColor;
}
SRC
FragmentShaderMask = <<SRC
#version 400
layout (location=0) out vec4 oFragColor;
in vec4 tColor;
void main()
{
oFragColor = tColor;
}
SRC
TessControlShaderMask = <<SRC
#version 400
layout (vertices=3) out;
in vec4 vColor[];
patch out vec4 pColor;
uniform vec2 uNumTess;
void main()
{
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
if (gl_InvocationID%3==0) {
pColor = vColor[gl_InvocationID];
vec3 p0 = gl_in[gl_InvocationID+0].gl_Position.xyz;
vec3 p1 = gl_in[gl_InvocationID+1].gl_Position.xyz;
vec3 p2 = gl_in[gl_InvocationID+2].gl_Position.xyz;
float d = (distance(p0, p1) + distance(p1, p2) + distance(p2, p0)) / 2 * uNumTess.x;
float c = (1.0+dot(normalize(p0-p1), normalize(p2-p1))) * uNumTess.y;
gl_TessLevelOuter[0] = 1.0;
gl_TessLevelOuter[1] = 1.0;
gl_TessLevelOuter[2] = clamp(d+c, 1.0, 16.0);
gl_TessLevelInner[0] = 1.0;
}
}
SRC
TessEvaluationShaderMask = <<SRC
#version 400
layout (triangles) in;
uniform mat4 uModelViewProjection;
uniform vec3 uOrigin;
patch in vec4 pColor;
out vec4 tColor;
void main()
{
float t0 = gl_TessCoord.x;
float t1 = 1-t0;
vec3 p0 = gl_in[0].gl_Position.xyz;
vec3 p1 = gl_in[1].gl_Position.xyz;
vec3 p2 = gl_in[2].gl_Position.xyz;
vec3 pt = p0*t1*t1 + p1*2*t1*t0 + p2*t0*t0;
gl_Position = uModelViewProjection * vec4(mix(pt, uOrigin, gl_TessCoord.z), 1.0);
tColor = pColor;
}
SRC
VertexShaderFill = <<SRC
#version 400
layout (location=0) in vec2 inPosition;
layout (location=1) in vec4 inColor;
uniform mat4 uModelViewProjection;
out vec4 vColor;
void main()
{
gl_Position = uModelViewProjection * vec4(inPosition, 0.0, 1.0);
vColor = inColor;
}
SRC
FragmentShaderFill = <<SRC
#version 400
layout (location=0) out vec4 oFragColor;
in vec4 vColor;
void main()
{
oFragColor = vColor;
}
SRC
class MyApplication
def initialize
#MSAAの倍数
msaa = 2
#画面モードの設定
#24bitフルカラー、深度値24bit(未使用だけど)、ステンシル8bit
mode = OpenTK::Graphics::GraphicsMode.new(OpenTK::Graphics::ColorFormat.new(24), 24, 8, msaa)
context_flags = OpenTK::Graphics::GraphicsContextFlags.default
#GL4.0
version_major = 4
version_minor = 0
#ウィンドウサイズ
@width = 640
@height = 480
#ウィンドウの作成
@window = OpenTK::GameWindow.new(
@width, @height,
mode,
'GameWindow',
OpenTK::GameWindowFlags.default,
OpenTK::DisplayDevice.default,
version_major, version_minor, context_flags)
#読み込み開始時のイベント設定
@window.load do |sender, args|
on_load
end
#毎フレーム実行されるイベント設定
@window.update_frame do |sender, args|
on_update
end
@window.key_down do |sender, args|
on_key(args.key)
end
@mask_shader = nil
@fill_shader = nil
end
#ウィンドウを表示して閉じられるまでイベントループを動かす
def run
@window.run
end
def self.run
self.new.run
end
#シェーダプログラムをビルドする
def build_shader_program(sources)
#新しいプログラムオブジェクトを作成
program = GL4.create_program
sources.each do |source|
#シェーダオブジェクトを指定のタイプで作成
shader = GL4.create_shader(source[0])
#ソースを設定してコンパイル
GL4.shader_source(shader, source[1])
GL4.compile_shader(shader)
#コンパイルエラーがあれば例外にして投げる、
if GL4.get_shader(shader, OpenGL4::ShaderParameter.compile_status)==0 then
raise RuntimeError, GL4.get_shader_info_log(shader)
end
#シェーダをプログラムにくっつける
GL4.attach_shader(program, shader)
GL4.delete_shader(shader)
end
#コンパイルされたシェーダをリンクする
GL4.link_program(program)
#リンクエラーがあれば例外にして投げる
if GL4.get_program(program, OpenGL4::ProgramParameter.link_status)==0 then
raise RuntimeError, GL4.get_program_info_log(program)
end
return program
end
#ウインドウが開かれる時に呼ばれる
def on_load
#OpenGLのバージョン情報・レンダラ情報を表示
p "#{GL4.get_string(OpenGL4::StringName.version)} #{GL4.get_string(OpenGL4::StringName.renderer)}"
#マスク用(線だけ書く時にも使う)シェーダプログラムをビルドする
@mask_shader = build_shader_program([
[OpenGL4::ShaderType.vertex_shader, VertexShaderMask],
[OpenGL4::ShaderType.tess_control_shader, TessControlShaderMask],
[OpenGL4::ShaderType.tess_evaluation_shader, TessEvaluationShaderMask],
[OpenGL4::ShaderType.fragment_shader, FragmentShaderMask],
])
#塗り潰し用シェーダプログラムをビルドする
@fill_shader = build_shader_program([
[OpenGL4::ShaderType.vertex_shader, VertexShaderFill],
[OpenGL4::ShaderType.fragment_shader, FragmentShaderFill],
])
end
#ウィンドウが開かれてる間、定期的に呼ばれる
def on_update
#MSAA有効
GL4.enable(OpenGL4::EnableCap.multisample)
#灰色でクリア
GL4.clear_color(0.2, 0.2, 0.2, 0.0)
#ステンシルを0で初期化
GL4.clear_stencil(0)
#画面の色とステンシルと深度値を実際にクリアする
GL4.clear(
OpenGL4::ClearBufferMask.color_buffer_bit |
OpenGL4::ClearBufferMask.depth_buffer_bit |
OpenGL4::ClearBufferMask.stencil_buffer_bit)
#(-320, -240)~(+320, +240)の座標系になる正射影行列
projection = [
2.0/@width, 0.0, 0.0, 0.0,
0.0, 2.0/@height, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]
#文字サイズは128ピクセル
size = 128.0
#長さによる分割は初期値で約16ピクセルに1分割増える
@factor_length ||= 16.0
#曲がり具合による分割は初期値で6(単位は謎)にする
@factor_curve ||= 6.0
#表示する文字列(フォントデータにこの5文字しかないけど)
str = 'あいうえお'
#水平方向は中央揃えで、垂直方向は中央よりちょい上を描画起点にする
pos = [-size*str.size/2, 0.5*size]
str.chars.each do |c|
#文字を塗り潰しで描画
advance = draw_glyph_fill(size, pos, c, projection, @factor_length, @factor_curve)
#一文字分右に進む
pos[0] += advance
end
#水平方向は中央揃えで、垂直方向は中央よりちょい下になるよう起点を決める
pos = [-size*str.size/2, -1.5*size]
#線の太さを設定する
GL4.line_width(0.5)
str.chars.each do |c|
#文字を線で描画
advance = draw_glyph_line(size, pos, c, projection, @factor_length, @factor_curve)
#一文字分右に進む
pos[0] += advance
end
#描画結果を画面に反映する
@window.swap_buffers
end
#キー入力があったときに呼ばれる
def on_key(key)
case key
when OpenTK::Input::Key.escape
#ESCで終了
@window.exit
when OpenTK::Input::Key.up
#上キーで長さによる分割数を増やす
@factor_length -= 1.0
when OpenTK::Input::Key.down
#下キーで長さによる分割数を減らす
@factor_length += 1.0
when OpenTK::Input::Key.left
#左キーで曲がり具合による分割数を減らす
@factor_curve -= 1.0
when OpenTK::Input::Key.right
#右キーで曲がり具合による分割数を増やす
@factor_curve += 1.0
end
@factor_length = 1.0 if @factor_length< 1.0
@factor_length = 40.0 if @factor_length>40.0
@factor_curve = 0.0 if @factor_curve < 0.0
@factor_curve = 20.0 if @factor_curve >20.0
end
#文字毎の頂点データを生成する
def create_glyph_vertex_array(glyph)
#頂点バッファを作る
buffer = GL4.gen_buffer
GL4.bind_buffer(OpenGL4::BufferTarget.array_buffer, buffer)
#頂点バッファに頂点情報を設定する
#制御点配列の後に塗り潰し用の頂点を4頂点追加しておく
GL4.buffer_data(
OpenGL4::BufferTarget.array_buffer,
4*(glyph['points'].size+8),
System::Array[System::Single].new(
glyph['points'] +
[
glyph['x_min'], glyph['y_max'],
glyph['x_min'], glyph['y_min'],
glyph['x_max'], glyph['y_max'],
glyph['x_max'], glyph['y_min'],
]),
OpenGL4::BufferUsageHint.static_draw)
#Vertex Array Objectを作る
vao = GL4.gen_vertex_array
GL4.bind_vertex_array(vao)
#頂点バッファを頂点属性0番に設定する
#1頂点は2要素のfloatだよ
GL4.enable_vertex_attrib_array(0)
GL4.vertex_attrib_pointer(0, 2, OpenGL4::VertexAttribPointerType.float, false, 8, 0)
GL4.bind_vertex_array(0)
GL4.bind_buffer(OpenGL4::BufferTarget.array_buffer, 0)
return vao
end
#文字を塗り潰しで描画する
def draw_glyph_fill(size, pos, char, projection, factor_length, factor_curve)
#文字座標系での文字サイズ
em = FontData['em']
#文字データを取得する
glyph = FontData['glyphs'][char]
#文字座標系からビュー座標系に変換する行列
modelview = [
size/em, 0.0, 0.0, pos[0],
0.0, size/em, 0.0, pos[1],
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]
#文字→ビュー行列と射影行列を掛けよう
mvp = Array.new(16) {|i|
r = i/4
c = i%4
projection[r*4+0] * modelview[0+c] +
projection[r*4+1] * modelview[4+c] +
projection[r*4+2] * modelview[8+c] +
projection[r*4+3] * modelview[12+c]
}
#ステンシルでマスク作成
#ステンシルテストを有効に
GL4.enable(OpenGL4::EnableCap.stencil_test)
#ステンシルテストは常時成功する
GL4.stencil_func(OpenGL4::StencilFunction.always, 0, -1)
#ステンシルテスト・深度テスト失敗時はステンシル値はいじらず(常に成功するけどさ…)
#成功した場合はステンシル値を反転する
GL4.StencilOp(OpenGL4::StencilOp.keep, OpenGL4::StencilOp.keep, OpenGL4::StencilOp.invert)
#ステンシル値だけ描きたいので色は全部書き込みOFF
GL4.color_mask(false, false, false, false)
#面を塗り潰すよ
GL4.polygon_mode(OpenGL4::MaterialFace.front_and_back, OpenGL4::PolygonMode.fill)
#シェーダ設定
GL4.use_program(@mask_shader)
#シェーダにMVP行列を渡す
GL4.uniform_matrix4(GL4.get_uniform_location(@mask_shader, 'uModelViewProjection'), 1, true, System::Array[System::Single].new(mvp))
#シェーダに分割数を渡す
GL4.uniform2f(GL4.get_uniform_location(@mask_shader, 'uNumTess'), size/em/factor_length, factor_curve)
#シェーダに文字の左下座標を渡す
GL4.uniform3f(GL4.get_uniform_location(@mask_shader, 'uOrigin'), glyph['x_min'], glyph['y_min'], 0.0)
#制御点3つでパッチ1つ
GL4.patch_parameter(OpenGL4::PatchParameterInt.patch_vertices, 3)
#文字データから頂点配列オブジェクトを作って設定する
vao = (glyph['vao'] ||= create_glyph_vertex_array(glyph))
GL4.bind_vertex_array(vao)
#1番の頂点属性(色として扱う)を一律(1,1,1,1)に
GL4.vertex_attrib4(1, 1.0, 1.0, 1.0, 1.0)
#パッチとして描画する。0番目の頂点から文字の頂点数分描画する
GL4.draw_arrays(OpenGL4::PrimitiveType.patches, 0, glyph['points'].size/2)
#ここまでマスクを作るところ
#マスクを使って塗りつぶす
#色の書き込みをONに
GL4.color_mask(true, true, true, true)
#ステンシルが0じゃない所のみ書き込むようにする
GL4.stencil_func(OpenGL4::StencilFunction.notequal, 0, -1)
#ステンシルの書き換えはしない
GL4.StencilOp(OpenGL4::StencilOp.keep, OpenGL4::StencilOp.keep, OpenGL4::StencilOp.keep)
#塗り潰し用シェーダを設定
GL4.use_program(@fill_shader)
#シェーダにMVP行列を渡す
GL4.uniform_matrix4(GL4.get_uniform_location(@fill_shader, 'uModelViewProjection'), 1, true, System::Array[System::Single].new(mvp))
#三角形を2つ描く。文字の制御点配列の後に文字を覆うサイズの頂点が4つあるのでそれを描く
GL4.draw_arrays(OpenGL4::PrimitiveType.triangle_strip, glyph['points'].size/2, 4)
#あと片付け
GL4.bind_vertex_array(0)
GL4.use_program(0)
#文字の進み分を返す
return glyph['advance']*size/em
end
#文字を線だけで描画する
def draw_glyph_line(size, pos, char, projection, factor_length, factor_curve)
#文字座標系での文字サイズ
em = FontData['em']
#文字データを取得する
glyph = FontData['glyphs'][char]
#文字座標系からビュー座標系に変換する行列
modelview = [
size/em, 0.0, 0.0, pos[0],
0.0, size/em, 0.0, pos[1],
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]
#文字→ビュー行列と射影行列を掛けよう
mvp = Array.new(16) {|i|
r = i/4
c = i%4
projection[r*4+0] * modelview[0+c] +
projection[r*4+1] * modelview[4+c] +
projection[r*4+2] * modelview[8+c] +
projection[r*4+3] * modelview[12+c]
}
#線だけ描画
#直接描画するのでステンシルテストは無効に
GL4.disable(OpenGL4::EnableCap.stencil_test)
#色の書き込みをONに
GL4.color_mask(true, true, true, true)
#面を塗らずに線だけ描くよ
GL4.polygon_mode(OpenGL4::MaterialFace.front_and_back, OpenGL4::PolygonMode.line)
#シェーダ設定
GL4.use_program(@mask_shader)
#シェーダにMVP行列を渡す
GL4.uniform_matrix4(GL4.get_uniform_location(@mask_shader, 'uModelViewProjection'), 1, true, System::Array[System::Single].new(mvp))
#シェーダに分割数を渡す
GL4.uniform2f(GL4.get_uniform_location(@mask_shader, 'uNumTess'), size/em/factor_length, factor_curve)
#シェーダに文字の左下座標を渡す
GL4.uniform3f(GL4.get_uniform_location(@mask_shader, 'uOrigin'), glyph['x_min'], glyph['y_min'], 0.0)
#制御点3つでパッチ1つ
GL4.patch_parameter(OpenGL4::PatchParameterInt.patch_vertices, 3)
#文字データから頂点配列オブジェクトを作って設定する
vao = (glyph['vao'] ||= create_glyph_vertex_array(glyph))
GL4.bind_vertex_array(vao)
#1番の頂点属性(色として扱う)を一律(1,1,1,1)に
GL4.vertex_attrib4(1, 1.0, 1.0, 1.0, 1.0)
#パッチとして描画する。0番目の頂点から文字の頂点数分描画する
GL4.draw_arrays(OpenGL4::PrimitiveType.patches, 0, glyph['points'].size/2)
#あと片付け
GL4.bind_vertex_array(0)
GL4.use_program(0)
#文字の進み分を返す
return glyph['advance']*size/em
end
end
require 'yaml'
FontData = YAML.load(<<EOS)
---
em: 1000.0
glyphs:
あ:
advance: 1000
x_min: 97
y_min: -63
x_max: 903
y_max: 903
points: [596, 3, 596.0, 3.0, 596, 3, 596, 3, 705, 24, 767.5, 84.0, 767.5, 84.0, 830, 144, 830, 227, 830, 227, 830, 357, 704, 406, 704, 406, 638, 213, 512.5, 100.0, 512.5, 100.0, 387, -13, 263, -13, 263, -13, 185, -13, 141.0, 33.5, 141.0, 33.5, 97, 80, 97, 163, 97, 163, 97, 265, 163.5, 345.5, 163.5, 345.5, 230, 426, 347, 465, 347, 465, 347.0, 539.0, 347, 613, 347, 613, 240.0, 613.0, 133, 613, 133, 613, 133.0, 645.0, 133, 677, 133, 677, 240.0, 677.0, 347, 677, 347, 677, 347.0, 740.0, 347, 803, 347, 803, 383.5, 803.0, 420, 803, 420, 803, 420.0, 740.0, 420, 677, 420, 677, 643.5, 677.0, 867, 677, 867, 677, 867.0, 645.0, 867, 613, 867, 613, 643.5, 613.0, 420, 613, 420, 613, 420.0, 548.5, 420, 484, 420, 484, 487, 497, 553, 497, 553, 497, 717, 497, 810.0, 424.5, 810.0, 424.5, 903, 352, 903, 227, 903, 227, 903, 116, 826.0, 39.0, 826.0, 39.0, 749, -38, 614, -63, 614, -63, 605.0, -30.0, 596, 3, 637, 424, 637.0, 424.0, 637, 424, 637, 424, 599, 430, 553, 430, 553, 430, 482, 430, 420, 415, 420, 415, 420.0, 263.0, 420, 111, 420, 111, 486, 159, 543.5, 239.5, 543.5, 239.5, 601, 320, 637, 424, 347, 392, 347.0, 392.0, 347, 392, 347, 392, 265, 358, 217.5, 299.5, 217.5, 299.5, 170, 241, 170, 170, 170, 170, 170, 114, 196.0, 83.5, 196.0, 83.5, 222, 53, 270, 53, 270, 53, 308, 53, 347, 69, 347, 69, 347.0, 230.5, 347, 392]
い:
advance: 1000
x_min: 117
y_min: -33
x_max: 910
y_max: 910
points: [701, 673, 701.0, 673.0, 701, 673, 701, 673, 736.0, 685.0, 771, 697, 771, 697, 838, 572, 874.0, 408.0, 874.0, 408.0, 910, 244, 910, 70, 910, 70, 871.5, 70.0, 833, 70, 833, 70, 833, 234, 798.5, 393.0, 798.5, 393.0, 764, 552, 701, 673, 236, 682, 236.0, 682.0, 236, 682, 236, 682, 193, 527, 193, 350, 193, 350, 193, 220, 239.0, 131.5, 239.0, 131.5, 285, 43, 332, 43, 332, 43, 364, 43, 414.5, 107.5, 414.5, 107.5, 465, 172, 510, 291, 510, 291, 545.0, 277.5, 580, 264, 580, 264, 531, 125, 459.5, 46.0, 459.5, 46.0, 388, -33, 327, -33, 327, -33, 249, -33, 183.0, 79.0, 183.0, 79.0, 117, 191, 117, 350, 117, 350, 117, 539, 162, 692, 162, 692, 199.0, 687.0, 236, 682]
う:
advance: 1000
x_min: 132
y_min: -40
x_max: 870
y_max: 870
points: [132, 460, 132.0, 460.0, 132, 460, 132, 460, 390, 523, 577, 523, 577, 523, 733, 523, 801.5, 466.0, 801.5, 466.0, 870, 409, 870, 320, 870, 320, 870, 173, 728.5, 77.0, 728.5, 77.0, 587, -19, 331, -40, 331, -40, 322.0, -5.0, 313, 30, 313, 30, 545, 52, 669.0, 130.0, 669.0, 130.0, 793, 208, 793, 317, 793, 317, 793, 453, 573, 453, 573, 453, 410, 453, 148, 392, 148, 392, 140.0, 426.0, 132, 460, 272, 702, 272.0, 702.0, 272, 702, 272, 702, 276.5, 736.0, 281, 770, 281, 770, 513, 733, 723, 733, 723, 733, 723.0, 698.0, 723, 663, 723, 663, 526, 663, 272, 702]
え:
advance: 1000
x_min: 102
y_min: -38
x_max: 908
y_max: 908
points: [167, 553, 167.0, 553.0, 167, 553, 167, 553, 477.5, 553.0, 788, 553, 788, 553, 788.0, 516.0, 788, 479, 788, 479, 664.0, 377.0, 540, 275, 540, 275, 540.5, 274.5, 541, 274, 541, 274, 551, 276, 557, 276, 557, 276, 591, 276, 611.5, 249.0, 611.5, 249.0, 632, 222, 653, 142, 653, 142, 671, 74, 691.5, 56.0, 691.5, 56.0, 712, 38, 767, 38, 767, 38, 832, 38, 895, 56, 895, 56, 901.5, 23.0, 908, -10, 908, -10, 835, -30, 760, -30, 760, -30, 680, -30, 643.0, -2.0, 643.0, -2.0, 606, 26, 587, 102, 587, 102, 570, 170, 552.0, 194.5, 552.0, 194.5, 534, 219, 507, 219, 507, 219, 491, 219, 481.0, 216.0, 481.0, 216.0, 471, 213, 431.5, 185.5, 431.5, 185.5, 392, 158, 333.0, 111.5, 333.0, 111.5, 274, 65, 146, -38, 146, -38, 124.0, -10.0, 102, 18, 102, 18, 391.5, 251.5, 681, 485, 681, 485, 680.5, 486.0, 680, 487, 680, 487, 423.5, 487.0, 167, 487, 167, 487, 167.0, 520.0, 167, 553, 272, 707, 272.0, 707.0, 272, 707, 272, 707, 276.5, 740.0, 281, 773, 281, 773, 506, 737, 723, 737, 723, 737, 723.0, 702.5, 723, 668, 723, 668, 526, 668, 272, 707]
お:
advance: 1000
x_min: 87
y_min: -47
x_max: 955
y_max: 955
points: [123, 667, 123.0, 667.0, 123, 667, 123, 667, 246.5, 667.0, 370, 667, 370, 667, 370.0, 735.0, 370, 803, 370, 803, 406.5, 803.0, 443, 803, 443, 803, 443.0, 735.0, 443, 667, 443, 667, 571.5, 667.0, 700, 667, 700, 667, 700.0, 635.0, 700, 603, 700, 603, 571.5, 603.0, 443, 603, 443, 603, 443.0, 517.5, 443, 432, 443, 432, 490, 437, 533, 437, 533, 437, 683, 437, 773.0, 370.5, 773.0, 370.5, 863, 304, 863, 213, 863, 213, 863, 99, 791.5, 32.5, 791.5, 32.5, 720, -34, 581, -47, 581, -47, 573.5, -13.5, 566, 20, 566, 20, 788, 44, 788, 210, 788, 210, 788, 273, 719.0, 320.0, 719.0, 320.0, 650, 367, 533, 367, 533, 367, 490, 367, 443, 362, 443, 362, 443.0, 234.5, 443, 107, 443, 107, 443, 32, 412.0, 1.0, 412.0, 1.0, 381, -30, 307, -30, 307, -30, 220, -30, 153.5, 29.0, 153.5, 29.0, 87, 88, 87, 167, 87, 167, 87, 253, 161.0, 323.0, 161.0, 323.0, 235, 393, 370, 421, 370, 421, 370.0, 512.0, 370, 603, 370, 603, 246.5, 603.0, 123, 603, 123, 603, 123.0, 635.0, 123, 667, 740, 663, 740.0, 663.0, 740, 663, 740, 663, 766.0, 684.0, 792, 705, 792, 705, 880, 610, 955, 495, 955, 495, 927.5, 477.0, 900, 459, 900, 459, 831, 566, 740, 663, 370, 350, 370.0, 350.0, 370, 350, 370, 350, 269, 327, 214.5, 277.0, 214.5, 277.0, 160, 227, 160, 167, 160, 167, 160, 117, 204.0, 76.0, 204.0, 76.0, 248, 35, 300, 35, 300, 35, 338, 35, 354.0, 51.5, 354.0, 51.5, 370, 68, 370, 108, 370, 108, 370.0, 229.0, 370, 350]
EOS
if $0==__FILE__ then
MyApplication.run
end
view raw beziertess.rb hosted with ❤ by GitHub

OpenTKという.NET用のOpenGL(とか)バインディングを使っちゃってるのでIronRubyでしか動きません1。それ以外の部分は実装依存してないんだけどね。OpenTKを落としてきてOpenTK.dllをスクリプトと同じディレクトリとか読める場所に置いて実行してください。もちろんIronRubyでね。あと当然ながらOpenGL4.0が動く環境じゃないと動かないです。うちではAtom Z3770とA10-7850で動作確認できました。単体GPU持ってないんかよ。

操作方法はコメント書いてある通りなんで。あとフォントデータはM+使ってます。「あいうえお」の5文字分しか入れてないけどね。

フォントのアウトラインデータは基本的にはTrueTypeだけど、始点と終点はつながるように始点を最後に追加してある、直線の場合は端点の中間に制御点が来るように点を追加してある、制御点が連続してる場合は中間に端点が来るように追加してある、など3点で1辺になるように前処理してあります。

普通に描くだけならこれで満足なんだけど、アウトライン描いたりもしたいから、もうちょっとTrueTypeのこと詳しくなりたいねぇ。あとできればOpenTypeも描画できるようにしたい。最近のフリーフォントはOpenTypeの物もそこそこあるもんね。

  1. 普通のRubyで使えるOpenGLバインディングとか調べたけど、最低でもglfwあたりは別途用意しなきゃならなかったのと、OpenTKが使い慣れちゃってたのでOpenTK使っちゃった。 


ページのトップへ | トップ «前の日記(2014-11-06) 最新 次の日記(2014-11-18)» | 編集 | kumaryu.net by kumaryu