/*
First author tiritomato 2013.

mqsdx is distributed under the GNU Lesser General Public License 3.0(LGPLv3).

support blog (Japanese only)
http://d.hatena.ne.jp/tiri_tomato/
*/

#ifdef __cplusplus_cli
#include <stdint.h>
#include "../MQCLI.hpp"

namespace MQCLI {

	/* private type define */

	template <typename T> struct DrawType;
	template <> struct DrawType<int> {
		typedef int value_type;
		typedef System::Drawing::Point Point;
		typedef System::Drawing::Size Size;
		typedef System::Drawing::Rectangle Rectangle;
	};
	template <> struct DrawType<float> {
		typedef float value_type;
		typedef System::Drawing::PointF Point;
		typedef System::Drawing::SizeF Size;
		typedef System::Drawing::RectangleF Rectangle;
	};

	struct FillTriangleLineFillInfo {
		int left_x, right_x;
		unsigned char left_r, left_g, left_b, left_a;
		unsigned char right_r, right_g, right_b, right_a;
		void Init( int Width ) {
			right_x = 0;
			left_x = Width;
		}
		uint32_t left_rgba() const {
			uint32_t rgba;
			unsigned char* const pixel = (unsigned char*)(&rgba);
			pixel[0] = left_b;
			pixel[1] = left_g;
			pixel[2] = left_r;
			pixel[3] = left_a;
			return rgba;
		}
		uint32_t right_rgba() const {
			uint32_t rgba;
			unsigned char* const pixel = (unsigned char*)(&rgba);
			pixel[0] = right_b;
			pixel[1] = right_g;
			pixel[2] = right_r;
			pixel[3] = right_a;
			return rgba;
		}
	};

	template <typename T>
	void _DrawTriangle( System::Drawing::Graphics^ g, array<typename DrawType<T>::Point>^ points, array<System::Drawing::Color>^ colors, float border_radius, bool isExcludeInside = true ) {
		
		if ( (g==nullptr)||(points==nullptr)||(colors==nullptr) ) return;
		
		const int Count = System::Math::Min( System::Math::Min( points->Length, colors->Length ), 3);
		if ( Count != 3 ) return;

		const float border = std::abs( border_radius );

		System::Drawing::Region^ registedClip = g->Clip;
		
		double center_x = 0.0, center_y = 0.0;
		for ( int ct = 0; ct < Count; ct++ ) { center_x += points[ct].X; center_y += points[ct].Y; }
		center_x /= 3.0; center_y /= 3.0;

		System::Drawing::Drawing2D::GraphicsPath^ inner_path = gcnew System::Drawing::Drawing2D::GraphicsPath();
		inner_path->AddPolygon( points );
		inner_path->CloseFigure();
		System::Drawing::Region^ edge_rgn = registedClip->Clone();
		edge_rgn->Exclude( inner_path );
		delete inner_path;

		array<typename DrawType<T>::Point>^ border_points = gcnew array<typename DrawType<T>::Point>(4);
		try {
			for ( int ct = 0; ct < Count; ct++ ) {
				const double toInside_x = center_x - points[ct].X;
				const double toInside_y = center_y - points[ct].Y;
				const int next_ct = ct < (Count-1) ? (ct+1) : 0;
				const double dist_x = double(points[next_ct].X) - double(points[ct].X);
				const double dist_y = double(points[next_ct].Y) - double(points[ct].Y);
				const double len = std::sqrt( dist_x * dist_x + dist_y * dist_y );
				double scale = 0.0; if ( double::Epsilon <= len ) scale = border / len;
				double toOutsideCross_x = dist_y * scale;
				double toOutsideCross_y = -dist_x * scale;
				if ( 0.0 < ( toInside_x * toOutsideCross_x + toInside_y * toOutsideCross_y ) ) {
					toOutsideCross_x = -toOutsideCross_x;
					toOutsideCross_y = -toOutsideCross_y;
				}
				border_points[0] = typename DrawType<T>::Point(
					T(points[ct].X + toOutsideCross_x),
					T(points[ct].Y + toOutsideCross_y)
					); // outside
				border_points[1] = typename DrawType<T>::Point(
					T(points[next_ct].X + toOutsideCross_x),
					T(points[next_ct].Y + toOutsideCross_y)
					); // outside
				border_points[2] = points[next_ct];
				border_points[3] = points[ct];

				array<System::Drawing::Color>^ border_colors = gcnew array<System::Drawing::Color>(4);
				border_colors[0] = colors[ct];
				border_colors[1] = colors[next_ct];
				border_colors[2] = colors[next_ct];
				border_colors[3] = colors[ct];

				System::Drawing::Drawing2D::GraphicsPath^ border_path = gcnew System::Drawing::Drawing2D::GraphicsPath();
				border_path->AddPolygon( border_points );
				border_path->CloseFigure();
				edge_rgn->Exclude( border_path );
				delete border_path;

				array<typename DrawType<T>::Point>^ draw_points = gcnew array<typename DrawType<T>::Point>(3);
				array<System::Drawing::Color>^ draw_colors = gcnew array<System::Drawing::Color>(3);
				draw_points[0] = border_points[0];
				draw_colors[0] = border_colors[0];
				draw_points[1] = border_points[1];
				draw_colors[1] = border_colors[1];
				draw_points[2] = border_points[2];
				draw_colors[2] = border_colors[2];
				_FillTriangle<T>( g, draw_points, draw_colors );
				draw_points[1] = border_points[3];
				draw_colors[1] = border_colors[3];
				_FillTriangle<T>( g, draw_points, draw_colors );
			}

			g->Clip = edge_rgn;
			for ( int ct = 0; ct < Count; ct++ ) {
				System::Drawing::SolidBrush^ brush = gcnew System::Drawing::SolidBrush( colors[ct] );
				g->FillEllipse( brush, points[ct].X - border, points[ct].Y - border, border * 2.0f, border * 2.0f );
				delete brush;
			}
		}
		catch ( System::Exception^ ) { throw; }
		finally {
			g->Clip = registedClip;
			delete edge_rgn;
		}


		/*
		if ( (g==nullptr)||(points==nullptr)||(colors==nullptr) ) return;

		const int Count = System::Math::Min( System::Math::Min( points->Length, colors->Length ), 3);

		if ( Count != 3 ) return;
		
		typename DrawType<T>::Point min( T::MaxValue, T::MaxValue );
		typename DrawType<T>::Point max( T::MinValue, T::MinValue );
		for ( int ct = 0; ct < Count; ct++ ) {
			min.X = System::Math::Min( min.X, points[ct].X );
			min.Y = System::Math::Min( min.Y, points[ct].Y );
			max.X = System::Math::Max( max.X, points[ct].X );
			max.Y = System::Math::Max( max.Y, points[ct].Y );
		}
		const float border = std::abs( border_radius );
		const int ceiled_border = int(MQ0x::ceil(border));
		const int ceiled_width = int(MQ0x::ceil(max.X - min.X));	// もし小数点だったらceiling計算をして多めに確保する
		const int ceiled_height = int(MQ0x::ceil(max.Y - min.Y));	//
		const int img_width = ceiled_width + ceiled_border * 2;
		const int img_height = ceiled_height + ceiled_border * 2;
		if ( (ceiled_width <= 0) || (ceiled_height <= 0) ) return;

		// ready clip region
		array<typename DrawType<T>::Point>^ pathPolyEdgeBuffer = gcnew array<typename DrawType<T>::Point>(4);
		System::Drawing::Region^ registedClip = g->Clip;
		System::Drawing::Region^ clip_region = gcnew System::Drawing::Region( System::Drawing::Rectangle(0,0,0,0) );
		for ( int ct = 0; ct < Count; ct++ ) {
			System::Drawing::Drawing2D::GraphicsPath^ addEllipse = gcnew System::Drawing::Drawing2D::GraphicsPath();
			addEllipse->AddEllipse( T(points[ct].X - border), T(points[ct].Y - border), T(border * 2.0f), T(border * 2.0f) );
			addEllipse->CloseFigure();
			clip_region->Union(addEllipse);
			delete addEllipse;
			const int next_ct = ct < (Count-1) ? (ct+1) : 0;
			const float dist_x = float(points[next_ct].X - points[ct].X);
			const float dist_y = float(points[next_ct].Y - points[ct].Y);
			const float len = std::sqrt( dist_x * dist_x + dist_y * dist_y );
			const float scale = border / len;
			const float cross_x = dist_y * scale;
			const float cross_y = dist_x * scale;
			pathPolyEdgeBuffer[0] = typename DrawType<T>::Point(
				T(points[ct].X - cross_x),
				T(points[ct].Y + cross_y)
				);
			pathPolyEdgeBuffer[1] = typename DrawType<T>::Point(
				T(points[next_ct].X - cross_x),
				T(points[next_ct].Y + cross_y)
				);
			pathPolyEdgeBuffer[2] = typename DrawType<T>::Point(
				T(points[next_ct].X + cross_x),
				T(points[next_ct].Y - cross_y)
				);
			pathPolyEdgeBuffer[3] = typename DrawType<T>::Point(
				T(points[ct].X + cross_x),
				T(points[ct].Y - cross_y)
				);
			System::Drawing::Drawing2D::GraphicsPath^ addPolygon = gcnew System::Drawing::Drawing2D::GraphicsPath();
			addPolygon->AddPolygon(pathPolyEdgeBuffer);
			addPolygon->CloseFigure();
			clip_region->Union(addPolygon);
			delete addPolygon;
		}
		
		if ( isExcludeInside ) {
			System::Drawing::Drawing2D::GraphicsPath^ nega_path = gcnew System::Drawing::Drawing2D::GraphicsPath();
			nega_path->AddLine(points[0],points[1]);
			nega_path->AddLine(points[1],points[2]);
			nega_path->CloseFigure();
			clip_region->Exclude(nega_path);
			delete nega_path;
			nega_path = nullptr;
		}
		clip_region->Intersect( registedClip );

		// ready fill info
		std::vector<FillTriangleLineFillInfo> fillinfo( ceiled_height );
		for ( int ctLine = 0; ctLine < ceiled_height; ctLine++ ) fillinfo[ctLine].Init( ceiled_width );
		for ( int ctPoint = 0; ctPoint < Count; ctPoint++ ) {
			const int ctNextPoint = ctPoint < (Count-1) ? ctPoint+1 : 0;
			int ctTopPoint = ctPoint, ctBottomPoint = ctNextPoint;
			if ( points[ctNextPoint].Y < points[ctPoint].Y ) {
				ctTopPoint = ctNextPoint;
				ctBottomPoint = ctPoint;
			}
			System::Drawing::Color top_color = colors[ctTopPoint];
			System::Drawing::Color bottom_color = colors[ctBottomPoint];
			const float top_x		= float(points[ctTopPoint].X - min.X);
			const int top_y			= int(points[ctTopPoint].Y - min.Y);
			const float bottom_x	= float(points[ctBottomPoint].X - min.X);
			const int bottom_y		= int(MQ0x::ceil(points[ctBottomPoint].Y - min.Y));
			const float	Width		= bottom_x - top_x; // マイナスにもなるWidth
			const float	Height		= float(bottom_y - top_y);
			const float top_x1024	= top_x * 1024;
			for ( int y = top_y; y < bottom_y; y++ ) {
				/*
				float weight = float(y - top_y) / Height;
				const int x = int( float(top_x) + Width * weight );
				const unsigned char r = unsigned char(std::min( int(float(top_color.R) * (1.0f - weight) + float(bottom_color.R) * weight + 0.5f), 0xFF ));
				const unsigned char g = unsigned char(std::min( int(float(top_color.G) * (1.0f - weight) + float(bottom_color.G) * weight + 0.5f), 0xFF ));
				const unsigned char b = unsigned char(std::min( int(float(top_color.B) * (1.0f - weight) + float(bottom_color.B) * weight + 0.5f), 0xFF ));
				const unsigned char a = unsigned char(std::min( int(float(top_color.A) * (1.0f - weight) + float(bottom_color.A) * weight + 0.5f), 0xFF ));
				*/
				/*const int weight = int(float((y - top_y) * 1024) / Height);
				const int x = int( top_x1024 + Width * weight ) / 1024;
				const unsigned char r = unsigned char(std::min( (top_color.R * (1024 - weight) + bottom_color.R * weight + 512) / 1024, 0xFF ));
				const unsigned char g = unsigned char(std::min( (top_color.G * (1024 - weight) + bottom_color.G * weight + 512) / 1024, 0xFF ));
				const unsigned char b = unsigned char(std::min( (top_color.B * (1024 - weight) + bottom_color.B * weight + 512) / 1024, 0xFF ));
				const unsigned char a = unsigned char(std::min( (top_color.A * (1024 - weight) + bottom_color.A * weight + 512) / 1024, 0xFF ));
				if ( x < fillinfo[y].left_x ) {
					fillinfo[y].left_x = x;
					fillinfo[y].left_r = r;
					fillinfo[y].left_g = g;
					fillinfo[y].left_b = b;
					fillinfo[y].left_a = a;
				}
				if ( fillinfo[y].right_x < x ) {
					fillinfo[y].right_x = x;
					fillinfo[y].right_r = r;
					fillinfo[y].right_g = g;
					fillinfo[y].right_b = b;
					fillinfo[y].right_a = a;
				}
			}
		}

		System::Drawing::Bitmap^ tex = gcnew System::Drawing::Bitmap(img_width,img_height,System::Drawing::Imaging::PixelFormat::Format32bppArgb);
		System::Drawing::Imaging::BitmapData^ bmpData = nullptr;
		try {
			bmpData = tex->LockBits( System::Drawing::Rectangle( 0, 0, img_width, img_height ),
				System::Drawing::Imaging::ImageLockMode::ReadWrite,
				System::Drawing::Imaging::PixelFormat::Format32bppArgb );
			unsigned char* const buffer_header = (unsigned char*)(bmpData->Scan0.ToPointer());
			for ( int y = 0; y < ceiled_height; y++ ) {
				const int lineOffset = bmpData->Stride * (y + ceiled_border);
				const uint32_t left_rgba = fillinfo[y].left_rgba();
				const uint32_t right_rgba = fillinfo[y].right_rgba();
				for ( int x = 0; x < (fillinfo[y].left_x + ceiled_border); x++ ) {
					/*
					unsigned char* const pixel = buffer_header + lineOffset + x * 4;
					pixel[0] = fillinfo[y].left_b;
					pixel[1] = fillinfo[y].left_g;
					pixel[2] = fillinfo[y].left_r;
					pixel[3] = fillinfo[y].left_a;
					*/
					/*((uint32_t*)(buffer_header + lineOffset))[x] = left_rgba;
				}
				unsigned char* const buffer_header_offset = buffer_header + lineOffset + (fillinfo[y].left_x + ceiled_border) * 4;
				const int line_width = fillinfo[y].right_x - fillinfo[y].left_x;
				for ( int x = 0; x < line_width; x++ ) {
					/*unsigned char* const pixel = buffer_header + lineOffset + (x + fillinfo[y].left_x + ceiled_border) * 4;
					const float weight = float(x) / float(line_width);
					pixel[0] = unsigned char(std::min(int(float(fillinfo[y].left_b) * (1.0f-weight) + float(fillinfo[y].right_b) * weight + 0.5f),0xFF));
					pixel[1] = unsigned char(std::min(int(float(fillinfo[y].left_g) * (1.0f-weight) + float(fillinfo[y].right_g) * weight + 0.5f),0xFF));
					pixel[2] = unsigned char(std::min(int(float(fillinfo[y].left_r) * (1.0f-weight) + float(fillinfo[y].right_r) * weight + 0.5f),0xFF));
					pixel[3] = unsigned char(std::min(int(float(fillinfo[y].left_a) * (1.0f-weight) + float(fillinfo[y].right_a) * weight + 0.5f),0xFF));
					*/
					/*unsigned char* const pixel = buffer_header_offset + x * 4;
					const int weight = int(float(1024 * x) / float(line_width));
					pixel[0] = unsigned char(std::min((fillinfo[y].left_b * (1024 - weight) + fillinfo[y].right_b * weight + 512) / 1024, 0xFF));
					pixel[1] = unsigned char(std::min((fillinfo[y].left_g * (1024 - weight) + fillinfo[y].right_g * weight + 512) / 1024, 0xFF));
					pixel[2] = unsigned char(std::min((fillinfo[y].left_r * (1024 - weight) + fillinfo[y].right_r * weight + 512) / 1024, 0xFF));
					pixel[3] = unsigned char(std::min((fillinfo[y].left_a * (1024 - weight) + fillinfo[y].right_a * weight + 512) / 1024, 0xFF));
				}
				for ( int x = ceiled_border + fillinfo[y].right_x; x < img_width; x++ ) {
					/*
					unsigned char* const pixel = buffer_header + lineOffset + x * 4;
					pixel[0] = fillinfo[y].right_b;
					pixel[1] = fillinfo[y].right_g;
					pixel[2] = fillinfo[y].right_r;
					pixel[3] = fillinfo[y].right_a;
					*/
					/*((uint32_t*)(buffer_header + lineOffset))[x] = right_rgba;
				}
			}
			if ( 0 < ceiled_border ) {
				{
					//const unsigned char* src_pixel_header = buffer_header + bmpData->Stride * ceiled_border;
					const uint32_t* src_pixels_header = (const uint32_t*)(buffer_header + bmpData->Stride * ceiled_border);
					for ( int y = 0; y < ceiled_border; y++ ) {
						const int lineOffset = bmpData->Stride * y;
						for ( int x = 0; x < img_width; x++ ) {
							/*
							const unsigned char* src_pixel = src_pixel_header + x * 4;
							unsigned char* const pixel = buffer_header + lineOffset + x * 4;
							pixel[0] = src_pixel[0];
							pixel[1] = src_pixel[1];
							pixel[2] = src_pixel[2];
							pixel[3] = src_pixel[3];
							*/
							/*((uint32_t*)(buffer_header + lineOffset))[x] = src_pixels_header[x];
						}
					}
				}
				{
					//const unsigned char* src_pixel_header = buffer_header + bmpData->Stride * (img_height - ceiled_border - 1);
					const uint32_t* src_pixels_header = (const uint32_t*)(buffer_header + bmpData->Stride * (img_height - ceiled_border - 1));
					for ( int y = (img_height - ceiled_border); y < img_height; y++ ) {
						const int lineOffset = bmpData->Stride * y;
						for ( int x = 0; x < img_width; x++ ) {
							/*
							const unsigned char* src_pixel = src_pixel_header + x * 4;
							unsigned char* const pixel = buffer_header + lineOffset + x * 4;
							pixel[0] = src_pixel[0];
							pixel[1] = src_pixel[1];
							pixel[2] = src_pixel[2];
							pixel[3] = src_pixel[3];
							*/
							/*((uint32_t*)(buffer_header + lineOffset))[x] = src_pixels_header[x];
						}
					}
				}
			}

			tex->UnlockBits( bmpData );
			delete bmpData; // dispose
			bmpData = nullptr;

			g->Clip = clip_region;
			g->DrawImage( tex, typename DrawType<T>::Point( min.X - ceiled_border, min.Y - ceiled_border ) );
		}
		catch ( System::Exception^ ) { throw; }
		finally {
			g->Clip = registedClip;
			if ( clip_region != nullptr ) { delete clip_region; clip_region = nullptr; }
			if ( tex != nullptr ) {
				if ( bmpData != nullptr ) {
					tex->UnlockBits( bmpData );
					delete bmpData; // dispose
					bmpData = nullptr;
				}
				delete tex;
				tex = nullptr;
			}
		}*/
	}

	template <typename T> void _FillTriangle( System::Drawing::Graphics^ g, array<typename DrawType<T>::Point>^ points, array<System::Drawing::Color>^ colors )
	{
		if ( (g==nullptr)||(points==nullptr)||(colors==nullptr) ) return;
		
		const int Count = System::Math::Min( System::Math::Min( points->Length, colors->Length ), 3 );
		if ( Count != 3 ) return;

		typename DrawType<T>::Point min( T::MaxValue, T::MaxValue );
		typename DrawType<T>::Point max( T::MinValue, T::MinValue );
		for ( int ct = 0; ct < Count; ct++ ) {
			min.X = System::Math::Min( min.X, points[ct].X );
			min.Y = System::Math::Min( min.Y, points[ct].Y );
			max.X = System::Math::Max( max.X, points[ct].X );
			max.Y = System::Math::Max( max.Y, points[ct].Y );
		}

		const int img_width = int(MQ0x::Ceil(max.X - min.X));	// もし小数点だったらceiling計算をして多めに確保する
		const int img_height = int(MQ0x::Ceil(max.Y - min.Y));	//
		if ( (img_width <= 0) || (img_height <= 0) ) return;

		System::Drawing::Bitmap^ tex = gcnew System::Drawing::Bitmap(img_width,img_height,System::Drawing::Imaging::PixelFormat::Format32bppArgb);
		std::vector<FillTriangleLineFillInfo> fillinfo( img_height );
		for ( int ctLine = 0; ctLine < img_height; ctLine++ ) fillinfo[ctLine].Init( img_width );
		for ( int ctPoint = 0; ctPoint < Count; ctPoint++ ) {
			const int ctNextPoint = ctPoint < (Count-1) ? ctPoint+1 : 0;
			int ctTopPoint = ctPoint, ctBottomPoint = ctNextPoint;
			if ( points[ctNextPoint].Y < points[ctPoint].Y ) {
				ctTopPoint = ctNextPoint;
				ctBottomPoint = ctPoint;
			}
			System::Drawing::Color top_color = colors[ctTopPoint];
			System::Drawing::Color bottom_color = colors[ctBottomPoint];
			const float	top_x		= float(points[ctTopPoint].X - min.X);
			const int	top_y		= int(points[ctTopPoint].Y - min.Y);
			const float	bottom_x	= float(points[ctBottomPoint].X - min.X);
			const int	bottom_y	= int(MQ0x::Ceil(points[ctBottomPoint].Y - min.Y));
			const float	Width		= bottom_x - top_x; // マイナスにもなるWidth
			const float	Height		= float(bottom_y - top_y);
			const float top_x1024		= top_x * 1024;
			for ( int y = top_y; y < bottom_y; y++ ) {
				/*
				float weight = float(y - top_y) / Height;
				const int x = int( float(top_x) + Width * weight );
				const unsigned char r = unsigned char(std::min( int(float(top_color.R) * (1.0f - weight) + float(bottom_color.R) * weight + 0.5f), 0xFF ));
				const unsigned char g = unsigned char(std::min( int(float(top_color.G) * (1.0f - weight) + float(bottom_color.G) * weight + 0.5f), 0xFF ));
				const unsigned char b = unsigned char(std::min( int(float(top_color.B) * (1.0f - weight) + float(bottom_color.B) * weight + 0.5f), 0xFF ));
				const unsigned char a = unsigned char(std::min( int(float(top_color.A) * (1.0f - weight) + float(bottom_color.A) * weight + 0.5f), 0xFF ));
				*/
				const int weight = int(float((y - top_y) * 1024) / Height);
				const int x = int( top_x1024 + Width * weight ) / 1024;
				const unsigned char r = unsigned char(std::min( (top_color.R * (1024 - weight) + bottom_color.R * weight + 512) / 1024, 0xFF ));
				const unsigned char g = unsigned char(std::min( (top_color.G * (1024 - weight) + bottom_color.G * weight + 512) / 1024, 0xFF ));
				const unsigned char b = unsigned char(std::min( (top_color.B * (1024 - weight) + bottom_color.B * weight + 512) / 1024, 0xFF ));
				const unsigned char a = unsigned char(std::min( (top_color.A * (1024 - weight) + bottom_color.A * weight + 512) / 1024, 0xFF ));
				if ( x < fillinfo[y].left_x ) {
					fillinfo[y].left_x = x;
					fillinfo[y].left_r = r;
					fillinfo[y].left_g = g;
					fillinfo[y].left_b = b;
					fillinfo[y].left_a = a;
				}
				if ( fillinfo[y].right_x < x ) {
					fillinfo[y].right_x = x;
					fillinfo[y].right_r = r;
					fillinfo[y].right_g = g;
					fillinfo[y].right_b = b;
					fillinfo[y].right_a = a;
				}
			}
		}

		System::Drawing::Imaging::BitmapData^ bmpData = nullptr;
		System::Drawing::Region^ registedClip = g->Clip;
		System::Drawing::Drawing2D::GraphicsPath^ drawPath = nullptr;
		System::Drawing::Region^ drawClip = nullptr;
		try {
			bmpData = tex->LockBits( System::Drawing::Rectangle( 0, 0, img_width, img_height ),
				System::Drawing::Imaging::ImageLockMode::ReadWrite,
				System::Drawing::Imaging::PixelFormat::Format32bppArgb );
			unsigned char* const buffer_header = (unsigned char*)(bmpData->Scan0.ToPointer());
			for ( int y = 0; y < img_height; y++ ) {
				const int lineOffset = bmpData->Stride * y;
				const uint32_t left_rgba = fillinfo[y].left_rgba();
				const uint32_t right_rgba = fillinfo[y].right_rgba();
				for ( int x = 0; x < fillinfo[y].left_x; x++ ) {
					/*unsigned char* const pixel = buffer_header + lineOffset + x * 4;
					pixel[0] = fillinfo[y].left_b;
					pixel[1] = fillinfo[y].left_g;
					pixel[2] = fillinfo[y].left_r;
					pixel[3] = fillinfo[y].left_a;*/
					((uint32_t*)(buffer_header + lineOffset))[x] = left_rgba;
				}
				unsigned char* const buffer_header_offset = buffer_header + lineOffset + fillinfo[y].left_x * 4;
				const int line_width = fillinfo[y].right_x - fillinfo[y].left_x;
				for ( int x = 0; x < line_width; x++ ) {
					//unsigned char* const pixel = buffer_header + lineOffset + (x + fillinfo[y].left_x) * 4;
					/*const float weight = float(x) / float(line_width);
					pixel[0] = unsigned char(std::min(int(float(fillinfo[y].left_b) * (1.0f-weight) + float(fillinfo[y].right_b) * weight + 0.5f),0xFF));
					pixel[1] = unsigned char(std::min(int(float(fillinfo[y].left_g) * (1.0f-weight) + float(fillinfo[y].right_g) * weight + 0.5f),0xFF));
					pixel[2] = unsigned char(std::min(int(float(fillinfo[y].left_r) * (1.0f-weight) + float(fillinfo[y].right_r) * weight + 0.5f),0xFF));
					pixel[3] = unsigned char(std::min(int(float(fillinfo[y].left_a) * (1.0f-weight) + float(fillinfo[y].right_a) * weight + 0.5f),0xFF));*/
					unsigned char* const pixel = buffer_header_offset + x * 4;
					const int weight = int(float(1024 * x) / float(line_width));
					pixel[0] = unsigned char(std::min((fillinfo[y].left_b * (1024 - weight) + fillinfo[y].right_b * weight + 512) / 1024, 0xFF));
					pixel[1] = unsigned char(std::min((fillinfo[y].left_g * (1024 - weight) + fillinfo[y].right_g * weight + 512) / 1024, 0xFF));
					pixel[2] = unsigned char(std::min((fillinfo[y].left_r * (1024 - weight) + fillinfo[y].right_r * weight + 512) / 1024, 0xFF));
					pixel[3] = unsigned char(std::min((fillinfo[y].left_a * (1024 - weight) + fillinfo[y].right_a * weight + 512) / 1024, 0xFF));
				}
				for ( int x = fillinfo[y].right_x; x < img_width; x++ ) {
					/*unsigned char* const pixel = buffer_header + lineOffset + x * 4;
					pixel[0] = fillinfo[y].right_b;
					pixel[1] = fillinfo[y].right_g;
					pixel[2] = fillinfo[y].right_r;
					pixel[3] = fillinfo[y].right_a;*/
					((uint32_t*)(buffer_header + lineOffset))[x] = right_rgba;
				}
			}
			tex->UnlockBits( bmpData );
			delete bmpData; // dispose
			bmpData = nullptr;
			
			drawPath = gcnew System::Drawing::Drawing2D::GraphicsPath();
			drawPath->AddPolygon(points);
			drawPath->CloseFigure();
			drawClip = gcnew System::Drawing::Region( drawPath );
			drawClip->Intersect( registedClip );
			g->Clip = drawClip;
			g->DrawImage( tex, min );
		}
		catch (System::Exception^) { throw; }
		finally {
			g->Clip = registedClip;
			if ( drawClip != nullptr ) { delete drawClip; drawClip = nullptr; }
			if ( drawPath != nullptr ) { delete drawPath; drawPath = nullptr; }
			if (tex != nullptr) {
				if ( bmpData != nullptr ) {
					tex->UnlockBits( bmpData );
					delete bmpData; // dispose
					bmpData = nullptr;
				}
				delete tex; // dispose
				tex = nullptr;
			}
		}
	}

	/* implements */
	Lock::Lock( System::Object^ pObject ) : m_pObject( pObject ) {
		System::Threading::Monitor::Enter( m_pObject );
	}

	Lock::!Lock() {
		if ( m_pObject != nullptr ) System::Threading::Monitor::Exit( m_pObject );
		m_pObject = nullptr;
	}

	void Drawing::DrawTriangle( System::Drawing::Graphics^ g, array<System::Drawing::Point>^ points, array<System::Drawing::Color>^ colors, float border_radius, bool isExcludeInside ) {
		_DrawTriangle<int>( g, points, colors, border_radius, isExcludeInside );
	}
	void Drawing::DrawTriangle( System::Drawing::Graphics^ g, array<System::Drawing::PointF>^ points, array<System::Drawing::Color>^ colors, float border_radius, bool isExcludeInside ) {
		_DrawTriangle<float>( g, points, colors, border_radius, isExcludeInside );
	}
	void Drawing::FillTriangle( System::Drawing::Graphics^ g, array<System::Drawing::Point>^ points, array<System::Drawing::Color>^ colors ) { _FillTriangle<int>( g, points, colors ); }
	void Drawing::FillTriangle( System::Drawing::Graphics^ g, array<System::Drawing::PointF>^ points, array<System::Drawing::Color>^ colors ) { _FillTriangle<float>( g, points, colors ); }
	
	namespace Plugins {

		bool PluginMainHolder::Regist( IBasePlugin^ pluginBody ) {
			Lock lock(m_lock);
			if ( m_pluginMain == nullptr && pluginBody != nullptr && pluginBody->basePlugin != NULL ) {
				m_pluginMain = pluginBody;
				return true;
			}
			return false;
		}

		MQBasePlugin* PluginMainHolder::pluginMain::get() {
			Lock lock(m_lock);
			if ( m_pluginMain == nullptr ) return NULL;
			return m_pluginMain->basePlugin;
		}
	
		BOOL PluginMainHolder::Activate(MQDocument doc, BOOL flag) {
			IActivate^ iPlugin = dynamic_cast<IActivate^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->Activate(doc,flag);
			return FALSE;
		}
		bool PluginMainHolder::ExecuteCallback(MQDocument doc, void *option) {
			IExecuteCallback^ iPlugin = dynamic_cast<IExecuteCallback^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->ExecuteCallback(doc, option);
			return CommandPluginDefault().ExecuteCallback(doc, option);
		}
		void PluginMainHolder::Exit() {
			IExit^ iPlugin = dynamic_cast<IExit^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->Exit();
		}
		BOOL PluginMainHolder::Initialize() {
			IInitialize^ iPlugin = dynamic_cast<IInitialize^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->Initialize();
			return FALSE;
		}
		BOOL PluginMainHolder::IsActivated(MQDocument doc) {
			IIsActivated^ iPlugin = dynamic_cast<IIsActivated^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->IsActivated(doc);
			return CommandPluginDefault().IsActivated(doc);
		}
		void PluginMainHolder::OnMinimize(MQDocument doc, BOOL flag) {
			IOnMinimize^ iPlugin = dynamic_cast<IOnMinimize^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnMinimize(doc, flag);
		}
		int PluginMainHolder::OnReceiveUserMessage(MQDocument doc, DWORD src_product, DWORD src_id, const char *description, void *message) {
			IOnReceiveUserMessage^ iPlugin = dynamic_cast<IOnReceiveUserMessage^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnReceiveUserMessage(doc,src_product,src_id,description,message);
			return CommandPluginDefault().OnReceiveUserMessage(doc,src_product,src_id,description,message);
		}
		void PluginMainHolder::OnDraw(MQDocument doc, MQScene scene, int Width, int Height) {
			IOnDraw^ iPlugin = dynamic_cast<IOnDraw^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnDraw(doc, scene, Width, Height);
		}
		void PluginMainHolder::OnNewDocument(MQDocument doc, const char *filename, MQStationPlugin::NEW_DOCUMENT_PARAM& param) {
			IOnNewDocument^ iPlugin = dynamic_cast<IOnNewDocument^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnNewDocument(doc, filename, param);
		}
		void PluginMainHolder::OnEndDocument(MQDocument doc) {
			IOnEndDocument^ iPlugin = dynamic_cast<IOnEndDocument^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnEndDocument(doc);
		}
		void PluginMainHolder::OnSaveDocument(MQDocument doc, const char *filename, MQStationPlugin::SAVE_DOCUMENT_PARAM& param) {
			IOnSaveDocument^ iPlugin = dynamic_cast<IOnSaveDocument^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnSaveDocument(doc, filename, param);
		}
		BOOL PluginMainHolder::OnUndo(MQDocument doc, int undo_state) {
			IOnUndo^ iPlugin = dynamic_cast<IOnUndo^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnUndo(doc, undo_state);
			return CommandPluginDefault().OnUndo(doc, undo_state);
		}
		BOOL PluginMainHolder::OnRedo(MQDocument doc, int redo_state) {
			IOnRedo^ iPlugin = dynamic_cast<IOnRedo^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnRedo(doc, redo_state);
			return CommandPluginDefault().OnRedo(doc, redo_state);
		}
		void PluginMainHolder::OnUpdateUndo(MQDocument doc, int undo_state, int undo_size) {
			IOnUpdateUndo^ iPlugin = dynamic_cast<IOnUpdateUndo^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnUpdateUndo(doc, undo_state, undo_size);
		}
		void PluginMainHolder::OnObjectModified(MQDocument doc) {
			IOnObjectModified^ iPlugin = dynamic_cast<IOnObjectModified^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnObjectModified(doc);
		}
		void PluginMainHolder::OnObjectSelected(MQDocument doc) {
			IOnObjectSelected^ iPlugin = dynamic_cast<IOnObjectSelected^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnObjectSelected(doc);
		}
		void PluginMainHolder::OnUpdateObjectList(MQDocument doc) {
			IOnUpdateObjectList^ iPlugin = dynamic_cast<IOnUpdateObjectList^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnUpdateObjectList(doc);
		}
		void PluginMainHolder::OnMaterialModified(MQDocument doc) {
			IOnMaterialModified^ iPlugin = dynamic_cast<IOnMaterialModified^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnMaterialModified(doc);
		}
		void PluginMainHolder::OnUpdateMaterialList(MQDocument doc) {
			IOnUpdateMaterialList^ iPlugin = dynamic_cast<IOnUpdateMaterialList^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnUpdateMaterialList(doc);
		}
		void PluginMainHolder::OnUpdateScene(MQDocument doc, MQScene scene) {
			IOnUpdateScene^ iPlugin = dynamic_cast<IOnUpdateScene^>(m_pluginMain);
			if ( iPlugin != nullptr ) iPlugin->OnUpdateScene(doc, scene);
		}
		BOOL PluginMainHolder::OnLeftButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnLeftButtonDown^ iPlugin = dynamic_cast<IOnLeftButtonDown^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnLeftButtonDown(doc, scene, state);
			return CommandPluginDefault().OnLeftButtonDown(doc, scene, state);
		}
		BOOL PluginMainHolder::OnLeftButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnLeftButtonMove^ iPlugin = dynamic_cast<IOnLeftButtonMove^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnLeftButtonMove(doc, scene, state);
			return CommandPluginDefault().OnLeftButtonMove(doc, scene, state);
		}
		BOOL PluginMainHolder::OnLeftButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnLeftButtonUp^ iPlugin = dynamic_cast<IOnLeftButtonUp^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnLeftButtonUp(doc, scene, state);
			return CommandPluginDefault().OnLeftButtonUp(doc, scene, state);
		}
		BOOL PluginMainHolder::OnMiddleButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnMiddleButtonDown^ iPlugin = dynamic_cast<IOnMiddleButtonDown^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnMiddleButtonDown(doc, scene, state);
			return CommandPluginDefault().OnMiddleButtonDown(doc, scene, state);
		}
		BOOL PluginMainHolder::OnMiddleButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnMiddleButtonMove^ iPlugin = dynamic_cast<IOnMiddleButtonMove^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnMiddleButtonMove(doc, scene, state);
			return CommandPluginDefault().OnMiddleButtonMove(doc, scene, state);
		}
		BOOL PluginMainHolder::OnMiddleButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnMiddleButtonUp^ iPlugin = dynamic_cast<IOnMiddleButtonUp^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnMiddleButtonUp(doc, scene, state);
			return CommandPluginDefault().OnMiddleButtonUp(doc, scene, state);
		}
		BOOL PluginMainHolder::OnRightButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnRightButtonDown^ iPlugin = dynamic_cast<IOnRightButtonDown^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnRightButtonDown(doc, scene, state);
			return CommandPluginDefault().OnRightButtonDown(doc, scene, state);
		}
		BOOL PluginMainHolder::OnRightButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnRightButtonMove^ iPlugin = dynamic_cast<IOnRightButtonMove^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnRightButtonMove(doc, scene, state);
			return CommandPluginDefault().OnRightButtonMove(doc, scene, state);
		}
		BOOL PluginMainHolder::OnRightButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnRightButtonUp^ iPlugin = dynamic_cast<IOnRightButtonUp^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnRightButtonUp(doc, scene, state);
			return CommandPluginDefault().OnRightButtonUp(doc, scene, state);
		}
		BOOL PluginMainHolder::OnMouseMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnMouseMove^ iPlugin = dynamic_cast<IOnMouseMove^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnMouseMove(doc, scene, state);
			return CommandPluginDefault().OnMouseMove(doc, scene, state);
		}
		BOOL PluginMainHolder::OnMouseWheel(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnMouseWheel^ iPlugin = dynamic_cast<IOnMouseWheel^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnMouseWheel(doc, scene, state);
			return CommandPluginDefault().OnMouseWheel(doc, scene, state);
		}
		BOOL PluginMainHolder::OnKeyDown(MQDocument doc, MQScene scene, int key, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnKeyDown^ iPlugin = dynamic_cast<IOnKeyDown^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnKeyDown(doc, scene, key, state);
			return CommandPluginDefault().OnKeyDown(doc, scene, key, state);
		}
		BOOL PluginMainHolder::OnKeyUp(MQDocument doc, MQScene scene, int key, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			IOnKeyUp^ iPlugin = dynamic_cast<IOnKeyUp^>(m_pluginMain);
			if ( iPlugin != nullptr ) return iPlugin->OnKeyUp(doc, scene, key, state);
			return CommandPluginDefault().OnKeyUp(doc, scene, key, state);
		}
		/// @endcond

		bool StationPluginsInterfacedBase::ExecuteCallback(MQDocument doc, void *option) {
			return CommandPluginDefault().ExecuteCallback(doc, option);
		}
		BOOL StationPluginsInterfacedBase::IsActivated(MQDocument doc) {
			return CommandPluginDefault().IsActivated(doc);
		}
		void StationPluginsInterfacedBase::OnMinimize(MQDocument doc, BOOL flag) {
			CommandPluginDefault().OnMinimize(doc, flag);
		}
		int StationPluginsInterfacedBase::OnReceiveUserMessage(MQDocument doc, DWORD src_product, DWORD src_id, const char *description, void *message) {
			return CommandPluginDefault().OnReceiveUserMessage(doc, src_product, src_id, description, message);
		}
		void StationPluginsInterfacedBase::OnDraw(MQDocument doc, MQScene scene, int Width, int Height) {
			CommandPluginDefault().OnDraw(doc, scene, Width, Height);
		}
		void StationPluginsInterfacedBase::OnNewDocument(MQDocument doc, const char *filename, MQStationPlugin::NEW_DOCUMENT_PARAM& param) {
			CommandPluginDefault().OnNewDocument(doc, filename, param);
		}
		void StationPluginsInterfacedBase::OnEndDocument(MQDocument doc) {
			CommandPluginDefault().OnEndDocument(doc);
		}
		void StationPluginsInterfacedBase::OnSaveDocument(MQDocument doc, const char *filename, MQStationPlugin::SAVE_DOCUMENT_PARAM& param) {
			CommandPluginDefault().OnSaveDocument(doc, filename, param);
		}
		BOOL StationPluginsInterfacedBase::OnUndo(MQDocument doc, int undo_state) {
			return CommandPluginDefault().OnUndo(doc, undo_state);
		}
		BOOL StationPluginsInterfacedBase::OnRedo(MQDocument doc, int redo_state) {
			return CommandPluginDefault().OnRedo(doc, redo_state);
		}
		void StationPluginsInterfacedBase::OnUpdateUndo(MQDocument doc, int undo_state, int undo_size) {
			CommandPluginDefault().OnUpdateUndo(doc, undo_state, undo_size);
		}
		void StationPluginsInterfacedBase::OnObjectModified(MQDocument doc) {
			CommandPluginDefault().OnObjectModified(doc);
		}
		void StationPluginsInterfacedBase::OnObjectSelected(MQDocument doc) {
			CommandPluginDefault().OnObjectSelected(doc);
		}
		void StationPluginsInterfacedBase::OnUpdateObjectList(MQDocument doc) {
			CommandPluginDefault().OnUpdateObjectList(doc);
		}
		void StationPluginsInterfacedBase::OnMaterialModified(MQDocument doc) {
			CommandPluginDefault().OnMaterialModified(doc);
		}
		void StationPluginsInterfacedBase::OnUpdateMaterialList(MQDocument doc) {
			CommandPluginDefault().OnUpdateMaterialList(doc);
		}
		void StationPluginsInterfacedBase::OnUpdateScene(MQDocument doc, MQScene scene) {
			CommandPluginDefault().OnUpdateScene(doc, scene);
		}
		int StationPluginsInterfacedBase::SendUserMessage(MQDocument doc, DWORD target_product, DWORD target_id, const char *description, void *param) {
			if ( basePlugin == NULL ) return 0;
			return basePlugin->SendUserMessage(doc,target_product,target_id,description,param);
		}
		void StationPluginsInterfacedBase::WindowClose() {
			MQStationPlugin* plugin = dynamic_cast<MQStationPlugin*>(basePlugin);
			if ( plugin != NULL ) plugin->WindowClose();
			else ::MessageBox(0,0,0,0);
		}
		void StationPluginsInterfacedBase::BeginCallback(void* option) {
			MQStationPlugin* plugin = dynamic_cast<MQStationPlugin*>(basePlugin);
			if ( plugin != NULL ) plugin->BeginCallback(option);
		}
		void StationPluginsInterfacedBase::GetPlugInID(DWORD *Product, DWORD *ID) {
			MQBasePlugin* plugin = basePlugin;
			if ( plugin != NULL ) return plugin->GetPlugInID(Product,ID);
		}
		DWORD StationPluginsInterfacedBase::ProductID::get() {
			DWORD ProductID = -1, PluginID = -1;
			GetPlugInID(&ProductID, &PluginID);
			return ProductID;
		}
		DWORD StationPluginsInterfacedBase::PluginID::get() {
			DWORD ProductID = -1, PluginID = -1;
			GetPlugInID(&ProductID, &PluginID);
			return PluginID;
		}
		const char* StationPluginsInterfacedBase::GetPlugInName() {
			MQBasePlugin* plugin = basePlugin;
			if ( plugin != NULL ) return plugin->GetPlugInName();
			return NULL;
		}
		int StationPluginsInterfacedBase::GetPlugInType() {
			MQBasePlugin* plugin = basePlugin;
			if ( plugin != NULL ) return plugin->GetPlugInType();
			return 0;
		}
		const char* StationPluginsInterfacedBase::EnumString() {
			MQStationPlugin* plugin = dynamic_cast<MQStationPlugin*>(basePlugin);
			if ( plugin != NULL ) plugin->EnumString();
			return NULL;
		}

		BOOL CommandPluginsInterfacedBase::OnLeftButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnLeftButtonDown(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnLeftButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnLeftButtonMove(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnLeftButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnLeftButtonUp(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnMiddleButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnMiddleButtonDown(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnMiddleButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnMiddleButtonMove(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnMiddleButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnMiddleButtonUp(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnRightButtonDown(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnRightButtonDown(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnRightButtonMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnRightButtonMove(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnRightButtonUp(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnRightButtonUp(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnMouseMove(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnMouseMove(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnMouseWheel(MQDocument doc, MQScene scene, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnMouseWheel(doc, scene, state);
		}
		BOOL CommandPluginsInterfacedBase::OnKeyDown(MQDocument doc, MQScene scene, int key, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnKeyDown(doc, scene, key, state);
		}
		BOOL CommandPluginsInterfacedBase::OnKeyUp(MQDocument doc, MQScene scene, int key, MQCommandPlugin::MOUSE_BUTTON_STATE& state) {
			return CommandPluginDefault().OnKeyUp(doc, scene, key, state);
		}
	}
	
/*! @brief MQCLIライブラリの初期化
@return Initializeは有効なインスタンスが設定された一回目だけ成功しtrueを返します。nullptrや二度目のInitializeは失敗してfalseを返します。
@details MQCLI::StationPluginを継承したクラスは一度だけそのプラグインクラスの継承インスタンスを確保し、以下のサンプルのように MQCLI::Initialize() に渡してください。
@code
#include "MQx/MQCLI.hpp"

public ref class CustomPlugin : MQCLI::StationPlugin {
public:
	CustomPlugin() : StationPlugin( "tiritomato", "Sample Copyright(C) 2013, tiritomato.", "SampleButton" ) {}
	virtual BOOL Activate(MQDocument doc, BOOL flag) override {
		if ( flag == TRUE ) ::MessageBox( MQ_GetWindowHandle(), "Activate!", NULL, 0 );
		return flag;
	}
};

static bool initialResult = MQCLI::Initialize( gcnew CustomPlugin() );
@endcode
このサンプルではコマンドプラグインのActivate()メソッドをオーバーライドして、コマンドボタンを選択した時にメッセージボックスを表示します。
@ref MQCLIの使い方 "プロジェクト設定"
に問題なければ、この数行のコンパイルは成功し、そのままプラグインDLLのインストールとテストが実行できるはずです。
*/
	bool Initialize( MQCLI::StationPlugin^ pluginBody ) { return Plugins::PluginMainHolder::Regist( pluginBody ); }
	
/*! @brief MQCLIライブラリの初期化
@return Initializeは有効なインスタンスが設定された一回目だけ成功しtrueを返します。nullptrや二度目のInitializeは失敗してfalseを返します。
@details MQCLI::CommandPluginを継承したクラスは一度だけそのプラグインクラスの継承インスタンスを確保し、以下のサンプルのように MQCLI::Initialize() に渡してください。
@code
#include "MQx/MQCLI.hpp"

public ref class CustomPlugin : MQCLI::CommandPlugin {
public:
	CustomPlugin() : CommandPlugin( "tiritomato", "Sample Copyright(C) 2013, tiritomato.", "SampleButton" ) {}
	virtual BOOL Activate(MQDocument doc, BOOL flag) override {
		if ( flag == TRUE ) ::MessageBox( MQ_GetWindowHandle(), "Activate!", NULL, 0 );
		return flag;
	}
};

static bool initialResult = MQCLI::Initialize( gcnew CustomPlugin() );
@endcode
このサンプルではコマンドプラグインのActivate()メソッドをオーバーライドして、コマンドボタンを選択した時にメッセージボックスを表示します。
@ref MQCLIの使い方 "プロジェクト設定"
に問題なければ、この数行のコンパイルは成功し、そのままプラグインDLLのインストールとテストが実行できるはずです。
*/
	bool Initialize( MQCLI::CommandPlugin^ pluginBody ) { return Plugins::PluginMainHolder::Regist( pluginBody ); }
}

/*!
	@brief DLLエントリーポイント
	@attention
		アンマネージド／マネージド混合アプリにおいてDLLMain中にマネージドコードを実行するとロックする危険があるため、DllMainでは何もしないで下さい。
		代わりに、グローバル変数の初期化ロジックで対応する事を検討してください。
*/
#pragma unmanaged
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    return TRUE;
}

#pragma managed
MQBasePlugin *GetPluginClass() {
	return MQCLI::Plugins::PluginMainHolder::pluginMain;
}

#endif