/* * 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 #include #include #include #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 }