IMathLib-ソースコード-

  • pocket
  • はてなブックマーク

#ifndef IMATHLIB_H_MEDIA_CAMERA_HPP
#define IMATHLIB_H_MEDIA_CAMERA_HPP

#include "IMathLib/math/liner_algebra.hpp"
#include "IMathLib/media/common/enabler_object.hpp"

#undef near
#undef far


// デフォルトのnear
#ifndef IMATHLIB_F_CAMERA_DEFAULT_NEAR
#define IMATHLIB_F_CAMERA_DEFAULT_NEAR			20
#endif
// デフォルトのfar
#ifndef IMATHLIB_F_CAMERA_DEFAULT_FAR
#define IMATHLIB_F_CAMERA_DEFAULT_FAR			600
#endif
// デフォルトのカメラからの距離
#ifndef IMATHLIB_F_CAMERA_DEFAULT_LENGTH
#define IMATHLIB_F_CAMERA_DEFAULT_LENGTH		100
#endif


namespace iml {
	namespace ml {

		// カメラの定数についての名前空間
		namespace cam {
			// カメラの投影法を示す定数
			inline constexpr size_t ortho_projection = 0;				// 垂直投影
			inline constexpr size_t frustum_projection = 1;			// 透視投影
		}

		// glLoadMatrixのラップ
		inline void glLoadMatrix(const matrix4<GLfloat>& m) { ::glLoadMatrixf(m[0]); }
		inline void glLoadMatrix(const matrix4<GLdouble>& m) { ::glLoadMatrixd(m[0]); }
		inline void glLoadTransposeMatrix(const matrix4<GLfloat>& m) { ::glLoadTransposeMatrixf(m[0]); }
		inline void glLoadTransposeMatrix(const matrix4<GLdouble>& m) { ::glLoadTransposeMatrixd(m[0]); }

		// glGetFloatvおよびglGetDoublevのラップ
		inline void glGetMatrix(GLenum name, matrix4<GLfloat>& m) { ::glGetFloatv(name, m[0]); }
		inline void glGetMatrix(GLenum name, matrix4<GLdouble>& m) { ::glGetDoublev(name, m[0]); }


		// カメラ制御系
		// OpenGLでは各行列を転置して扱わなければならない
		template <class T>
		class camera {
			template <class, size_t>
			friend class light;
			// ビュー行列に関するパラメータ
			vector3<T>			target_pos_m;			// 注視点座標
			vector3<T>			coordinate_m;			// 注視点からの相対座標により定義されるカメラの座標(angle_h,angle_v,length)
			vector3<T>			front_direction_m;		// カメラの座標系
			vector3<T>			right_direction_m;		// *
			vector3<T>			up_direction_m;			// *
			// プロジェクション行列に関するパラメータ
			T					near_m, far_m;			// 3D空間の遠近
			rect<T>				rect_m;					// カメラのnear面の領域(投影先の面の領域)
			size_t				projection_m;			// 投影法
			// カメラの移動制御に関するパラメータ
			vector3<T>			trans_descartes_m;		// 線型でカメラの移動の持越し(デカルト座標)
			vector3<T>			trans_polar_m;			// 線型でカメラの移動の持越し(極座標)
			vector3<T>			trans_target_m;			// 線型で注視点の移動の持越し(デカルト座標)


			// 極座標系をデカルト座標系に変換(y-up/z-front系)
			static vector3<T> polar_convert(const T& angle_h, const T& angle_v) {
				return vector3<T>(cos(angle_v)*sin(angle_h), sin(angle_v), cos(angle_v)*cos(angle_h));
			}
			// 射影行列のセット
			/*void set_projection_matrix() {
				// 射影行列の設定GL_TRANSPOSE_PROJECTION_MATRIX
				glMatrixMode(GL_PROJECTION);
				switch (projection_m) {
				case cam::ortho_projection:
					glLoadMatrix(transpose_ortho_projection_matrix(rect_m.left, rect_m.right, rect_m.bottom, rect_m.top, near_m, far_m));
					//gluOrtho2D(rect_m.left, rect_m.right, rect_m.bottom, rect_m.top, near_m, far_m)
					break;
				case cam::frustum_projection:
					glLoadMatrix(transpose_frustum_projection_matrix(rect_m.left, rect_m.right, rect_m.bottom, rect_m.top, near_m, far_m));
					//glFrustum(rect_m.left, rect_m.right, rect_m.bottom, rect_m.top, near_m, far_m)
					break;
				}
			}
			// ビュー行列のセット
			void set_view_matrix() {
				glMatrixMode(GL_MODELVIEW);
				// y-up系だからこの順序
				glLoadMatrix(transpose_view_matrix(camera_pos(), right_direction_m, up_direction_m, front_direction_m));
				//gluLookAt(
				//	camera_pos[0], camera_pos[1], camera_pos[2],			// 視点の位置x,y,z;
				//	target_pos_m[0], target_pos_m[1], target_pos_m[2],			// 視界の中心位置の参照点座標x,y,z
				//	up_direction_m[0], up_direction_m[1], up_direction_m[2]);		// 視界の上方向のベクトルx,y,z
			}*/
			// coordinate_mからカメラの座標系の設定
			void set_camera() {
				// 値の補正
				while (this->coordinate_m[1] > pi_v<T>) this->coordinate_m[1] -= 2 * pi_v<T>;
				while (this->coordinate_m[1] < -pi_v<T>) this->coordinate_m[1] += 2 * pi_v<T>;
				while (this->coordinate_m[0] > 2 * pi_v<T>) this->coordinate_m[0] -= 2 * pi_v<T>;
				while (this->coordinate_m[0] < -2 * pi_v<T>) this->coordinate_m[0] += 2 * pi_v<T>;
				if (this->coordinate_m[2] < near_m) this->coordinate_m[2] = near_m;
				if (this->coordinate_m[2] > far_m) this->coordinate_m[2] = far_m;
				// カメラ座標系の変換
				this->front_direction_m = camera::polar_convert(this->coordinate_m[0], this->coordinate_m[1]);
				// 水平角度によって右は変わる
				if (abs(this->coordinate_m[1]) > pi_v<T> / 2) this->right_direction_m = unit(vector3<T>(0, -1, 0) % this->front_direction_m);
				else this->right_direction_m = unit(vector3<T>(0, 1, 0) % this->front_direction_m);
				this->up_direction_m = this->front_direction_m% this->right_direction_m;
			}
		public:
			constexpr camera() : near_m(IMATHLIB_F_CAMERA_DEFAULT_NEAR), far_m(IMATHLIB_F_CAMERA_DEFAULT_FAR)
				, coordinate_m(0, 0, IMATHLIB_F_CAMERA_DEFAULT_LENGTH)
				, front_direction_m(0, 0, 1), right_direction_m(1, 0, 0), up_direction_m(0, 1, 0)
				, projection_m(cam::frustum_projection) {
			}
			~camera() {}
			// カメラモードの設定
			camera& camera_mode(size_t mode) { projection_m = mode; return *this; }

			// 極座標でカメラの移動(vector3<T>(angle_h, angle_v, length))
			camera& move_camera_polar(const vector3<T>& v, const T& trans = 0) {
				vector3<T> temp = v + this->trans_polar_m;
				this->coordinate_m += temp;
				this->set_camera();

				// 次回への持ち越し量
				this->trans_polar_m = temp * trans;
				return *this;
			}
			camera& set_camera_polar(const vector3<T>& v) {
				this->coordinate_m = v;
				this->set_camera();

				// 持ち越しのリセット
				this->trans_polar_m[0] = this->trans_polar_m[1] = this->trans_polar_m[2] = 0;
				return *this;
			}
			// デカルト座標でカメラの位置の移動(flag:abs(angle_v)がpi/2を超えるかのフラグ)
			camera& move_camera_descartes(const vector3<T>& v, const T& trans = 0) {
				vector3<T> temp = v + this->trans_descartes_m;
				vector3<T> camera_pos = this->coordinate_m[2] * camera::polar_convert(this->coordinate_m[0], this->coordinate_m[1]) + temp;
				// 直交座標系から極座標系への変換
				this->coordinate_m[2] = abs(camera_pos);
				// up_direction_mが-y方向であるとき
				if (abs(this->coordinate_m[1]) > pi_v<T> / 2) {
					this->coordinate_m[1] = pi_v<T> - asin(camera_pos[1] / this->coordinate_m[2]);
					if ((camera_pos[0] == 0) && (camera_pos[2] == 0)) this->coordinate_m[0] = pi_v<T>;
					else {
						// 演算誤差を考慮する必要がある
						auto temp2 = camera_pos[2] / sqrt(camera_pos[0] * camera_pos[0] + camera_pos[2] * camera_pos[2]);
						if (temp2 <= -1) this->coordinate_m[0] = pi_v<T> * (1 + sgn(camera_pos[0]));
						else if (1 <= temp2) this->coordinate_m[0] = pi_v<T>;
						else this->coordinate_m[0] = pi_v<T> + sgn(camera_pos[0])*acos(temp2);
					}
				}
				else {
					// 演算誤差を考慮する
					auto temp3 = camera_pos[1] / this->coordinate_m[2];
					if (temp3 <= -1) this->coordinate_m[1] = -pi_v<T> / 2;
					else if (temp3 >= 1) this->coordinate_m[1] = pi_v<T> / 2;
					else this->coordinate_m[1] = asin(camera_pos[1] / this->coordinate_m[2]);
					if ((camera_pos[0] == 0) && (camera_pos[2] == 0)) this->coordinate_m[0] = 0;
					else {
						// 演算誤差を考慮する
						auto temp2 = camera_pos[2] / sqrt(camera_pos[0] * camera_pos[0] + camera_pos[2] * camera_pos[2]);
						if (temp2 <= -1) this->coordinate_m[0] = sgn(camera_pos[0]) * pi_v<T>;
						else if (1 <= temp2) this->coordinate_m[0] = 0;
						else this->coordinate_m[0] = sgn(camera_pos[0])*acos(temp2);
					}
				}
				this->set_camera();

				// 次回への持ち越し量
				this->trans_descartes_m = temp * trans;
				return *this;
			}
			camera& set_camera_descartes(const vector3<T>& v) {
				// 直交座標系から極座標系への変換
				this->coordinate_m[2] = abs(v);
				// up_direction_mが-y方向であるとき
				if (abs(this->coordinate_m[1]) > pi_v<T> / 2) {
					this->coordinate_m[1] = pi_v<T> -asin(v[1] / this->coordinate_m[2]);
					if ((v[0] == 0) && (v[2] == 0)) this->coordinate_m[0] = pi_v<T>;
					else {
						// 演算誤差を考慮する必要がある
						auto temp2 = v[2] / sqrt(v[0] * v[0] + v[2] * v[2]);
						if (temp2 <= -1) this->coordinate_m[0] = pi_v<T> * (1 + sgn(v[0]));
						else if (1 <= temp2) this->coordinate_m[0] = pi_v<T>;
						else this->coordinate_m[0] = pi_v<T> + sgn(v[0])*acos(temp2);
					}
				}
				else {
					this->coordinate_m[1] = asin(v[1] / this->coordinate_m[2]);
					if ((v[0] == 0) && (v[2] == 0)) this->coordinate_m[0] = 0;
					else {
						// 演算誤差を考慮する必要がある
						auto temp2 = v[2] / sqrt(v[0] * v[0] + v[2] * v[2]);
						if (temp2 <= -1) this->coordinate_m[0] = sgn(v[0]) * pi_v<T>;
						else if (1 <= temp2) this->coordinate_m[0] = 0;
						else this->coordinate_m[0] = sgn(v[0])*acos(temp2);
					}
				}
				this->set_camera();

				// 持ち越しのリセット
				this->trans_descartes_m[0] = this->trans_descartes_m[1] = this->trans_descartes_m[2] = 0;
				return *this;
			}
			// カメラのターゲットの平行移動(カメラの極座標系をも連動する)
			camera& move_target(const vector3<T>& v, const T& trans = 0) {
				vector3<T> temp = v + this->trans_target_m;
				this->target_pos_m += temp;

				// 次回への持ち越し量
				this->trans_target_m = temp * trans;
				return *this;
			}
			// カメラのターゲットのビューポート面に対する平行移動
			camera& move_target(const vector2<T>& v, const T& trans = 0) {
				vector3<T> temp = (v[0] * this->right_direction_m + v[1] * this->up_direction_m) + this->trans_target_m;
				this->target_pos_m += temp;

				// 次回への持ち越し量
				this->trans_target_m = temp * trans;
				return *this;
			}
			camera& set_target(const vector3<T>& v) {
				this->target_pos_m = v;

				// 持ち越しのリセット
				this->trans_target_m[0] = this->trans_target_m[1] = this->trans_target_m[2] = 0;
				return *this;
			}

			// 視野角からnear面の領域の構築
			camera& viewing_angle(const T& angle_x, const T& angle_y) {
				this->rect_m.right = this->near_m*tan(angle_x / 2);
				this->rect_m.left = -this->rect_m.right;
				this->rect_m.top = this->near_m*tan(angle_y / 2);
				this->rect_m.bottom = -this->rect_m.top;
				return *this;
			}
			// x方向の視野角とアスペクト比からnear面の領域の構築
			camera& viewing_angle_magnific(const T& angle_x, const T& ratio) {
				this->rect_m.right = this->near_m*tan(angle_x / 2);
				this->rect_m.left = -this->rect_m.right;
				this->rect_m.top = this->near_m*tan(angle_x*ratio / 2);
				this->rect_m.bottom = -this->rect_m.top;
				return *this;
			}
			// 直接領域を構築
			camera& surface_rect(const rect<T>& rect) { this->rect_m = rect; return *this; }

			// カメラの遠近の設定
			camera& near(const T& n) { this->near_m = n; return *this; }
			camera& far(const T& f) { this->far_m = f; return *this; }

			// 各種カメラの情報の取得
			const T& near() const { return this->near_m; }
			const T& far() const { return this->far_m; }
			const vector3<T>& target_pos() const { return this->target_pos_m; }
			const T& angle_h() const { return this->coordinate_m[0]; }
			const T& angle_v() const { return this->coordinate_m[1]; }
			const T& length() const { return this->coordinate_m[2]; }
			vector3<T> camera_pos() const { return this->target_pos_m + this->coordinate_m[2] * camera::polar_convert(this->coordinate_m[0], this->coordinate_m[1]); }

			// 射影行列の取得
			matrix4<T> projection_matrix() const {
				switch (this->projection_m) {
				case cam::ortho_projection:
					return iml::ortho_projection_matrix(this->rect_m.left, this->rect_m.right, this->rect_m.bottom, this->rect_m.top, this->near_m, this->far_m);
				case cam::frustum_projection:
					return iml::frustum_projection_matrix(this->rect_m.left, this->rect_m.right, this->rect_m.bottom, this->rect_m.top, this->near_m, this->far_m);
				default:
					return matrix4<T>();
				}
			}
			// ビュー行列の取得
			matrix4<T> view_matrix() const {
				return iml::view_matrix(this->camera_pos(), this->right_direction_m, this->up_direction_m, this->front_direction_m);
			}
		};


		// カメラ(ビュー行列及びプロジェクション行列)の設定
		template <class T>
		struct CAMERA_OBJECT : ENABLER_OBJECT_BASE<pair<matrix4<T>, matrix4<T>>, CAMERA_OBJECT<T>> {
			// pairの第一成分は射影行列,第二成分はビュー行列
			using base_class = ENABLER_OBJECT_BASE<pair<matrix4<T>, matrix4<T>>, CAMERA_OBJECT>;
			friend base_class;

		private:
			// 初期状態のためのコンストラクタ
			CAMERA_OBJECT(enabler_object_init_tag) : base_class() { base_class::init_state_construct(); }
			CAMERA_OBJECT(enabler_object_init_tag, const camera<T>& c) : base_class(pair<matrix4<T>, matrix4<T>>(c.projection_matrix(), c.view_matrix())) {
				base_class::init_state_construct();
			}
		public:
			// 通常のコンストラクタ
			CAMERA_OBJECT() : base_class() { base_class::construct(); }
			// 状態は共有しない
			CAMERA_OBJECT(const CAMERA_OBJECT& c) : base_class(pair<matrix4<T>, matrix4<T>>(c.projection_matrix(), c.view_matrix())) {
				base_class::construct();
			}
			CAMERA_OBJECT(CAMERA_OBJECT&& c) noexcept : base_class(std::move(c.obj_m)) {}
			CAMERA_OBJECT(const camera<T>& c) : base_class(pair<matrix4<T>, matrix4<T>>(c.projection_matrix(), c.view_matrix())) {
				base_class::construct();
			}
			CAMERA_OBJECT(const matrix4<T>& projection, const matrix4<T>& view) : base_class(pair<matrix4<T>, matrix4<T>>(projection, view)) {
				base_class::construct();
			}
			~CAMERA_OBJECT() {
				// 状態を持つならば処理する
				if (this->obj_m.get() != nullptr) base_class::destroy();
			}

			// ENABLER_OBJECT_CONTROLのエイリアス
			using base_class::enabler_object_control_t;

			CAMERA_OBJECT& operator=(const CAMERA_OBJECT& c) {
				this->obj_m = c.obj_m;
				return *this;
			}
			CAMERA_OBJECT& operator=(CAMERA_OBJECT&& c) {
				this->obj_m = std::move(c.obj_m);
				return *this;
			}

			// 状態を更新するメソッド
			void push_state() {
				glMatrixMode(GL_PROJECTION);
				glPushMatrix();
				glLoadTransposeMatrix(this->projection_matrix());
				glMatrixMode(GL_MODELVIEW);
				glPushMatrix();
				glLoadTransposeMatrix(this->view_matrix());
			}
			// 状態を外すメソッド
			void pop_state() {
				glMatrixMode(GL_PROJECTION);
				glPopMatrix();
				glMatrixMode(GL_MODELVIEW);
				glPopMatrix();
			}
			// 状態を設定するメソッド
			void set_state() {
				glMatrixMode(GL_PROJECTION);
				glLoadTransposeMatrix(this->obj_m->first);
				glMatrixMode(GL_MODELVIEW);
				glLoadTransposeMatrix(this->obj_m->second);
			}

			// 各種行列の取得
			const matrix4<T>& projection_matrix() const { return this->obj_m->first; }
			const matrix4<T>& view_matrix() const { return this->obj_m->second; }

			// 標準状態のカメラの取得
			static CAMERA_OBJECT<T>& default_camera() { return *static_cast<CAMERA_OBJECT<T>*>(base_class::default_m); }
		};
		template <class T>
		inline CAMERA_OBJECT<T> CREATE_CAMERA_OBJECT(const camera<T>& c) {
			return CAMERA_OBJECT<T>(c);
		}
		// 現在のカメラの状態をcと共通化
		template <class T>
		inline void set_camera(const CAMERA_OBJECT<T>& c) {
			using enabler_object_control_t = typename CAMERA_OBJECT<T>::enabler_object_control_t;
			enabler_object_control_t::inst()->top()->set(c);
		}
		// 現在のカメラの状態をobjにより変更
		template <class T>
		inline void set_camera(const camera<T>& c) {
			using enabler_object_control_t = typename CAMERA_OBJECT<T>::enabler_object_control_t;
			enabler_object_control_t::inst()->top()->set(pair<matrix4<T>, matrix4<T>>(c.projection_matrix(), c.view_matrix()));
		}
		// 現在のビュー行列およびプロジェクション行列の取得
		template <class T>
		inline matrix4<T> projection_matrix() {
			using enabler_object_control_t = typename CAMERA_OBJECT<T>::enabler_object_control_t;
			return static_cast<CAMERA_OBJECT<T>*>(enabler_object_control_t::inst()->top())->projection_matrix();
		}
		template <class T>
		inline matrix4<T> view_matrix() {
			using enabler_object_control_t = typename CAMERA_OBJECT<T>::enabler_object_control_t;
			return static_cast<CAMERA_OBJECT<T>*>(enabler_object_control_t::inst()->top())->view_matrix();
		}
		// 標準状態のカメラの取得
		template <class T>
		inline CAMERA_OBJECT<T>& default_camera() { return CAMERA_OBJECT<T>::default_camera(); }
		// カメラの初期化(これは厳密にカメラ利用前に実行しなければならないように定義)
		template <class T>
		inline void init_camera() {
			CAMERA_OBJECT<T>::init();
		}
		template <class T>
		inline void init_camera(const camera<T>& c) {
			CAMERA_OBJECT<T>::init(pair<matrix4<T>, matrix4<T>>(c.projection_matrix(), c.view_matrix()));
		}
		// カメラの終了
		template <class T>
		inline void quit_camera() {
			CAMERA_OBJECT<T>::quit();
		}
#define IMATHLIB_CAMERA(NAME, CAMERA)	IMATHLIB_ENABLER_OBJECT(auto NAME = ::iml::ml::CREATE_CAMERA_OBJECT(CAMERA))

		// ビューポートの設定
		struct VIEWPORT_OBJECT : ENABLER_OBJECT_BASE<rect<int_t>, VIEWPORT_OBJECT> {
			using base_class = ENABLER_OBJECT_BASE<rect<int_t>, VIEWPORT_OBJECT>;
			friend base_class;

		private:
			// スケーリングが行われたかを示すbool値
			bool is_scaling_m = false;

			// 初期状態のためのコンストラクタ
			VIEWPORT_OBJECT(enabler_object_init_tag) : base_class() { base_class::init_state_construct(); }
			VIEWPORT_OBJECT(enabler_object_init_tag, const rect<int_t>& r) : base_class(r) { base_class::init_state_construct(); }
		public:
			// 通常のコンストラクタ
			VIEWPORT_OBJECT() : base_class() { base_class::construct(); }
			// 状態は共有しない
			VIEWPORT_OBJECT(const VIEWPORT_OBJECT& v) : base_class(v.viewport_rect()) { base_class::construct(); }
			VIEWPORT_OBJECT(VIEWPORT_OBJECT&& v) noexcept : base_class(std::move(v.obj_m)) {}
			VIEWPORT_OBJECT(const rect<int_t>& r) : base_class(r) { base_class::construct(); }
			~VIEWPORT_OBJECT() {
				// 状態を持つならば処理する
				if (this->obj_m.get() != nullptr) base_class::destroy();
				/*if (this->is_scaling_m) {
					glMatrixMode(GL_MODELVIEW);
					glPopMatrix();
				}*/
			}

			// ENABLER_OBJECT_CONTROLのエイリアス
			using base_class::enabler_object_control_t;

			VIEWPORT_OBJECT& operator=(const VIEWPORT_OBJECT& v) {
				this->obj_m = v.obj_m;
				return *this;
			}
			VIEWPORT_OBJECT& operator=(VIEWPORT_OBJECT&& v) noexcept {
				this->obj_m = std::move(v.obj_m);
				return *this;
			}

			// 状態を更新するメソッド
			void push_state() {
				glViewport(*(this->obj_m));
			}
			// 状態を外すメソッド
			void pop_state() {}
			// 状態を設定するメソッド
			void set_state() {
				glViewport(*(this->obj_m));
			}

			// スクリーンに対してビューポート領域が正規化されるようにビュー行列をスケーリング
			void unit_scaling() {
				/*if (!this->is_scaling_m && (this->camera_m != nullptr)) {
					this->is_scaling_m = true;
					glMatrixMode(GL_MODELVIEW);
					glPushMatrix();
					glLoadTransposeMatrix(this->camera_m->view_matrix());
					glScalef(float(screen_rect::base_width()) / (this->obj_m->right - this->obj_m->left), float(screen_rect::base_height()) / (this->obj_m->bottom - this->obj_m->top), 1);
				}*/
			}

			// ビューポート行列の取得
			template <class T>
			matrix4<T> viewport_matrix() const {
				return iml::viewport_matrix<T>(this->obj_m->left, this->obj_m->top, this->obj_m->right - this->obj_m->left, this->obj_m->bottom - this->obj_m->top, 0, 1);
			}
			// ビューポート領域の取得
			const rect<int_t>& viewport_rect() const {
				return *(this->obj_m);
			}
		};
		inline VIEWPORT_OBJECT CREATE_VIEWPORT_OBJECT(const rect<int_t>& r) {
			return VIEWPORT_OBJECT(r);
		}
		// 現在のビューポートの状態をvと共通化
		inline void set_viewport(const VIEWPORT_OBJECT& v) {
			using enabler_object_control_t = typename VIEWPORT_OBJECT::enabler_object_control_t;
			enabler_object_control_t::inst()->top()->set(v);
		}
		// 現在のビューポートの状態をrにより変更
		inline void set_viewport(const rect<int_t>& r) {
			using enabler_object_control_t = typename VIEWPORT_OBJECT::enabler_object_control_t;
			enabler_object_control_t::inst()->top()->set(r);
		}
		inline void set_viewport(int_t left, int_t right, int_t bottom, int_t top) {
			using enabler_object_control_t = typename VIEWPORT_OBJECT::enabler_object_control_t;
			enabler_object_control_t::inst()->top()->set(rect<int_t>(left, right, bottom, top));
		}
		// 現在のビューポート行列の取得
		template <class T>
		inline matrix4<T> viewport_matrix() {
			using enabler_object_control_t = typename VIEWPORT_OBJECT::enabler_object_control_t;
			return static_cast<VIEWPORT_OBJECT*>(enabler_object_control_t::inst()->top())->viewport_matrix<T>();
		}
		// 現在のビューポート領域の取得
		template <class T>
		inline const rect<int_t>& viewport_rect() {
			using enabler_object_control_t = typename VIEWPORT_OBJECT::enabler_object_control_t;
			return static_cast<VIEWPORT_OBJECT*>(enabler_object_control_t::inst()->top())->viewport_rect();
		}
		// 現在のワールド座標から現在のスクリーン座標の取得
		template <class T>
		vector3<T> world_to_screen(const vector3<T>& v) {
			// ワールド座標系からの投影は左下を(0, 0)として扱っているため、その補正(まだしてない)
			auto temp = iml::ml::viewport_matrix<T>() * iml::ml::projection_matrix<T>() * iml::ml::view_matrix<T>()
				* vector4<T>(v[0], v[1], v[2], 1);
			return vector3<T>(temp[0] / temp[3], temp[1] / temp[3], temp[2] / temp[3]);
		}
		template <class T>
		vector3<T> world_to_screen(const vector3<T>& v, const CAMERA_OBJECT<T>& ca, const VIEWPORT_OBJECT& vp) {
			// ワールド座標系からの投影は左下を(0, 0)として扱っているため、その補正(まだしてない)
			auto temp = vp.viewport_matrix<T>() * ca.projection_matrix() * ca.view_matrix()
				* vector4<T>(v[0], v[1], v[2], 1);
			return vector3<T>(temp[0] / temp[3], temp[1] / temp[3], temp[2] / temp[3]);
		}
		// 現在のスクリーン座標から現在のワールド座標の取得
		template <class T>
		vector3<T> screen_to_world(const vector3<T>& v) {
			// ワールド座標系からの投影は左下を(0, 0)として扱っているため、その補正(まだしてない)
			auto temp = inverse_matrix(iml::ml::viewport_matrix<T>() * iml::ml::projection_matrix<T>() * iml::ml::view_matrix<T>())
				* vector4<T>(v[0], v[1], v[2], 1);
			return vector3<T>(temp[0] / temp[3], temp[1] / temp[3], temp[2] / temp[3]);
		}
		template <class T>
		vector3<T> screen_to_world(const vector3<T>& v, const CAMERA_OBJECT<T>& ca, const VIEWPORT_OBJECT& vp) {
			// ワールド座標系からの投影は左下を(0, 0)として扱っているため、その補正(まだしてない)
			auto temp = inverse_matrix(vp.viewport_matrix<T>() * ca.projection_matrix() * ca.view_matrix())
				* vector4<T>(v[0], v[1], v[2], 1);
			return vector3<T>(temp[0] / temp[3], temp[1] / temp[3], temp[2] / temp[3]);
		}
		// ビューポートの初期化
		inline void init_viewport() {
			// rootウィンドウのウィンドウサイズで初期化
			VIEWPORT_OBJECT::init();
		}
		inline void init_viewport(const rect<int_t>& r) {
			VIEWPORT_OBJECT::init(r);
		}
		inline void init_viewport(int_t left, int_t right, int_t bottom, int_t top) {
			VIEWPORT_OBJECT::init(rect<int_t>(left, right, bottom, top));
		}
		// ビューポートの終了
		inline void quit_viewport() {
			VIEWPORT_OBJECT::quit();
		}
#define IMATHLIB_VIEWPORT(NAME, RECT)	IMATHLIB_ENABLER_OBJECT(auto NAME = ::iml::ml::CREATE_VIEWPORT_OBJECT(iml::ml::rect<iml::int_t>##RECT))

		// スクリーンモード
		struct SCREEN_MODE_OBJECT {
		private:
			VIEWPORT_OBJECT		viewport_m;
		public:
			SCREEN_MODE_OBJECT(const VIEWPORT_OBJECT& v) : SCREEN_MODE_OBJECT(v.viewport_rect()) {}
			SCREEN_MODE_OBJECT(const rect<int_t>& r) : viewport_m(r) {
				// スクリーン領域で平行投影にする
				glMatrixMode(GL_PROJECTION);
				glPushMatrix();
				glLoadTransposeMatrix(iml::ortho_projection_matrix<float>(0, r.right - r.left, r.bottom - r.top, 0, -1, 1));
				//gluOrtho2D(0, r.right - r.left, r.bottom - r.top, 0);
				glMatrixMode(GL_MODELVIEW);
				glPushMatrix();
				glLoadIdentity();
			}
			~SCREEN_MODE_OBJECT() {
				glMatrixMode(GL_PROJECTION);
				glPopMatrix();
				glMatrixMode(GL_MODELVIEW);
				glPopMatrix();
			}

			// enabler objectの参照の取得
			VIEWPORT_OBJECT& viewport_object() { return this->viewport_m; }
			const VIEWPORT_OBJECT& viewport_object() const { return this->viewport_m; }
		};
		inline SCREEN_MODE_OBJECT CREATE_SCREEN_MODE_OBJECT(const rect<int_t>& r) {
			return SCREEN_MODE_OBJECT(r);
		}
#define IMATHLIB_SCREEN_MODE(NAME, RECT)				IMATHLIB_ENABLER_OBJECT(auto NAME = ::iml::ml::CREATE_SCREEN_MODE_OBJECT(iml::ml::rect<iml::int_t>##RECT))

	}
}

#endif