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:
parent
0e81d474e7
commit
43a75cae5c
@ -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";
|
||||
|
63
src/apps/3dmov/Application.cpp
Normal file
63
src/apps/3dmov/Application.cpp
Normal 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;
|
||||
}
|
244
src/apps/3dmov/GLUtility.cpp
Normal file
244
src/apps/3dmov/GLUtility.cpp
Normal 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);
|
||||
}
|
58
src/apps/3dmov/GLUtility.h
Normal file
58
src/apps/3dmov/GLUtility.h
Normal 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_
|
@ -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
|
||||
;
|
||||
|
248
src/apps/3dmov/MainWindow.cpp
Normal file
248
src/apps/3dmov/MainWindow.cpp
Normal 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
|
||||
}
|
||||
|
46
src/apps/3dmov/MainWindow.h
Normal file
46
src/apps/3dmov/MainWindow.h
Normal 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
208
src/apps/3dmov/Video.cpp
Normal 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
45
src/apps/3dmov/Video.h
Normal 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
525
src/apps/3dmov/ViewBook.cpp
Normal 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
51
src/apps/3dmov/ViewBook.h
Normal 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
353
src/apps/3dmov/ViewCube.cpp
Normal 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
49
src/apps/3dmov/ViewCube.h
Normal 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_
|
372
src/apps/3dmov/ViewObject.cpp
Normal file
372
src/apps/3dmov/ViewObject.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
77
src/apps/3dmov/ViewObject.h
Normal file
77
src/apps/3dmov/ViewObject.h
Normal 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_
|
||||
|
||||
|
322
src/apps/3dmov/ViewSphere.cpp
Normal file
322
src/apps/3dmov/ViewSphere.cpp
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
45
src/apps/3dmov/ViewSphere.h
Normal file
45
src/apps/3dmov/ViewSphere.h
Normal 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_
|
BIN
src/apps/3dmov/instructions.png
Normal file
BIN
src/apps/3dmov/instructions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
Loading…
Reference in New Issue
Block a user