//=============================================================================
// MirageFilter.js
// Copyright (c) 2024- 村人Ａ
//=============================================================================
/*:
 * @target MZ
 * @plugindesc マップ画面に蜃気楼のような歪み効果を与えるフィルターを適用します。
 * @author 村人Ａ
 *
 * @param amp
 * @text 揺れ幅
 * @desc 波の幅を指定します(初期値:5)。値が大きいほど揺れが強くなります。
 * @default 5
 * @type number
 *
 * @param frequency
 * @text 振動の速さ
 * @desc 波の振動の速さを指定します(初期値:2)。
 * 2を基準として、大きいほど振動が速く、小さいほど遅くなります。
 * @default 2
 * @type number
 *
 * @command switchFilter
 * @text フィルターのON/OFF
 * @desc 蜃気楼フィルターを適用開始します。
 *
 * @command fadeoutFilter
 * @text フィルターを終わる
 * @desc 蜃気楼フィルターを徐々に弱め、自然な形で終了させます。
 *
 * @help
 * ============================================================================
 * バージョン管理
 * ============================================================================
 * 24/12/10 ver 1.0 リリース
 *
 * ============================================================================
 * 概要
 * ============================================================================
 * このプラグインは、マップ画面に蜃気楼(ミラージュ)のようなゆらめく歪み効果を
 * 付与するフィルターを適用します。フィルターをONにすると、地面や背景が波打つ
 * ような視覚効果が追加され、暑い砂漠や異世界の雰囲気を演出することができます。
 * また、フェードアウト機能を使うことで、揺らめきを自然に収束させ、違和感なく
 * 効果を終了させることが可能です。
 *
 * ============================================================================
 * パラメータ
 * ============================================================================
 * - **揺れ幅（amp）**
 *   波の振幅（ゆらめきの強さ）を指定します。
 *   値が大きいほどゆらめきが激しくなります。
 *
 * - **振動の速さ（frequency）**
 *   揺れが進行する速さを指定します。2が基準値で、それより大きくすれば速く、
 *   小さくすれば遅くなります。
 *
 * これらの値を調整することで、マップ上の蜃気楼表現を微調整できます。
 *
 * ============================================================================
 * プラグインコマンド
 * ============================================================================
 * ### フィルターのON/OFF (switchFilter)
 * 蜃気楼フィルターを適用開始します。
 * 実行後、マップ上に揺らめく歪み効果が発生します。
 *
 * ### フィルターを終わる (fadeoutFilter)
 * 適用中の蜃気楼フィルターを自然に収束させます。
 * 実行後、ゆらめきは徐々に弱まり、最終的にフィルターが自動的に解除されます。
 *
 * ============================================================================
 * 使い方
 * ============================================================================
 * 1. **プラグインの導入**
 *    プラグインマネージャーで「MirageFilter.js」を有効にしてください。
 *
 * 2. **パラメータ設定**
 *    - `揺れ幅（amp）`でゆらめきの強さを調節します。
 *    - `振動の速さ（frequency）`で揺れが進行する速度を変更します。
 *
 * 3. **フィルターの適用・解除**
 *    イベントで「プラグインコマンド」を使用します。
 *    - 「フィルターのON/OFF (switchFilter)」で蜃気楼効果を開始
 *    - 「フィルターを終わる (fadeoutFilter)」で徐々に収束させて終了
 *
 * 例:
 * ```
 * ◆プラグインコマンド：MirageFilter, フィルターのON/OFF
 * （マップが蜃気楼状態に）
 *
 * --- イベント進行後またはしばらく待った後 ---
 *
 * ◆プラグインコマンド：MirageFilter, フィルターを終わる
 * （ゆらめきがゆっくりと収まる）
 * ```
 *
 * ============================================================================
 * 注意事項
 * ============================================================================
 * - フィルター適用中は描画負荷が若干増加する場合があります。
 * - 他の描画系プラグインやフィルターとの併用時には挙動を確認してください。
 * - 利用規約は以下からご確認ください。
 *   https://www.rpgmaker-script-wiki.xyz/kiyaku.php
 *
 * ============================================================================
 * 不具合報告
 * ============================================================================
 * 不具合はXやメールで報告してください。
 * Xアカウント：＠rpgmaker_villaA
 * メール：villaa.contact＠gmail.com
 *
 */

{
	'use strict';
	
	const pluginName = "villaA_MirageFilter";
    const param      = PluginManager.parameters(pluginName);
	const waveAmp = Number(param.amp) * 0.001;
	const waveFrequency = Number(param.frequency) * 0.01;
	
	//-----------------------------------------------------------------------------
	// MirageFilter
	//
	
	function MirageFilter() {
		this.initialize(...arguments);
	}

	MirageFilter.prototype = Object.create(PIXI.Filter.prototype);
	MirageFilter.prototype.constructor = MirageFilter;

	MirageFilter.prototype.initialize = function() {
		PIXI.Filter.call(this, null, this._fragmentSrc());
		this.isFadeout = false;
		this.reset();
	};
	
	MirageFilter.prototype.reset = function() {
		this.uniforms.iTime = 0.0;
		this.uniforms.amp = 0.0;
	};

	MirageFilter.prototype.fadeout = function() {
		this.uniforms.iTime = this.uniforms.iTime % 3.1415;
		this.isFadeout = true;
	};

	MirageFilter.prototype.updateTime = function() {
    this.updateOffset();
		this.uniforms.iTime += waveFrequency;
		this.uniforms.amp = this.isFadeout ? waveAmp * Math.min(3.1415 - this.uniforms.iTime, 1.0) : waveAmp * Math.min(this.uniforms.iTime, 1.0);
		if (this.isFadeout && this.uniforms.amp <= 0.0) {
			this.uniforms.iTime = 0.0;
			$gameSystem.switchMirageFiter = false;
			if (SceneManager._scene && SceneManager._scene.removeMirageFilter) {
				SceneManager._scene.removeMirageFilter();
			}
		}
	};
	
	MirageFilter.prototype.updateOffset = function() {
		this.uniforms.offsetX = $gameMap.displayX();
		this.uniforms.offsetY = $gameMap.displayY();
	};

	MirageFilter.prototype._fragmentSrc = function() {
		let src =
			"varying vec2 vTextureCoord;" +
			"uniform float iTime;" +
			"uniform float amp;" +
			"uniform float offsetX;" +
			"uniform float offsetY;" +
			"uniform sampler2D uSampler;" +
			"void main(){gl_FragColor = texture2D(uSampler, vTextureCoord + vec2(sin((vTextureCoord.y + offsetY * 0.1) * 10.0 + iTime * 2.0) * amp, 0.0));}";
		return src;
	};


	//-----------------------------------------------------------------------------
	// PluginManager
	//
	
	PluginManager.registerCommand(pluginName, "switchFilter", args => {
		$gameSystem.switchMirageFiter = true;
		SceneManager._scene.setMirageFilterToSpriteset();
	});
	
	PluginManager.registerCommand(pluginName, "fadeoutFilter", args => {
		SceneManager._scene.mirageFilter.fadeout();
	});
	
	//-----------------------------------------------------------------------------
	// PluginManager
	//
	
	const _alias_Game_System_initialize = Game_System.prototype.initialize;
	Game_System.prototype.initialize = function() {
		_alias_Game_System_initialize.call(this)
		this.switchMirageFiter = false;
	};

	//-----------------------------------------------------------------------------
	// Scene_Map
	//
	
	const _alias_Scene_Map_createSpriteset = Scene_Map.prototype.createSpriteset;
	Scene_Map.prototype.createSpriteset = function() {
		_alias_Scene_Map_createSpriteset.call(this)
		if(!this._spriteset.filters){
			this._spriteset.filters = [];
		}
		if($gameSystem.switchMirageFiter){
			this.setMirageFilterToSpriteset()
		}
	};
	
	Scene_Map.prototype.setMirageFilterToSpriteset = function() {
		if(this.mirageFilter){
			this.mirageFilter.reset();
		} else {
			this.mirageFilter = new MirageFilter();
			this._spriteset.filters.push(this.mirageFilter)
		}
	};
	
	Scene_Map.prototype.removeMirageFilter = function() {
		if (this.mirageFilter) {
			this._spriteset.filters = this._spriteset.filters.filter(filter => filter !== this.mirageFilter);
			this.mirageFilter = null;
		};
	};

	const _alias_Scene_Map_update = Scene_Map.prototype.update;
	Scene_Map.prototype.update = function() {
		_alias_Scene_Map_update.call(this)
		if(this.mirageFilter){this.mirageFilter.updateTime()}
	};
};
































