ブラシスクリプト概要

mdiappはブラシ処理でスクリプト(Lua)を用いたプログラム制御が行えます。

http://staff.aist.go.jp/yutaka.ueno/lua/docsjp.html (Lua言語について

プログラム制御をすることで、

こういった形で自由度の高いブラシを作成することが可能です。ブラシスクリプトは、拡張子 (*.bs) で作成します。ブラシデザインウィンドウからスタイルで「プログラム」を選び、下のボタンを押しスクリプトを指定します (ファイルをブラシウィンドウにドラッグ&ドロップでもOKです)。正しくパースできた場合のみ、インストールが可能です。参照したファイルは実行ファイルと同階層の "bs" フォルダにコピーされます。

一番シンプルなスクリプトは、こんな具合です。

function main( x, y, p )

  local r,g,b,a = bs_pixel_get( x, y )
  bs_pixel_set( x,y, 255-r,255-g,255-b, 255 )
  return 1
end

プログラムブラシの場合、ブラシ描画に使うマウスやタブレットから取得した座標の各頂点間を、十分に細かい頻度で (ブラシの直径に応じた細かさ) main( x,y,p ) 関数が呼ばれます。かなりの頻度で呼ばれる事になるので、間隔調整が必要になります。

上記のスクリプトの場合、bs_pixel_get命令で、x,y座標のRGBA値を取得し、bs_pixel_set命令で、RGB値を反転した値のピクセルを書き込むような処理になっています。

何かしら描画した場合は return 1 を、何も描かなかった場合は return 0 してください。

次はもう少し複雑なスクリプトを見てみましょう。

function main( x, y, p )

  local w = bs_width()
  if w < 5 then
    w = 5
  end

  if not firstDraw then
    local distance = bs_distance( lastDrawX - x, lastDrawY - y )
    if distance < w then
      return 0
    end
  end

  local dx,dy = bs_dir()
  local nx,ny = bs_normal()

  bs_polygon( x + nx * w/3, y + ny * w/3 )
  bs_polygon( x - nx * w/3, y - ny * w/3 )
  bs_polygon( x + dx * w, y + dy * w )

  local r,g,b = bs_fore()
  bs_fill( r,g,b, 255 )

  lastDrawX = x
  lastDrawY = y
  firstDraw = false

  return 1
end

lastDrawX = 0
lastDrawY = 0
firstDraw = true

最後の3行に注目してください。ここはグローバル宣言部なので、main(x,y,p) が呼び出される前に、一度だけ必ず実行されます。ここでは、firstDraw = true といったように、最初の描画を判定する為の変数を初期化しています。

  local w = bs_width()
  if w < 5 then
    w = 5
  end

bs_width() は現在のブラシ幅(直径)を所得する関数です (筆圧適用した幅)。5pixel以下のブラシ幅にしないように調整しています。

  if not firstDraw then
    local distance = bs_distance( lastDrawX - x, lastDrawY - y )
    if distance < w then
      return 0
    end
  end

最初の描画でない時、あまりにブラシが進んでいない場合は描画を避けるような処理をしています。bs_distance() で差分の距離を測っています。

  local dx,dy = bs_dir()
  local nx,ny = bs_normal()

bs_dir() はブラシの進行方向の正規ベクトル、bs_normal() はブラシの進行方向の垂直方向の正規ベクトルを取得する関数です。正規ベクトルとは、大きさが1になるベクトルのことです。進行方向が必要なので取得しています。


  bs_polygon( x + nx * w/3, y + ny * w/3 )
  bs_polygon( x - nx * w/3, y - ny * w/3 )
  bs_polygon( x + dx * w, y + dy * w )

bs_polygon() は多角形を設定する命令です。現在の座標値 x, y をベースに、進行方向を指す3頂点を指定しています。


  local r,g,b = bs_fore()
  bs_fill( r,g,b, 255 )

bs_fore() で前景色のRGB値を取得し、その色を使い bs_fill() で先ほど定義した3頂点を塗りつぶしています。

ストロークの最後だけ何かしたい

全てのストローク処理が終わった後、last関数が呼ばれます。このスクリプトを参考にしてください。last関数は、実装されていなくても構いません。

function last( x, y, p )

  local r,g,b = bs_fore()
  local w = bs_width_max()
  bs_ellipse( x, y, w*2, w, 0, r,g,b, bs_opaque()*255 )
  return 1
end

function main( x, y, p )
  return 1
end

API一覧 (基本命令)

w = bs_width()
w = bs_width_max()
w = bs_width_min()
  • bs_width()
    • 筆圧を適用したブラシ幅(直径)を取得します
  • bs_width_max()
    • ブラシの最大幅を取得します (最大筆圧時の直径)
  • bs_width_min()
    • ブラシの最小幅を取得します (最小筆圧時の直径)
distance = bs_distance( x, y )
rad = bs_atan( x, y )
x, y = bs_rotate( x, y, radAngle )
value = bs_grand( ave, std )
milisec = bs_ms()
num = bs_count()
  • bs_distance( x, y )
    • 原点から (x,y) の距離を取得します
  • bs_atan( x, y )
    • 原点から (x,y) の角度を取得します (ラジアン)
  • bs_rotate( x, y, radAngle )
    • x,y座標を原点を中心に、radAngle(ラジアン) だけ回転させます
  • bs_grand( ave, sd1 )
    • aveを中心に、±sd1の範囲に約68%の確率で収まるようなガウス分布の乱数値を取得します
  • bs_ms()
    • OS起動時からの経過ミリ秒を取得します
  • bs_count()
    • mdiappの起動後、ブラシスクリプトが呼ばれた回数を取得します
    • 1ストローク毎に何かを変えたい場合などに用います
w = bs_canvas_width()
h = bs_canvas_height()
dpi = bs_canvas_dpi()
rad = bs_canvas_angle()
  • bs_canvas_width()
    • キャンバスの幅を取得します
  • bs_canvas_height()
    • キャンバスの高さを取得します
  • bs_canvas_dpi()
    • キャンバスのdpiを取得します
  • bs_canvas_angle()
    • キャンバスの回転角度を取得します (ラジアン角)
r,g,b = bs_fore()
r,g,b = bs_bg()
r,g,b = bs_forebg( t )
alpha = bs_opaque()
  • bs_fore()
    • 前景色のRGB値を取得します
  • bs_bg()
    • 背景色のRGB値を取得します
  • bs_forebg( t )
    • 前景色と背景色の補間値を取得します (0.0〜1.0)
    • 0.0: 背景色, 0.5:中間色, 1.0: 前景色
  • bs_opaque()
    • ブラシの不透明度 (0.0〜1.0) を取得します
dx,dy = bs_dir()
nx,ny = bs_normal()
  • bs_dir()
    • ブラシの進行方向のベクトルを取得します (正規ベクトル)
  • bs_normal()
    • ブラシの進行方向から90度傾けたベクトル(法線方向) を取得します (正規ベクトル)

API一覧 (描画命令)

r,g,b,a = bs_pixel_get( x, y )
alpha = bs_pixel_get_alpha( x, y )
bs_pixel_set( x, y, r,g,b,a )
  • bs_pixel_get( x, y )
    • x,y座標のRGBA値を取得します
    • R,G,B,A = 0〜255
    • 1,8bppレイヤーのA値は、常に255です
  • bs_pixel_get_alpha( x, y )
    • x,y座標のA値 (不透明度・濃度) を取得します
    • alpha = 0〜255
    • 1bppレイヤーの場合は、0 または 255 です
  • bs_pixel_set( x, y, r,g,b,a )
    • x,y座標に、RGB値を不透明度Aで描画します
    • R,G,B,A = 0〜255
    • bs_pixel_set を使って沢山描画するのは現実的ではありません
bs_polygon( x, y )
bs_polygon_move( dx, dy )
bs_polygon_move_center()
bs_polygon_rotate( radAngle )
bs_polygon_mul( zx, zy )
bs_polygon_clear()
rx,ry,rw,rh = bs_polygon_region()
  • bs_polygon( x, y )
    • 多角形を定義する為、頂点x,yを追加します
    • 三角形を定義する場合は、bs_polygon命令を三回実行します
  • bs_polygon_move( dx, dy )
    • 追加されている多角形の頂点を、dx,dyだけ移動させます
  • bs_polygon_move_center()
    • 追加されている多角形の頂点を、重心を原点に移動させます
  • bs_polygon_rotate( radAngle )
    • 追加されている多角形の頂点を、原点を中心に radAngle だけ回転させます
  • bs_polygon_mul( zx, zy )
    • 追加されている多角形の頂点を、x方向にzx倍、y方向にzy倍にします
  • bs_polygon_clear()
    • 追加されている多角形をクリアします (bs_fill 直後にも自動的にクリアされます)
  • rx,ry,rw,rh = bs_polygon_region()
    • 追加されている多角形の範囲を取得します (rx:X始点、ry:Y始点、rw:幅、rh:高さ)
    • 多角形が設定されていない場合、面積のない場合の戻り値は不定です
bs_bezier_begin( x, y )
bs_bezier_c( x1, y1, x2, y2, x3, y3 )
bs_bezier_v( x2, y2, x3, y3 )
bs_bezier_y( x1, y1, x3, y3 )
bs_bezier_l( x3, y3 )
bs_bezier_m( x, y )
bs_bezier_move( dx, dy )
bs_bezier_move_center()
bs_bezier_rotate( rad )
bs_bezier_mul( zx, zy )
bs_bezier_clear()
rx,ry,rw,rh = bs_bezier_region()
  • bs_bezier_begin( x, y )
  • bs_bezier_c( x1, y1, x2, y2, x3, y3 )
    • 制御点1 (x1,y1) 制御点2 (x2,y2)、次点 (x3,y3) の辺を追加します
  • bs_bezier_v( x2, y2, x3, y3 )
    • 制御点1は現在位置、制御点2 (x2,y2)、次点 (x3,y3) の辺を追加します
  • bs_bezier_y( x1, y1, x3, y3 )
    • 制御点1 (x1,y1)、制御点2&次点 (x3,y3) の辺を追加します
  • bs_bezier_l( x3, y3 )
    • 直線の辺を加えます
  • bs_bezier_m( x, y )
  • bs_bezier_move( dx, dy )
  • bs_bezier_move_center()
    • 追加されているベジェ曲線の頂点を、重心を原点に移動させます
  • bs_bezier_rotate( rad )
    • 追加されているベジェ曲線の頂点を、原点を中心に radAngle だけ回転させます
  • bs_bezier_mul( zx, zy )
    • 追加されているベジェ曲線の頂点を、x方向にzx倍、y方向にzy倍にします
  • bs_bezier_clear()
    • 追加されているパスをクリアします (bs_fill 直後にも自動的にクリアされます)
  • rx,ry,rw,rh = bs_bezier_region()
    • 追加されているパスの範囲を取得します (rx:X始点、ry:Y始点、rw:幅、rh:高さ)
    • パスが設定されていない場合、面積のない場合の戻り値は不定です
bs_fill( r, g, b, a )
bs_rect( x, y, w, h, r,g,b,a )
bs_ellipse( mx, my, w, h, radAngle , r,g,b,a )
  • bs_rect( x, y, w, h, r,g,b,a )
    • 座標(x,y) に、幅高さ (w,h) の矩形を描画します
  • bs_ellipse( mx, my, w, h, radAngle , r,g,b,a )
    • 座標(mx,my) を中心に、幅高さ (w,h) 角度 (radAngle) の楕円を描画します
    • アンチエイリアシングの有無はブラシ設定に依存します
    • 真円 (w == h) の場合、高速描画されます

基点の指定

左右対称・回転対称ブラシなど、基点(基準点)が必要な場合があります。

基点が必要なブラシは、キャンバス上でCtrl+クリックをする事で基点が指定できます。

基点を使いたいスクリプトは、スクリプト内で、

function use_base()
  return true
end

と定義しておきます。設定された起点は、

local bsx,bsy = bs_base()

という形で、bs_base()命令を使い取得できます。

基点が指定されてない場合は、(-1,-1) が返ります。(-1,-1)の場合は、特別処理を入れておくと良いでしょう。

パラメータの扱い

function param1()
  return "param1", 0, 100, 50
end

function param2()
  return "param2", 50, 100, 75
end

function param3()
  return "param3", 10, 20, 15
end

function param4()
  return "checked", 0, 1, 0
end

function param5()
  return "unchecked", 0, 1, 1
end

スクリプト内に param1(), param2(), param3() ... という関数を定義しておくと、ブラシコントロールウィンドウでパラメータ設定、取得できるようになります (最大10個>param1 から param10 まで)。

  • 第1 戻り値
    • ブラシコントロール上に表示される文字です(英語のみ)
  • 第2 戻り値
    • 設定の最小値です(0〜100まで)
  • 第3 戻り値
    • 設定の最大値です(0〜100まで)
  • 第4 戻り値
    • 設定のデフォルト値です(0〜100まで)

設定値はスクリプト内で、

local param1 = bs_param1()
local param2 = bs_param2()
local param3 = bs_param3()
local param4 = bs_param4()
local param5 = bs_param5()

といった形で取得できます。


最小値が0、最大値が1の場合

チェックボックス表示になります。チェックされている場合は1、チェックされていない場合は0が戻り値になります。

デフォルトのサイズ(幅・最小サイズ)

ブラシによっては、細いものを推奨するものもあれば、太いものを推奨するものもあります。

function default_size()
  return 17, 0.25
end

という関数をスクリプト内で定義しておけば、デフォルトの幅、デフォルトの最小サイズを指定することができます。この場合、最大幅は17px、最小サイズは 25% になります。

描画モード (mdiap+ 0.9.137 より)

指定のない通常のモードでは、カラーレイヤーならRGB好きな色を指定して描画できます。しかし、半透明で描画した際に、重なる部分が濃くなってしまいます。滑らかなブラシ処理には向きません。そこで、

bs_setmode( 1 )

というコードを初期化部分に追加すると、通常のペンのように、半透明部分の合成が綺麗になるモードになります。ただし、RGB任意の色で図形を描画することはできず、前景色を使った描画になります。

通常のモード

bs_setmode( 1 ) を指定


参考スクリプト

bs_setmode は「最初に」「一度だけ」呼ぶようにしてください。

プレビュー中か判定する (0.9.140 から)

ブラシのプレビュー画像が描画されない場合があります (マウスやタブレットの場合は問題ないのに)。時間情報 (bs_ms()) を使った場合に起こりやすい問題です。

if bs_preview() then
  プレビュー時の特殊処理をここに挟む
end

のような感じで、bs_preview() 関数を使ってプレビュー中か判定できます。