kansen1/data/plugin/stmove.ks
2023-10-23 17:21:57 -05:00

697 lines
No EOL
15 KiB
Text

@if exp="typeof(global.stmove_object) == 'undefined'"
@iscript
/*
背景/前景画像の拡大縮小移動効果による表示を行うプラグインver.1.0
*/
class stmovePlugin extends KAGPlugin
{
var pluginName = "stmove"; // プラグインの名前
var cx, cy; // 回転中心
var time; // 描画時間
var accel; // 加速度的な動きを行うか ( 負 : 0 : 正 )
var targetLayerName; // 対象レイヤ名
var targetLayer; // 対象レイヤ
var targetPage; // 対象ページ(表/裏画面)
var type; // 描画レイヤータイプ
var storage; // 画像名
var opa; // 不透明度
var index; // 重ね合わせ順序
var flipud; // 上下反転
var fliplr; // 左右反転
var blur; // ブラーをかけるか
var blur_x, blur_y; // ブラーの強さ
var tempLayer; // テンポラリレイヤ
var totalTime; // 描画総時間
var path_array = void; // 移動位置用配列
var pointCount;
// スプライン補間
var zx = []; // スプラインワーク
var zy = []; // スプラインワーク
var spline; // スプライン補間を行うか
var actionFunc; // 移動位置計算関数
var first = false; // 始動判定フラグ
var moving = false; // 動作中フラグ
var nextstop; // 次回停止フラグ
var startTick; // 開始ティック
var lasttick = 0; // 前回ハンドラが描画開始した時間
var processTime; // stmove開始から終了までの時間
function stmovePlugin(window)
{
super.KAGPlugin();
this.window = window;
}
function finalize()
{
// finalize メソッド
// このクラスの管理するすべてのオブジェクトを明示的に破棄
stop();
invalidate tempLayer if tempLayer !== void;
super.finalize(...);
}
function startstmove(elm)
{
// storage : 表示画像
// layer : 対象レイヤ
// page : 対象ページ
// opacity : 不透明度
// path : 移動位置
// cx, cy : 回転中心位置(画像上)
// time : 描画を行っている時間
// accel : 加速をつけるかどうか
// blur : 画像をぼかすか
// blur_x,blur_y : ブラーの強さ
// spline : スプライン補間をするか
this.processTime = System.getTickCount();
var base = window.fore.base;
// 既存の動作を停止
stop();
// 対象レイヤーの設定
this.targetLayerName = elm.layer;
// 対象ページの設定
if(elm.page == "")
this.targetPage = "fore";
else
this.targetPage = elm.page;
// ブラーの強さの設定
this.blur_x = elm.blur_x;
this.blur_y = elm.blur_y;
// テンポラリレイヤを確保
{
if(tempLayer === void)
{
// 元画像の設定
this.storage = elm.storage;
tempLayer = new Layer(window, base);
//storageが指定されていない時は、対象レイヤーのpage=foreの画像を使用
if(storage == "")
{
if(targetLayerName == 'base')
{
tempLayer.assignImages(window.fore.base);
}
else
{
tempLayer.assignImages(window.fore.layers[+targetLayerName]);
}
}
else
{
tempLayer.loadImages(storage, clNone);
}
// 上下左右反転、ブラーの設定
if(elm.flipud == "")
this.flipud = false;
else
this.flipud = elm.flipud;
if(elm.fliplr == "")
this.fliplr = false;
else
this.fliplr = elm.fliplr;
if(elm.blur == "")
this.blur = false;
else
this.blur = elm.blur;
if(flipud)
tempLayer.flipUD();
if(fliplr)
tempLayer.flipLR();
if(blur)
tempLayer.doBoxBlur(blur_x, blur_y);
}
tempLayer.setSizeToImageSize();
}
// 対象レイヤを設定
{
// 重なり順序の設定
this.index = elm.index;
if(targetLayerName == 'base')
{
index = 0;
}
else
{
if(index == "")
index = int(+targetLayerName * 1000 + 1000);
else
index = int(index);
}
// 対象レイヤー・ページ、レイヤープロパティの設定
if(targetLayerName == 'base')
{
if(targetPage == 'back')
this.targetLayer = window.back.base;
else
this.targetLayer = window.fore.base;
targetLayer.type = ltOpaque;;
targetLayer.face = dfOpaque;
targetLayer.holdAlpha = false;
}
else
{
if(targetPage == 'back')
this.targetLayer = window.back.layers[+targetLayerName];
else
this.targetLayer = window.fore.layers[+targetLayerName];
this.type = (string)elm.type;
switch(type)// Layer.typeを判定
{
case "ltOpaque":
targetLayer.type = ltOpaque;
break;
case "ltAlpha":
targetLayer.type = ltAlpha;
break;
case "ltAddAlpha":
targetLayer.type = ltAddAlpha;
break;
case "ltAdditive":
targetLayer.type = ltAdditive;
break;
case "ltSubtractive":
targetLayer.type = ltSubtractive;
break;
case "ltMultiplicative":
targetLayer.type = ltMultiplicative;
break;
case "ltDodge":
targetLayer.type = ltDodge;
break;
case "ltDarken":
targetLayer.type = ltDarken;
break;
case "ltLighten":
targetLayer.type = ltLighten;
break;
case "ltScreen":
targetLayer.type = ltScreen;
break;
case "ltPsNormal":
targetLayer.type = ltPsNormal;
break;
case "ltPsAdditive":
targetLayer.type = ltPsAdditive;
break;
case "ltPsSubtractive":
targetLayer.type = ltPsSubtractive;
break;
case "ltPsMultiplicative":
targetLayer.type = ltPsMultiplicative;
break;
case "ltPsScreen":
targetLayer.type = ltPsScreen;
break;
case "ltPsOverlay":
targetLayer.type = ltPsOverlay;
break;
case "ltPsHardLight":
targetLayer.type = ltPsHardLight;
break;
case "ltPsSoftLight":
targetLayer.type = ltPsSoftLight;
break;
case "ltPsColorDodge":
targetLayer.type = ltPsColorDodge;
break;
case "ltPsColorDodge5":
targetLayer.type = ltPsColorDodge5;
break;
case "ltPsColorBurn":
targetLayer.type = ltPsColorBurn;
break;
case "ltPsLighten":
targetLayer.type = ltPsLighten;
break;
case "ltPsDarken":
targetLayer.type = ltPsDarken;
break;
case "ltPsDifference":
targetLayer.type = ltPsDifference;
break;
case "ltPsDifference5":
targetLayer.type = ltPsDifference5;
break;
case "ltPsExclusion":
targetLayer.type = ltPsExclusion;
break;
default:
targetLayer.type = ltAlpha;
}
// レイヤーtypeがltOpaqueなら、stFastLinear用にプロパティを設定
if(targetLayer.type == ltOpaque)
{
targetLayer.face = dfOpaque;
targetLayer.holdAlpha = false;
}
else
targetLayer.face = dfAuto;
targetLayer.setImageSize(base.imageWidth, base.imageHeight);
targetLayer.setPos(0,0, base.imageWidth,base.imageHeight);
targetLayer.absolute = index;
}
// 不透明度の設定
this.opa = (elm.opacity !== void) ? +elm.opacity : 255;
if(targetLayerName != 'base')
{
targetLayer.opacity = +opa;
}
}
// オブジェクトにパラメータを設定
{
// 描画時間の設定、pathの分解
if(elm.time == "")
this.time = 1000;
else
this.time = (int)elm.time;
this.path = elm.path;
path_array = [].split("(), ", path, , true);
var a = path_array.count - 1;
for(var i = a; i>=0; i--)
path_array[i] = +path_array[i];
pointCount = (path_array.count \ 3) - 1;
totalTime = pointCount * time;
// 回転中心
if(elm.cx == "" || elm.cx == 'c')
this.cx = tempLayer.imageWidth \ 2;
else if(typeof +cx == 'Real')
this.cx = tempLayer.imageWidth * +elm.cx;
else
this.cx = (int)elm.cx;
if(elm.cy == "" || elm.cy == 'c')
this.cy = tempLayer.imageHeight \ 2;
else if(typeof +elm.cy == 'Real')
this.cy = tempLayer.imageHeight * +elm.cy;
else
this.cy = (int)elm.cy;
// 加速度の設定
if(elm.accel == "")
this.accel = 0;
else
this.accel = (real)elm.accel;
}
// スプライン設定
if(elm.spline == "")
this.spline = false ;
else
this.spline = elm.spline;
// コンソールにstmoveの情報を出力
dm('■stmove : layer = ' + targetLayerName + ' : spline = ' + spline+ ' : index = '+index);
// スプライン補間を行うか?
if(spline)
{
// 移動位置計算関数の設定
if(path_array.count < 9)
{
// 3 点以下 ( 指定するのはそのうちの2点 ) は補完できない
throw new Exception("2 点以上を指定してください");
}
// スプライン補間に必要なワークを計算
var points = path_array.count \ 3;
var tmpx = [], tmpy = [];
var tx = zx, ty = zy;
tx[0] = 0;
ty[0] = 0;
tx[points-1] = 0;
ty[points-1] = 0;
for(var i = points-2, pi = path_array.count-6; i >= 0; i--, pi -= 3)
{
tmpx[i+1] = (path_array[pi + 3] - path_array[pi ]);
tmpy[i+1] = (path_array[pi + 4] - path_array[pi+1]);
}
tx[1] = tmpx[2] - tmpx[1] - tx[0];
ty[1] = tmpy[2] - tmpy[1] - ty[0];
tmpx[1] = 4;
tmpy[1] = 4;
var lim = points - 2;
for(var i = 1, pi = 3; i < lim; i++, pi += 3)
{
var x = 1 / tmpx[i];
var y = 1 / tmpy[i];
tx[i+1] = tmpx[i+2] - tmpx[i+1] - tmpx[i] * x;
ty[i+1] = tmpy[i+2] - tmpy[i+1] - tmpy[i] * y;
tmpx[i+1] = 4 - x;
tmpy[i+1] = 4 - y;
}
tx[points-2] -= tx[points-1];
ty[points-2] -= ty[points-1];
for(var i = points-2, pi = path_array.count-6; i>0; i--, pi -= 3)
{
tx[i] = (tx[i] - tx[i+1]) / tmpx[i];
ty[i] = (ty[i] - ty[i+1]) / tmpy[i];
}
// 移動位置計算関数の設定
actionFunc = splineMover;
}
else
{
// 移動位置計算関数の設定
actionFunc = defaultMover;
}
// 描画の開始
if(time <= 0)// timeが0以下ならすぐに終了処理へ
targetLayer.visible = true,finish();
else
{
// 初期位置に表示
actionFunc(0);
targetLayer.visible = true;
// 開始
first = true;
System.addContinuousHandler(continuousHandler);
moving = true;
nextstop = false;
}
}
// スプライン補間用、移動位置計算関数
/*static*/ function splineMover(tick)
{
var inde;
var pindex = (inde = tick \ time) * 3;
var d = tick % time / time;
var p = path_array;
var l = (((zx[inde+1] - zx[inde])*d +
zx[inde]*3)*d +
((p[pindex + 3] - p[pindex]) -
(zx[inde]*2 + zx[inde+1]))) * d +
p[pindex];
var t = (((zy[inde+1] - zy[inde])*d +
zy[inde]*3)*d +
((p[pindex + 4] - p[pindex+1]) -
(zy[inde]*2 + zy[inde+1]))) * d +
p[pindex+1];
var sm = p[pindex+2];
var em = p[pindex+5];
var s = (em - sm) * d + sm;
var m00, m01, mtx, mty;
m00 = tempLayer.imageWidth * s;
m01 = tempLayer.imageHeight * s;
mtx = -(cx) * s + l;
mty = -(cy) * s + t;
// m00 m01 mtx mty 位置に移動
targetLayer.visible = true;
// レイヤを一度クリアする
targetLayer.fillRect(0,0, targetLayer.imageWidth,targetLayer.imageHeight, 0);
// 拡大縮小転送
if(targetLayer.type == ltOpaque)
{
dm("stFastLinear");
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omOpaque, 255, stFastLinear);
}
else
{
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omAuto, 255, stNearest);
}
}
// 通常用、移動位置計算関数
/*static*/ function defaultMover(tick)
{
// 位置計算
var indexM = tick \ time * 3;
var ratio = tick % time / time;
var p = path_array;
var sx = p[indexM];
var sy = p[indexM+1];
var sm = p[indexM+2];
var ex = p[indexM+3];
var ey = p[indexM+4];
var em = p[indexM+5];
var s = (em - sm) * ratio + sm;
var x = (ex - sx) * ratio + sx;
var y = (ey - sy) * ratio + sy;
var m00, m01, mtx, mty;
m00 = tempLayer.imageWidth * s;
m01 = tempLayer.imageHeight * s;
mtx = -(cx) * s + x;
mty = -(cy) * s +y;
// m00 m01 mtx mty 位置に移動
targetLayer.visible = true;
// レイヤを一度クリアする
targetLayer.fillRect(0,0, targetLayer.imageWidth,targetLayer.imageHeight, 0);
// 拡大縮小転送
if(targetLayer.type == ltOpaque)// レイヤータイプがltOpaqueならstFastLinear(線形補間)
{
dm("stFastLinear");
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omOpaque, 255, stFastLinear);
}
else
{
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omAuto, 255, stNearest);
}
}
function continuousHandler(tick)
{
// 移動中に呼ばれる
if(nextstop) { finish(); return; }
if(first) startTick = tick, first = false;
tick -= startTick;
if(tick >= totalTime)
{
nextstop = true;
return;
}
var intervalTime = System.getTickCount() - lasttick;
if(intervalTime > 15)// ハンドラが15ms以内に呼ばれたら、描画しない
{
if(accel < 0)
{
// 上弦 ( 最初が動きが早く、徐々に遅くなる )
tick = 1.0 - tick / totalTime;
tick = Math.pow(tick, -accel);
tick = int ( (1.0 - tick) * totalTime );
}
else if(accel > 0)
{
// 下弦 ( 最初は動きが遅く、徐々に早くなる )
tick = tick / totalTime;
tick = Math.pow(tick, accel);
tick = int (tick * totalTime);
}
lasttick = System.getTickCount();
// 移動
actionFunc(tick);
}
}
function finish()
{
// 最終位置に移動
var idx = int(pointCount * 3);
var pz = path_array;
var m00, m01, mtx, mty;
m00 = tempLayer.imageWidth * pz[idx+2];
m01 = tempLayer.imageHeight * pz[idx+2];
mtx = -(cx) * pz[idx+2] + pz[idx];
mty = -(cy) * pz[idx+2] + pz[idx+1];
targetLayer.visible = true;
// レイヤを一度クリアする
targetLayer.fillRect(0,0, targetLayer.imageWidth,targetLayer.imageHeight, 0);
// 拡大縮小転送
if(targetLayer.type == ltOpaque)// レイヤータイプがltOpaqueならstFastLinear(線形補間)
{
dm("stFastLinear");
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omOpaque, 255, stFastLinear);
}
else
{
targetLayer.operateStretch(mtx, mty, m00, m01,
tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, omAuto, 255, stNearest);
}
// 回転ズームの終了
stop(); // 停止
}
function stop()
{
// 停止
if(moving)
{
window.trigger(pluginName);
System.removeContinuousHandler(continuousHandler);
moving = false;
dm("■stmove実行時間 :"+ (System.getTickCount() - processTime) +"ms■");
}
invalidate tempLayer if tempLayer !== void;
tempLayer = void;
targetLayer = void;
}
function onStore(f, elm)
{
}
function onRestore(f, clear, elm)
{
// 栞を読み出すとき
stop(); // 動作を停止
}
function onStableStateChanged(stable)
{
}
function onMessageHiddenStateChanged(hidden)
{
}
function onCopyLayer(toback)
{
}
function onExchangeForeBack()
{
}
}
// プラグインオブジェクトを作成し、登録する
kag.addPlugin(global.stmove_object = new stmovePlugin(kag));
@endscript
@endif
; マクロ登録
@macro name="stmove"
;skipModeが2以上のときは描画しない
@eval exp="mp.time = 0" cond="kag.skipMode >= 2"
@eval exp="stmove_object.startstmove(mp)"
@endmacro
;
@macro name="wstmove"
@if exp="stmove_object.moving"
@eval exp="stmove_object.finish()" cond="kag.skipMode >= 2"
@waittrig * name="stmove" onskip="stmove_object.finish()" canskip=%canskip|true
@endif
@endmacro
;
@macro name=wsm
@wstmove *
@endmacro
;
@return