
#include <GL/gl.h>
#include "vec4.h"
#include "halfedge.h"
#include "subdobj.h"
#include "painters_line.h"
#include "painters_poly.h"
#include "painters_obj_list.h"


SubdObj& SubdObj::DrawFace(HalfEdge *first) {

	if (!first->_link)
		return *this;

	HalfEdge *he = first->_link->_other_half;

	int donormals = first->_v->_has_normal;

	glBegin(GL_POLYGON);

		if (!donormals) {
			Vec4 nml = CalcFaceNormal(first);
			glNormal3f(-nml.x(), -nml.y(), -nml.z());
		}
		else {
			Vec4 nml(first->_v->GetNormal(), first->_v->Point());
			glNormal3f(-nml.x(), -nml.y(), -nml.z());
		}

		glVertex3f(first->_v->Point().x(),
				   first->_v->Point().y(),
				   first->_v->Point().z());
		first->_flag = 1;

		while (he && (he != first)) {

			if (donormals) {
				Vec4 nml(he->_v->GetNormal(), he->_v->Point());
				glNormal3f(-nml.x(), -nml.y(), -nml.z());
			}
			glVertex3f(he->_v->Point().x(),
					   he->_v->Point().y(),
					   he->_v->Point().z());
			he->_flag = 1;
			he = he->_link->_other_half;
		}

	glEnd();

	return *this;
}

SubdObj& SubdObj::Draw() {

	ClearHalfEdgeFlags();

	if (_half_edge_list)
		for (HalfEdge *he = _half_edge_list; he; he = he->_next)
			if (!he->_flag)
				DrawFace(he);

	return *this;
}

SubdObj& SubdObj::DrawPainters() {

	int i;
	PaintersObjList POL_Lines;
	PaintersObjList POL_Polys;


	Matrix M1, M2;
	glGetFloatv(GL_MODELVIEW_MATRIX, (float*) M1);
	glGetFloatv(GL_PROJECTION_MATRIX, (float*) M2);

	JLmatrix JLM1(M1);
	JLmatrix JLM2(M2);

	JLmatrix VT = JLM1 * JLM2;


	ClearHalfEdgeFlags();

	if (_half_edge_list)
		for (HalfEdge *he = _half_edge_list; he; he = he->_next)
			if (he->_link && !he->_flag)
				POL_Polys.PlaceInList(new PaintersPoly(VT, he));


	ClearHalfEdgeFlags();

	if (_half_edge_list)
		for (HalfEdge *he = _half_edge_list; he; he = he->_next)
			if (!he->_flag)
				POL_Lines.PlaceInList(new PaintersLine(VT, he));


	POL_Polys.SortByDepth();


	glLineWidth(1.5);

	for (i=0; i<POL_Lines.Size(); i++)
		POL_Lines[i].Draw();

	glLineWidth(1);


	glEnable(GL_BLEND);
	glEnable(GL_LINE_SMOOTH);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	for (i=0; i<POL_Polys.Size(); i++)
		POL_Polys[i].Draw();

	glDisable(GL_LINE_SMOOTH);
	glDisable(GL_BLEND);


	return *this;
}

SubdObj& SubdObj::DrawNormals(float length) {

	Vec4 v2;

	ClearVertexFlags();

	if (_half_edge_list)
		for (HalfEdge *he = _half_edge_list; he; he = he->_next)
			if (!he->_v->_flag && he->_v->_has_normal) {
				he->_v->_flag = 1;

				glBegin(GL_LINES);
				glVertex3f(he->_v->Point().x(),
						   he->_v->Point().y(),
						   he->_v->Point().z());
				Vec4FastAddScale(v2, he->_v->Point(),
									 he->_v->GetNormal(), length);
				glVertex3f(v2.x(), v2.y(), v2.z());
				glEnd();
			}

	return *this;
}
