/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
#include "stdafx.h"
#include "mgGL/OpenGLView.h"
#include "EvalCmd/EvalEdgeGraphic.h"
#include "topo/Loop.h"
#include "topo/Edge.h"
#include "topo/Shell.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

MGEvalEdgeGraphic::MGEvalEdgeGraphic(int fid, MGObject* surf, COLORREF colEdge)
	 : mgSysGL(fid, surf),
	   m_colEdge(colEdge)
{
}

MGEvalEdgeGraphic* MGEvalEdgeGraphic::clone() const
{
	return new MGEvalEdgeGraphic(*this);
}

namespace
{
	// Note: 描画効率に関して最適化していない。
	void DrawSurfBounds(MGEvalEdgeGraphic& vbo,const MGSurface& surf, MGOpenGLView& glv)
	{
		// まず面の縁を描画する。
		vbo.LineWidth(2.);
		surf.drawWireFS_to_highlight(vbo, 0);

		// 次に辺端点を描画する。
		// 同じ点を二度描画するゆえ、効率が悪い。
		int nperi = surf.perimeter_num();
		for(int i = 0; i < nperi; ++i){
			std::unique_ptr<MGCurve> spCurve(surf.perimeter_curve(i));
			vbo.drawPoint(spCurve->start_point());
			vbo.drawPoint(spCurve->end_point());
		}
	}

	// Note: 描画効率に関して最適化していない。
	void DrawFaceBounds(MGEvalEdgeGraphic& vbo,const MGFace& f, MGOpenGLView& glv)
	{
		vbo.LineWidth(2.);
		f.drawWireFS_to_highlight(vbo, 0);

		// 頂点を描画するために全エッジを iterate する。
		std::vector<const MGLoop*> loops;
		f.extract_loops(loops);
		const size_t nloop = loops.size();
		for(size_t i = 0; i < nloop; ++i){
			const MGLoop* loopi = loops[i];
			const size_t nedge = loopi->number_of_edges();
			for(size_t j = 0; j < nedge; ++j){

				// エッジ形状
				const MGEdge* edgej = loopi->edge((int)j);
				
				// エッジに付いている頂点
				if(edgej->active_start()){
					vbo.drawPoint(f.eval(edgej->start_point()));
				}
				if(edgej->active_end()){
					vbo.drawPoint(f.eval(edgej->end_point()));
				}
			}
		}
	}

	// ただ Face をループで回しているだけ。論外。
	void DrawShellBounds(MGEvalEdgeGraphic& vbo,const MGShell& shell, MGOpenGLView& glv)
	{
		const size_t nface = shell.number_of_faces();
		for(size_t i = 0; i < nface; ++i){
			DrawFaceBounds(vbo,*shell.face((int)i), glv);
		}
	}
}

void MGEvalEdgeGraphic::drawSysGL(){
	auto obj = dynamic_cast<const MGObject*>(object_id());
	if(!obj)
		return;

	// エッジと頂点を描画する。単純な線画となる。
	//::glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT);

	// ダイアログから持ってきたであろう色をセット。
	setStaticAttribColor(FromCOLORREF(m_colEdge));

	MGOpenGLView& glv=*(MGOpenGLView::getCurrentOpenGLView());
	auto surf = dynamic_cast<const MGSurface*>(obj);
	if(surf){
		DrawSurfBounds(*this, *surf, glv);
		return;
	}

	auto f = dynamic_cast<const MGFace*>(obj);
	if(f){
		DrawFaceBounds(*this,*f, glv);
		return;
	}

	auto shell = dynamic_cast<const MGShell*>(obj);
	if(shell){
		DrawShellBounds(*this,*shell, glv);
	}
}
