/* ***** BEGIN LICENSE BLOCK ***** Copyright (c) 2018-2020 Famibee (famibee.blog38.fc2.com) This software is released under the MIT License. http://opensource.org/licenses/mit-license.php ** ***** END LICENSE BLOCK ***** */ import {CmnLib, getDateStr, uint, IEvtMng, cnvTweenArg, hMemberCnt, argChk_Boolean, argChk_Num, getExt} from './CmnLib'; import {CmnTween, ITwInf} from './CmnTween'; import {IHTag, IVariable, IMain, HPage, HArg} from './CmnInterface'; import {Pages} from './Pages'; import {GrpLayer} from './GrpLayer'; import {TxtLayer} from './TxtLayer'; import {RubySpliter} from './RubySpliter'; import {Config} from './Config'; import {ScriptIterator} from './ScriptIterator'; import {SysBase} from './SysBase'; import {FrameMng} from './FrameMng'; import {Button} from './Button'; const Tween = require('@tweenjs/tween.js').default; import {Container, Application, Graphics, Texture, Filter, RenderTexture, Sprite, DisplayObject, autoDetectRenderer} from 'pixi.js'; import {EventListenerCtn} from './EventListenerCtn'; export class LayerMng { private stage : Container; private fore = new Container; private back = new Container; private frmMng : FrameMng; constructor(private readonly cfg: Config, private readonly hTag: IHTag, private readonly appPixi: Application, private readonly val: IVariable, private readonly main: IMain, private readonly scrItr: ScriptIterator, private readonly sys: SysBase) { // レスポンシブや回転の対応 const cvs = document.getElementById(CmnLib.SN_ID) as HTMLCanvasElement; const fncResizeLay = ()=> { if (! CmnLib.cvsResize(cvs)) return; this.aLayName.forEach(layer=> { const pg = this.hPages[layer]; pg.fore.cvsResize(); pg.back.cvsResize(); }); this.frmMng.cvsResize(); }; if (CmnLib.isMobile) { window.addEventListener('orientationchange', fncResizeLay, {passive: true}); } else { let tid: any = 0; window.addEventListener('resize', ()=> { if (tid) return; tid = setTimeout(()=> {tid = 0; fncResizeLay();}, 500); }, {passive: true}); } CmnLib.cvsResize(cvs); TxtLayer.init(cfg, hTag, val, (txt: string)=> this.recText(txt)); GrpLayer.init(main, cfg, sys); this.frmMng = new FrameMng(this.cfg, this.hTag, this.appPixi, this.val, main, this.sys, this.hTwInf); sys.hFactoryCls.grp = ()=> new GrpLayer; sys.hFactoryCls.txt = ()=> new TxtLayer; // システム hTag.loadplugin = o=> this.loadplugin(o); // プラグインの読み込み hTag.set_focus = o=> this.set_focus(o); // フォーカス移動 hTag.snapshot = o=> this.snapshot(o); // スナップショット // レイヤ共通 hTag.add_lay = o=> this.add_lay(o); // レイヤを追加する hTag.clear_lay = o=> this.clear_lay(o); // レイヤ設定の消去 hTag.finish_trans = ()=> this.finish_trans(); // トランス強制終了 hTag.lay = o=> this.lay(o); // レイヤ設定 hTag.trans = o=> this.trans(o); // ページ裏表を交換 hTag.wt = o=> this.wt(o); // トランス終了待ち hTag.quake = o=> this.quake(o); // 画面を揺らす hTag.stop_quake = o=> hTag.finish_trans(o); // 画面揺らし中断 hTag.wq = o=> hTag.wt(o); // 画面揺らし終了待ち hTag.pause_tsy = o=> this.pause_tsy(o); // 一時停止 hTag.resume_tsy = o=> this.resume_tsy(o); // 一時停止再開 hTag.stop_tsy = o=> this.stop_tsy(o); // トゥイーン中断 hTag.tsy = o=> this.tsy(o); // トゥイーン開始 hTag.wait_tsy = o=> this.wait_tsy(o); // トゥイーン終了待ち // 文字・文字レイヤ // hTag.auto_pager = o=> this.auto_pager(o); // 自動改ページの設定 //hTag.autowc // TxtLayer.ts で定義 // 文字ごとのウェイト hTag.ch = o=> this.ch(o); // 文字を追加する //hTag.ch_in_style // TxtLayer.ts で定義 // 文字出現文字出現演出 //hTag.ch_out_style // TxtLayer.ts で定義 // 文字消去文字出現演出 hTag.clear_text = o=> this.clear_text(o); // 文字消去 hTag.current = o=> this.current(o); // デフォルト文字レイヤ設定 hTag.endlink = ()=> this.endlink(); // ハイパーリンクの終了 hTag.er = o=> this.er(o); // ページ両面の文字消去 hTag.graph = o=> this.graph(o); // インライン画像表示 hTag.link = o=> this.link(o); // ハイパーリンク hTag.r = o=> this.r(o); // 改行 hTag.rec_ch = o=> this.rec_ch(o); // 履歴書き込み hTag.rec_r = ()=> this.rec_r(); // 履歴改行 hTag.reset_rec = o=> this.reset_rec(o); // 履歴リセット //hTag.ruby = o=> this.ruby(o); // 直前一文字のルビ(廃止 // タグでは無く、「|@《》」というスクリプト書き換えで良い hTag.ruby2 = o=> this.ruby2(o); // 文字列と複数ルビの追加 hTag.span = o=> this.span(o); // インラインスタイル設定 hTag.tcy = o=> this.tcy(o); // 縦中横を表示する // 画像・画像レイヤ hTag.add_face = o=> GrpLayer.add_face(o); // 差分名称の定義 // ムービーレイヤ hTag.wv = o=> GrpLayer.wv(o); // ムービー再生終了待ち // デバッグ・その他 hTag.dump_lay = o=> this.dump_lay(o); // レイヤのダンプ // イベント hTag.enable_event = o=> this.enable_event(o); // イベント有無の切替 // ラベル・ジャンプ hTag.button = o=> this.button(o); // ボタンを表示 if (cfg.existsBreakline) this.breakLine = ()=> this.cmdTxt('grp|{"id":"break","pic":"breakline"}'); if (cfg.existsBreakpage) this.breakPage = ()=> this.cmdTxt('grp|{"id":"break","pic":"breakpage"}'); const grp = new Graphics; grp.beginFill(cfg.oCfg.init.bg_color, 1); // イベントを受け取るためにも塗る grp.lineStyle(0, cfg.oCfg.init.bg_color); grp.drawRect(0, 0, CmnLib.stageW, CmnLib.stageH); grp.endFill(); this.fore.addChild(grp.clone()); this.back.addChild(grp); this.back.visible = false; this.stage = this.appPixi.stage; this.stage.addChild(this.back); this.stage.addChild(this.fore); this.stage.addChild(this.spTransBack); this.stage.addChild(this.spTransFore); this.appPixi.ticker.add(this.fncTicker); // TWEEN 更新 /* console.group('new DispMng info'); console.info(this.appPixi.renderer); console.info('utils.isMobile():'+ utils.isMobile.any); // https://github.com/kaimallea/isMobile console.info('utils.isWebGLSupported():'+ utils.isWebGLSupported()); console.info('w:%O: h:%O:', CmnLib.stageW, CmnLib.stageH); console.groupEnd(); */ const fncTxt_b_alpha = (_name: string, val: any)=> { this.foreachRedrawTxtLayBack(Number(val)) }; fncTxt_b_alpha('', val.getVal('sys:TextLayer.Back.Alpha', 1)); val.defValTrg('sys:TextLayer.Back.Alpha', fncTxt_b_alpha); const fncBtnFont = (_name: string, val: any)=> { Button.fontFamily = val; }; fncBtnFont('', val.getVal('tmp:sn.button.fontFamily', Button.fontFamily)); val.defValTrg('tmp:sn.button.fontFamily', fncBtnFont); val.defTmp('const.sn.log.json', ()=> JSON.stringify( [...this.aPageLog, this.oLastPage] )); val.defTmp('const.sn.last_page_text', ()=> { const tl = this.getCurrentTxtlayFore(); return tl ?tl.pageText :''; }); } private fncTicker = ()=> Tween.update(); private grpCover : Graphics | null = null; cover(visible: boolean, bg_color: number = 0x0) { if (this.grpCover) { this.stage.removeChild(this.grpCover); this.grpCover.destroy(); this.grpCover = null; } if (visible) { this.grpCover = new Graphics; this.grpCover.beginFill(bg_color); this.grpCover.lineStyle(0, bg_color); this.grpCover.drawRect(0, 0, CmnLib.stageW, CmnLib.stageH); this.grpCover.endFill(); this.stage.addChild(this.grpCover); } } private evtMng : IEvtMng; setEvtMng(evtMng: IEvtMng) { this.evtMng = evtMng; this.frmMng.setEvtMng(evtMng); GrpLayer.setEvtMng(evtMng); } before_destroy() {for (const pg in this.hPages) this.hPages[pg].destroy();} destroy() { GrpLayer.destroy(); RubySpliter.destroy(); this.frmMng.destroy(); Tween.removeAll(); this.appPixi.ticker.remove(this.fncTicker); LayerMng.$msecChWait = 10; } // 既存の全文字レイヤの実際のバック不透明度、を再計算 private foreachRedrawTxtLayBack(g_alpha: number): void { const vct = this.getLayers(); const len = vct.length; for (let i=0; i tl.tagCh('| 《'+ cmd +'》'); goTxt = ()=> {}; breakLine = ()=> {}; breakPage = ()=> {}; clearBreak() { if (! this.getCurrentTxtlayFore()) return; this.clearBreak = ()=> this.cmdTxt('del|break'); this.clearBreak(); } clickTxtLay(): boolean { // true is stay const tl = this.getCurrentTxtlayFore(); if (! tl) return true; // イベントを受ける文字レイヤが一つでも存在すれば、クリック待ち解除(false)する const vct = this.getLayers(); const len = vct.length; for (let i=0; i 0x1000000) && (ext === 'png'), antialias: argChk_Boolean(hArg, 'smoothing', false), preserveDrawingBuffer: true, backgroundColor: uint(b_color) & 0xFFFFFF, autoDensity: true, }); const a = []; if (this.twInfTrans.tw) { // [trans]中 a.push(new Promise(re=> { this.back.visible = true; for (const lay of this.aBackTransAfter) { renderer.render(lay, undefined, false); } this.back.visible = false; this.spTransBack.visible = true; this.fore.filters = this.spTransFore.filters; this.fore.visible = true; renderer.render(this.fore, undefined, false); this.fore.visible = false; this.fore.filters = []; re(); })); } else { const pg = (hArg.page !== 'back') ?'fore' :'back'; for (const v of this.getLayers(hArg.layer)) a.push(new Promise( re=> this.hPages[v][pg].snapshot(renderer, re) )); } Promise.all(a).then(()=> { this.sys.savePic( this.cfg.searchPath(fn), this.appPixi.renderer.extract.base64(this.stage) ); if (! this.twInfTrans.tw) { const pg = (hArg.page !== 'back') ?'fore' :'back'; for (const v of this.getLayers(hArg.layer)) this.hPages[v][pg].snapshot_end(); } renderer.destroy(true); }); return false; } // プラグインの読み込み private loadplugin(hArg: HArg) { const fn = hArg.fn; if (! fn) throw 'fnは必須です'; const join = argChk_Boolean(hArg, 'join', true); switch (getExt(fn)) { case 'css': // 読み込んで