1/*
2 * Copyright 2008 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Alexandre Deckner
7 *
8 */
9
10/*
11 * Original Be Sample source modified to use a quaternion for the object's orientation
12 */
13
14/*
15	Copyright 1999, Be Incorporated.   All Rights Reserved.
16	This file may be used under the terms of the Be Sample Code License.
17*/
18
19
20#include "GLObject.h"
21
22#include <Application.h>
23#include <GL/gl.h>
24#include <InterfaceKit.h>
25#include <Resources.h>
26
27#include "glob.h"
28
29
30struct material {
31	float ambient[3], diffuse[3], specular[3];
32};
33
34float *colors[] = {NULL, white, yellow, blue, red, green};
35
36material materials[] = {
37	// Null
38	{
39		{0.1745, 0.03175, 0.03175},
40		{0.61424, 0.10136, 0.10136},
41		{0.727811, 0.626959, 0.626959}
42	},
43	// White
44	{
45		{0.1745, 0.1745, 0.1745},
46		{0.61424, 0.61424, 0.61424},
47		{0.727811, 0.727811, 0.727811}
48	},
49	// Yellow
50	{
51		{0.1745, 0.1745, 0.03175},
52		{0.61424, 0.61424, 0.10136},
53		{0.727811, 0.727811, 0.626959}
54	},
55	// Blue
56	{
57		{0.03175, 0.03175, 0.1745},
58		{0.10136, 0.10136, 0.61424},
59		{0.626959, 0.626959, 0.727811}
60	},
61	// Red
62	{
63		{0.1745, 0.03175, 0.03175},
64		{0.61424, 0.10136, 0.10136},
65		{0.727811, 0.626959, 0.626959}
66	},
67	// Green
68	{
69		{0.03175, 0.1745, 0.03175},
70		{0.10136, 0.61424, 0.10136},
71		{0.626959, 0.727811, 0.626959}
72	},
73};
74
75#define USE_QUAD_STRIPS 1
76
77extern long setEvent(sem_id event);
78
79
80GLObject::GLObject(ObjectView* ov)
81	:
82	x(0),
83	y(0),
84	z(-2.0),
85	fRotation(0.0f, 0.0f, 0.0f, 1.0f),
86	spinX(2),
87	spinY(2),
88	solidity(0),
89	color(4),
90	changed(false),
91	fObjView(ov)
92{
93}
94
95
96GLObject::~GLObject()
97{
98}
99
100
101void
102GLObject::MenuInvoked(BPoint point)
103{
104	BPopUpMenu* m = new BPopUpMenu("Object",false,false);
105	BMenuItem* i;
106
107	int c = 1;
108	m->AddItem(i = new BMenuItem("White",NULL));
109	if (color == c++)
110		i->SetMarked(true);
111	m->AddItem(i = new BMenuItem("Yellow",NULL));
112	if (color == c++)
113		i->SetMarked(true);
114	m->AddItem(i = new BMenuItem("Blue",NULL));
115	if (color == c++)
116		i->SetMarked(true);
117	m->AddItem(i = new BMenuItem("Red",NULL));
118	if (color == c++)
119		i->SetMarked(true);
120	m->AddItem(i = new BMenuItem("Green",NULL));
121	if (color == c++)
122		i->SetMarked(true);
123	m->AddSeparatorItem();
124
125	c = 0;
126	m->AddItem(i = new BMenuItem("Solid",NULL));
127	if (solidity == c++)
128		i->SetMarked(true);
129	m->AddItem(i = new BMenuItem("Translucent",NULL));
130	if (solidity == c++)
131		i->SetMarked(true);
132	m->AddItem(i = new BMenuItem("Transparent",NULL));
133	if (solidity == c++)
134		i->SetMarked(true);
135
136	i = m->Go(point);
137	int32 index = m->IndexOf(i);
138	delete m;
139
140	if (index < 5) {
141		color = index+1;
142	} else if (index > 5) {
143		solidity = index-6;
144	}
145	changed = true;
146	setEvent(fObjView->drawEvent);
147}
148
149
150int
151GLObject::Solidity() const
152{
153	return solidity;
154}
155
156
157
158bool
159GLObject::SpinIt()
160{
161	bool c = changed;
162	c = c || ((spinX != 0.0f) || (spinY != 0.0f));
163
164	if (c)
165		RotateWorldSpace(spinY, spinX);
166
167	return c;
168}
169
170
171void
172GLObject::Spin(float rx, float ry)
173{
174	spinX = rx;
175	spinY = ry;
176}
177
178
179void
180GLObject::RotateWorldSpace(float rx, float ry)
181{
182	fRotation = Quaternion(Vector3(0.0f, 1.0f, 0.0f), 0.01f * rx) * fRotation;
183	fRotation = Quaternion(Vector3(1.0f, 0.0f, 0.0f), 0.01f * ry) * fRotation;
184	changed = true;
185}
186
187
188void
189GLObject::Draw(bool forID, float IDcolor[])
190{
191	glPushMatrix();
192		glTranslatef(x, y, z);
193
194		float mat[4][4];
195		fRotation.toOpenGLMatrix(mat);
196		glMultMatrixf((GLfloat*)mat);
197
198		if (forID) {
199			glColor3fv(IDcolor);
200		}
201
202		DoDrawing(forID);
203
204	glPopMatrix();
205
206	changed = false;
207}
208
209
210TriangleObject::TriangleObject(ObjectView* ov)
211		:
212		GLObject(ov),
213		fStatus(B_NO_INIT),
214		fPoints(100, 100),
215		fTriangles(100, 100),
216		fQs(50, 50)
217{
218	BResources *res = BApplication::AppResources();
219	if (res == NULL)
220		return;
221
222	size_t size = 0;
223	int32 *arrayOfPoints
224					= (int32*)res->LoadResource(B_RAW_TYPE, "points", &size);
225	if (arrayOfPoints == NULL)
226		return;
227
228	float maxp = 0;
229	size_t numPt = size / sizeof(int32);
230	for (size_t i = 0; i < numPt; i += 6) {
231		point p;
232		p.x = 1e-6 * arrayOfPoints[i];
233		p.y = 1e-6 * arrayOfPoints[i + 1];
234		p.z = 1e-6 * arrayOfPoints[i + 2];
235		p.nx = 1e-6 * arrayOfPoints[i + 3];
236		p.ny = 1e-6 * arrayOfPoints[i + 4];
237		p.nz = 1e-6 * arrayOfPoints[i + 5];
238
239		if (fabs(p.x) > maxp)
240			maxp = fabs(p.x);
241		if (fabs(p.y) > maxp)
242			maxp = fabs(p.y);
243		if (fabs(p.z) > maxp)
244			maxp = fabs(p.z);
245
246		fPoints.add(p);
247	}
248
249	for (int i = 0; i < fPoints.num_items; i++) {
250		fPoints[i].x /= maxp;
251		fPoints[i].y /= maxp;
252		fPoints[i].z /= maxp;
253	}
254
255	int32 *arrayOfTriangles
256					= (int32*)res->LoadResource(B_RAW_TYPE, "triangles", &size);
257	if (arrayOfTriangles == NULL)
258		return;
259
260	size_t numTriPoints = size / sizeof(int32);
261	for (size_t i = 0; i < numTriPoints; i += 3) {
262		tri t;
263		t.p1 = arrayOfTriangles[i];
264		t.p2 = arrayOfTriangles[i + 1];
265		t.p3 = arrayOfTriangles[i + 2];
266		fTriangles.add(t);
267	}
268
269	size_t numTri = numTriPoints / 3;
270
271	int qpts = 4;
272	int qp[1024];
273	quadStrip q;
274	q.pts = qp;
275	q.numpts = 4;
276	q.pts[2] = fTriangles[0].p1;
277	q.pts[0] = fTriangles[0].p2;
278	q.pts[1] = fTriangles[0].p3;
279	q.pts[3] = fTriangles[1].p3;
280
281	for (size_t i = 2; i < numTri; i += 2) {
282		if ((fTriangles[i - 1].p1 == fTriangles[i].p2) &&
283			(fTriangles[i - 1].p3 == fTriangles[i].p3)) {
284			q.pts[q.numpts++] = fTriangles[i + 1].p1;
285			q.pts[q.numpts++] = fTriangles[i + 1].p3;
286			qpts+=2;
287		} else {
288			int *np = (int*)malloc(sizeof(int)*q.numpts);
289			memcpy(np, qp, q.numpts * sizeof(int));
290			quadStrip nqs;
291			nqs.numpts = q.numpts;
292			nqs.pts = np;
293			fQs.add(nqs);
294
295			qpts += 4;
296			q.numpts = 4;
297			q.pts[2] = fTriangles[i].p1;
298			q.pts[0] = fTriangles[i].p2;
299			q.pts[1] = fTriangles[i].p3;
300			q.pts[3] = fTriangles[i + 1].p3;
301		}
302	}
303
304	int* np = (int*)malloc(sizeof(int)*q.numpts);
305	memcpy(np, qp, q.numpts * sizeof(int));
306	quadStrip nqs;
307	nqs.numpts = q.numpts;
308	nqs.pts = np;
309	fQs.add(nqs);
310
311	fStatus = B_OK;
312}
313
314
315TriangleObject::~TriangleObject()
316{
317	for (int i = 0; i < fQs.num_items; i++) {
318		free(fQs[i].pts);
319	}
320}
321
322
323status_t
324TriangleObject::InitCheck() const
325{
326	return fStatus;
327}
328
329
330void
331TriangleObject::DoDrawing(bool forID)
332{
333	if (!forID) {
334		float c[3][4];
335		c[0][0] = materials[color].ambient[0];
336		c[0][1] = materials[color].ambient[1];
337		c[0][2] = materials[color].ambient[2];
338		c[1][0] = materials[color].diffuse[0];
339		c[1][1] = materials[color].diffuse[1];
340		c[1][2] = materials[color].diffuse[2];
341		c[2][0] = materials[color].specular[0];
342		c[2][1] = materials[color].specular[1];
343		c[2][2] = materials[color].specular[2];
344
345		float alpha = 1;
346		if (solidity == 0)
347			alpha = 1.0;
348		else if (solidity == 1)
349			alpha = 0.95;
350		else if (solidity == 2)
351			alpha = 0.6;
352		c[0][3] = c[1][3] = c[2][3] = alpha;
353		if (solidity != 0) {
354			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
355			glEnable(GL_BLEND);
356			glDepthMask(GL_FALSE);
357			glDisable(GL_CULL_FACE);
358		} else {
359			glDisable(GL_BLEND);
360			glDepthMask(GL_TRUE);
361		}
362		glMaterialfv(GL_FRONT, GL_AMBIENT, c[0]);
363		glMaterialfv(GL_FRONT, GL_DIFFUSE, c[1]);
364		glMaterialfv(GL_FRONT, GL_SPECULAR, c[2]);
365	} else {
366		glDisable(GL_BLEND);
367		glDepthMask(GL_TRUE);
368	}
369
370#if USE_QUAD_STRIPS
371		for (int i = 0; i < fQs.num_items; i++) {
372 			glBegin(GL_QUAD_STRIP);
373			for (int j = 0; j < fQs[i].numpts; j++) {
374 				glNormal3f(
375					fPoints[fQs[i].pts[j]].nx,
376					fPoints[fQs[i].pts[j]].ny,
377					fPoints[fQs[i].pts[j]].nz
378				);
379 				glVertex3f(
380					fPoints[fQs[i].pts[j]].x,
381					fPoints[fQs[i].pts[j]].y,
382					fPoints[fQs[i].pts[j]].z
383				);
384			}
385			glEnd();
386		}
387#else
388 		glBegin(GL_TRIANGLES);
389		for (int i = 0; i < fTriangles.num_items; i++) {
390			int v3 = fTriangles[i].p1;
391			int v1 = fTriangles[i].p2;
392			int v2 = fTriangles[i].p3;
393 	  		glNormal3f(
394				fPoints[v1].nx,
395				fPoints[v1].ny,
396				fPoints[v1].nz
397			);
398 			glVertex3f(
399				fPoints[v1].x,
400				fPoints[v1].y,
401				fPoints[v1].z
402			);
403 			glNormal3f(
404				fPoints[v2].nx,
405				fPoints[v2].ny,
406				fPoints[v2].nz
407			);
408 			glVertex3f(
409				fPoints[v2].x,
410				fPoints[v2].y,
411				fPoints[v2].z
412			);
413 			glNormal3f(
414				fPoints[v3].nx,
415				fPoints[v3].ny,
416				fPoints[v3].nz
417			);
418			glVertex3f(
419				fPoints[v3].x,
420				fPoints[v3].y,
421				fPoints[v3].z
422			);
423		}
424		glEnd();
425 #endif
426}
427
428