// opengl.cpp
//
// Copyright 1998 by David K. McAllister
//
// This file implements the API calls that draw particle groups in OpenGL.

#include "general.h"

#ifdef WIN32
// This is for something in gl.h.
#include <windows.h>
#endif

#include <GL/gl.h>
// XXX #include <iostream.h>

// Emit OpenGL calls to draw the particles. These are drawn with
// whatever primitive type the user specified(GL_POINTS, for
// example). The color and radius are set per primitive, by default.
// For GL_LINES, the other vertex of the line is the velocity vector.
// XXX const_size is ignored.
PARTICLEDLL_API void pDrawGroupp(int primitive, bool const_size, bool const_color)
{
	_ParticleState &_ps = _GetPState();

	// Get a pointer to the particles in gp memory
	ParticleGroup *pg = _ps.pgrp;

	if(pg == NULL)
		return; // ERROR
	
	if(pg->p_count < 1)
		return;
	
	if(primitive == GL_POINTS)
	{
		glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
		glEnableClientState(GL_VERTEX_ARRAY);
		if(!const_color)
		{
			glEnableClientState(GL_COLOR_ARRAY);
			glColorPointer(4, GL_FLOAT, sizeof(Particle), &pg->list[0].color);
		}
		
		glVertexPointer(3, GL_FLOAT, sizeof(Particle), &pg->list[0].pos);
		glDrawArrays((GLenum)primitive, 0, pg->p_count);
		glPopClientAttrib();
		// XXX For E&S
		glDisableClientState(GL_COLOR_ARRAY);
	}
	else
	{
		// Assume GL_LINES
		glBegin((GLenum)primitive);
		
		if(!const_color)
		{
			for(int i = 0; i < pg->p_count; i++)
			{
				Particle &m = pg->list[i];
				
				// Warning: this depends on alpha following color in the Particle struct.
				glColor4fv((GLfloat *)&m.color);
				glVertex3fv((GLfloat *)&m.pos);
				
				// For lines, make a tail with the velocity vector's direction and
				// a length of radius.
				pVector tail = m.pos - m.vel;			
				glVertex3fv((GLfloat *)&tail);
			}
		}
		else
		{
			for(int i = 0; i < pg->p_count; i++)
			{
				Particle &m = pg->list[i];
				glVertex3fv((GLfloat *)&m.pos);
				
				// For lines, make a tail with the velocity vector's direction and
				// a length of radius.
				pVector tail = m.pos - m.vel;			
				glVertex3fv((GLfloat *)&tail);
			}
		}
		glEnd();
	}
}

PARTICLEDLL_API void pDrawGroupl(int dlist, bool const_size, bool const_color, bool const_rotation)
{
	_ParticleState &_ps = _GetPState();

	// Get a pointer to the particles in gp memory
	ParticleGroup *pg = _ps.pgrp;
	if(pg == NULL)
		return; // ERROR
	
	if(pg->p_count < 1)
		return;

	//if(const_color)
	//	glColor4fv((GLfloat *)&pg->list[0].color);

	for(int i = 0; i < pg->p_count; i++)
	{
		Particle &m = pg->list[i];

		glPushMatrix();
		glTranslatef(m.pos.x, m.pos.y, m.pos.z);

		if(!const_size)
			glScalef(m.size.x, m.size.y, m.size.z);
		else
			glScalef(pg->list[i].size.x, pg->list[i].size.y, pg->list[i].size.z);

		// Expensive! A sqrt, cross prod and acos. Yow.
		if(!const_rotation)
		{
			pVector vN(m.vel);
			vN.normalize();
			pVector voN(m.velB);
			voN.normalize();

			pVector biN;
			if(voN.x == vN.x && voN.y == vN.y && voN.z == vN.z)
				biN = pVector(0, 1, 0);
			else
				biN = vN ^ voN;
			biN.normalize();

			pVector N(vN ^ biN);

			double M[16];
			M[0] = vN.x;  M[4] = biN.x;  M[8] = N.x;  M[12] = 0;
			M[1] = vN.y;  M[5] = biN.y;  M[9] = N.y;  M[13] = 0;
			M[2] = vN.z;  M[6] = biN.z;  M[10] = N.z; M[14] = 0;
			M[3] = 0;     M[7] = 0;      M[11] = 0;   M[15] = 1;
			glMultMatrixd(M);
		}

		// Warning: this depends on alpha following color in the Particle struct.
		if(!const_color)
			glColor4fv((GLfloat *)&m.color);

		glCallList(dlist);

		glPopMatrix();
	}
}