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