Created
November 7, 2014 17:25
-
-
Save kumaryu/579780948a38e04db402 to your computer and use it in GitHub Desktop.
IronRubyとOpenTKを使ってOpenGL4.0のテッセレーションで文字を描く
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment