⛏️ index : haiku.git

/*
 * Copyright 2008 Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Alexandre Deckner
 *
 */

/*
 * Original Be Sample source modified to use a quaternion for the object's orientation
 */

/*
	Copyright 1999, Be Incorporated.   All Rights Reserved.
	This file may be used under the terms of the Be Sample Code License.
*/


#include "GLObject.h"

#include <Application.h>
#include <GL/gl.h>
#include <InterfaceKit.h>
#include <Resources.h>

#include "glob.h"


struct material {
	float ambient[3], diffuse[3], specular[3];
};

float *colors[] = {NULL, white, yellow, blue, red, green};

material materials[] = {
	// Null
	{
		{0.1745, 0.03175, 0.03175},
		{0.61424, 0.10136, 0.10136},
		{0.727811, 0.626959, 0.626959}
	},
	// White
	{
		{0.1745, 0.1745, 0.1745},
		{0.61424, 0.61424, 0.61424},
		{0.727811, 0.727811, 0.727811}
	},
	// Yellow
	{
		{0.1745, 0.1745, 0.03175},
		{0.61424, 0.61424, 0.10136},
		{0.727811, 0.727811, 0.626959}
	},
	// Blue
	{
		{0.03175, 0.03175, 0.1745},
		{0.10136, 0.10136, 0.61424},
		{0.626959, 0.626959, 0.727811}
	},
	// Red
	{
		{0.1745, 0.03175, 0.03175},
		{0.61424, 0.10136, 0.10136},
		{0.727811, 0.626959, 0.626959}
	},
	// Green
	{
		{0.03175, 0.1745, 0.03175},
		{0.10136, 0.61424, 0.10136},
		{0.626959, 0.727811, 0.626959}
	},
};

#define USE_QUAD_STRIPS 1

extern long setEvent(sem_id event);


GLObject::GLObject(ObjectView* ov)
	:
	x(0),
	y(0),
	z(-2.0),
	fRotation(0.0f, 0.0f, 0.0f, 1.0f),
	spinX(2),
	spinY(2),
	solidity(0),
	color(4),
	changed(false),
	fObjView(ov)
{
}


GLObject::~GLObject()
{
}


void
GLObject::MenuInvoked(BPoint point)
{
	BPopUpMenu* m = new BPopUpMenu("Object",false,false);
	BMenuItem* i;

	int c = 1;
	m->AddItem(i = new BMenuItem("White",NULL));
	if (color == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Yellow",NULL));
	if (color == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Blue",NULL));
	if (color == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Red",NULL));
	if (color == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Green",NULL));
	if (color == c++)
		i->SetMarked(true);
	m->AddSeparatorItem();

	c = 0;
	m->AddItem(i = new BMenuItem("Solid",NULL));
	if (solidity == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Translucent",NULL));
	if (solidity == c++)
		i->SetMarked(true);
	m->AddItem(i = new BMenuItem("Transparent",NULL));
	if (solidity == c++)
		i->SetMarked(true);

	i = m->Go(point);
	int32 index = m->IndexOf(i);
	delete m;

	if (index < 5) {
		color = index+1;
	} else if (index > 5) {
		solidity = index-6;
	}
	changed = true;
	setEvent(fObjView->drawEvent);
}


int
GLObject::Solidity() const
{
	return solidity;
}



bool
GLObject::SpinIt()
{
	bool c = changed;
	c = c || ((spinX != 0.0f) || (spinY != 0.0f));

	if (c)
		RotateWorldSpace(spinY, spinX);

	return c;
}


void
GLObject::Spin(float rx, float ry)
{
	spinX = rx;
	spinY = ry;
}


void
GLObject::RotateWorldSpace(float rx, float ry)
{
	fRotation = Quaternion(Vector3(0.0f, 1.0f, 0.0f), 0.01f * rx) * fRotation;
	fRotation = Quaternion(Vector3(1.0f, 0.0f, 0.0f), 0.01f * ry) * fRotation;
	fRotation.normalize();
	changed = true;
}


void
GLObject::Draw(bool forID, float IDcolor[])
{
	glPushMatrix();
		glTranslatef(x, y, z);

		float mat[4][4];
		fRotation.toOpenGLMatrix(mat);
		glMultMatrixf((GLfloat*)mat);

		if (forID) {
			glColor3fv(IDcolor);
		}

		DoDrawing(forID);

	glPopMatrix();

	changed = false;
}


TriangleObject::TriangleObject(ObjectView* ov)
		:
		GLObject(ov),
		fStatus(B_NO_INIT),
		fPoints(100, 100),
		fTriangles(100, 100),
		fQs(50, 50)
{
	BResources *res = BApplication::AppResources();
	if (res == NULL)
		return;

	size_t size = 0;
	int32 *arrayOfPoints
					= (int32*)res->LoadResource(B_RAW_TYPE, "points", &size);
	if (arrayOfPoints == NULL)
		return;

	float maxp = 0;
	size_t numPt = size / sizeof(int32);
	for (size_t i = 0; i < numPt; i += 6) {
		point p;
		p.x = 1e-6 * arrayOfPoints[i];
		p.y = 1e-6 * arrayOfPoints[i + 1];
		p.z = 1e-6 * arrayOfPoints[i + 2];
		p.nx = 1e-6 * arrayOfPoints[i + 3];
		p.ny = 1e-6 * arrayOfPoints[i + 4];
		p.nz = 1e-6 * arrayOfPoints[i + 5];

		if (fabs(p.x) > maxp)
			maxp = fabs(p.x);
		if (fabs(p.y) > maxp)
			maxp = fabs(p.y);
		if (fabs(p.z) > maxp)
			maxp = fabs(p.z);

		fPoints.add(p);
	}

	for (int i = 0; i < fPoints.num_items; i++) {
		fPoints[i].x /= maxp;
		fPoints[i].y /= maxp;
		fPoints[i].z /= maxp;
	}

	int32 *arrayOfTriangles
					= (int32*)res->LoadResource(B_RAW_TYPE, "triangles", &size);
	if (arrayOfTriangles == NULL)
		return;

	size_t numTriPoints = size / sizeof(int32);
	for (size_t i = 0; i < numTriPoints; i += 3) {
		tri t;
		t.p1 = arrayOfTriangles[i];
		t.p2 = arrayOfTriangles[i + 1];
		t.p3 = arrayOfTriangles[i + 2];
		fTriangles.add(t);
	}

	size_t numTri = numTriPoints / 3;

	int qpts = 4;
	int qp[1024];
	quadStrip q;
	q.pts = qp;
	q.numpts = 4;
	q.pts[2] = fTriangles[0].p1;
	q.pts[0] = fTriangles[0].p2;
	q.pts[1] = fTriangles[0].p3;
	q.pts[3] = fTriangles[1].p3;

	for (size_t i = 2; i < numTri; i += 2) {
		if ((fTriangles[i - 1].p1 == fTriangles[i].p2) &&
			(fTriangles[i - 1].p3 == fTriangles[i].p3)) {
			q.pts[q.numpts++] = fTriangles[i + 1].p1;
			q.pts[q.numpts++] = fTriangles[i + 1].p3;
			qpts+=2;
		} else {
			int *np = (int*)malloc(sizeof(int)*q.numpts);
			memcpy(np, qp, q.numpts * sizeof(int));
			quadStrip nqs;
			nqs.numpts = q.numpts;
			nqs.pts = np;
			fQs.add(nqs);

			qpts += 4;
			q.numpts = 4;
			q.pts[2] = fTriangles[i].p1;
			q.pts[0] = fTriangles[i].p2;
			q.pts[1] = fTriangles[i].p3;
			q.pts[3] = fTriangles[i + 1].p3;
		}
	}

	int* np = (int*)malloc(sizeof(int)*q.numpts);
	memcpy(np, qp, q.numpts * sizeof(int));
	quadStrip nqs;
	nqs.numpts = q.numpts;
	nqs.pts = np;
	fQs.add(nqs);

	fStatus = B_OK;
}


TriangleObject::~TriangleObject()
{
	for (int i = 0; i < fQs.num_items; i++) {
		free(fQs[i].pts);
	}
}


status_t
TriangleObject::InitCheck() const
{
	return fStatus;
}


void
TriangleObject::DoDrawing(bool forID)
{
	if (!forID) {
		float c[3][4];
		c[0][0] = materials[color].ambient[0];
		c[0][1] = materials[color].ambient[1];
		c[0][2] = materials[color].ambient[2];
		c[1][0] = materials[color].diffuse[0];
		c[1][1] = materials[color].diffuse[1];
		c[1][2] = materials[color].diffuse[2];
		c[2][0] = materials[color].specular[0];
		c[2][1] = materials[color].specular[1];
		c[2][2] = materials[color].specular[2];

		float alpha = 1;
		if (solidity == 0)
			alpha = 1.0;
		else if (solidity == 1)
			alpha = 0.95;
		else if (solidity == 2)
			alpha = 0.6;
		c[0][3] = c[1][3] = c[2][3] = alpha;
		if (solidity != 0) {
			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
			glEnable(GL_BLEND);
			glDepthMask(GL_FALSE);
			glDisable(GL_CULL_FACE);
		} else {
			glDisable(GL_BLEND);
			glDepthMask(GL_TRUE);
		}
		glMaterialfv(GL_FRONT, GL_AMBIENT, c[0]);
		glMaterialfv(GL_FRONT, GL_DIFFUSE, c[1]);
		glMaterialfv(GL_FRONT, GL_SPECULAR, c[2]);
	} else {
		glDisable(GL_BLEND);
		glDepthMask(GL_TRUE);
	}

#if USE_QUAD_STRIPS
		for (int i = 0; i < fQs.num_items; i++) {
 			glBegin(GL_QUAD_STRIP);
			for (int j = 0; j < fQs[i].numpts; j++) {
 				glNormal3f(
					fPoints[fQs[i].pts[j]].nx,
					fPoints[fQs[i].pts[j]].ny,
					fPoints[fQs[i].pts[j]].nz
				);
 				glVertex3f(
					fPoints[fQs[i].pts[j]].x,
					fPoints[fQs[i].pts[j]].y,
					fPoints[fQs[i].pts[j]].z
				);
			}
			glEnd();
		}
#else
 		glBegin(GL_TRIANGLES);
		for (int i = 0; i < fTriangles.num_items; i++) {
			int v3 = fTriangles[i].p1;
			int v1 = fTriangles[i].p2;
			int v2 = fTriangles[i].p3;
 	  		glNormal3f(
				fPoints[v1].nx,
				fPoints[v1].ny,
				fPoints[v1].nz
			);
 			glVertex3f(
				fPoints[v1].x,
				fPoints[v1].y,
				fPoints[v1].z
			);
 			glNormal3f(
				fPoints[v2].nx,
				fPoints[v2].ny,
				fPoints[v2].nz
			);
 			glVertex3f(
				fPoints[v2].x,
				fPoints[v2].y,
				fPoints[v2].z
			);
 			glNormal3f(
				fPoints[v3].nx,
				fPoints[v3].ny,
				fPoints[v3].nz
			);
			glVertex3f(
				fPoints[v3].x,
				fPoints[v3].y,
				fPoints[v3].z
			);
		}
		glEnd();
 #endif
}