1/*
2 * Copyright 2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * 		Alexandre Deckner <alex@zappotek.com>
7 */
8
9#include "RenderView.h"
10
11#include "BitmapTexture.h"
12#include "Camera.h"
13#include "MeshInstance.h"
14#include "StaticMesh.h"
15#include "VideoFileTexture.h"
16
17#include <GL/gl.h>
18#include <GL/glu.h>
19
20#include <TranslationKit.h>
21#include <TranslationUtils.h>
22
23#include <stdio.h>
24
25RenderView::RenderView(BRect frame)
26	:
27	BGLView(frame, "renderView", B_FOLLOW_ALL, B_WILL_DRAW,
28		BGL_RGB | BGL_DOUBLE | BGL_DEPTH),
29	fMainCamera(NULL),
30	fRenderThread(-1),
31	fStopRendering(false),
32	fRes(0, 0),
33	fNextRes(0, 0),
34	fLastFrameTime(0)
35{
36}
37
38
39RenderView::~RenderView()
40{
41}
42
43
44void
45RenderView::AttachedToWindow()
46{
47	BGLView::AttachedToWindow();
48
49	_CreateScene();
50	_InitGL();
51	if (_CreateRenderThread() != B_OK)
52		printf("Error trying to start the render thread!\n");
53}
54
55
56void
57RenderView::DetachedFromWindow()
58{
59	_StopRenderThread();
60	_DeleteScene();
61
62	BGLView::DetachedFromWindow();
63}
64
65
66uint32
67RenderView::_CreateRenderThread()
68{
69	fRenderThread = spawn_thread(RenderView::_RenderThreadEntry, "renderThread",
70		B_NORMAL_PRIORITY, this);
71
72	if (fRenderThread < 0)
73		return fRenderThread;
74
75	return resume_thread(fRenderThread);
76}
77
78
79void
80RenderView::_StopRenderThread()
81{
82	LockGL();
83	fStopRendering = true;
84	UnlockGL();
85
86	if (fRenderThread >= 0)
87		wait_for_thread(fRenderThread, NULL);
88}
89
90
91int32
92RenderView::_RenderThreadEntry(void* pointer)
93{
94	return reinterpret_cast<RenderView*>(pointer)->_RenderLoop();
95}
96
97
98int32
99RenderView::_RenderLoop()
100{
101	fLastFrameTime = system_time();
102
103	while (_Render()) {
104		snooze(10000);
105	}
106	return B_OK;
107}
108
109
110void RenderView::_InitGL(void)
111{
112	LockGL();
113
114	float position[] = {0.0, 3.0, 6.0, 0.0};
115	float local_view[] = {0.0, 0.0};
116
117	glLightfv(GL_LIGHT0, GL_POSITION, position);
118	glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
119
120	float white[3] = {1.0, 1.0, 1.0};
121
122	glEnable(GL_LIGHT0);
123	glLightfv(GL_LIGHT0, GL_SPECULAR, white);
124	glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
125	glLightfv(GL_LIGHT0, GL_AMBIENT, white);
126
127	glMaterialf(GL_FRONT, GL_SHININESS, 0.6 * 128.0);
128
129	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
130	glEnable(GL_CULL_FACE);
131	glEnable(GL_DEPTH_TEST);
132	glEnable(GL_LIGHTING);
133	glEnable(GL_TEXTURE_2D);
134
135	fNextRes.Set(Bounds().Width(), Bounds().Height());
136	_UpdateViewport();
137
138	UnlockGL();
139}
140
141
142void
143RenderView::_CreateScene()
144{
145	LockGL();
146
147	Texture* texture = new BitmapTexture(
148		BTranslationUtils::GetBitmap(B_PNG_FORMAT, "texture"));
149
150	float spacing = 1.6f;
151	float timeSpacing = 5.0f;
152	float yOffset = -1.0f;
153	float zOffset = -16;
154
155	Mesh* mesh = new StaticMesh("LetterH");
156	MeshInstance* instance = new MeshInstance(mesh, texture,
157		Vector3(-3.6 * spacing, yOffset, zOffset),
158		Quaternion(0, 0, 0, 1), 0.0f);
159	fMeshInstances.push_back(instance);
160	mesh->ReleaseReference();
161
162	mesh = new StaticMesh("LetterA");
163	instance = new MeshInstance(mesh, texture,
164		Vector3(-1.6 * spacing, yOffset, zOffset),
165		Quaternion(0, 0, 0, 1), 1.0f * timeSpacing);
166	fMeshInstances.push_back(instance);
167	mesh->ReleaseReference();
168
169	mesh = new StaticMesh("LetterI");
170	instance = new MeshInstance(mesh, texture,
171		Vector3(0 * spacing, yOffset, zOffset),
172		Quaternion(0, 0, 0, 1), 2.0f * timeSpacing);
173	fMeshInstances.push_back(instance);
174	mesh->ReleaseReference();
175
176	mesh = new StaticMesh("LetterK");
177	instance = new MeshInstance(mesh, texture,
178		Vector3(1.5 * spacing, yOffset, zOffset),
179		Quaternion(0, 0, 0, 1), 3.0f * timeSpacing);
180	fMeshInstances.push_back(instance);
181	mesh->ReleaseReference();
182
183	mesh = new StaticMesh("LetterU");
184	instance = new MeshInstance(mesh, texture,
185		Vector3(3.4 * spacing, yOffset, zOffset),
186		Quaternion(0, 0, 0, 1), 4.0f * timeSpacing);
187	fMeshInstances.push_back(instance);
188	mesh->ReleaseReference();
189	texture->ReleaseReference();
190
191	fMainCamera = new Camera(Vector3(0, 0, 0), Quaternion(0, 0, 0, 1), 50);
192
193	UnlockGL();
194}
195
196
197void
198RenderView::_DeleteScene()
199{
200	LockGL();
201
202	MeshInstanceList::iterator it = fMeshInstances.begin();
203	for (; it != fMeshInstances.end(); it++) {
204		delete (*it);
205	}
206	fMeshInstances.clear();
207
208	UnlockGL();
209}
210
211
212void
213RenderView::_UpdateViewport()
214{
215	if (fNextRes != fRes && fNextRes.x >= 1.0 && fNextRes.y >= 1.0) {
216		glViewport(0, 0, (GLint) fNextRes.x + 1, (GLint) fNextRes.y + 1);
217		fRes = fNextRes;
218		_UpdateCamera();
219	}
220}
221
222
223void
224RenderView::_UpdateCamera()
225{
226	// TODO: take camera orientation into account
227	glMatrixMode(GL_PROJECTION);
228	glLoadIdentity();
229	gluPerspective(fMainCamera->FieldOfView(), fNextRes.x / fNextRes.y,
230		fMainCamera->Near(), fMainCamera->Far());
231	glMatrixMode(GL_MODELVIEW);
232}
233
234
235bool
236RenderView::_Render()
237{
238	LockGL();
239
240	_UpdateViewport();
241
242	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
243	glLoadIdentity();
244
245	bigtime_t time = system_time();
246	float deltaTime = 0.000001 * (float)(time - fLastFrameTime);
247	fLastFrameTime = time;
248
249	MeshInstanceList::iterator it = fMeshInstances.begin();
250	for (; it != fMeshInstances.end(); it++) {
251		(*it)->Update(deltaTime);
252		(*it)->Render();
253	}
254
255	if (fStopRendering) {
256		UnlockGL();
257		return false;
258	}
259	SwapBuffers(false); // true = vsync
260	UnlockGL();
261	return true;
262}
263
264
265void
266RenderView::FrameResized(float width, float height)
267{
268	LockGL();
269	fNextRes.Set(width, height);
270	UnlockGL();
271	BGLView::FrameResized(width, height);
272}
273
274
275void
276RenderView::ErrorCallback(unsigned long error)
277{
278	fprintf(stderr, "OpenGL error (%lu): %s\n", error, gluErrorString(error));
279}
280