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	fRotation.normalize();
185	changed = true;
186}
187
188
189void
190GLObject::Draw(bool forID, float IDcolor[])
191{
192	glPushMatrix();
193		glTranslatef(x, y, z);
194
195		float mat[4][4];
196		fRotation.toOpenGLMatrix(mat);
197		glMultMatrixf((GLfloat*)mat);
198
199		if (forID) {
200			glColor3fv(IDcolor);
201		}
202
203		DoDrawing(forID);
204
205	glPopMatrix();
206
207	changed = false;
208}
209
210
211TriangleObject::TriangleObject(ObjectView* ov)
212		:
213		GLObject(ov),
214		fStatus(B_NO_INIT),
215		fPoints(100, 100),
216		fTriangles(100, 100),
217		fQs(50, 50)
218{
219	BResources *res = BApplication::AppResources();
220	if (res == NULL)
221		return;
222
223	size_t size = 0;
224	int32 *arrayOfPoints
225					= (int32*)res->LoadResource(B_RAW_TYPE, "points", &size);
226	if (arrayOfPoints == NULL)
227		return;
228
229	float maxp = 0;
230	size_t numPt = size / sizeof(int32);
231	for (size_t i = 0; i < numPt; i += 6) {
232		point p;
233		p.x = 1e-6 * arrayOfPoints[i];
234		p.y = 1e-6 * arrayOfPoints[i + 1];
235		p.z = 1e-6 * arrayOfPoints[i + 2];
236		p.nx = 1e-6 * arrayOfPoints[i + 3];
237		p.ny = 1e-6 * arrayOfPoints[i + 4];
238		p.nz = 1e-6 * arrayOfPoints[i + 5];
239
240		if (fabs(p.x) > maxp)
241			maxp = fabs(p.x);
242		if (fabs(p.y) > maxp)
243			maxp = fabs(p.y);
244		if (fabs(p.z) > maxp)
245			maxp = fabs(p.z);
246
247		fPoints.add(p);
248	}
249
250	for (int i = 0; i < fPoints.num_items; i++) {
251		fPoints[i].x /= maxp;
252		fPoints[i].y /= maxp;
253		fPoints[i].z /= maxp;
254	}
255
256	int32 *arrayOfTriangles
257					= (int32*)res->LoadResource(B_RAW_TYPE, "triangles", &size);
258	if (arrayOfTriangles == NULL)
259		return;
260
261	size_t numTriPoints = size / sizeof(int32);
262	for (size_t i = 0; i < numTriPoints; i += 3) {
263		tri t;
264		t.p1 = arrayOfTriangles[i];
265		t.p2 = arrayOfTriangles[i + 1];
266		t.p3 = arrayOfTriangles[i + 2];
267		fTriangles.add(t);
268	}
269
270	size_t numTri = numTriPoints / 3;
271
272	int qpts = 4;
273	int qp[1024];
274	quadStrip q;
275	q.pts = qp;
276	q.numpts = 4;
277	q.pts[2] = fTriangles[0].p1;
278	q.pts[0] = fTriangles[0].p2;
279	q.pts[1] = fTriangles[0].p3;
280	q.pts[3] = fTriangles[1].p3;
281
282	for (size_t i = 2; i < numTri; i += 2) {
283		if ((fTriangles[i - 1].p1 == fTriangles[i].p2) &&
284			(fTriangles[i - 1].p3 == fTriangles[i].p3)) {
285			q.pts[q.numpts++] = fTriangles[i + 1].p1;
286			q.pts[q.numpts++] = fTriangles[i + 1].p3;
287			qpts+=2;
288		} else {
289			int *np = (int*)malloc(sizeof(int)*q.numpts);
290			memcpy(np, qp, q.numpts * sizeof(int));
291			quadStrip nqs;
292			nqs.numpts = q.numpts;
293			nqs.pts = np;
294			fQs.add(nqs);
295
296			qpts += 4;
297			q.numpts = 4;
298			q.pts[2] = fTriangles[i].p1;
299			q.pts[0] = fTriangles[i].p2;
300			q.pts[1] = fTriangles[i].p3;
301			q.pts[3] = fTriangles[i + 1].p3;
302		}
303	}
304
305	int* np = (int*)malloc(sizeof(int)*q.numpts);
306	memcpy(np, qp, q.numpts * sizeof(int));
307	quadStrip nqs;
308	nqs.numpts = q.numpts;
309	nqs.pts = np;
310	fQs.add(nqs);
311
312	fStatus = B_OK;
313}
314
315
316TriangleObject::~TriangleObject()
317{
318	for (int i = 0; i < fQs.num_items; i++) {
319		free(fQs[i].pts);
320	}
321}
322
323
324status_t
325TriangleObject::InitCheck() const
326{
327	return fStatus;
328}
329
330
331void
332TriangleObject::DoDrawing(bool forID)
333{
334	if (!forID) {
335		float c[3][4];
336		c[0][0] = materials[color].ambient[0];
337		c[0][1] = materials[color].ambient[1];
338		c[0][2] = materials[color].ambient[2];
339		c[1][0] = materials[color].diffuse[0];
340		c[1][1] = materials[color].diffuse[1];
341		c[1][2] = materials[color].diffuse[2];
342		c[2][0] = materials[color].specular[0];
343		c[2][1] = materials[color].specular[1];
344		c[2][2] = materials[color].specular[2];
345
346		float alpha = 1;
347		if (solidity == 0)
348			alpha = 1.0;
349		else if (solidity == 1)
350			alpha = 0.95;
351		else if (solidity == 2)
352			alpha = 0.6;
353		c[0][3] = c[1][3] = c[2][3] = alpha;
354		if (solidity != 0) {
355			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
356			glEnable(GL_BLEND);
357			glDepthMask(GL_FALSE);
358			glDisable(GL_CULL_FACE);
359		} else {
360			glDisable(GL_BLEND);
361			glDepthMask(GL_TRUE);
362		}
363		glMaterialfv(GL_FRONT, GL_AMBIENT, c[0]);
364		glMaterialfv(GL_FRONT, GL_DIFFUSE, c[1]);
365		glMaterialfv(GL_FRONT, GL_SPECULAR, c[2]);
366	} else {
367		glDisable(GL_BLEND);
368		glDepthMask(GL_TRUE);
369	}
370
371#if USE_QUAD_STRIPS
372		for (int i = 0; i < fQs.num_items; i++) {
373 			glBegin(GL_QUAD_STRIP);
374			for (int j = 0; j < fQs[i].numpts; j++) {
375 				glNormal3f(
376					fPoints[fQs[i].pts[j]].nx,
377					fPoints[fQs[i].pts[j]].ny,
378					fPoints[fQs[i].pts[j]].nz
379				);
380 				glVertex3f(
381					fPoints[fQs[i].pts[j]].x,
382					fPoints[fQs[i].pts[j]].y,
383					fPoints[fQs[i].pts[j]].z
384				);
385			}
386			glEnd();
387		}
388#else
389 		glBegin(GL_TRIANGLES);
390		for (int i = 0; i < fTriangles.num_items; i++) {
391			int v3 = fTriangles[i].p1;
392			int v1 = fTriangles[i].p2;
393			int v2 = fTriangles[i].p3;
394 	  		glNormal3f(
395				fPoints[v1].nx,
396				fPoints[v1].ny,
397				fPoints[v1].nz
398			);
399 			glVertex3f(
400				fPoints[v1].x,
401				fPoints[v1].y,
402				fPoints[v1].z
403			);
404 			glNormal3f(
405				fPoints[v2].nx,
406				fPoints[v2].ny,
407				fPoints[v2].nz
408			);
409 			glVertex3f(
410				fPoints[v2].x,
411				fPoints[v2].y,
412				fPoints[v2].z
413			);
414 			glNormal3f(
415				fPoints[v3].nx,
416				fPoints[v3].ny,
417				fPoints[v3].nz
418			);
419			glVertex3f(
420				fPoints[v3].x,
421				fPoints[v3].y,
422				fPoints[v3].z
423			);
424		}
425		glEnd();
426 #endif
427}
428
429