//------------------------------------------------------------------------------
// 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/Enumeration/GraphicsAdapterInformation.h"
#include "Graphics/Enumeration/GraphicsDeviceEnumeration.h"
#include "Graphics/System/LampGraphics.h"
#include "Graphics/Primitive/GraphicsBufferFormat.h"

namespace Lamp{

//------------------------------------------------------------------------------
// ディスプレイモード比較
static int displayModeCompare(
	const D3DDISPLAYMODE* left, const D3DDISPLAYMODE* right){
	if(left->Width > right->Width){ return 1; }
	if(left->Width < right->Width){ return -1; }
	if(left->Height > right->Height){ return 1; }
	if(left->Height < right->Height){ return -1; }
	if(left->Format > right->Format){ return 1; }
	if(left->Format < right->Format){ return -1; }
	if(left->RefreshRate > right->RefreshRate){ return 1; }
	if(left->RefreshRate < right->RefreshRate){ return -1; }
	return 0;
}
//------------------------------------------------------------------------------
// コンストラクタ
GraphicsAdapterInformation::GraphicsAdapterInformation(int adapterOrdinal) :
	adapterOrdinal_(adapterOrdinal){
}
//------------------------------------------------------------------------------
// デストラクタ
GraphicsAdapterInformation::~GraphicsAdapterInformation(){
	// デバイスの削除
	for(int i = getDeviceCount() - 1; i >= 0; i--){
		delete getDevice(i);
	}
}
//------------------------------------------------------------------------------
// 列挙
void GraphicsAdapterInformation::enumerate(
	GraphicsDeviceEnumeration* enumeration){
	// アダプタ識別子の取得
	Direct3D* direct3D = LampGraphics::getDirect3D();
	direct3D->GetAdapterIdentifier(adapterOrdinal_, 0, &identifier_);
	name_ = identifier_.Description;
	driverName_ = identifier_.Driver;
	u_int minimumWidth = enumeration->getMinimumFullscreenWidth();
	u_int minimumHeight = enumeration->getMinimumFullscreenHeight();
	u_int minimumColorBits = enumeration->getMinimumAdapterColorChannelBits();
	// 許可フォーマットによるディスプレイモードの列挙
	int allowedFormatCount = enumeration->getAllowedFormatCount();
	for(int i = 0; i < allowedFormatCount; i++){
		D3DFORMAT allowedFormat = enumeration->getAllowedFormat(i);
		GraphicsBufferFormat bufferFormat(allowedFormat);
		u_int adapterModesCount =
			direct3D->GetAdapterModeCount(adapterOrdinal_, allowedFormat);
		for(u_int j = 0; j < adapterModesCount; j++){
			D3DDISPLAYMODE displayMode;
			direct3D->EnumAdapterModes(
				adapterOrdinal_, allowedFormat, j, &displayMode);
			// 条件に合わないディスプレイモードは無視
			if(displayMode.Width < minimumWidth ||
				displayMode.Height < minimumHeight ||
				bufferFormat.getColorChannelBits() < minimumColorBits){
				continue;
			}
			// ディスプレイモードの格納
			displayModes_.add(displayMode);
			if(adapterFormats_.indexOf(displayMode.Format) == -1){
				adapterFormats_.add(displayMode.Format);
			}
		}
	}
	// ディスプレイモードのソート
	displayModes_.sort(displayModeCompare);
	// 全てのデバイスタイプ
	// D3DDEVTYPE_SWを有効にしていると以下のワーニングが出る場合がある
	// No SW device has been registered. GetAdapterCaps fails.
	const D3DDEVTYPE deviceTypes[] = {
		D3DDEVTYPE_HAL,
		D3DDEVTYPE_SW,
		D3DDEVTYPE_REF
	};
	const u_int deviceTypesCount = sizeof(deviceTypes) / sizeof(deviceTypes[0]);
	for(int i = 0; i < deviceTypesCount; i++){
		GraphicsDeviceInformation* device = new GraphicsDeviceInformation();
		bool result = device->enumerate(enumeration, this, deviceTypes[i]);
		// 列挙失敗かデバイスコンボが0なら削除
		if((!result) || (device->getDeviceComboCount() == 0)){
			delete device;
			continue;
		}
		devices_.add(device);
	}
}
//------------------------------------------------------------------------------
// 文字列への変換
String GraphicsAdapterInformation::toString(){
	String result;
	result.format("%s %d", name_.getBytes(), adapterOrdinal_);
/*
	for(int i = 0; i < getDisplayModeCount(); i++){
		D3DDISPLAYMODE displayMode = getDisplayMode(i);
		GraphicsBufferFormat bufferFormat(displayMode.Format);
		String displayModeString;
		displayModeString.format("\t%s ( %d x %d ) %dHz\n",
			bufferFormat.getName().getBytes(), displayMode.Width, displayMode.Height,
			displayMode.RefreshRate);
		result += displayModeString;
	}
*/
	return result;
}
//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
