//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * レベルオブディティールシーンノード実装
 * @author Junpee
 */

#include "LampBasic.h"
#include "Graphics/SceneNode/LODSceneNode.h"
#include "Graphics/SceneNode/SceneNodeManager.h"
#include "Graphics/Model/Model.h"

namespace Lamp{

//------------------------------------------------------------------------------
// コンストラクタ
LODSceneNode::LODSceneNode(const String& name, Scene* scene) :
	SceneNode(name, scene), lodThresholdCount_(0), lodThreshold_(NULL){
}
//------------------------------------------------------------------------------
// デストラクタ
LODSceneNode::~LODSceneNode(){
	SafeArrayDelete(lodThreshold_);
}
//------------------------------------------------------------------------------
// レベルオブディティールシーンノードコピー
LODSceneNode* LODSceneNode::copyLODSceneNode(u_int copyMask) const{
	SceneNodeManager* manager = scene_->getSceneNodeManager();
	LODSceneNode* destination =
		manager->createLODSceneNode(manager->rename(name_));
	copySceneNodeValue(destination, copyMask);
	// LOD情報のコピー
	destination->setLODThresholdCount(lodThresholdCount_);
	for(int i = 0; i < lodThresholdCount_; i++){
		destination->setLODThreshold(i, lodThreshold_[i]);
	}
	return destination;
}
//------------------------------------------------------------------------------
// 走査
void LODSceneNode::traverse(const Matrix34& parentMatrix,
	const Vector3& cameraPosition, bool parentEnabled, bool parentScaled,
	bool parentChanged){
	bool preGlobalEnabled = isGlobalEnabled();
	bool globalEnabled = (parentEnabled && isEnabled());
	setGlobalEnabled(globalEnabled);
	// 前回がdisabledでdisabledのままならトラバースしない
	if((!preGlobalEnabled) && (!globalEnabled)){ return; }

	// 行列の計算
	bool globalChanged = calcMatrix(parentMatrix, parentChanged);
	setGlobalChanged(globalChanged);
	// グローバルスケールフラグ設定
	bool globalScaled = (parentScaled || isScaled());
	setGlobalScaled(globalScaled);
	const Matrix34& worldMatrix = getWorldMatrix(); 
	if(globalEnabled){
		// LOD処理
		Vector3 worldPosition = worldMatrix.getTranslation();
		worldPosition -= cameraPosition;
		float distance = worldPosition.getLength();
		// LOD処理
		int sceneNodeCount = getSceneNodeCount();
		Assert((lodThresholdCount_ - 1) == sceneNodeCount);
		for(int i = 0; i < sceneNodeCount; i++){
			Assert(lodThreshold_[i] < lodThreshold_[i + 1]);
			// 範囲に入っていれば有効、範囲でなければ無効
			bool childEnable = ((distance >= lodThreshold_[i]) &&
				(distance < lodThreshold_[i + 1]));
			// LOD範囲の変更に対してChangedフラグを立てる必要がある
			// 前回使用したLODかどうかを判別できれば効率化可能
			getSceneNode(i)->traverse(
				worldMatrix, cameraPosition,
//				childEnable, globalScaled, globalChanged);
				childEnable, globalScaled, (childEnable || globalChanged));
		}
	}else{
		// 有効でない場合は全て無効を設定
		int sceneNodeCount = getSceneNodeCount();
		for(int i = 0; i < sceneNodeCount; i++){
			getSceneNode(i)->traverse(worldMatrix, cameraPosition,
				globalEnabled, globalScaled, globalChanged);
		}
	}
	// シーンリーフを呼ぶ
	int sceneLeafCount = getSceneLeafCount();
	for(int i = 0; i < sceneLeafCount; i++){
		getSceneLeaf(i)->traverse(worldMatrix,
			globalEnabled, globalScaled, globalChanged);
	}
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
