/* PROJECT: 3Dmov AUTHORS: Zenja Solaja COPYRIGHT: 2009 Haiku Inc DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov Just drag'n'drop media files to the 3D objects */ #include #include #include #include #include #include "GLUtility.h" #include "ViewCube.h" // Local definitions // Local functions // Local variables /******************************** Cube scene *********************************/ class Cube { public: enum FACE { FACE_RIGHT, FACE_LEFT, FACE_FRONT, FACE_BACK, FACE_TOP, FACE_BOTTOM, NUMBER_CUBE_FACES, }; Cube(const float half_extent); ~Cube(); void Render(); void SetMediaSource(FACE face, MediaSource *source) {fMediaSources[face] = source;} void SetAngle(float angle_x, float angle_y, float angle_z); private: MediaSource *fMediaSources[NUMBER_CUBE_FACES]; float fRotationX, fRotationY, fRotationZ; float *fGeometry; }; /* FUNCTION: Cube :: Cube ARGUMENTS: half_extent RETURN: n/a DESCRIPTION: Constructor */ Cube :: Cube(const float half_extent) { for (int i=0; i < NUMBER_CUBE_FACES; i++) fMediaSources[i] = 0; fRotationX = fRotationY = fRotationZ = 0; const float kVertices[NUMBER_CUBE_FACES][4][3] = { { // FACE_RIGHT {half_extent, -half_extent, -half_extent}, {half_extent, half_extent, -half_extent}, {half_extent, -half_extent, half_extent}, {half_extent, half_extent, half_extent}, }, { // FACE_LEFT {-half_extent, half_extent, -half_extent}, {-half_extent, -half_extent, -half_extent}, {-half_extent, half_extent, half_extent}, {-half_extent, -half_extent, half_extent}, }, { // FACE_FRONT {-half_extent, -half_extent, -half_extent}, {half_extent, -half_extent, -half_extent}, {-half_extent, -half_extent, half_extent}, {half_extent, -half_extent, half_extent}, }, { // FACE_BACK {half_extent, half_extent, -half_extent}, {-half_extent, half_extent, -half_extent}, {half_extent, half_extent, half_extent}, {-half_extent, half_extent, half_extent}, }, { // FACE_TOP {-half_extent, -half_extent, half_extent}, {half_extent, -half_extent, half_extent}, {-half_extent, half_extent, half_extent}, {half_extent, half_extent, half_extent}, }, { // FACE_BOTTOM {-half_extent, half_extent, -half_extent}, {half_extent, half_extent, -half_extent}, {-half_extent, -half_extent, -half_extent}, {half_extent, -half_extent, -half_extent}, }, }; fGeometry = new float [sizeof(kVertices)/sizeof(float)]; memcpy(fGeometry, kVertices, sizeof(kVertices)); } /* FUNCTION: Cube :: ~Cube ARGUMENTS: n/a RETURN: n/a DESCRIPTION: Destructor - fMediaSources owned by ViewCube */ Cube :: ~Cube() { delete fGeometry; } /* FUNCTION: Cube :: SetAngle ARGUMENTS: angle_x angle_y angle_z RETURN: n/a DESCRIPTION: Rotate cube by Euler angles */ void Cube :: SetAngle(float angle_x, float angle_y, float angle_z) { fRotationX = angle_x; fRotationY = angle_y; fRotationZ = angle_z; } /* FUNCTION: Cube :: Render ARGUMENTS: none RETURN: n/a DESCRIPTION: Draw sphere */ void Cube :: Render() { const float kTextureCoords[4*2] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; glPushMatrix(); glRotatef(fRotationX, 1, 0, 0); glRotatef(fRotationY, 0, 1, 0); glRotatef(fRotationZ, 0, 0, 1); glColor4f(1,1,1,1); for (int i=0; i < NUMBER_CUBE_FACES; i++) { glBindTexture(GL_TEXTURE_2D, fMediaSources[i]->mTextureID); glTexCoordPointer(2, GL_FLOAT, 0, kTextureCoords); glVertexPointer(3, GL_FLOAT, 0, fGeometry + i*3*4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } glPopMatrix(); } /******************************** ViewCube *********************************/ /* FUNCTION: ViewCube :: ViewCube ARGUMENTS: frame RETURN: n/a DESCRIPTION: Constructor */ ViewCube :: ViewCube(BRect frame) : ViewObject(frame) { fStartTime = real_time_clock_usecs(); for (int i=0; i < NUMBER_FACES; i++) fMediaSources[i] = 0; fCube = 0; fSpeed = 10; fMouseTracking = false; } /* FUNCTION: ViewCube :: ~ViewCube ARGUMENTS: n/a RETURN: n/a DESCRIPTION: Destructor */ ViewCube :: ~ViewCube() { delete fCube; for (int i=0; i < NUMBER_FACES; i++) { if (fMediaSources[i] != GetDefaultMediaSource()) delete fMediaSources[i]; } } /* FUNCTION: ViewCube :: ViewCube ARGUMENTS: none RETURN: n/a DESCRIPTION: Hook function called when view attached to window (looper) */ void ViewCube :: AttachedToWindow(void) { ViewObject::AttachedToWindow(); LockGL(); glClearColor(0,0,0,1); fCube = new Cube(0.075f); for (int i=0; i < NUMBER_FACES; i++) { fMediaSources[i] = GetDefaultMediaSource(); fCube->SetMediaSource((Cube::FACE) i, fMediaSources[i]); } UnlockGL(); } /* FUNCTION: ViewCube :: Render ARGUMENTS: none RETURN: n/a DESCRIPTION: Draw view contents */ void ViewCube :: Render(void) { LockGL(); bigtime_t current_time = real_time_clock_usecs(); bigtime_t delta = current_time - fStartTime; fStartTime = current_time; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); fCubeAngle += fSpeed*(float)delta/1000000.0f; fCube->SetAngle(0, 0, fCubeAngle); glPushMatrix(); glTranslatef(0.0f, 0.0f, 0.15f); fCube->Render(); glPopMatrix(); glFlush(); SwapBuffers(); // Display frame rate /* static int fps = 0; static int time_delta = 0; fps++; time_delta += delta; if (time_delta > 1000000) { printf("%d fps\n", fps); fps = 0; time_delta = 0; } */ UnlockGL(); } /* FUNCTION: ViewCube :: MouseDown ARGUMENTS: p RETURN: n/a DESCRIPTION: Hook function called when mouse down detected */ void ViewCube :: MouseDown(BPoint p) { // Determine mouse button BMessage* msg = Window()->CurrentMessage(); uint32 buttons; msg->FindInt32("buttons", (int32*)&buttons); if (buttons & B_PRIMARY_MOUSE_BUTTON) { SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); fMouseTracking = true; fMousePosition = p; } } /* FUNCTION: ViewCube :: MouseMoved ARGUMENTS: p transit message RETURN: n/a DESCRIPTION: Hook function called when mouse move detected */ void ViewCube :: MouseMoved(BPoint p, uint32 transit, const BMessage *message) { if (fMouseTracking) { if (transit == B_INSIDE_VIEW) { fSpeed = 5.0f*(p.x - fMousePosition.x); fMousePosition = p; } } } /* FUNCTION: ViewSphere :: MouseUp ARGUMENTS: p RETURN: n/a DESCRIPTION: Hook function called when mouse up detected */ void ViewCube :: MouseUp(BPoint p) { fMouseTracking = false; } /* FUNCTION: ViewSphere :: DragDropImage ARGUMENTS: texture_id mouse_x mouse_y RETURN: true if source ownership acquired DESCRIPTION: Hook function called when user drags/drops image to app window. TODO - actually determine exact face where refs received. For this release, we only rely on current fCubeAngle. */ bool ViewCube :: SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y) { // determine face BRect frame = Bounds(); Cube::FACE face = Cube::NUMBER_CUBE_FACES; if (mouse_y < frame.Height()*0.33f) face = Cube::FACE_TOP; else { if (fCubeAngle < 45) face = Cube::FACE_FRONT; else if (fCubeAngle < 135) face = Cube::FACE_LEFT; else if (fCubeAngle < 225) face = Cube::FACE_BACK; else if (fCubeAngle < 315) face = Cube::FACE_RIGHT; else face = Cube::FACE_FRONT; } if (fMediaSources[face] != GetDefaultMediaSource()) delete fMediaSources[face]; fMediaSources[face] = source; fCube->SetMediaSource(face, source); return true; }