1/*	PROJECT:		3Dmov
2	AUTHORS:		Zenja Solaja
3	COPYRIGHT:		2009 Haiku Inc
4	DESCRIPTION:	Haiku version of the famous BeInc demo 3Dmov
5					Just drag'n'drop media files to the 3D objects
6*/
7
8#include <stdio.h>
9#include <string.h>
10#include <assert.h>
11
12#include <Bitmap.h>
13#include <TranslationUtils.h>
14
15#include "GLUtility.h"
16#include "ViewCube.h"
17
18//	Local definitions
19
20// 	Local functions
21
22//	Local variables
23
24/********************************
25	Cube scene
26*********************************/
27class Cube
28{
29public:
30	enum FACE
31	{
32		FACE_RIGHT,
33		FACE_LEFT,
34		FACE_FRONT,
35		FACE_BACK,
36		FACE_TOP,
37		FACE_BOTTOM,
38		NUMBER_CUBE_FACES,
39	};
40			Cube(const float half_extent);
41			~Cube();
42	void	Render();
43	void	SetMediaSource(FACE face, MediaSource *source) {fMediaSources[face] = source;}
44	void	SetAngle(float angle_x, float angle_y, float angle_z);
45
46private:
47	MediaSource		*fMediaSources[NUMBER_CUBE_FACES];
48	float			fRotationX, fRotationY, fRotationZ;
49	float			*fGeometry;
50};
51
52/*	FUNCTION:		Cube :: Cube
53	ARGUMENTS:		half_extent
54	RETURN:			n/a
55	DESCRIPTION:	Constructor
56*/
57Cube :: Cube(const float half_extent)
58{
59	for (int i=0; i < NUMBER_CUBE_FACES; i++)
60		fMediaSources[i] = 0;
61	fRotationX = fRotationY = fRotationZ = 0;
62
63	const float kVertices[NUMBER_CUBE_FACES][4][3] =
64	{
65		{	// FACE_RIGHT
66			{half_extent, -half_extent, -half_extent},
67			{half_extent, half_extent, -half_extent},
68			{half_extent, -half_extent, half_extent},
69			{half_extent, half_extent, half_extent},
70		},
71		{	// FACE_LEFT
72			{-half_extent, half_extent, -half_extent},
73			{-half_extent, -half_extent, -half_extent},
74			{-half_extent, half_extent, half_extent},
75			{-half_extent, -half_extent, half_extent},
76		},
77		{	// FACE_FRONT
78			{-half_extent, -half_extent, -half_extent},
79			{half_extent, -half_extent, -half_extent},
80			{-half_extent, -half_extent, half_extent},
81			{half_extent, -half_extent, half_extent},
82		},
83		{	// FACE_BACK
84			{half_extent, half_extent, -half_extent},
85			{-half_extent, half_extent, -half_extent},
86			{half_extent, half_extent, half_extent},
87			{-half_extent, half_extent, half_extent},
88		},
89		{	// FACE_TOP
90			{-half_extent, -half_extent, half_extent},
91			{half_extent, -half_extent, half_extent},
92			{-half_extent, half_extent, half_extent},
93			{half_extent, half_extent, half_extent},
94		},
95		{	// FACE_BOTTOM
96			{-half_extent, half_extent, -half_extent},
97			{half_extent, half_extent, -half_extent},
98			{-half_extent, -half_extent, -half_extent},
99			{half_extent, -half_extent, -half_extent},
100		},
101	};
102	fGeometry = new float [sizeof(kVertices)/sizeof(float)];
103	memcpy(fGeometry, kVertices, sizeof(kVertices));
104}
105
106/*	FUNCTION:		Cube :: ~Cube
107	ARGUMENTS:		n/a
108	RETURN:			n/a
109	DESCRIPTION:	Destructor - fMediaSources owned by ViewCube
110*/
111Cube :: ~Cube()
112{
113	delete [] fGeometry;
114}
115
116/*	FUNCTION:		Cube :: SetAngle
117	ARGUMENTS:		angle_x
118					angle_y
119					angle_z
120	RETURN:			n/a
121	DESCRIPTION:	Rotate cube by Euler angles
122*/
123void Cube :: SetAngle(float angle_x, float angle_y, float angle_z)
124{
125	fRotationX = angle_x;
126	fRotationY = angle_y;
127	fRotationZ = angle_z;
128}
129
130/*	FUNCTION:		Cube :: Render
131	ARGUMENTS:		none
132	RETURN:			n/a
133	DESCRIPTION:	Draw sphere
134*/
135void Cube :: Render()
136{
137	const float kTextureCoords[4*2] =
138	{
139		0.0f, 1.0f,
140		1.0f, 1.0f,
141		0.0f, 0.0f,
142		1.0f, 0.0f,
143	};
144
145	glPushMatrix();
146	glRotatef(fRotationX, 1, 0, 0);
147	glRotatef(fRotationY, 0, 1, 0);
148	glRotatef(fRotationZ, 0, 0, 1);
149
150	glColor4f(1,1,1,1);
151	for (int i=0; i < NUMBER_CUBE_FACES; i++)
152	{
153		glBindTexture(GL_TEXTURE_2D, fMediaSources[i]->mTextureID);
154		glTexCoordPointer(2, GL_FLOAT, 0, kTextureCoords);
155		glVertexPointer(3, GL_FLOAT, 0, fGeometry + i*3*4);
156		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
157	}
158	glPopMatrix();
159}
160
161/********************************
162	ViewCube
163*********************************/
164
165/*	FUNCTION:		ViewCube :: ViewCube
166	ARGUMENTS:		frame
167	RETURN:			n/a
168	DESCRIPTION:	Constructor
169*/
170ViewCube :: ViewCube(BRect frame)
171	: ViewObject(frame)
172{
173	fStartTime = real_time_clock_usecs();
174
175	for (int i=0; i < NUMBER_FACES; i++)
176		fMediaSources[i] = 0;
177	fCube = 0;
178	fSpeed = 10;
179	fMouseTracking = false;
180}
181
182/*	FUNCTION:		ViewCube :: ~ViewCube
183	ARGUMENTS:		n/a
184	RETURN:			n/a
185	DESCRIPTION:	Destructor
186*/
187ViewCube :: ~ViewCube()
188{
189	delete fCube;
190	for (int i=0; i < NUMBER_FACES; i++)
191	{
192		if (fMediaSources[i] != GetDefaultMediaSource())
193			delete fMediaSources[i];
194	}
195}
196
197/*	FUNCTION:		ViewCube :: ViewCube
198	ARGUMENTS:		none
199	RETURN:			n/a
200	DESCRIPTION:	Hook function called when view attached to window (looper)
201*/
202void ViewCube :: AttachedToWindow(void)
203{
204	ViewObject::AttachedToWindow();
205
206	LockGL();
207	glClearColor(0,0,0,1);
208
209	fCube = new Cube(0.075f);
210
211	for (int i=0; i < NUMBER_FACES; i++)
212	{
213		fMediaSources[i] = GetDefaultMediaSource();
214		fCube->SetMediaSource((Cube::FACE) i, fMediaSources[i]);
215	}
216
217	UnlockGL();
218}
219
220/*	FUNCTION:		ViewCube :: Render
221	ARGUMENTS:		none
222	RETURN:			n/a
223	DESCRIPTION:	Draw view contents
224*/
225void ViewCube :: Render(void)
226{
227	LockGL();
228
229	bigtime_t	current_time = real_time_clock_usecs();
230	bigtime_t	delta = current_time - fStartTime;
231	fStartTime = current_time;
232
233	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
234
235	fCubeAngle += fSpeed*(float)delta/1000000.0f;
236	fCube->SetAngle(0, 0, fCubeAngle);
237
238	glPushMatrix();
239	glTranslatef(0.0f, 0.0f, 0.15f);
240	fCube->Render();
241	glPopMatrix();
242
243	glFlush();
244	SwapBuffers();
245
246	//	Display frame rate
247	/*
248	static int fps = 0;
249	static int time_delta = 0;
250	fps++;
251	time_delta += delta;
252	if (time_delta > 1000000)
253	{
254		printf("%d fps\n", fps);
255		fps = 0;
256		time_delta = 0;
257	}
258	*/
259	UnlockGL();
260}
261
262/*	FUNCTION:		ViewCube :: MouseDown
263	ARGUMENTS:		p
264	RETURN:			n/a
265	DESCRIPTION:	Hook function called when mouse down detected
266*/
267void ViewCube :: MouseDown(BPoint p)
268{
269	//	Determine mouse button
270	BMessage* msg = Window()->CurrentMessage();
271	uint32 buttons;
272
273	msg->FindInt32("buttons", (int32*)&buttons);
274
275	if (buttons & B_PRIMARY_MOUSE_BUTTON)
276	{
277		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
278		fMouseTracking = true;
279		fMousePosition = p;
280	}
281}
282
283/*	FUNCTION:		ViewCube :: MouseMoved
284	ARGUMENTS:		p
285					transit
286					message
287	RETURN:			n/a
288	DESCRIPTION:	Hook function called when mouse move detected
289*/
290void ViewCube :: MouseMoved(BPoint p, uint32 transit, const BMessage *message)
291{
292	if (fMouseTracking)
293	{
294		if (transit == B_INSIDE_VIEW)
295		{
296			fSpeed = 5.0f*(p.x - fMousePosition.x);
297			fMousePosition = p;
298		}
299	}
300
301}
302
303/*	FUNCTION:		ViewSphere :: MouseUp
304	ARGUMENTS:		p
305	RETURN:			n/a
306	DESCRIPTION:	Hook function called when mouse up detected
307*/
308void ViewCube :: MouseUp(BPoint p)
309{
310	fMouseTracking = false;
311}
312
313/*	FUNCTION:		ViewSphere :: DragDropImage
314	ARGUMENTS:		texture_id
315					mouse_x
316					mouse_y
317	RETURN:			true if source ownership acquired
318	DESCRIPTION:	Hook function called when user drags/drops image to app window.
319					TODO - actually determine exact face where refs received.  For this
320					release, we only rely on current fCubeAngle.
321*/
322bool ViewCube :: SurfaceUpdate(MediaSource *source, float mouse_x, float mouse_y)
323{
324	// determine face
325	BRect frame = Bounds();
326	Cube::FACE face = Cube::NUMBER_CUBE_FACES;
327
328	if (mouse_y < frame.Height()*0.33f)
329		face = Cube::FACE_TOP;
330	else
331	{
332		if (fCubeAngle < 45)
333			face = Cube::FACE_FRONT;
334		else if (fCubeAngle < 135)
335			face = Cube::FACE_LEFT;
336		else if (fCubeAngle < 225)
337			face = Cube::FACE_BACK;
338		else if (fCubeAngle < 315)
339			face = Cube::FACE_RIGHT;
340		else
341			face = Cube::FACE_FRONT;
342	}
343	if (fMediaSources[face] != GetDefaultMediaSource())
344		delete fMediaSources[face];
345	fMediaSources[face] = source;
346	fCube->SetMediaSource(face, source);
347
348	return true;
349}
350
351
352
353
354