Import Zenja Solaja's 3DMov over françois skeleton.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35341 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Philippe Houdoin 2010-01-30 11:14:16 +00:00
parent 0e81d474e7
commit 43a75cae5c
18 changed files with 2719 additions and 35 deletions

View File

@ -1,37 +1,11 @@
/*
* Copyright 2004-2009, Haiku Inc. All rights reserved.
* Copyright 2009, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
* Zenja Solaja
*/
resource(1, "BEOS:APP_FLAGS") (#'APPF') $"00000000";
resource(1, "BEOS:APP_VERSION") #'APPV' array {
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"0000000000000000000000000000000000000000000000000000000000000000"
$"000000000000000000000000000000000000000080031200FC105760EC111000"
$"EC088BC800000000FC1057808003220080052980800294408000600380032200"
$"8005298000000002FC1057C0FC105A7C000000018003E7800000000280032200"
$"800529808002944080006003EC02ECB88005298000000000FC1057D0EC111000"
$"EC01BE200000000200000000FC105A7C000000018003E7800000000280006003"
$"000000028001DEE88001DEF8EC02ECB88004B38000000000FC1058108003E780"
$"EC01BE20EC02ECB8FC105810EC111000EC01BE7C00000001FC10582000000000"
$"EC02ECBCFFFFFFFFEC05B434FC1058B88005298080029440FC10585080019244"
$"FC1059B8EC02ECB8FC105850EC111000EC01BE7C8002A680FC105870EC111000"
$"80052980FFFFFFFFEC05B434FC10593800000004000201DC800060038003E780"
$"8005298000000000FC105890420C0000EC019C080000010043300000EC111000"
$"8004B38000000000"
};
resource(1, "BEOS:APP_SIG") (#'MIMS') "application/x-vnd.Haiku-3DMov";
resource app_signature "application/x-vnd.Haiku-3DMov";
resource(1, "instructions.png") #'PNG ' import "instructions.png";

View File

@ -0,0 +1,63 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov
There is an issue in Haiku when creating a 2nd BGLView which doesn't exist in Zeta
(see MainWindow.cpp for details). Until that issue is resolved,
I've allowed specifying of shape type (0-2) as a command line argument.
*/
#include <Application.h>
#include "MainWindow.h"
/*****************************
Main application
******************************/
class MainApp : public BApplication
{
public:
MainApp(MainWindow::SHAPE shape);
private:
MainWindow *fWindow;
};
/* FUNCTION: MainApp :: MainApp
ARGS: none
RETURN: n/a
DESCRIPTION: Application constructor
*/
MainApp :: MainApp(MainWindow::SHAPE shape)
: BApplication("application/x_vnd.Haiku")
{
BRect frame(50, 50, 50+400, 50+300);
fWindow = new MainWindow(frame, shape);
}
/******************************
Program entry point
*******************************/
/* FUNCTION: main
ARGS: arc number of command line arguments
argv vector to arguments
RETURN: Exit status
DESCRIPTION: main program entry point
*/
int main(int argc, char **argv)
{
// Check if shape specified on command line
MainWindow::SHAPE shape = MainWindow::BOOK;
if (argc > 1)
{
int value = *argv[1] - '0';
if (value >= 0 && value < MainWindow::NUMBER_OF_SHAPES)
shape = (MainWindow::SHAPE) value;
}
MainApp *app = new MainApp(shape);
app->Run();
delete app;
}

View File

@ -0,0 +1,244 @@
/* 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 <GL/gl.h>
#include <string.h>
#include "GLUtility.h"
// Local definitions
// Local functions
// Local variables
/* FUNCTION: GLCreateIdentityMatrix
ARGUMENTS: m destination matrix
RETURN: n/a
DESCRIPTION: Create identity matrix
*/
void GLCreateIdentityMatrix(float *m)
{
const float kIdentity[16] =
{
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
};
memcpy(m, kIdentity, 16*sizeof(float));
}
/* FUNCTION: GLMatrixMultiply
ARGUMENTS: product
m1, m2
RETURN: product
DESCRIPTION: Perform a 4x4 matrix multiplication (product = m1 x m2)
*/
void GLMatrixMultiply(float *product, float *m1, float *m2)
{
product[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
product[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
product[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
product[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
product[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
product[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
product[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
product[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
product[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
product[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
product[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
product[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
product[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
product[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
product[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
product[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
}
/* FUNCTION: GLCreatePerspectiveMatrix
ARGUMENTS: m destination matrix
fov field of view
aspect aspect ratio
znear near plane
zfar far plane
RETURN: n/a
DESCRIPTION: Same as gluPerspective
*/
void GLCreatePerspectiveMatrix(float *m, float fov, float aspect, float znear, float zfar)
{
const float h = 1.0f/tand(fov/2.0f);
float neg_depth = znear-zfar;
m[0] = h / aspect;
m[1] = 0;
m[2] = 0;
m[3] = 0;
m[4] = 0;
m[5] = h;
m[6] = 0;
m[7] = 0;
m[8] = 0;
m[9] = 0;
m[10] = (zfar + znear)/neg_depth;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = 2.0f*(znear*zfar)/neg_depth;
m[15] = 0;
}
/* FUNCTION: GLCreateModelViewMatrix
ARGUMENTS: m destination matrix
x,y,z position
yaw compass direction, 0-north, 90-east, 180-south, 270-west
pitch azimuth, -90 down, 0 forwad, 90 up
roll rotation around forward axis
RETURN: n/a
DESCRIPTION: Position camera
*/
void GLCreateModelViewMatrix(float *m, float x, float y, float z, float yaw, float pitch, float roll)
{
// same as gluLookAt
Quaternion q, qDir, qAzim;
qAzim.GenerateLocalRotation(pitch + 90.0f, -1.0f, 0.0f, 0.0f);
qDir.GenerateLocalRotation(yaw, 0.0f, 0.0f, 1.0f);
q = qAzim * qDir;
if (roll != 0)
{
Quaternion qTilt;
qTilt.GenerateLocalRotation(roll, 0, 0, 1);
q = qTilt * q;
}
q.CreateRotatedQuaternion(m);
// move camera
float mov[16];
GLCreateIdentityMatrix(mov);
mov[12] = -x;
mov[13] = -y;
mov[14] = -z;
GLMatrixMultiply(m, m, mov);
}
/**************************
Quaternion class
***************************/
/* FUNCTION: Quaternion
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Constructor. No rotation.
*/
Quaternion :: Quaternion()
{
x = y = z = 0.0f;
w = 1.0f;
}
/* FUNCTION: Quaternion :: GenerateLocalRotation
ARGUMENTS: angle
x_axis, y_axis, z_axis axis of rotation
RETURN: n/a
DESCRIPTION: Create unit quaterion corresponding to a rotation through angle <angle>
about axis <a,b,c>.
q = cos (angle/2) + A(a,b,c)*sin(angle/2)
*/
void Quaternion :: GenerateLocalRotation(float angle, float x_axis, float y_axis, float z_axis)
{
float temp = sind(0.5f*angle);
w = cosd(0.5f*angle);
x = x_axis * temp;
y = y_axis * temp;
z = z_axis * temp;
}
/* FUNCTION: Quaternion :: GenerateFromEuler
ARGUMENTS: roll (degrees)
pitch (degrees)
yaw (degrees)
RETURN: n/a
DESCRIPTION: Creates quaternion from euler angles. Borowed from Bullet
*/
void Quaternion :: GenerateFromEuler(float roll, float pitch, float yaw)
{
float halfYaw = 0.5f * yaw;
float halfPitch = 0.5f * pitch;
float halfRoll = 0.5f * roll;
float cosYaw = cosd(halfYaw);
float sinYaw = sind(halfYaw);
float cosPitch = cosd(halfPitch);
float sinPitch = sind(halfPitch);
float cosRoll = cosd(halfRoll);
float sinRoll = sind(halfRoll);
x = sinRoll*cosPitch*cosYaw - cosRoll*sinPitch*sinYaw;
y = cosRoll*sinPitch*cosYaw + sinRoll*cosPitch*sinYaw;
z = cosRoll*cosPitch*sinYaw - sinRoll*sinPitch*cosYaw;
w = cosRoll*cosPitch*cosYaw + sinRoll*sinPitch*sinYaw;
}
/* FUNCTION: Quaternion :: CreateRotatedQuaternion
ARGUMENTS: matrix
RETURN: n/a
DESCRIPTION: Creates rotated quaterion. Always call GenerateLocalRotation() prior
to calling this method
*/
void Quaternion :: CreateRotatedQuaternion(float *matrix)
{
if (!matrix)
return;
// first row
matrix[0] = 1.0f - 2.0f*(y*y + z*z);
matrix[1] = 2.0f*(x*y + w*z);
matrix[2] = 2.0f*(x*z - w*y);
matrix[3] = 0.0f;
// second row
matrix[4] = 2.0f*(x*y - w*z);
matrix[5] = 1.0f - 2.0f*(x*x + z*z);
matrix[6] = 2.0f*(y*z + w*x);
matrix[7] = 0.0f;
// third row
matrix[8] = 2.0f*(x*z + w*y);
matrix[9] = 2.0f*(y*z - w*x);
matrix[10] = 1.0f - 2.0f*(x*x + y*y);
matrix[11] = 0.0f;
// forth row
matrix[12] = 0;
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1.0f;
}
/* FUNCTION: operator *
ARGUMENTS: q
RETURN: multiplied quaternion
DESCRIPTION: Creates rotated quaternion
*/
const Quaternion Quaternion::operator *(Quaternion q)
{
Quaternion p;
p.x = w*q.x + x*q.w + y*q.z - z*q.y; // (w1x2 + x1w2 + y1z2 - z1y2)i
p.y = w*q.y - x*q.z + y*q.w + z*q.x; // (w1y2 - x1z2 + y1w2 + z1x2)j
p.z = w*q.z + x*q.y - y*q.x + z*q.w; // (w1z2 + x1y2 - y1x2 + z1w2)k
p.w = w*q.w - x*q.x - y*q.y - z*q.z; // (w1w2 - x1x2 - y1y2 - z1z2)
return(p);
}

View File

@ -0,0 +1,58 @@
/* 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
*/
#ifndef _GL_UTILITY_H_
#define _GL_UTILITY_H_
#include <cmath>
/**************************
Definitions
***************************/
#define Y_PI 3.14159265358979323846f
#define Y_PI_DIV_180 (Y_PI/180.0f)
/**************************
Macros
***************************/
#define sind(a) (sinf((a) * Y_PI_DIV_180))
#define cosd(a) (cosf((a) * Y_PI_DIV_180))
#define tand(a) (tanf((a) * Y_PI_DIV_180))
/**************************
Functions
***************************/
void GLCreateIdentityMatrix(float *m);
void GLMatrixMultiply(float *destination, float *matrix_a, float *matrix_b);
void GLCreatePerspectiveMatrix(float *m, float fov, float aspect, float znear, float zfar);
void GLCreateModelViewMatrix(float *m, float x, float y, float z, float yaw, float pitch, float roll=0.0f);
/**************************
Quaternion class
***************************/
class Quaternion
{
public:
Quaternion();
void GenerateLocalRotation(float angle, float x_axis, float y_axis, float z_axis);
void CreateRotatedQuaternion(float *matrix);
void GenerateFromEuler(float roll, float pitch, float yaw);
// Operators
inline const Quaternion operator+=(const Quaternion &q) {x += q.x; y += q.y; z += q.z; w += q.w; return *this;}
inline const Quaternion operator-=(const Quaternion &q) {x -= q.x; y -= q.y; z -= q.z; w -= q.w; return *this;}
const Quaternion operator *(Quaternion q);
private:
float x;
float y;
float z;
float w;
};
#endif //#ifndef _GL_UTILITY_H_

View File

@ -3,10 +3,14 @@ SubDir HAIKU_TOP src apps 3dmov ;
SetSubDirSupportedPlatformsBeOSCompatible ;
Application 3DMov :
CubeView.cpp
GLMovApp.cpp
GLMovView.cpp
GLMovWindow.cpp
: be GL game $(TARGET_LIBSUPC++)
Application.cpp
MainWindow.cpp
ViewObject.cpp
Video.cpp
ViewBook.cpp
ViewCube.cpp
ViewSphere.cpp
GLUtility.cpp
: be GL game media translation $(TARGET_LIBSUPC++)
: 3dmov.rdef
;

View File

@ -0,0 +1,248 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov.
TODO:
There is a bug in Haiku which doesn't allow a 2nd BGLView to be created.
Originally I tried AddChild(new BGLView), however nothing would be drawn in the view.
On Zeta, both AddChild(new BGLView) and new MainWindow work without any problems.
*/
#include <InterfaceKit.h>
#include <GLView.h>
#include <Messenger.h>
#include "MainWindow.h"
#include "ViewObject.h"
#include "ViewBook.h"
#include "ViewCube.h"
#include "ViewSphere.h"
// Local definitions
static const float MENU_BAR_HEIGHT = 19;
static const unsigned int MSG_FILE_OPEN = 'fopn';
static const unsigned int MSG_ABOUT = 'info';
static const unsigned int MSG_SHAPE_BOOK = 'spbk';
static const unsigned int MSG_SHAPE_CUBE = 'spcb';
static const unsigned int MSG_SHAPE_SPHERE = 'spsp';
static const unsigned int MSG_OPTION_WIREFRAME = 'opwf';
static const unsigned int MSG_FULLSCREEN = 'full';
static const char *ABOUT_TEXT = "\
Drag and drop media files (pictures and videos) onto the 3D shapes. \
Use your mouse to interact with the 3D shape.\n\
Pick up your jaw from the floor.\n\n\
Inspired by the original BeInc 3dmov demo.\n\
Written by Zenja Solaja, 2009";
// Local functions
static int32 animation_thread(void *cookie);
// Local variables
static int sMainWindowCount = 0; // keep track of number of spawned windows
/* FUNCTION: MainWindow :: MainWindow
ARGUMENTS: frame
shape
RETURN: n/a
DESCRIPTION: Constructor
*/
MainWindow :: MainWindow(BRect frame, SHAPE shape)
: BDirectWindow(frame, "3Dmov", B_TITLED_WINDOW, 0)
{
sMainWindowCount++;
fOptionWireframe = false;
// Add menu bar
frame.OffsetTo(B_ORIGIN);
BRect aRect = frame;
aRect.bottom = MENU_BAR_HEIGHT;
frame.top = MENU_BAR_HEIGHT;
SetupMenuBar(aRect);
// Add book view
switch (shape)
{
case BOOK: AddChild(fCurrentView = new ViewBook(frame)); break;
case CUBE: AddChild(fCurrentView = new ViewCube(frame)); break;
case SPHERE: AddChild(fCurrentView = new ViewSphere(frame)); break;
}
//AddShortcut('f', B_COMMAND_KEY, new BMessage(MSG_FULLSCREEN));
// Window should never be larger than 2048
SetSizeLimits(40.0, 2047.0, 40.0, 2047.0);
Show();
fAnimationThreadID = spawn_thread(animation_thread, "Animation Thread", B_NORMAL_PRIORITY, fCurrentView);
resume_thread(fAnimationThreadID);
}
/* FUNCTION: MainWindow :: ~MainWindow
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
MainWindow :: ~MainWindow()
{
kill_thread(fAnimationThreadID);
RemoveChild(fCurrentView);
delete fCurrentView;
sMainWindowCount--;
if (sMainWindowCount == 0)
be_app->PostMessage(B_QUIT_REQUESTED);
}
/* FUNCTION: MainWindow :: SetupMenuBar
ARGUMENTS: frame
RETURN: n/a
DESCRIPTION: Initialise menu bar
*/
void MainWindow :: SetupMenuBar(BRect frame)
{
// File
BMenu *menu_file = new BMenu("File");
//menu_file->AddItem(new BMenuItem("Open", new BMessage(MSG_FILE_OPEN), 'N'));
menu_file->AddItem(new BMenuItem("About", new BMessage(MSG_ABOUT)));
menu_file->AddItem(new BMenuItem("Exit", new BMessage(B_QUIT_REQUESTED)));
// Shape
BMenu *menu_shape = new BMenu("Shape");
menu_shape->AddItem(new BMenuItem("Book", new BMessage(MSG_SHAPE_BOOK), '1'));
menu_shape->AddItem(new BMenuItem("Cube", new BMessage(MSG_SHAPE_CUBE), '2'));
menu_shape->AddItem(new BMenuItem("Sphere", new BMessage(MSG_SHAPE_SPHERE), '3'));
// Options
BMenu *menu_options = new BMenu("Options");
menu_options->AddItem(new BMenuItem("Wireframe", new BMessage(MSG_OPTION_WIREFRAME), 'S'));
//menu_options->AddItem(new BMenuItem("Fullscreen", new BMessage(MSG_FULLSCREEN), 'F'));
// Menu bar
fMenuBar = new BMenuBar(frame, "menubar");
fMenuBar->AddItem(menu_file);
fMenuBar->AddItem(menu_shape);
fMenuBar->AddItem(menu_options);
AddChild(fMenuBar);
}
/* FUNCTION: MainWindow :: MessageReceived
ARGUMENTS: message
RETURN: n/a
DESCRIPTION: Called by BeOS
*/
void MainWindow :: MessageReceived(BMessage *message)
{
switch (message->what)
{
case MSG_FULLSCREEN:
SetFullScreen(!IsFullScreen());
break;
case MSG_ABOUT:
{
BAlert *about = new BAlert("3Dmov", ABOUT_TEXT, "Wow");
about->SetShortcut(0, B_ESCAPE);
about->Go(NULL);
break;
}
/* TODO - Due to a bug when creating a 2nd BGLView in Haiku, I've decided to spawn a new window
instead of creating a new BGLView (and using AddChild(new_view) / RemoveChild(old_view).
Under Zeta, there is no problem replacing the current view with a new view.
*/
case MSG_SHAPE_BOOK:
new MainWindow(BRect(50, 50, 400+50, 300+50), BOOK);
break;
case MSG_SHAPE_CUBE:
new MainWindow(BRect(50, 50, 400+50, 300+50), CUBE);
break;
case MSG_SHAPE_SPHERE:
new MainWindow(BRect(50, 50, 400+50, 300+50), SPHERE);
break;
case MSG_OPTION_WIREFRAME:
fOptionWireframe = !fOptionWireframe;
fCurrentView->ToggleWireframe(fOptionWireframe);
break;
case 'DATA': // user drag/dropped file from Tracker
{
BPoint point;
message->FindPoint("_drop_point_", &point);
BRect frame = Frame();
point.x -= frame.left;
point.y -= frame.top;
entry_ref aRef;
message->FindRef("refs", &aRef);
fCurrentView->DragDrop(&aRef, point.x, point.y);
break;
}
default:
BDirectWindow::MessageReceived(message);
break;
}
}
/* FUNCTION: MainWindow :: QuitRequested
ARGUMENTS: none
RETURN: true if success
DESCRIPTION: Called when window closed
*/
bool MainWindow :: QuitRequested()
{
//be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
/* FUNCTION: MainWindow :: DirectConnected
ARGUMENTS: info
RETURN: n/a
DESCRIPTION: Hook functions called when full screen mode toggled
*/
void MainWindow :: DirectConnected(direct_buffer_info *info)
{
switch (info->buffer_state & B_DIRECT_MODE_MASK)
{
// start a direct screen connection.
case B_DIRECT_START :
break;
// stop a direct screen connection.
case B_DIRECT_STOP :
break;
// modify the state of a direct screen connection.
case B_DIRECT_MODIFY :
break;
default :
break;
}
}
/* FUNCTION: animation_thread
ARGUMENTS: cookie
RETURN: exit status
DESCRIPTION: Main rendering thread
*/
#include <stdio.h>
static int32 animation_thread(void *cookie)
{
ViewObject *view = (ViewObject *) cookie;
while (1)
{
view->Render();
view->GLCheckError();
snooze(1);
}
return B_OK; // keep compiler happy
}

View File

@ -0,0 +1,46 @@
/* 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
*/
#ifndef _MAIN_WINDOW_H_
#define _MAIN_WINDOW_H_
#include "DirectWindow.h"
class BMenuBar;
class ViewObject;
/************************************
Main application window
*************************************/
class MainWindow : public BDirectWindow
{
public:
enum SHAPE
{
BOOK,
CUBE,
SPHERE,
NUMBER_OF_SHAPES
};
MainWindow(BRect frame, SHAPE shape);
~MainWindow();
void MessageReceived(BMessage *message);
void DirectConnected(direct_buffer_info *info);
bool QuitRequested();
private:
void SetupMenuBar(BRect frame);
BMenuBar *fMenuBar;
bool fOptionWireframe;
int32 fAnimationThreadID;
ViewObject *fCurrentView;
};
#endif

208
src/apps/3dmov/Video.cpp Normal file
View File

@ -0,0 +1,208 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov
This file handles video playback for ViewObject base class.
*/
#include <stdio.h>
#include <Bitmap.h>
#include <Screen.h>
#include "ViewObject.h"
#include "Video.h"
/* FUNCTION: Video :: Video
ARGUMENTS: ref
RETURN: n/a
DESCRIPTION: Constructor
*/
Video :: Video(entry_ref *ref)
{
fMediaFile = 0;
fVideoTrack = 0;
fBitmap = 0;
fVideoThread = 0;
fMediaFile = new BMediaFile(ref, B_MEDIA_FILE_BIG_BUFFERS);
fStatus = fMediaFile->InitCheck();
if (fStatus != B_OK)
return;
int32 num_tracks = fMediaFile->CountTracks();
for (int32 i=0; i < num_tracks; i++)
{
BMediaTrack *track = fMediaFile->TrackAt(i);
if (track == NULL)
{
fMediaFile->ReleaseAllTracks();
printf("Media file claims to have %ld tracks, cannot find track %ld\n", num_tracks, i);
fVideoTrack = 0;
return;
}
media_format mf;
fStatus = track->EncodedFormat(&mf);
if (fStatus == B_OK)
{
switch (mf.type)
{
case B_MEDIA_ENCODED_VIDEO:
case B_MEDIA_RAW_VIDEO:
if (fVideoTrack == 0)
{
fVideoTrack = track;
InitPlayer(&mf);
}
else
printf("Multiple video tracks not supported\n");
break;
default:
fStatus = B_ERROR;
}
}
if (fStatus != B_OK)
fMediaFile->ReleaseTrack(track);
}
if (fVideoTrack)
fStatus = B_OK;
}
/* FUNCTION: Video :: ~Video
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
Video :: ~Video()
{
if (fVideoThread > 0)
kill_thread(fVideoThread);
delete fMediaFile;
delete fBitmap;
}
/* FUNCTION: Video :: InitPlayer
ARGUMENTS: format
RETURN: n/a
DESCRIPTION: Create frame buffer and init decoder
*/
void Video :: InitPlayer(media_format *format)
{
BRect frame(0, 0,
format->u.encoded_video.output.display.line_width - 1.0f,
format->u.encoded_video.output.display.line_count - 1.0f);
BScreen screen;
color_space cs = screen.ColorSpace();
// Loop asking the track for a format we can deal with
for (;;)
{
fBitmap = new BBitmap(frame, cs);
media_format mf, old_mf;
memset(&mf, 0, sizeof(media_format));
media_raw_video_format *rvf = &mf.u.raw_video;
rvf->last_active = (uint32)(frame.Height() - 1.0f);
rvf->orientation = B_VIDEO_TOP_LEFT_RIGHT;
rvf->pixel_width_aspect = 1;
rvf->pixel_height_aspect = 3;
rvf->display.format = cs;
rvf->display.line_width = (int32)frame.Width();
rvf->display.line_count = (int32)frame.Height();
rvf->display.bytes_per_row = fBitmap->BytesPerRow();
old_mf = mf;
fVideoTrack->DecodedFormat(&mf);
// check if match found
if (old_mf.u.raw_video.display.format == mf.u.raw_video.display.format)
break;
// otherwise, change colour space
cs = mf.u.raw_video.display.format;
delete fBitmap;
}
media_header mh;
fVideoTrack->SeekToTime(0);
int64 dummy_num_frames;
fVideoTrack->ReadFrames((char *)fBitmap->Bits(), &dummy_num_frames, &mh);
fVideoTrack->SeekToTime(0);
}
/* FUNCTION: Video :: Start
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Start playing video
*/
void Video :: Start()
{
fVideoThread = spawn_thread(Video::VideoThread, "Video thread", B_NORMAL_PRIORITY, this);
if (fVideoThread > 0)
resume_thread(fVideoThread);
}
/* FUNCTION: Video :: ShowNextFrame
ARGUMENTS: none
RETURN: status
DESCRIPTION: Read next frame, update texture
*/
status_t Video :: ShowNextFrame()
{
status_t err;
media_header mh;
int64 dummy = 0;
fBitmap->LockBits();
err = fVideoTrack->ReadFrames((char *)fBitmap->Bits(), &dummy, &mh);
fBitmap->UnlockBits();
if (err != B_OK)
{
// restart video
fVideoTrack->SeekToTime(0);
return B_OK;
}
fMediaSource->mOwner->UpdateFrame(fMediaSource);
return B_OK;
}
/* FUNCTION: Video :: VideoThread
ARGUMENTS: cookie
RETURN: thread exit status
DESCRIPTION: Video playback thread
*/
int32 Video :: VideoThread(void *cookie)
{
Video *video = (Video *) cookie;
if (video->fVideoTrack == NULL)
{
exit_thread(B_ERROR);
return B_ERROR;
}
float frames_per_second = (float)video->fVideoTrack->CountFrames() / (float)video->fVideoTrack->Duration() * 1000000.0f;
bigtime_t frame_time = (bigtime_t) (1000000.0f / frames_per_second);
video->fPerformanceTime = real_time_clock_usecs() + frame_time;
status_t err = B_OK;
printf("frame_rate = %f\n", frames_per_second);
while (1)
{
err = video->ShowNextFrame();
bigtime_t zzz = video->fPerformanceTime - real_time_clock_usecs();
if (zzz < 0)
zzz = 1;
video->fPerformanceTime += frame_time;
snooze(zzz);
}
exit_thread(err);
return err;
}

45
src/apps/3dmov/Video.h Normal file
View File

@ -0,0 +1,45 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov
Media playback support.
*/
#ifndef _VIDEO_H_
#define _VIDEO_H_
#include <MediaKit.h>
class BBitmap;
class MediaSource;
/*****************************
Video class handles media playback
******************************/
class Video
{
public:
Video(entry_ref *ref);
~Video();
status_t GetStatus() {return fStatus;}
BBitmap *GetBitmap() {return fBitmap;}
void Start();
void SetMediaSource(MediaSource *source) {fMediaSource = source;}
private:
MediaSource *fMediaSource;
status_t fStatus;
BMediaFile *fMediaFile;
BMediaTrack *fVideoTrack;
BBitmap *fBitmap;
thread_id fVideoThread;
bigtime_t fPerformanceTime;
void InitPlayer(media_format *format);
status_t ShowNextFrame();
static int32 VideoThread(void *arg); // one thread per object is spawned
};
#endif //#ifndef _VIDEO_H_

525
src/apps/3dmov/ViewBook.cpp Normal file
View File

@ -0,0 +1,525 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov
The book has 4 pages with images, and the user can move pages 2/3.
Texture management is really primitive - only the default image is
shared, while the other page images are unique instances.
*/
#include <stdio.h>
#include <assert.h>
#include <Bitmap.h>
#include "GLUtility.h"
#include "ViewBook.h"
// Local definitions
// Local functions
// void GetPage(Paper *
// Local variables
/********************************
Paper scene
*********************************/
class Paper
{
public:
enum ORIENTATION
{
FRONT_FACING,
BACK_FACING,
FRONT_AND_BACK_FACING,
};
enum TEXTURE_SIDE
{
FRONT_TEXTURE,
BACK_TEXTURE,
UNASSIGNED_TEXTURE,
};
Paper(float x_size, float y_size, ORIENTATION orientation, const int number_columns = 6, const int number_rows = 4);
~Paper();
void Render();
void SetMediaSource(TEXTURE_SIDE side, MediaSource *source);
void SetAngle(float angle);
private:
ORIENTATION fOrientation;
MediaSource *fFrontMediaSource;
MediaSource *fBackMediaSource;
float *fGeometry;
float *fTextureCoords;
int fNumberVertices;
float fWidth, fHeight;
int fNumberColumns, fNumberRows;
void InitTextureCoordinates();
void ModifyGeometry();
float fAngle;
};
/* FUNCTION: Paper :: Paper
ARGUMENTS: x_size, y_size
number_columns
number_rows;
RETURN: n/a
DESCRIPTION: Constructor
*/
Paper :: Paper(float x_size, float y_size, ORIENTATION orientation, const int number_columns, const int number_rows)
{
assert(number_rows%2 == 0); // rows must be divisible by 2
fOrientation = orientation;
fFrontMediaSource = 0;
fBackMediaSource = 0;
fWidth = x_size;
fHeight = y_size;
fNumberColumns = number_columns;
fNumberRows = number_rows;
fNumberVertices = (fNumberColumns*2+1)*fNumberRows + 1;
fGeometry = new float [fNumberVertices*3];
fTextureCoords = new float [fNumberVertices * 2];
InitTextureCoordinates();
SetAngle(0);
}
/* FUNCTION: Paper :: ~Paper
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor. MediaSource destruction handled by ViewBook
*/
Paper :: ~Paper()
{
delete [] fGeometry;
delete [] fTextureCoords;
}
/* FUNCTION: Paper :: SetMediaSource
ARGUMENTS: side
source
RETURN: n/a
DESCRIPTION: Assign paper texture id
*/
void Paper :: SetMediaSource(TEXTURE_SIDE side, MediaSource *source)
{
if (side == FRONT_TEXTURE)
fFrontMediaSource = source;
else
fBackMediaSource = source;
}
/* FUNCTION: Paper :: SetAngle
ARGUMENTS: angle 0 - paper is on left side of book
90 - paper is vertical
180 - paper is on right side of book
RETURN: n/a
DESCRIPTION: Set paper angle and recalculate geometry
*/
void Paper :: SetAngle(float angle)
{
fAngle = angle;
ModifyGeometry();
}
/* FUNCTION: Paper :: Render
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Draw paper
*/
void Paper :: Render()
{
glPushMatrix();
glTranslatef(-0.5f*fWidth, -0.5f*fHeight, 0);
if ((fOrientation == FRONT_FACING) || (fOrientation == FRONT_AND_BACK_FACING))
{
glColor4f(1,1,1,1);
glBindTexture(GL_TEXTURE_2D, fFrontMediaSource->mTextureID);
glTexCoordPointer(2, GL_FLOAT, 0, fTextureCoords);
glVertexPointer(3, GL_FLOAT, 0, fGeometry);
glDrawArrays(GL_TRIANGLE_STRIP, 0, fNumberVertices);
}
if ((fOrientation == BACK_FACING) || (fOrientation == FRONT_AND_BACK_FACING))
{
glColor4f(1,1,1,1);
glBindTexture(GL_TEXTURE_2D, fBackMediaSource->mTextureID);
// Mirror texture coordinates
glMatrixMode(GL_TEXTURE);
glScalef(-1,1,1);
glFrontFace(GL_CW);
glTexCoordPointer(2, GL_FLOAT, 0, fTextureCoords);
glVertexPointer(3, GL_FLOAT, 0, fGeometry);
glDrawArrays(GL_TRIANGLE_STRIP, 0, fNumberVertices);
glFrontFace(GL_CCW);
// Restore texture mirroring
glScalef(-1,1,1);
glMatrixMode(GL_MODELVIEW);
}
glPopMatrix();
}
/* FUNCTION: Paper :: InitTextureCoordinates
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Set texture coordinates (they never change)
*/
void Paper :: InitTextureCoordinates()
{
float *p = fTextureCoords;
for (int r = fNumberRows-2; r >= 0; r-=2)
{
if (r == fNumberRows-2)
{
*p++ = 0;
*p++ = 0;
}
for (int c=0; c < fNumberColumns; c++)
{
*p++ = (float)c/fNumberColumns;
*p++ = 1 - (float)(r+1)/fNumberRows;
*p++ = (float)(c+1)/fNumberColumns;
*p++ = 1 - (float)(r+2)/fNumberRows;
}
for (int c = fNumberColumns; c >= 0; c--)
{
*p++ = (float)c/fNumberColumns;
*p++ = 1 - (float)(r+1)/fNumberRows;
*p++ = (float)c/fNumberColumns;
*p++ = 1 - (float)r/fNumberRows;
}
}
}
/* FUNCTION: Paper :: ModifyGeometry
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Modify vertices only
*/
void Paper :: ModifyGeometry()
{
float *p = fGeometry;
const float kPageConcaveHeight = 0.1f*fWidth;
// Cache frequent calculations
float ca = cosd(fAngle);
float w = fWidth * sind(fAngle);
for (int r = fNumberRows-2; r >= 0; r-=2)
{
if (r == fNumberRows-2)
{
*p++ = (1-ca)*fWidth;
*p++ = fHeight;
*p++ = w;
}
for (int c=0; c < fNumberColumns; c++)
{
*p++ = (1-ca)*fWidth + ca*(float)c/fNumberColumns * fWidth;
*p++ = (float)(r+1)/fNumberRows * fHeight;
*p++ = (1-(float)c/fNumberColumns) * w + kPageConcaveHeight*sind(180*(float)c/fNumberColumns);
*p++ = (1-ca)*fWidth + ca*(float)(c+1)/fNumberColumns * fWidth;
*p++ = (float)(r+2)/fNumberRows * fHeight;
*p++ = (1-(float)(c+1)/fNumberColumns) * w + + kPageConcaveHeight*sind(180*(float)(c+1)/fNumberColumns);
}
for (int c = fNumberColumns; c >= 0; c--)
{
*p++ = (1-ca)*fWidth + ca*(float)c/fNumberColumns * fWidth;
*p++ = (float)(r+1)/fNumberRows * fHeight;
*p++ = (1-(float)c/fNumberColumns) * w + kPageConcaveHeight*sind(180*(float)c/fNumberColumns);
*p++ = (1-ca)*fWidth + ca*(float)c/fNumberColumns * fWidth;
*p++ = (float)r/fNumberRows * fHeight;
*p++ = (1-(float)c/fNumberColumns) * w + kPageConcaveHeight*sind(180*(float)c/fNumberColumns);
}
}
}
/********************************
ViewBook
*********************************/
static const float kPageWidth = 0.210f; // A4 book
static const float kPageHeight = 0.297f;
static const float kPageMinAngle = 4.0f;
static const float kPageMaxAngle = 176.0f;
/* FUNCTION: ViewBook :: ViewBook
ARGUMENTS: frame
RETURN: n/a
DESCRIPTION: Constructor
*/
ViewBook :: ViewBook(BRect frame)
: ViewObject(frame)
{
fStartTime = real_time_clock_usecs();
for (int i=0; i < NUMBER_SOURCES; i++)
fMediaSources[i] = 0;
for (int i=0; i < NUMBER_PAGES; i++)
fPages[i] = 0;
fMouseTracking = false;
fPageAngle = kPageMaxAngle;
}
/* FUNCTION: ViewBook :: ~ViewBook
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
ViewBook :: ~ViewBook()
{
for (int i=0; i < NUMBER_SOURCES; i++)
{
if (fMediaSources[i] != GetDefaultMediaSource())
delete fMediaSources[i];
}
for (int i=0; i < NUMBER_PAGES; i++)
delete fPages[i];
}
/* FUNCTION: ViewBook :: AttachedToWindow
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Hook function called when view attached to window (looper)
*/
void ViewBook :: AttachedToWindow(void)
{
ViewObject::AttachedToWindow();
LockGL();
glClearColor(0,0,0,1);
fPages[PAGE_MIDDLE] = new Paper(kPageWidth, kPageHeight, Paper::FRONT_AND_BACK_FACING);
fPages[PAGE_LEFT] = new Paper(kPageWidth, kPageHeight, Paper::FRONT_FACING);
fPages[PAGE_RIGHT] = new Paper(kPageWidth, kPageHeight, Paper::BACK_FACING);
for (int i=0; i < NUMBER_SOURCES; i++)
fMediaSources[i] = GetDefaultMediaSource();
MediaSource *default_source = GetDefaultMediaSource();
// left page
fPages[PAGE_LEFT]->SetMediaSource(Paper::FRONT_TEXTURE, fMediaSources[0]);
// middle page
fPages[PAGE_MIDDLE]->SetMediaSource(Paper::FRONT_TEXTURE, fMediaSources[1]);
fPages[PAGE_MIDDLE]->SetMediaSource(Paper::BACK_TEXTURE, fMediaSources[2]);
// right page
fPages[PAGE_RIGHT]->SetMediaSource(Paper::BACK_TEXTURE, fMediaSources[3]);
fPages[PAGE_RIGHT]->SetAngle(180);
UnlockGL();
}
/* FUNCTION: ViewBook :: Render
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Draw view contents
*/
void ViewBook :: 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);
// page freefall (gravity)
if (!fMouseTracking && (fPageAngle > kPageMinAngle) && (fPageAngle < kPageMaxAngle))
{
if (fPageAngle < 90)
fPageAngle -= 30*(float)delta/1000000.0f;
else
fPageAngle += 30*(float)delta/1000000.0f;
}
fPages[PAGE_MIDDLE]->SetAngle(fPageAngle);
// Draw pages
glPushMatrix();
glTranslatef(-0.5f*kPageWidth, 0.5f*kPageHeight, 0);
fPages[PAGE_MIDDLE]->Render();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.5f*kPageWidth, 0.5f*kPageHeight, 0);
fPages[PAGE_LEFT]->Render();
glPopMatrix();
glPushMatrix();
glTranslatef(-0.5f*kPageWidth, 0.5f*kPageHeight, 0);
fPages[PAGE_RIGHT]->Render();
glPopMatrix();
glFlush();
SwapBuffers();
// 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: ViewBook :: MouseDown
ARGUMENTS: p
RETURN: n/a
DESCRIPTION: Hook function called when mouse down detected
*/
void ViewBook :: MouseDown(BPoint p)
{
// Determine mouse button
BMessage* msg = Window()->CurrentMessage();
uint32 buttons;
msg->FindInt32("buttons", (int32*)&buttons);
if (buttons & B_PRIMARY_MOUSE_BUTTON)
{
Paper::TEXTURE_SIDE side = Paper::UNASSIGNED_TEXTURE;
Paper *page = GetPage(p.x, p.y, (int *)&side);
if (page == fPages[PAGE_MIDDLE])
{
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
fMouseTracking = true;
}
}
}
/* FUNCTION: ViewBook :: MouseMoved
ARGUMENTS: p
transit
message
RETURN: n/a
DESCRIPTION: Hook function called when mouse move detected
*/
void ViewBook :: MouseMoved(BPoint p, uint32 transit, const BMessage *message)
{
if (fMouseTracking)
{
if (transit == B_INSIDE_VIEW)
{
BRect frame = Bounds();
fPageAngle = 180 * p.x / frame.Width();
if (fPageAngle < kPageMinAngle)
fPageAngle = kPageMinAngle;
if (fPageAngle > kPageMaxAngle)
fPageAngle = kPageMaxAngle;
}
}
}
/* FUNCTION: ViewBook :: MouseUp
ARGUMENTS: p
RETURN: n/a
DESCRIPTION: Hook function called when mouse up detected
*/
void ViewBook :: MouseUp(BPoint p)
{
fMouseTracking = false;
}
/* FUNCTION: ViewBook :: GetPage
ARGUMENTS: mouse_x
mouse_y
RETURN: page corresponding to mouse_x, mouse_y
DESCRIPTION: Determine which page does mouse_x/mouse_y correspond to
*/
Paper * ViewBook :: GetPage(float mouse_x, float mouse_y, int *side)
{
BRect frame = Bounds();
Paper *page = 0;
if (fPageAngle > 90)
{
if (mouse_x < 0.5f*frame.Width())
{
page = fPages[PAGE_LEFT];
*side = Paper::FRONT_TEXTURE;
}
else
{
page = fPages[PAGE_MIDDLE];
*side = Paper::BACK_TEXTURE;
}
}
else
{
if (mouse_x < 0.5f*frame.Width())
{
page = fPages[PAGE_MIDDLE];
*side = Paper::FRONT_TEXTURE;
}
else
{
page = fPages[PAGE_RIGHT];
*side = Paper::BACK_TEXTURE;
}
}
return page;
}
/* FUNCTION: ViewBook :: 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
*/
bool ViewBook :: SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y)
{
Paper::TEXTURE_SIDE side = Paper::UNASSIGNED_TEXTURE;
Paper *page = GetPage(mouse_x, mouse_y, (int *)&side);
LockGL();
int index = -1;
if (page == fPages[PAGE_LEFT])
index = 0;
else if (page == fPages[PAGE_RIGHT])
index = 3;
else if (page == fPages[PAGE_MIDDLE])
{
if (side == Paper::FRONT_TEXTURE)
index = 1;
else if (side == Paper::BACK_TEXTURE)
index = 2;
}
if (index >= 0)
{
if (fMediaSources[index] != GetDefaultMediaSource())
delete fMediaSources[index];
}
page->SetMediaSource(side, source);
fMediaSources[index] = source;
UnlockGL();
return true;
}

51
src/apps/3dmov/ViewBook.h Normal file
View File

@ -0,0 +1,51 @@
/* 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
*/
#ifndef _VIEW_BOOK_H_
#define _VIEW_BOOK_H_
#ifndef _VIEW_OBJECT_H_
#include "ViewObject.h"
#endif
class Paper;
/**********************************
ViewBook displays a book with turnable pages
***********************************/
class ViewBook : public ViewObject
{
public:
ViewBook(BRect frame);
~ViewBook();
void AttachedToWindow();
void MouseDown(BPoint);
void MouseMoved(BPoint p, uint32 transit, const BMessage *message);
void MouseUp(BPoint);
void Render();
bool SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y);
private:
enum
{
PAGE_LEFT = 0,
PAGE_MIDDLE = 1,
PAGE_RIGHT = 2,
NUMBER_PAGES = 3,
NUMBER_SOURCES = 4,
};
Paper *GetPage(float mouse_x, float mouse_y, int *side);
bool fMouseTracking;
float fPageAngle;
bigtime_t fStartTime;
Paper *fPages[NUMBER_PAGES];
MediaSource *fMediaSources[NUMBER_SOURCES];
};
#endif //#ifndef _VIEW_BOOK_H_

353
src/apps/3dmov/ViewCube.cpp Normal file
View File

@ -0,0 +1,353 @@
/* 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 <stdio.h>
#include <string.h>
#include <assert.h>
#include <Bitmap.h>
#include <TranslationUtils.h>
#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;
}

49
src/apps/3dmov/ViewCube.h Normal file
View File

@ -0,0 +1,49 @@
/* 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
*/
#ifndef _VIEW_CUBE_H_
#define _VIEW_CUBE_H_
#ifndef _VIEW_OBJECT_H_
#include "ViewObject.h"
#endif
class Cube;
/**********************************
ViewCube displays a rotating box.
***********************************/
class ViewCube : public ViewObject
{
public:
ViewCube(BRect frame);
~ViewCube();
void AttachedToWindow();
void MouseDown(BPoint);
void MouseMoved(BPoint p, uint32 transit, const BMessage *message);
void MouseUp(BPoint);
void Render();
protected:
bool SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y);
private:
enum
{
NUMBER_FACES = 6,
};
bigtime_t fStartTime;
MediaSource *fMediaSources[NUMBER_FACES];
Cube *fCube;
float fCubeAngle;
float fSpeed;
BPoint fMousePosition;
bool fMouseTracking;
};
#endif //#ifndef _VIEW_CUBE_H_

View File

@ -0,0 +1,372 @@
/* PROJECT: 3Dmov
AUTHORS: Zenja Solaja
COPYRIGHT: 2009 Haiku Inc
DESCRIPTION: Haiku version of the famous BeInc demo 3Dmov
This is the base class for all View shapes.
*/
#include <stdio.h>
#include <assert.h>
#include <GLView.h>
#include <GL/glext.h>
#include <Bitmap.h>
#include <TranslationUtils.h>
#include <TranslatorFormats.h>
#include <Path.h>
#include "Video.h"
#include "GLUtility.h"
#include "ViewObject.h"
// Local definitions
// Local functions
// Local variables
MediaSource* ViewObject::sDefaultMediaSource = NULL;
BBitmap* ViewObject::sDefaultImage = NULL;
static int sCountViewObjects = 0;
/***********************************
MediaSurface
************************************/
/* FUNCTION: MediaSource :: MediaSource
ARGUMENTS: owner
RETURN: n/a
DESCRIPTION: Constructor
*/
MediaSource :: MediaSource(ViewObject *owner)
{
mOwner = owner;
mTextureID = 0;
mVideo = 0;
}
/* FUNCTION: MediaSource :: ~MediaSource
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
MediaSource :: ~MediaSource()
{
if (mTextureID > 0)
glDeleteTextures(1, &mTextureID);
delete mVideo;
}
/* FUNCTION: MediaSurface :: SetVideo
ARGUMENTS: video
RETURN: n/a
DESCRIPTION: Destructor
*/
void MediaSource :: SetVideo(Video *video)
{
mVideo = video;
mVideo->SetMediaSource(this);
}
/***********************************
ViewObject
************************************/
/* FUNCTION: ViewObject :: ViewObject
ARGUMENTS: frame
RETURN: n/a
DESCRIPTION: Constructor
*/
ViewObject :: ViewObject(BRect frame)
: BGLView(frame, (char *) "3Dmov_view", B_FOLLOW_ALL_SIDES, 0, BGL_RGB | BGL_DOUBLE | BGL_DEPTH)
{
sCountViewObjects++;
FrameResized(frame.Width(), frame.Height());
}
/* FUNCTION: ViewObject :: ~ViewObject
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
ViewObject :: ~ViewObject()
{
if (--sCountViewObjects == 0)
{
delete sDefaultMediaSource;
sDefaultMediaSource = 0;
delete sDefaultImage;
}
}
/* FUNCTION: ViewObject :: AttachedToWindow
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Hook function called when view attached to window (looper)
*/
void ViewObject :: AttachedToWindow(void)
{
LockGL();
BGLView::AttachedToWindow();
// init OpenGL state
glClearColor(0, 0, 0, 1);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glDepthFunc(GL_LESS);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// init default texture (drag and drop media files)
if (sDefaultMediaSource == 0)
{
sDefaultImage = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "instructions.png");
sDefaultMediaSource = new MediaSource(this);
glGenTextures(1, &sDefaultMediaSource->mTextureID);
glBindTexture(GL_TEXTURE_2D, sDefaultMediaSource->mTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
int num_bytes;
GLDetermineFormat(sDefaultImage->ColorSpace(), &sDefaultMediaSource->mTextureFormat, &num_bytes);
glTexImage2D(GL_TEXTURE_2D,
0, // mipmap level
num_bytes, // internal format
sDefaultImage->Bounds().IntegerWidth() + 1, // width
sDefaultImage->Bounds().IntegerHeight() + 1, // height
0, // border
sDefaultMediaSource->mTextureFormat, // format of pixel data
GL_UNSIGNED_BYTE, // data type
(unsigned char *) sDefaultImage->Bits()); // pixels
}
MakeFocus(true);
UnlockGL();
}
/* FUNCTION: ViewObject :: FrameResized
ARGUMENTS: width
height
RETURN: n/a
DESCRIPTION: Hook function called when view resized.
Since we have a static camera, we configure it here.
If we had a dynamic camera, then we'd have to reposition
the camera in the derived view.
*/
void ViewObject :: FrameResized(float width, float height)
{
LockGL();
BGLView::FrameResized(width, height);
glViewport(0, 0, (int)width, (int)height);
// Camera projection
glMatrixMode(GL_PROJECTION);
float m[16];
GLCreatePerspectiveMatrix(m, 30, width/height, 0.1f, 10);
glLoadMatrixf(m);
// Camera position
glMatrixMode(GL_MODELVIEW);
GLCreateModelViewMatrix(m, 0, -0.45f, 0.4f, 0, -30);
glLoadMatrixf(m);
UnlockGL();
}
/* FUNCTION: ViewObject :: GLDetermineFormat
ARGUMENTS: cs Haiku colour space
format Equivalent OpenGL format (see glPixelStore)
num_bytes number of bytes needed to store pixel at given format
RETURN: via argument pointers
DESCRIPTION: Haiku colour space is different to OpenGL colour space.
This function will convert it.
*/
void ViewObject :: GLDetermineFormat(color_space cs, GLenum *format, int *num_bytes)
{
switch (cs)
{
case B_RGBA32:
*num_bytes = 4;
*format = GL_BGRA;
break;
case B_RGB32:
*num_bytes = 4;
*format = GL_BGRA;
break;
case B_RGB24:
*num_bytes = 3;
*format = GL_BGR;
break;
case B_RGB15:
case B_RGB16:
*num_bytes = 2;
*format = GL_BGR; // OpenGL supports 4444, 5551, 444 and 555, but BBitmap doesn't
break;
case B_CMAP8:
*num_bytes = 1;
*format = GL_COLOR_INDEX;
break;
case B_GRAY8:
*num_bytes = 1;
*format = GL_LUMINANCE;
break;
default: // all other formats are unsupported
*num_bytes = 4;
*format = GL_RGBA;
}
}
/* FUNCTION: ViewObject :: GLCreateTexture
ARGUMENTS: bitmap
RETURN: OpenGL texture reference
DESCRIPTION: Create an OpenGL texture from a BBitmap.
The client takes ownership of the create media source.
*/
void ViewObject :: GLCreateTexture(MediaSource *media, BBitmap *bitmap)
{
assert(media != 0);
assert(bitmap != 0);
LockGL();
glGenTextures(1, &media->mTextureID);
glBindTexture(GL_TEXTURE_2D, media->mTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
int num_bytes;
GLDetermineFormat(bitmap->ColorSpace(), &media->mTextureFormat, &num_bytes);
media->mTextureWidth = (int)(bitmap->Bounds().Width() + 1);
media->mTextureHeight = (int)(bitmap->Bounds().Height() + 1);
glTexImage2D(GL_TEXTURE_2D,
0, // mipmap level
num_bytes, // internal format
media->mTextureWidth, // width
media->mTextureHeight, // height
0, // border
media->mTextureFormat, // format of pixel data
GL_UNSIGNED_BYTE, // data type
(unsigned char *)bitmap->Bits()); // pixels
UnlockGL();
}
/* FUNCTION: ViewObject :: Render
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Should be overriden by derived class
*/
void ViewObject :: Render(void)
{
LockGL();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// derived class should draw something here
glFlush();
SwapBuffers();
UnlockGL();
}
/* FUNCTION: ViewObject :: DragDrop
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Hook function called when user drops files in application window.
Essentially, determine if file is image or video.
*/
void ViewObject :: DragDrop(entry_ref *ref, float mouse_x, float mouse_y)
{
// Image file?
BPath path(ref);
BBitmap *bitmap = BTranslationUtils::GetBitmap(path.Path(), NULL);
if (bitmap)
{
MediaSource *media = new MediaSource(this);
GLCreateTexture(media, bitmap);
if (!SurfaceUpdate(media, mouse_x, mouse_y))
delete media;
delete bitmap;
return;
}
// Video file
Video *video = new Video(ref);
if (video->GetStatus() == B_OK)
{
MediaSource *media = new MediaSource(this);
GLCreateTexture(media, video->GetBitmap());
media->SetVideo(video);
if (SurfaceUpdate(media, mouse_x, mouse_y))
video->Start();
else
delete media;
return;
}
else
delete video;
printf("Unsupported file\n");
}
/* FUNCTION: ViewObject :: UpdateFrame
ARGUMENTS: source
RETURN: n/a
DESCRIPTION: Called by Video thread - update video texture
*/
void ViewObject :: UpdateFrame(MediaSource *source)
{
LockGL();
glBindTexture(GL_TEXTURE_2D, source->mTextureID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, source->mTextureWidth, source->mTextureHeight,
source->mTextureFormat, GL_UNSIGNED_BYTE, source->mVideo->GetBitmap()->Bits());
UnlockGL();
}
/* FUNCTION: ViewObject :: ToggleWireframe
ARGUMENTS: enable
RETURN: n/a
DESCRIPTION: Switch beteeen wireframe and fill polygon modes
*/
void ViewObject :: ToggleWireframe(bool enable)
{
LockGL();
if (enable)
glPolygonMode(GL_FRONT, GL_LINE);
else
glPolygonMode(GL_FRONT, GL_FILL);
UnlockGL();
}
/* FUNCTION: ViewObject :: GLCheckError
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Check for OpenGL errors
*/
void ViewObject :: GLCheckError()
{
GLenum err;
LockGL();
while ((err = glGetError()) != GL_NO_ERROR)
{
printf("[GL Error] ");
switch (err)
{
case GL_INVALID_ENUM: printf("GL_INVALID_ENUM\n"); break;
case GL_INVALID_VALUE: printf("GL_INVALID_VALUE\n"); break;
case GL_INVALID_OPERATION: printf("GL_INVALID_OPERATION\n"); break;
case GL_STACK_OVERFLOW: printf("GL_STACK_OVERFLOW\n"); break;
case GL_STACK_UNDERFLOW: printf("GL_STACK_UNDERFLOW\n"); break;
case GL_OUT_OF_MEMORY: printf("GL_OUT_OF_MEMORY\n"); break;
default: printf("%d\n", err); break;
}
}
UnlockGL();
}

View File

@ -0,0 +1,77 @@
/* 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
This is the base class for all 3Dmov objects.
As a bare minimum, the derived classes need to implement the Render() method.
*/
#ifndef _VIEW_OBJECT_H_
#define _VIEW_OBJECT_H_
#include <GLView.h>
class BBitmap;
class Video;
class ViewObject;
/**********************************
MediaSource can be an image or video.
A ViewObject can contain multiple media sources (eg. a cube has 6)
***********************************/
class MediaSource
{
public:
MediaSource(ViewObject *owner);
~MediaSource();
void SetVideo(Video *video);
GLuint mTextureID; // OpenGL handle to texture
GLenum mTextureFormat; // OpenGL texture format
int mTextureWidth;
int mTextureHeight;
ViewObject *mOwner;
Video *mVideo; // video decoder
};
/**********************************
A ViewObject is the base class for various 3Dmov shapes.
The shapes will typically override the Render method.
***********************************/
class ViewObject : public BGLView
{
public:
ViewObject(BRect frame);
virtual ~ViewObject();
virtual void AttachedToWindow(void);
virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint) {}
virtual void MouseMoved(BPoint p, uint32 transit, const BMessage *message = NULL) {}
virtual void MouseUp(BPoint) {}
virtual void Render(void);
void DragDrop(entry_ref *ref, float mouse_x, float mouse_y);
void UpdateFrame(MediaSource *source); // called by video thread
void ToggleWireframe(bool enable);
void GLCheckError();
protected:
virtual bool SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y) {return false;}
MediaSource *GetDefaultMediaSource() {return sDefaultMediaSource;}
private:
void GLDetermineFormat(color_space cs, GLenum *format, int *num_bytes);
void GLCreateTexture(MediaSource *source, BBitmap *bitmap);
static MediaSource *sDefaultMediaSource; // instructions image, shared to conserve resources
static BBitmap* sDefaultImage;
};
#endif //#ifndef _VIEW_OBJECT_H_

View File

@ -0,0 +1,322 @@
/* 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 <stdio.h>
#include <assert.h>
#include <Bitmap.h>
#include <TranslationUtils.h>
#include "GLUtility.h"
#include "ViewSphere.h"
// Local definitions
// Local functions
// Local variables
/********************************
Sphere scene
*********************************/
class Sphere
{
public:
Sphere(const float radius, const int stacks = 10, const int slices = 10);
~Sphere();
void Render();
void SetMediaSource(MediaSource *source) {fMediaSource = source;}
void SetAngle(float angle_y, float angle_z);
private:
MediaSource *fMediaSource;
int fNumberVertices;
float *fGeometry;
float *fTextureCoords;
float fRotationY, fRotationZ;
};
/* FUNCTION: Sphere :: Sphere
ARGUMENTS: radius
stacks vertical stacks
slices horizontal slices
RETURN: n/a
DESCRIPTION: Constructor
*/
Sphere :: Sphere(const float radius, const int stacks, const int slices)
{
fGeometry = 0;
fTextureCoords = 0;
fMediaSource = 0;
fRotationY = 0;
fRotationZ = 0;
fNumberVertices = 2*stacks*(slices+1);
fGeometry = new float [fNumberVertices*3];
fTextureCoords = new float [fNumberVertices*2];
float *v = fGeometry;
float *t = fTextureCoords;
float z0, z1, r0, r1;
float x, y, z;
//YVector3 normal; // not used in 3Dmov, but useful to know
for (int i=0; i < stacks; i++)
{
z0 = (float)i/(float)stacks;
z1 = (float)(i+1)/(float)stacks;
r0 = radius * sind(180 * (float)i/(float)stacks);
r1 = radius * sind(180 * (float)(i+1)/(float)stacks);
for (int j=0; j < (slices + 1); j++)
{
x = sind(360.0f * (float)j/(float)slices);
y = cosd(360.0f * (float)j/(float)slices);
z = radius * cosd(180*z0);
// Vertices
*v++ = x * r0;
*v++ = -y * r0;
*v++ = z;
// Normal not used in 3Dmov, but if you ever need it
//normal.Set(x*r0, -y*r0, z);
//normal.Normalise();
// Textures
*t++ = (float)j/(float)slices;
*t++ = z0;
z = radius * cosd(180*z1);
// Vertices
*v++ = x * r1;
*v++ = -y * r1;
*v++ = z;
// Normals not used in 3Dmov, but if you ever need it
//normal.Set(x*r1, -y*r1, z);
//normal.Normalise();
// Textures
*t++ = (float)j/(float)slices;
*t++ = z1;
}
}
}
/* FUNCTION: Sphere :: ~Sphere
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor. fMediaSource destroyed by ViewSphere
*/
Sphere :: ~Sphere()
{
delete [] fGeometry;
delete [] fTextureCoords;
}
/* FUNCTION: Sphere :: SetAngle
ARGUMENTS: angle_y
angle_z
RETURN: n/a
DESCRIPTION: Rotate sphere by Euler angles
*/
void Sphere :: SetAngle(float angle_y, float angle_z)
{
fRotationY = angle_y;
fRotationZ = angle_z;
}
/* FUNCTION: Sphere :: Render
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Draw sphere
*/
void Sphere :: Render()
{
glColor4f(1,1,1,1);
glBindTexture(GL_TEXTURE_2D, fMediaSource->mTextureID);
glPushMatrix();
glRotatef(-30, 1, 0, 0);
glRotatef(fRotationY, 0, 1, 0);
glRotatef(fRotationZ, 0, 0, 1);
glTexCoordPointer(2, GL_FLOAT, 0, fTextureCoords);
glVertexPointer(3, GL_FLOAT, 0, fGeometry);
glDrawArrays(GL_TRIANGLE_STRIP, 0, fNumberVertices);
glPopMatrix();
}
/********************************
ViewSphere
*********************************/
/* FUNCTION: ViewSphere :: ViewSphere
ARGUMENTS: frame
RETURN: n/a
DESCRIPTION: Constructor
*/
ViewSphere :: ViewSphere(BRect frame)
: ViewObject(frame)
{
fStartTime = real_time_clock_usecs();
fSphere = 0;
fMediaSource = 0;
fSpeedZ = 10.0f;
fSpeedY = 0.0f;
fAngleY = 0;
fAngleZ = 0;
}
/* FUNCTION: ViewSphere :: ~ViewSphere
ARGUMENTS: n/a
RETURN: n/a
DESCRIPTION: Destructor
*/
ViewSphere :: ~ViewSphere()
{
delete fSphere;
if (fMediaSource != GetDefaultMediaSource())
delete fMediaSource;
}
/* FUNCTION: ViewSphere :: AttachedToWindow
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Hook function called when view attached to window (looper)
*/
void ViewSphere :: AttachedToWindow(void)
{
ViewObject::AttachedToWindow();
LockGL();
glClearColor(0,0,0,1);
fSphere = new Sphere(0.1f, 10, 10);
fMediaSource = GetDefaultMediaSource();
fSphere->SetMediaSource(fMediaSource);
UnlockGL();
}
/* FUNCTION: ViewSphere :: Render
ARGUMENTS: none
RETURN: n/a
DESCRIPTION: Draw view contents
*/
void ViewSphere :: 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);
fAngleY += fSpeedY*(float)delta/1000000.0f;
fAngleZ += fSpeedZ*(float)delta/1000000.0f;
fSphere->SetAngle(fAngleY, fAngleZ);
glPushMatrix();
glTranslatef(0.0f, 0.0f, 0.15f);
fSphere->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: ViewSphere :: MouseDown
ARGUMENTS: p
RETURN: n/a
DESCRIPTION: Hook function called when mouse down detected
*/
void ViewSphere :: 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: ViewSphere :: MouseMoved
ARGUMENTS: p
transit
message
RETURN: n/a
DESCRIPTION: Hook function called when mouse move detected.
This demo is succeptable to Gimbal lock, but it doesn't really matter.
*/
void ViewSphere :: MouseMoved(BPoint p, uint32 transit, const BMessage *message)
{
if (fMouseTracking)
{
if (transit == B_INSIDE_VIEW)
{
fSpeedY = 5*(p.y - fMousePosition.y);
fSpeedZ = 5*(p.x - fMousePosition.x);
fMousePosition = p;
}
}
}
/* FUNCTION: ViewSphere :: MouseUp
ARGUMENTS: p
RETURN: n/a
DESCRIPTION: Hook function called when mouse up detected
*/
void ViewSphere :: 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
*/
bool ViewSphere :: SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y)
{
LockGL();
if (fMediaSource != GetDefaultMediaSource())
delete fMediaSource;
fMediaSource = source;
fSphere->SetMediaSource(source);
UnlockGL();
return true;
}

View File

@ -0,0 +1,45 @@
/* 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
*/
#ifndef _VIEW_SPHERE_H_
#define _VIEW_SPHERE_H_
#ifndef _VIEW_OBJECT_H_
#include "ViewObject.h"
#endif
class Sphere;
/**********************************
ViewSphere displays a rotating sphere.
***********************************/
class ViewSphere : public ViewObject
{
public:
ViewSphere(BRect frame);
~ViewSphere();
void AttachedToWindow();
void MouseDown(BPoint);
void MouseMoved(BPoint p, uint32 transit, const BMessage *message);
void MouseUp(BPoint);
void Render();
protected:
bool SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y);
private:
bigtime_t fStartTime;
MediaSource *fMediaSource;
Sphere *fSphere;
bool fMouseTracking;
BPoint fMousePosition;
float fAngleY, fAngleZ;
float fSpeedY, fSpeedZ;
};
#endif //#ifndef _VIEW_SPHERE_H_

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB