/* * Copyright 2008, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Alexandre Deckner */ #include "RenderView.h" #include "BitmapTexture.h" #include "Camera.h" #include "MeshInstance.h" #include "StaticMesh.h" #include "VideoFileTexture.h" #include #include #include #include #include RenderView::RenderView(BRect frame) : BGLView(frame, "renderView", B_FOLLOW_ALL, B_WILL_DRAW, BGL_RGB | BGL_DOUBLE | BGL_DEPTH), fMainCamera(NULL), fRenderThread(-1), fStopRendering(false), fRes(0, 0), fNextRes(0, 0), fLastFrameTime(0) { } RenderView::~RenderView() { } void RenderView::AttachedToWindow() { BGLView::AttachedToWindow(); _CreateScene(); _InitGL(); if (_CreateRenderThread() != B_OK) printf("Error trying to start the render thread!\n"); } void RenderView::DetachedFromWindow() { _StopRenderThread(); _DeleteScene(); BGLView::DetachedFromWindow(); } uint32 RenderView::_CreateRenderThread() { fRenderThread = spawn_thread(RenderView::_RenderThreadEntry, "renderThread", B_NORMAL_PRIORITY, this); if (fRenderThread < 0) return fRenderThread; return resume_thread(fRenderThread); } void RenderView::_StopRenderThread() { LockGL(); fStopRendering = true; UnlockGL(); if (fRenderThread >= 0) wait_for_thread(fRenderThread, NULL); } int32 RenderView::_RenderThreadEntry(void* pointer) { return reinterpret_cast(pointer)->_RenderLoop(); } int32 RenderView::_RenderLoop() { fLastFrameTime = system_time(); while (_Render()) { snooze(10000); } return B_OK; } void RenderView::_InitGL(void) { LockGL(); float position[] = {0.0, 3.0, 6.0, 0.0}; float local_view[] = {0.0, 0.0}; glLightfv(GL_LIGHT0, GL_POSITION, position); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); float white[3] = {1.0, 1.0, 1.0}; glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_SPECULAR, white); glLightfv(GL_LIGHT0, GL_DIFFUSE, white); glLightfv(GL_LIGHT0, GL_AMBIENT, white); glMaterialf(GL_FRONT, GL_SHININESS, 0.6 * 128.0); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); fNextRes.Set(Bounds().Width(), Bounds().Height()); _UpdateViewport(); UnlockGL(); } void RenderView::_CreateScene() { LockGL(); Texture* texture = new BitmapTexture( BTranslationUtils::GetBitmap(B_PNG_FORMAT, "texture")); float spacing = 1.6f; float timeSpacing = 5.0f; float yOffset = -1.0f; float zOffset = -16; Mesh* mesh = new StaticMesh("LetterH"); MeshInstance* instance = new MeshInstance(mesh, texture, Vector3(-3.6 * spacing, yOffset, zOffset), Quaternion(0, 0, 0, 1), 0.0f); fMeshInstances.push_back(instance); mesh->ReleaseReference(); mesh = new StaticMesh("LetterA"); instance = new MeshInstance(mesh, texture, Vector3(-1.6 * spacing, yOffset, zOffset), Quaternion(0, 0, 0, 1), 1.0f * timeSpacing); fMeshInstances.push_back(instance); mesh->ReleaseReference(); mesh = new StaticMesh("LetterI"); instance = new MeshInstance(mesh, texture, Vector3(0 * spacing, yOffset, zOffset), Quaternion(0, 0, 0, 1), 2.0f * timeSpacing); fMeshInstances.push_back(instance); mesh->ReleaseReference(); mesh = new StaticMesh("LetterK"); instance = new MeshInstance(mesh, texture, Vector3(1.5 * spacing, yOffset, zOffset), Quaternion(0, 0, 0, 1), 3.0f * timeSpacing); fMeshInstances.push_back(instance); mesh->ReleaseReference(); mesh = new StaticMesh("LetterU"); instance = new MeshInstance(mesh, texture, Vector3(3.4 * spacing, yOffset, zOffset), Quaternion(0, 0, 0, 1), 4.0f * timeSpacing); fMeshInstances.push_back(instance); mesh->ReleaseReference(); texture->ReleaseReference(); fMainCamera = new Camera(Vector3(0, 0, 0), Quaternion(0, 0, 0, 1), 50); UnlockGL(); } void RenderView::_DeleteScene() { LockGL(); MeshInstanceList::iterator it = fMeshInstances.begin(); for (; it != fMeshInstances.end(); it++) { delete (*it); } fMeshInstances.clear(); UnlockGL(); } void RenderView::_UpdateViewport() { if (fNextRes != fRes && fNextRes.x >= 1.0 && fNextRes.y >= 1.0) { glViewport(0, 0, (GLint) fNextRes.x + 1, (GLint) fNextRes.y + 1); fRes = fNextRes; _UpdateCamera(); } } void RenderView::_UpdateCamera() { // TODO: take camera orientation into account glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fMainCamera->FieldOfView(), fNextRes.x / fNextRes.y, fMainCamera->Near(), fMainCamera->Far()); glMatrixMode(GL_MODELVIEW); } bool RenderView::_Render() { LockGL(); _UpdateViewport(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); bigtime_t time = system_time(); float deltaTime = 0.000001 * (float)(time - fLastFrameTime); fLastFrameTime = time; MeshInstanceList::iterator it = fMeshInstances.begin(); for (; it != fMeshInstances.end(); it++) { (*it)->Update(deltaTime); (*it)->Render(); } if (fStopRendering) { UnlockGL(); return false; } SwapBuffers(false); // true = vsync UnlockGL(); return true; } void RenderView::FrameResized(float width, float height) { LockGL(); fNextRes.Set(width, height); UnlockGL(); BGLView::FrameResized(width, height); } void RenderView::ErrorCallback(unsigned long error) { fprintf(stderr, "OpenGL error (%lu): %s\n", error, gluErrorString(error)); }