/******************************************************************************
* Determines the display color of a single particle.
******************************************************************************/
ColorA ParticleDisplay::particleColor(size_t particleIndex, ParticlePropertyObject* colorProperty, ParticleTypeProperty* typeProperty, ParticlePropertyObject* selectionProperty, ParticlePropertyObject* transparencyProperty)
{
	OVITO_ASSERT(colorProperty == nullptr || colorProperty->type() == ParticleProperty::ColorProperty);
	OVITO_ASSERT(typeProperty == nullptr || typeProperty->type() == ParticleProperty::ParticleTypeProperty);
	OVITO_ASSERT(selectionProperty == nullptr || selectionProperty->type() == ParticleProperty::SelectionProperty);
	OVITO_ASSERT(transparencyProperty == nullptr || transparencyProperty->type() == ParticleProperty::TransparencyProperty);

	// Check if particle is selected.
	if(selectionProperty) {
		OVITO_ASSERT(particleIndex < selectionProperty->size());
		if(selectionProperty->getInt(particleIndex))
			return selectionParticleColor();
	}

	ColorA c = defaultParticleColor();
	if(colorProperty) {
		// Take particle color directly from the color property.
		OVITO_ASSERT(particleIndex < colorProperty->size());
		c = colorProperty->getColor(particleIndex);
	}
	else if(typeProperty) {
		// Return color based on particle types.
		OVITO_ASSERT(particleIndex < typeProperty->size());
		ParticleType* ptype = typeProperty->particleType(typeProperty->getInt(particleIndex));
		if(ptype)
			c = ptype->color();
	}

	// Apply alpha component.
	if(transparencyProperty) {
		OVITO_ASSERT(particleIndex < transparencyProperty->size());
		c.a() = FloatType(1) - transparencyProperty->getFloat(particleIndex);
	}

	return c;
}
/******************************************************************************
* Renders a 2d polyline in the viewport.
******************************************************************************/
void ViewportSceneRenderer::render2DPolyline(const Point2* points, int count, const ColorA& color, bool closed)
{
	OVITO_STATIC_ASSERT(sizeof(points[0]) == 2*sizeof(GLfloat));

	// Load OpenGL shader.
	QOpenGLShaderProgram* shader = loadShaderProgram("line", ":/core/glsl/lines/line.vs", ":/core/glsl/lines/line.fs");
	if(!shader->bind())
		throw Exception(tr("Failed to bind OpenGL shader."));

	bool wasDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
	glDisable(GL_DEPTH_TEST);

	GLint vc[4];
	glGetIntegerv(GL_VIEWPORT, vc);
	QMatrix4x4 tm;
	tm.ortho(vc[0], vc[0] + vc[2], vc[1] + vc[3], vc[1], -1, 1);
	OVITO_CHECK_OPENGL(shader->setUniformValue("modelview_projection_matrix", tm));

	QOpenGLBuffer vertexBuffer;
	if(glformat().majorVersion() >= 3) {
		if(!vertexBuffer.create())
			throw Exception(tr("Failed to create OpenGL vertex buffer."));
		if(!vertexBuffer.bind())
				throw Exception(tr("Failed to bind OpenGL vertex buffer."));
		vertexBuffer.allocate(points, 2 * sizeof(GLfloat) * count);
		OVITO_CHECK_OPENGL(shader->enableAttributeArray("position"));
		OVITO_CHECK_OPENGL(shader->setAttributeBuffer("position", GL_FLOAT, 0, 2));
		vertexBuffer.release();
	}
	else {
		OVITO_CHECK_OPENGL(glEnableClientState(GL_VERTEX_ARRAY));
		OVITO_CHECK_OPENGL(glVertexPointer(2, GL_FLOAT, 0, points));
	}

	if(glformat().majorVersion() >= 3) {
		OVITO_CHECK_OPENGL(shader->disableAttributeArray("color"));
		OVITO_CHECK_OPENGL(shader->setAttributeValue("color", color.r(), color.g(), color.b(), color.a()));
	}
	else {
		OVITO_CHECK_OPENGL(glColor4(color));
	}

	OVITO_CHECK_OPENGL(glDrawArrays(closed ? GL_LINE_LOOP : GL_LINE_STRIP, 0, count));

	if(glformat().majorVersion() >= 3) {
		shader->disableAttributeArray("position");
	}
	else {
		OVITO_CHECK_OPENGL(glDisableClientState(GL_VERTEX_ARRAY));
	}
	shader->release();
	if(wasDepthTestEnabled) glEnable(GL_DEPTH_TEST);
}