/*---------------------------------------------------------------------*//**
	デシリアライズ(セーブデータ読み込み)通知
**//*---------------------------------------------------------------------*/
void FocusCursor::notifyDeserialize()
{
	// フォーカスを復帰
	UnitManager* unitmng = Game::getGame()->getUnitManager();	ASSERT(unitmng != 0L);
	for(int i = 0; i < unitmng->getUnitNum(); i++)
	{
		Unit* unit = unitmng->getUnitFromIndex(i); ASSERT(unit != 0L);
		if(unit->isGuiFocused())
		{
			setFocus(0, unit);
		}
	}
}
/*---------------------------------------------------------------------*//**
	描画
**//*---------------------------------------------------------------------*/
void FocusCursor::draw(const RenderCtx* rc)
{
	if(!_isEnableOut || !_isEnableSelf)	{	return;	}	// 無効化中
	
	GameRenderCtx* grc = (GameRenderCtx*)rc;
	Renderer* rdr = rc->getRenderer();
	RectF32 uv;

	// テクスチャ設定
	rdr->bindTexture(_texRef);
	// 加算アルファ合成
	rdr->setAlphaBlendFunc(Renderer::AFUNC_ADD);
	// 2D 解像描画比
	f32 rate2dr = Env_get2drRate();
	// 頂点カラーを基本色に
	rdr->setSolidColor(255, 255, 255, 255);

	// クリック対象を描画
	{
		Tfw* tfw = Game::getGame()->getTfw();						ASSERT(tfw != 0L);
		View* view = tfw->getView();								ASSERT(view != 0L);
		SorSgm* sgm = (SorSgm*)tfw->getSgManager();					ASSERT(sgm != 0L);
		Camera* cam = sgm->getVisibleCamera();
		if(cam != 0L)
		{
			UnitManager* unitmng = Game::getGame()->getUnitManager();	ASSERT(unitmng != 0L);
			for(int i = 0; i < unitmng->getUnitNum(); i++)
			{
				const Unit* unit = unitmng->getUnitFromIndex(i); ASSERT(unit != 0L);
				if(!unit->isEnable())				{	continue;	}	// 無効なユニットは除外
				if(!unit->isEnableFocus())			{	continue;	}	// フォーカスされないユニットは除外
				if(unit->isHidden())				{	continue;	}	// 隠し属性ユニットは除外
				if(unit->isHiddenClick())			{	continue;	}	// クリック選択不可
				if(unit->getUnitType() == UNITTYPE_EQUIPMENT_ITEM)	{	continue;	}	// 所持品は除外
				if(unit->getCenterPos()->z() >= cam->getLoc()->z())	{	continue;	}	// カメラより手前は除外

				// 既にフォーカスがあるユニットは不要
				bool isHadFocus = false;
				for(s32 j = 0; j < NUM_FOCUS_MAX; j++)
				{
					if(_focusarr->getUnit(j) == unit)
					{
						isHadFocus = true;
						break;
					}
				}
				if(isHadFocus)						{	continue;	}

				// スクリーン座標に変換
				Vector2F vScr;
				Gcalc::conv3dPosToScreenPos(&vScr, unit->getCenterPos(), cam, view);

				// 画面外チェック
				if(	((vScr.x() + W_FOCUS_CIRC) < 0) ||
					((vScr.x() - W_FOCUS_CIRC) >= Game::getGame()->getLogicalWidth()) ||
					((vScr.y() + H_FOCUS_CIRC) < 0) ||
					((vScr.y() - H_FOCUS_CIRC) >= Game::getGame()->getLogicalHeight()) )
				{
					continue;
				}

				// 描画
				::glPushMatrix();	// 行列を保存
				::glTranslatef(vScr.x(), vScr.y(), 0.0f);
				drawQuestIcon(rdr, unit, rate2dr);	// クエストアイコン表示
				::glRotatef(_dangFocusable, 0.0f, 0.0f, 1.0f);
				// フォーカス可能アイコン表示
				RectF32 vtx(- W_FOCUS_CIRC / 2, - H_FOCUS_CIRC / 2, W_FOCUS_CIRC, H_FOCUS_CIRC);
				RendererUtils::draw2dTextureRect(rdr, &vtx, Gcalc::calcTexUv(&uv, UV_FOCUSABLE, W_TEX, H_TEX, rate2dr));
				::glPopMatrix();	// 行列を戻す
			}
		}
	}

	// フォーカスカーソル表示
	drawFocusCursor(rdr, _focusarr, 1.0f, rate2dr);

	// マジッククラスターのフォーカスを表示
	MagicSys* mgsys = Game::getGame()->getMagicSys();
	for(int i = 0; i < mgsys->getMaxClusterNum(); i++)
	{
		MagicCluster* mc = mgsys->getClusterFromIndex(i);
		if(mc == 0L)			{	continue;	}
		if(!mc->isValid())		{	continue;	}
		if(!TFW_IS_FLAG(mc->getConfFlags(), MagicCluster::CONFF_SHOW_FC))	{	continue;	}
		rdr->setSolidColor(63, 0, 255, 255);
		drawFocusCursor(rdr, mc->getFocusArray(), 0.5f, rate2dr);
	}

	// 通常アルファ合成
	rdr->setAlphaBlendFunc(Renderer::AFUNC_NORMAL);

	// フォーカスゲージ表示
	for(s32 i = 0; i < NUM_FOCUS_MAX; i++)
	{
		const Unit* unitFocused = _focusarr->getUnit(i);
		if(unitFocused == 0L)	{	continue;	}	// フォーカスがある場合のみ以下を処理する
		const Vector2F* posScr = _focusarr->getScreenPos(i);

		f32 x = posScr->x() + W_FOCUS_CIRC * 0.5f;
		f32 y = posScr->y();

		// ゲージ表示
		if(unitFocused->isCategory(Unit::UNITCAT_CHAR))
		{
			const CharUnit* cunit = (CharUnit*)unitFocused;
			const CharStat* cstat = cunit->getCharStat();
			if(cstat != 0L)
			{
				StatusDrawer::drawCharStat(rc, _texRef, cstat, x, y, StatusDrawer::W_GAUGE_DEFAULT, StatusDrawer::H_GAUGE_DEFAULT, false, false);
			}
		}
		else if(unitFocused->getUnitType() == UNITTYPE_EQUIPMENT_ITEM)
		{
			const EquipmentItemUnit* iunit = (EquipmentItemUnit*)unitFocused;
			const Item* item = iunit->getItem();
			if(item != 0L)
			{
				// 名前表示
				const VcString* name = item->getItemDef()->getName(Env_getLangId());
				if(name != 0L)
				{
					rdr->setSolidColor(255, 255, 255, 255);
					Font* fontJp = grc->getFontSet()->getFont(GameFontSet::JP);
					EasyStringDrawer::draw(fontJp, name, x, y, 8, rc);
					y += 8.0f;
				}

				const EleneStat* eestat = item->getEleneStat();
				if(eestat != 0L)
				{
					StatusDrawer::drawEleneStat(rc, _texRef, eestat, x, y, 60.0f, StatusDrawer::H_ENEGAUGE_DEFAULT, false);
				}
			}
		}
		else if(unitFocused->getUnitType() == UNITTYPE_PUT_ITEM)
		{
			const PutItemUnit* diunit = (PutItemUnit*)unitFocused;
			const ItemDef* itmdf = diunit->getItemDef();
			if(itmdf != 0L)
			{
				// 名前表示
				const VcString* name = itmdf->getName(Env_getLangId());
				if(name != 0L)
				{
					rdr->setSolidColor(255, 255, 255, 255);
					Font* fontJp = grc->getFontSet()->getFont(GameFontSet::JP);
					EasyStringDrawer::draw(fontJp, name, x, y, 8, rc);
					y += 8.0f;
				}
			}
			const EleneStat* eestat = diunit->getEleneStat();
			if(eestat != 0L)
			{
				StatusDrawer::drawEleneStat(rc, _texRef, eestat, x, y, 60.0f, StatusDrawer::H_ENEGAUGE_DEFAULT, false);
			}
		}
	}
}
/*---------------------------------------------------------------------*//**
	フレーム制御
**//*---------------------------------------------------------------------*/
void FocusCursor::exec(ExecRes* res, const ExecCtx* ec)
{
	if(!_isEnableOut)	{	return;	}	// 外部からの無効化

	GameExecCtx* gec = (GameExecCtx*)ec;
	TouchPanel* ui = gec->getTouchPanel(); 

	// フォーカスの有効性更新
	_focusarr->updateValidity();
	// フォーカスの座標値をリセット
	for(s32 i = 0; i < NUM_FOCUS_MAX; i++)
	{
		_focusarr->invalidateScreenPos(i);
	}

	// 有効性判定
	_isEnableSelf = !gec->isLockOperating();
	bool isEnableUiReact = _isEnableSelf && !gec->isOpenedLockGui() && !ui->isReacted() && (_fcntPreventTap == 0.0f);

	// タッチ操作による処理
	if(isEnableUiReact) 
	{
		PointF32 ptTouch, ptStart;
		bool isTap = false;
		bool isDblTapRel = false;
		if(!ui->isReacted())
		{
			const f32 DIFF_TAP_RANGE = 20.0f;
			if(ui->isTapRelease(&ptTouch, &ptStart)) { isTap = ptTouch.isNear(&ptStart, DIFF_TAP_RANGE, DIFF_TAP_RANGE); }	// 面積が狭いので、isClickRelease だとストレスに感じる
			if(ui->isDoubleClickRelease(&ptTouch)) { isDblTapRel = true; }
		}
		if(isTap || isDblTapRel)
		{
			Tfw* tfw = Game::getGame()->getTfw();						ASSERT(tfw != 0L);
			View* view = tfw->getView();								ASSERT(view != 0L);
			SorSgm* sgm = (SorSgm*)tfw->getSgManager();					ASSERT(sgm != 0L);
			Camera* cam = sgm->getVisibleCamera();						ASSERT(cam != 0L);

			UnitManager* unitmng = Game::getGame()->getUnitManager();	ASSERT(unitmng != 0L);
			for(int i = 0; i < unitmng->getUnitNum(); i++)
			{
				Unit* unit = unitmng->getUnitFromIndex(i);				ASSERT(unit != 0L);
				if(!unit->isEnable())		{	continue;	}	// 無効なユニットは除外
				if(!unit->isEnableFocus())	{	continue;	}	// フォーカスされないユニットは除外
				if(unit->isHidden())		{	continue;	}	// 隠し属性ユニットは除外
				if(unit->getUnitType() == UNITTYPE_EQUIPMENT_ITEM)	{	continue;	}	// 所持品は除外
				if(unit->getCenterPos()->z() >= cam->getLoc()->z())	{	continue;	}	// カメラより手前は除外

				// スクリーン座標に変換
				Vector2F vScr;
				Gcalc::conv3dPosToScreenPos(&vScr, unit->getCenterPos(), cam, view);

				if(isDblTapRel)	// ダブルクリック時は直接フォーカスをセットする
				{
					// 一度フォーカスをリセット
					for(int j = 0; j < NUM_FOCUS_MAX; j++)
					{
						setFocus(j, 0L, 0L);
					}
					// 範囲内かどうか判定して、範囲内だったらフォーカス設定する
					if(TFW_IS_NEAR(vScr.x(), ptTouch.x(), RANGE_TOTRG) && TFW_IS_NEAR(vScr.y(), ptTouch.y(), RANGE_TOTRG))
					{
						// フォーカスをセット(上部でリセットしているので、[0] 決めうち)
						setFocus(0, unit, &vScr);
						// UI に反応済みフラグを立てる
						ui->setReacted(true);
						break;
					}
				}
				else if(isTap)	// タップ時はメニューを表示
				{
					// 範囲内かどうか判定して、範囲内だったらメニューを表示する
					TRACELN("{FocusCursor::exec} unit touch?; scr_x=%f, scr_y=%f, click_x=%d, click_y=%d", vScr.x(), vScr.y(), ptTouch.x(), ptTouch.y());
					if(TFW_IS_NEAR(vScr.x(), ptTouch.x(), RANGE_TOTRG) && TFW_IS_NEAR(vScr.y(), ptTouch.y(), RANGE_TOTRG))
					{
						showFocusMenu(unit, &vScr);		// フォーカスメニュー表示
						ui->setReacted(true);	// UI に反応済みフラグを立てる
					}
				}
			}
		}
	}

	// フォーカスカーソルの画面位置を計算
	for(s32 i = 0; i < NUM_FOCUS_MAX; i++)
	{
		// 無効になったユニットは外す
		const Unit* unitFocused = _focusarr->getUnit(i);
		if(unitFocused == 0L)	{	continue;	}
		if(!unitFocused->isEnable())
		{
			setFocus(i, 0L, 0L);
		}

		// スクリーン座標値が未計算の場合、計算する
		if(!_focusarr->isValidScreenPos(i))
		{
			_focusarr->calcScreenPos(i);
		}
	}

	// マジッククラスターのフォーカスの画面位置を計算
	MagicSys* mgsys = Game::getGame()->getMagicSys();
	for(int i = 0; i < mgsys->getMaxClusterNum(); i++)
	{
		MagicCluster* mc = mgsys->getClusterFromIndex(i);
		if(mc == 0L)		{	continue;	}
		if(!mc->isValid())	{	continue;	}
		mc->focusArray()->calcScreenPosAll();
	}

	// タップ防止カウンタの更新
	if(_fcntPreventTap > 0.0f)
	{
		_fcntPreventTap -= ec->getDeltaFrame();
		if(_fcntPreventTap < 0.0f)	{	_fcntPreventTap = 0.0f;	}
	}

	// カーソル回転角度の更新
	_dangFocus += DANG_FOCUS_DELTA;
	if(_dangFocus > 180.0f)		{	_dangFocus -= 360.0f;		}
	_dangFocusable += DANG_FOCUSABLE_DELTA;
	if(_dangFocusable > 180.0f)	{	_dangFocusable -= 360.0f;	}
}