/* * PolyCamera.cpp * Poly * * Created by Ivan Safrin on 3/26/08. * Copyright 2008 Ivan Safrin. All rights reserved. * */ #include "PolyCamera.h" using namespace Polycode; Camera::Camera(Scene *parentScene) : SceneEntity() { setParentScene(parentScene); orthoMode = false; fov = 45.0f; exposureLevel = 1.0f; _hasFilterShader = false; fovSet = false; } Camera::~Camera() { } void Camera::setExposureLevel(float level) { exposureLevel = level; } float Camera::getExposureLevel() { return exposureLevel; } void Camera::setFOV(float fov) { this->fov = fov; fovSet = true; } float Camera::getFOV() { return fov; } bool Camera::isSphereInFrustrum(Vector3 pos, float fRadius) { for( int i = 0; i < 6; ++i ) { if( frustumPlanes[i][0] * pos.x + frustumPlanes[i][1] * pos.y + frustumPlanes[i][2] * pos.z + frustumPlanes[i][3] <= -fRadius ) return false; } return true; } void Camera::setOrthoMode(bool mode) { orthoMode = mode; } bool Camera::getOrthoMode() { return orthoMode; } void Camera::buildFrustrumPlanes() { Matrix4 p; Matrix4 mv; Matrix4 mvp; float t; p = CoreServices::getInstance()->getRenderer()->getProjectionMatrix(); mv = CoreServices::getInstance()->getRenderer()->getModelviewMatrix(); // // Concatenate the projection matrix and the model-view matrix to produce // a combined model-view-projection matrix. // mvp.ml[ 0] = mv.ml[ 0] * p.ml[ 0] + mv.ml[ 1] * p.ml[ 4] + mv.ml[ 2] * p.ml[ 8] + mv.ml[ 3] * p.ml[12]; mvp.ml[ 1] = mv.ml[ 0] * p.ml[ 1] + mv.ml[ 1] * p.ml[ 5] + mv.ml[ 2] * p.ml[ 9] + mv.ml[ 3] * p.ml[13]; mvp.ml[ 2] = mv.ml[ 0] * p.ml[ 2] + mv.ml[ 1] * p.ml[ 6] + mv.ml[ 2] * p.ml[10] + mv.ml[ 3] * p.ml[14]; mvp.ml[ 3] = mv.ml[ 0] * p.ml[ 3] + mv.ml[ 1] * p.ml[ 7] + mv.ml[ 2] * p.ml[11] + mv.ml[ 3] * p.ml[15]; mvp.ml[ 4] = mv.ml[ 4] * p.ml[ 0] + mv.ml[ 5] * p.ml[ 4] + mv.ml[ 6] * p.ml[ 8] + mv.ml[ 7] * p.ml[12]; mvp.ml[ 5] = mv.ml[ 4] * p.ml[ 1] + mv.ml[ 5] * p.ml[ 5] + mv.ml[ 6] * p.ml[ 9] + mv.ml[ 7] * p.ml[13]; mvp.ml[ 6] = mv.ml[ 4] * p.ml[ 2] + mv.ml[ 5] * p.ml[ 6] + mv.ml[ 6] * p.ml[10] + mv.ml[ 7] * p.ml[14]; mvp.ml[ 7] = mv.ml[ 4] * p.ml[ 3] + mv.ml[ 5] * p.ml[ 7] + mv.ml[ 6] * p.ml[11] + mv.ml[ 7] * p.ml[15]; mvp.ml[ 8] = mv.ml[ 8] * p.ml[ 0] + mv.ml[ 9] * p.ml[ 4] + mv.ml[10] * p.ml[ 8] + mv.ml[11] * p.ml[12]; mvp.ml[ 9] = mv.ml[ 8] * p.ml[ 1] + mv.ml[ 9] * p.ml[ 5] + mv.ml[10] * p.ml[ 9] + mv.ml[11] * p.ml[13]; mvp.ml[10] = mv.ml[ 8] * p.ml[ 2] + mv.ml[ 9] * p.ml[ 6] + mv.ml[10] * p.ml[10] + mv.ml[11] * p.ml[14]; mvp.ml[11] = mv.ml[ 8] * p.ml[ 3] + mv.ml[ 9] * p.ml[ 7] + mv.ml[10] * p.ml[11] + mv.ml[11] * p.ml[15]; mvp.ml[12] = mv.ml[12] * p.ml[ 0] + mv.ml[13] * p.ml[ 4] + mv.ml[14] * p.ml[ 8] + mv.ml[15] * p.ml[12]; mvp.ml[13] = mv.ml[12] * p.ml[ 1] + mv.ml[13] * p.ml[ 5] + mv.ml[14] * p.ml[ 9] + mv.ml[15] * p.ml[13]; mvp.ml[14] = mv.ml[12] * p.ml[ 2] + mv.ml[13] * p.ml[ 6] + mv.ml[14] * p.ml[10] + mv.ml[15] * p.ml[14]; mvp.ml[15] = mv.ml[12] * p.ml[ 3] + mv.ml[13] * p.ml[ 7] + mv.ml[14] * p.ml[11] + mv.ml[15] * p.ml[15]; // // Extract the frustum's right clipping plane and normalize it. // frustumPlanes[0][0] = mvp.ml[ 3] - mvp.ml[ 0]; frustumPlanes[0][1] = mvp.ml[ 7] - mvp.ml[ 4]; frustumPlanes[0][2] = mvp.ml[11] - mvp.ml[ 8]; frustumPlanes[0][3] = mvp.ml[15] - mvp.ml[12]; t = (float) sqrt( frustumPlanes[0][0] * frustumPlanes[0][0] + frustumPlanes[0][1] * frustumPlanes[0][1] + frustumPlanes[0][2] * frustumPlanes[0][2] ); frustumPlanes[0][0] /= t; frustumPlanes[0][1] /= t; frustumPlanes[0][2] /= t; frustumPlanes[0][3] /= t; // // Extract the frustum's left clipping plane and normalize it. // frustumPlanes[1][0] = mvp.ml[ 3] + mvp.ml[ 0]; frustumPlanes[1][1] = mvp.ml[ 7] + mvp.ml[ 4]; frustumPlanes[1][2] = mvp.ml[11] + mvp.ml[ 8]; frustumPlanes[1][3] = mvp.ml[15] + mvp.ml[12]; t = (float) sqrt( frustumPlanes[1][0] * frustumPlanes[1][0] + frustumPlanes[1][1] * frustumPlanes[1][1] + frustumPlanes[1][2] * frustumPlanes[1][2] ); frustumPlanes[1][0] /= t; frustumPlanes[1][1] /= t; frustumPlanes[1][2] /= t; frustumPlanes[1][3] /= t; // // Extract the frustum's bottom clipping plane and normalize it. // frustumPlanes[2][0] = mvp.ml[ 3] + mvp.ml[ 1]; frustumPlanes[2][1] = mvp.ml[ 7] + mvp.ml[ 5]; frustumPlanes[2][2] = mvp.ml[11] + mvp.ml[ 9]; frustumPlanes[2][3] = mvp.ml[15] + mvp.ml[13]; t = (float) sqrt( frustumPlanes[2][0] * frustumPlanes[2][0] + frustumPlanes[2][1] * frustumPlanes[2][1] + frustumPlanes[2][2] * frustumPlanes[2][2] ); frustumPlanes[2][0] /= t; frustumPlanes[2][1] /= t; frustumPlanes[2][2] /= t; frustumPlanes[2][3] /= t; // // Extract the frustum's top clipping plane and normalize it. // frustumPlanes[3][0] = mvp.ml[ 3] - mvp.ml[ 1]; frustumPlanes[3][1] = mvp.ml[ 7] - mvp.ml[ 5]; frustumPlanes[3][2] = mvp.ml[11] - mvp.ml[ 9]; frustumPlanes[3][3] = mvp.ml[15] - mvp.ml[13]; t = (float) sqrt( frustumPlanes[3][0] * frustumPlanes[3][0] + frustumPlanes[3][1] * frustumPlanes[3][1] + frustumPlanes[3][2] * frustumPlanes[3][2] ); frustumPlanes[3][0] /= t; frustumPlanes[3][1] /= t; frustumPlanes[3][2] /= t; frustumPlanes[3][3] /= t; // // Extract the frustum's far clipping plane and normalize it. // frustumPlanes[4][0] = mvp.ml[ 3] - mvp.ml[ 2]; frustumPlanes[4][1] = mvp.ml[ 7] - mvp.ml[ 6]; frustumPlanes[4][2] = mvp.ml[11] - mvp.ml[10]; frustumPlanes[4][3] = mvp.ml[15] - mvp.ml[14]; t = (float) sqrt( frustumPlanes[4][0] * frustumPlanes[4][0] + frustumPlanes[4][1] * frustumPlanes[4][1] + frustumPlanes[4][2] * frustumPlanes[4][2] ); frustumPlanes[4][0] /= t; frustumPlanes[4][1] /= t; frustumPlanes[4][2] /= t; frustumPlanes[4][3] /= t; // // Extract the frustum's near clipping plane and normalize it. // frustumPlanes[5][0] = mvp.ml[ 3] + mvp.ml[ 2]; frustumPlanes[5][1] = mvp.ml[ 7] + mvp.ml[ 6]; frustumPlanes[5][2] = mvp.ml[11] + mvp.ml[10]; frustumPlanes[5][3] = mvp.ml[15] + mvp.ml[14]; t = (float) sqrt( frustumPlanes[5][0] * frustumPlanes[5][0] + frustumPlanes[5][1] * frustumPlanes[5][1] + frustumPlanes[5][2] * frustumPlanes[5][2] ); frustumPlanes[5][0] /= t; frustumPlanes[5][1] /= t; frustumPlanes[5][2] /= t; frustumPlanes[5][3] /= t; } bool Camera::canSee(SceneEntity *entity) { return isSphereInFrustrum(*entity->getPosition(), entity->getBBoxRadius()); } void Camera::setParentScene(Scene *parentScene) { this->parentScene = parentScene; } void Camera::setPostFilter(string shaderName) { Material *shaderMaterial = (Material*) CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_MATERIAL, shaderName); if(shaderMaterial) createPostFilter(shaderMaterial); } void Camera::createPostFilter(Material *shaderMaterial) { if(!shaderMaterial) return; if(shaderMaterial->getNumShaders() == 0) return; this->filterShaderMaterial = shaderMaterial; // TODO: make it save the textures to resource manager and check if they there // originalSceneTexture = CoreServices::getInstance()->getMaterialManager()->createNewTexture(CoreServices::getInstance()->getCore()->getXRes(), CoreServices::getInstance()->getCore()->getYRes()); // zBufferSceneTexture = CoreServices::getInstance()->getMaterialManager()->createFramebufferTexture(CoreServices::getInstance()->getCore()->getXRes(), CoreServices::getInstance()->getCore()->getYRes(), 0); CoreServices::getInstance()->getRenderer()->createRenderTextures(&originalSceneTexture, &zBufferSceneTexture, CoreServices::getInstance()->getCore()->getXRes(), CoreServices::getInstance()->getCore()->getYRes()); for(int i=0; i < shaderMaterial->getNumShaders(); i++) { ShaderBinding* binding = shaderMaterial->getShader(i)->createBinding(); binding->addTexture("PolySceneRender", originalSceneTexture); binding->addTexture("PolySceneZBuffer", zBufferSceneTexture); localShaderOptions.push_back(binding); } _hasFilterShader = true; } bool Camera::hasFilterShader() { return _hasFilterShader; } void Camera::setLightDepthTexture(Texture *texture) { for(int i=0; i < localShaderOptions.size(); i++) { localShaderOptions[i]->clearTexture("PolyLight0ZBuffer"); localShaderOptions[i]->addTexture("PolyLight0ZBuffer", texture); } } void Camera::drawFilter() { if(!filterShaderMaterial) return; CoreServices::getInstance()->getRenderer()->bindFrameBufferTexture(zBufferSceneTexture); parentScene->Render(); CoreServices::getInstance()->getRenderer()->unbindFramebuffers(); ShaderBinding* materialBinding; for(int i=0; i < filterShaderMaterial->getNumShaders(); i++) { materialBinding = filterShaderMaterial->getShaderBinding(i); CoreServices::getInstance()->getRenderer()->applyMaterial(filterShaderMaterial, localShaderOptions[i], i); if(i==filterShaderMaterial->getNumShaders()-1) { CoreServices::getInstance()->getRenderer()->clearScreen(); CoreServices::getInstance()->getRenderer()->loadIdentity(); CoreServices::getInstance()->getRenderer()->drawScreenQuad(CoreServices::getInstance()->getRenderer()->getXRes(), CoreServices::getInstance()->getRenderer()->getYRes()); } else { for(int j=0; j < materialBinding->getNumOutTargetBindings(); j++) { CoreServices::getInstance()->getRenderer()->bindFrameBufferTexture(materialBinding->getOutTargetBinding(j)->texture); CoreServices::getInstance()->getRenderer()->drawScreenQuad(materialBinding->getOutTargetBinding(j)->width, materialBinding->getOutTargetBinding(j)->height); CoreServices::getInstance()->getRenderer()->unbindFramebuffers(); } } CoreServices::getInstance()->getRenderer()->clearShader(); CoreServices::getInstance()->getRenderer()->loadIdentity(); } } void Camera::doCameraTransform() { if(fovSet) CoreServices::getInstance()->getRenderer()->setFOV(fov); CoreServices::getInstance()->getRenderer()->setExposureLevel(exposureLevel); if(matrixDirty) { rebuildTransformMatrix(); } Matrix4 camMatrix = getConcatenatedMatrix(); CoreServices::getInstance()->getRenderer()->setCameraMatrix(camMatrix); camMatrix = camMatrix.inverse(); CoreServices::getInstance()->getRenderer()->multModelviewMatrix(camMatrix); }