module y4d_draw.glextensions;

private import opengl;

/// <summary>
/// 特定のOpenGL Extensionsを有するかどうかを調べる。
/// singleton objectである Instanceメンバ経由で扱う。
/// </summary>
/// <remarks>
/// 例)
///		if (GlExtensions.Instance.IsAvaliable(GL_ARB_texture_non_power_of_two))
///               ....
/// </remarks>
public class GlExtensions
{
	
	private static GlExtensions m_instance;
	/// <summary>
	/// このクラスのsingleton instance
	/// </summary>
	public static GlExtensions instance() {
		if (m_instance is null) {
			m_instance = new GlExtensions();
		}
		return m_instance;
	}

	private this()
	{
		// コンストラクタでGL Extensionのリストを取得しておく。

		char[] ext = cast(char[]) std.string.toString(cast(char*) opengl.glGetString(opengl.GL_EXTENSIONS));
		char[][] exts = cast(char[][]) std.string.split(ext, " ");

		// 利用可能なextensionをhashtableにmarkしておく
		foreach (char[] s; exts) {
			extlist[s] = null;
		}
		
		initialize();
	}
	
	/** 初期化処理 */
	private void initialize() {
		checkNpot();
		m_isAvailableRectTexture = 
				isAvailable(cast(char[]) "GL_NV_texture_rectangle")
			||	isAvailable(cast(char[]) "GL_EXT_texture_rectangle")
			||	isAvailable(cast(char[]) "GL_ARB_texture_rectangle");

		// この３つは、定数の値や使い方が同じなので、ひとまとめに扱って
		// 構わない。

		// 利用可能であるならば、最大矩形を得ておく。
		if (m_isAvailableRectTexture)
		{
			int max;
			opengl.glGetIntegerv(opengl.GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &max);
			m_rectTextureMax = max;
		}
	}
	
	/// <summary>
	/// あるExtensionが利用可能であるかを返す
	/// </summary>
	/// <remarks>
	/// 例)
	///		if (GlExtensions.Instance.IsAvaliable(GL_ARB_texture_non_power_of_two))
	///			....
	/// </remarks>
	/// <param name="extName"></param>
	/// <returns></returns>
	public bool isAvailable(char[] extName)
	{
		return (extName in extlist) != null;
	}

	/// <summary>
	/// NPOT(GL_ARB_texture_non_power_of_two)が使えるかどうかのフラグ。
	/// GeForce系では遅くならないが、
	/// Radeon系(ATI)では遅くなって使い物にならないらしい。
	/// なので、ATIならば、NPOTを使わないようにする。
	/// 他にも遅くなって使い物にならないベンダーがあれば登録します。
	/// </summary>
	public bool NPOT() {
		return npot;
	}
	private bool npot = false;

	/// <summary>
	/// NPOTが使えるかどうか。
	/// </summary>
	private void checkNpot()
	{
		{
			bool npot = isAvailable(cast(char[]) "GL_ARB_texture_non_power_of_two");

			// ATI系だと大変遅いので、ATIの場合、使えないとして扱う。

			char[] vendor = cast(char[]) std.string.toString(
					cast(char*) opengl.glGetString(opengl.GL_VENDOR));

			// ATIならば"ATI Technologies Inc."という文字列が戻るのだけども
			// サードパーティ製ドライバのこともあるので小文字化して、
			// Containsで比較すべき。
			if (-1 != std.string.ifind(vendor, "ati technologies"))
			// ↑ATI以外にも糞ドライバがあればこの条件に追加してちょうだい。
			{
				npot = false;
			}

			this.npot = npot;
		}
	}

	/// <summary>
	/// GL_XXX_texture_rectangleが使えるかどうかの判定。
	/// </summary>
	/// <param name="width">作成するテクスチャの横幅</param>
	/// <param name="height">作成するテクスチャの縦幅</param>
	public bool isAvailableRectTexture(int width, int height)
	{
		// texture_rectangleに対応していなければ
		if (!m_isAvailableRectTexture)
		{
			return false;
		}
		
		// 作成するサイズが大きすぎたらfalse
		return (width <= m_rectTextureMax && height <= m_rectTextureMax);
	}

	/// <summary>
	///		GL_NV_texture_rectangle
	///		GL_EXT_texture_rectangle
	///		GL_ARB_texture_rectangle
	/// のいずれかに対応しているか。
	/// </summary>
	/// <remarks>
	/// 未調査ならばnull
	/// </remarks>
	private bool m_isAvailableRectTexture;

	/// <summary>
	/// texture_rectangleの最大値
	/// </summary>
	private int m_rectTextureMax = 0;

	/// <summary>
	/// GL Extensionの名前リスト
	/// </summary>
//	private Dictionary<char[], object> extlist = new Dictionary<char[],object>();
	private Object[char[]] extlist;
}
