module yamalib.draw.drawassist;

private import y4d_draw.screen;
private import y4d_draw.texturebase;
private import y4d_draw.drawbase;

/**
 * テクスチャが２のべき乗にリサイズされるOpenGLでは、
 * 同時にテクスチャを大量にしようすると、メモリを逼迫する
 * そこで、画質とメモリをトレードオフで、２のべき乗サイズに縮小しておき
 * それをオリジナルのサイズで拡大描画する
 * 回転時に縦横比が維持されていないと、描画先を計算しないといけない。
 * そこで、回転を使用するものは、縦横比が維持されていることを。
 * （回転しないものは、指定したSizeで伸張して描画します）
 */
class DrawAssist {
public:
	static final const Context SCREEN_SIZE;	// とりあえず背景用 640 * 480

	/// 静的コンストラクタ
	static this() {
		auto size = new Size();
		size.setSize(640u,480u);
		SCREEN_SIZE = new Context(size);
	}

	/// コンテクストにしたがって描画を行う
	static void blt(Screen screen, ITextureBase texture, int x, int y, Context context) {
		Size size;
		Rect srcRect;
		Rect dstRect;
		
		if (context.enableSrcRect) {
			Rect* orgRect = context.srcRect;
			if ( !(orgRect is null) ) {
				float xRate = (texture.getWidth() / cast(float) context.originalSize.cx);
				float yRate = (texture.getHeight() / cast(float) context.originalSize.cy);
				srcRect.left = orgRect.left * xRate;
				srcRect.right = orgRect.right * xRate;
				srcRect.top = orgRect.top * yRate;
				srcRect.bottom = orgRect.bottom * yRate;
				size.setSize(
					cast(int) (srcRect.getWidth() * xRate),
					cast(int) (srcRect.getHeight() * yRate) );
			}
		}
		
		if (context.enableRad) {
			//-- 回転
			float rate = 1.0f;
			// 拡大率の換算
			if (context.enableRate) {
				rate = (context.originalSize.cx * context.rate) 
						/ texture.getWidth();
			} else {
				rate = context.getSizeToRate(texture);
			}
			screen.bltRotate(texture, x, y, context.rad, rate, context.offsetType);
		} else if (context.enableRate) {
			//-- 拡大縮小
			if (context.enableSrcRect && !(context.srcRect is null) ) {
				size.cx = cast(uint) (context.srcRect.getWidth() * context.rate);
				size.cy = cast(uint) (context.srcRect.getHeight() * context.rate);
				
			} else {
				size.setSize(cast(int) (context.originalSize.cx * context.rate),
					  cast(int) (context.originalSize.cy * context.rate) );
			}

			screen.blt(texture, x, y, 
					context.enableSrcRect ? &srcRect : null, &size);
		
		} else {
			if (context.enableSrcRect) {			
				screen.blt(texture, x, y, &srcRect, &size);
			} else {
				// 通常描画
				screen.blt(texture, x, y, null, context.originalSize);
			}
		}
	}
	
	/// このクラスを描画するコンテクスト
	private static class Context {
		/// コンストラクタ
		// originalSize は想定するオリジナルのサイズ
		// このサイズが本来のサイズと想定して、その他の描画オプションを実行する
		this(Size* originalSize) {
			this.m_originalSize = originalSize;
		}
		
		/// サイズから、rate 換算を行う（縦横比は維持されているものとし、x方向を基準にサイズを割り出します。
		float getSizeToRate(ITextureBase texture) {
			return this.m_originalSize.cx / texture.getWidth();
		}
		
		/// 取得のみ(この参照を変更したりしないこと
		Size* originalSize() {
			return this.m_originalSize;
		}
		
		/// 拡大縮小
		float rate() {
			return this.m_rate;
		}
		float rate(float r) {
			return this.m_rate = r;
		}
		bool enableRate() {
			return this.m_enableRate;
		}
		bool enableRate(bool b) {
			return this.m_enableRate = b;
		}
		
		/// 拡大縮小で描画するときの、位置のオフセットタイプ
		/**
		 * 
		 * baseは転送元画像どの点が(x,y)に来るかを指定します。<BR>
		 *	0	 : 左上。		1 : 上辺の中点　2:右上<BR>
		 *	3	 : 左辺の中点	4 : 画像中心	5:右辺の中点<BR>
		 *	6	 : 左下。　	7 : 下辺の中点	8:右下<BR>
		 */
		int offsetType() {
			return m_offsetType;
		}
		int offsetType(int type) {
			return m_offsetType = type;
		}
		
		/// 回転
		int rad() {
			return m_rad;
		}
		int radBx() {
			return this.m_radBaseX;
		}
		int radBy() {
			return this.m_radBaseY;
		}
		void setRad(int rad_, int bx_, int by_) {
			m_rad = rad_;
			m_radBaseX = bx_;
			m_radBaseY = by_;
		}
		/// 回転を有効にする、転送元、転送先矩形は無視されます
		bool enableRad() {
			return this.m_enableRad;
		}
		bool enableRad(bool b) {
			return this.m_enableRad = b;
		}
		
		/// 転送先矩形の設定
		Rect* srcRect() {
			return this.m_srcRect;
		}
		Rect* srcRect(Rect* rect) {
			return this.m_srcRect = rect;
		}
		bool enableSrcRect() {
			return this.m_enableSrcRect;
		}
		bool enableSrcRect(bool b) {
			return this.m_enableSrcRect = b;
		}
		
		/// 転送元矩形の設定
		Rect* dstRect() {
			return this.m_dstRect;
		}
		Rect* dstRect(Rect* rect) {
			return this.m_dstRect = rect;
		}
		bool enableDstRect() {
			return this.m_enableDstRect;
		}
		bool enableDstRect(bool b) {
			return this.m_enableDstRect = b;
		}
		
		
	private:
		Size* m_originalSize;
		
		int m_rad = 0;
		int m_radBaseX;
		int m_radBaseY;
		bool m_enableRad = false;
		float m_rate = 1.0f;
		bool m_enableRate = false;
		int m_offsetType;
		Rect* m_srcRect;
		bool m_enableSrcRect = false;
		Rect* m_dstRect;
		bool m_enableDstRect = false;
		
		// Point[4] m_srcPoint;	こんなの使用せーへんかな...
		// Point[4] m_dstPoint;
	}
	
private:


}