kick
/Users/morten/Programmering/cpp/kick/src/kick/scene/camera.cpp
00001 //
00002 //  camera.cpp
00003 //  KickCPP
00004 //
00005 //  Created by morten on 8/12/13.
00006 //  Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved.
00007 //
00008 
00009 #include "kick/scene/camera.h"
00010 #include <iostream>
00011 #include <glm/ext.hpp>
00012 #include <cmath>
00013 #include <algorithm>
00014 #include "kick/scene/game_object.h"
00015 #include "kick/scene/transform.h"
00016 #include "kick/scene/scene.h"
00017 #include "kick/scene/component_renderable.h"
00018 #include "kick/texture/texture_render_target.h"
00019 #include "kick/core/engine.h"
00020 #include "kick/scene/light.h"
00021 #include "kick/math/misc.h"
00022 #include "kick/material/material.h"
00023 #include "kick/core/debug.h"
00024 #include "time.h"
00025 
00026 using namespace std;
00027 using namespace glm;
00028 
00029 namespace kick {
00030     
00031     Camera::Camera(GameObject *gameObject)
00032     :Component(gameObject){
00033         Scene* scene = gameObject->scene();
00034         componentListener = scene->componentEvents.createListener([&](pair<std::shared_ptr<Component>, ComponentUpdateStatus> value){
00035             auto r = std::dynamic_pointer_cast<ComponentRenderable>(value.first);
00036             if (r) {
00037                 if (value.second == ComponentUpdateStatus::Created) {
00038                     mRenderableComponents.push_back(r);
00039 
00040                 } else if (value.second == ComponentUpdateStatus::Destroyed) {
00041                     auto iter = find(mRenderableComponents.begin(), mRenderableComponents.end(), r);
00042                     if (iter != mRenderableComponents.end()) {
00043                         mRenderableComponents.erase(iter);
00044                     }
00045                 }
00046             }
00047         });
00048         createComponentList();
00049     }
00050 
00051     Camera::~Camera() {
00052         destroyShadowMap();
00053         delete mPickingRenderTarget;
00054     }
00055     
00056 
00057     
00058     void Camera::createComponentList(){
00059         mRenderableComponents.clear();
00060         for (auto & gameObject_ : *gameObject()->scene()) {
00061             for (auto & component :  *gameObject_){
00062                 auto r = std::dynamic_pointer_cast<ComponentRenderable>(component);
00063                 if (r){
00064                     mRenderableComponents.push_back(r);
00065                 }
00066             }
00067         }
00068     }
00069 
00070     void Camera::deactivated(){
00071         // remove listener
00072         componentListener = {};
00073     }
00074     
00075     glm::vec4 Camera::clearColor(){
00076         return mClearColor;
00077     }
00078     
00079     void Camera::setClearColor(glm::vec4 clearColor){
00080         this->mClearColor = clearColor;
00081     }
00082     
00083     void Camera::setupViewport(vec2 &offset, vec2 &dim){
00084         offset = round(offset);
00085         dim = round(dim);
00086         int offsetX = (int)offset.x;
00087         int offsetY = (int)offset.y;
00088         int width = (int)dim.x;
00089         int height = (int)dim.y;
00090         glViewport(offsetX, offsetY, width, height);
00091         glScissor(offsetX, offsetY, width, height);
00092     }
00093     
00094     void Camera::setupCamera(EngineUniforms *engineUniforms) {
00095 
00096         vec2 viewportDimension = (vec2)/*renderTarget? renderTarget.dimension : */ engineUniforms->viewportDimension.getValue();
00097         vec2 offset = viewportDimension * mNormalizedViewportOffset;
00098         vec2 dim = viewportDimension * mNormalizedViewportDim;
00099         setupViewport(offset, dim);
00100         if (mClearFlag) {
00101             if (clearColorBuffer()) {
00102                 glClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a);
00103             }
00104             glClear(mClearFlag);
00105         }
00106 
00107         engineUniforms->viewMatrix = viewMatrix();
00108         engineUniforms->viewProjectionMatrix = mProjectionMatrix * engineUniforms->viewMatrix;
00109         engineUniforms->projectionMatrix = mProjectionMatrix;
00110     }
00111 
00112     glm::mat4 Camera::viewMatrix(){
00113         return mGameObject->transform()->globalTRSInverse();
00114     }
00115 
00116     void Camera::renderShadowMap(Light* directionalLight){
00117 
00118     }
00119     
00120     void Camera::render(EngineUniforms *engineUniforms){
00121         auto sceneLights = engineUniforms->sceneLights;
00122         engineUniforms->currentCameraTransform = transform().get();
00123 
00124         if (mShadow && sceneLights->directionalLight && sceneLights->directionalLight->shadowType() != ShadowType::None) {
00125             renderShadowMap(sceneLights->directionalLight.get());
00126         }
00127 
00128         if (mTarget){
00129             mTarget->bind();
00130         }
00131         bool customViewport = mNormalizedViewportOffset != vec2{0} || mNormalizedViewportDim != vec2{1};
00132         if (customViewport){
00133             glEnable(GL_SCISSOR_TEST);
00134         }
00135         setupCamera(engineUniforms);
00136         engineUniforms->sceneLights->recomputeLight(engineUniforms->viewMatrix);
00137         auto components = cull();
00138 
00139         sort(components.begin(), components.end(), [](ComponentRenderable* r1, ComponentRenderable* r2){
00140             return r1->renderOrder() < r2->renderOrder();
00141         });
00142 
00143         for (auto c : components){
00144             c->render(engineUniforms, mReplacementMaterial.get());
00145         }
00146         if (mTarget){
00147             mTarget->unbind();
00148         }
00149 
00150         if (mPickQueue.size() > 0){
00151             handleObjectPicking(engineUniforms, components);
00152         }
00153         if (customViewport){
00154             glDisable(GL_SCISSOR_TEST);
00155         }
00156     }
00157 
00158     void Camera::handleObjectPicking(EngineUniforms *engineUniforms, std::vector<ComponentRenderable*>& components) {
00159         auto viewportSize = engineUniforms->viewportDimension.getValue();
00160         if (mPickingRenderTarget == nullptr || viewportSize != mPickingRenderTarget->size()){
00161             delete mPickingRenderTarget;
00162             mPickingRenderTarget = new TextureRenderTarget();
00163             mPickingRenderTarget->setSize(viewportSize);
00164             if (mPickingTexture == nullptr){
00165                 mPickingTexture = make_shared<Texture2D>();
00166             }
00167             ImageFormat imageFormat{};
00168             imageFormat.mipmap = Mipmap::None;
00169             TextureSampler sampler{};
00170             sampler.filterMag = TextureFilter::Nearest;
00171             sampler.filterMin = TextureFilter::Nearest;
00172             sampler.wrapS = TextureWrap::ClampToEdge;
00173             sampler.wrapT = TextureWrap::ClampToEdge;
00174             mPickingTexture->setTextureSampler(sampler);
00175             mPickingTexture->setData(viewportSize.x, viewportSize.y, nullptr, imageFormat);
00176 
00177             mPickingRenderTarget->setColorTexture(0, mPickingTexture);
00178             if (mPickingMaterial.get() == nullptr){
00179                 mPickingMaterial = std::shared_ptr<Material>(new Material());
00180                 mPickingMaterial->setShader(Project::loadShader("assets/shaders/__pick.shader"));
00181             }
00182             mPickingRenderTarget->apply();
00183             glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00184             glPixelStorei(GL_PACK_ALIGNMENT, 1);
00185         }
00186         mPickingRenderTarget->bind();
00187         glClearColor(0, 0, 0, 0);
00188         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00189         for (auto c : components){
00190             c->render(engineUniforms, mPickingMaterial.get());
00191         }
00192         for (auto q : mPickQueue){
00193             vector<glm::u8vec4> data((int)(q.size.x * q.size.y));
00194             glReadPixels(q.point.x, q.point.y, q.size.x, q.size.y, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) glm::value_ptr(*data.data()));
00195             std::map<int,int> gameObjectFrequency;
00196             for (auto p : data){
00197                 int uid = vec4ToUint32(p);
00198                 if (uid != 0){
00199                     auto iter = gameObjectFrequency.find(uid);
00200                     if (iter != gameObjectFrequency.end()){
00201                         iter->second++;
00202                     } else {
00203                         gameObjectFrequency.insert(pair<int,int>(uid,1));
00204                     }
00205                 }
00206             }
00207             auto scene = mGameObject->scene();
00208             for (auto uid : gameObjectFrequency){
00209                 auto hitGameObject = scene->gameObjectByUID(uid.first);
00210                 if (hitGameObject) {
00211                     q.onPicked(hitGameObject, uid.second);
00212                 }
00213             }
00214             if (gameObjectFrequency.empty() && q.returnNullptrOnNoHit){
00215                 q.onPicked(nullptr, 0);
00216             }
00217         }
00218         mPickingRenderTarget->unbind();
00219         mPickQueue.clear();
00220     }
00221 
00222     void Camera::setClearColorBuffer(bool clear){
00223         if (clear){
00224             mClearFlag |= GL_COLOR_BUFFER_BIT;
00225         } else {
00226             mClearFlag &= ~GL_COLOR_BUFFER_BIT;
00227         }
00228     }
00229     
00230     bool Camera::clearColorBuffer(){
00231         return (bool) (mClearFlag & GL_COLOR_BUFFER_BIT);
00232     }
00233     
00234     void Camera::setClearDepthBuffer(bool clear){
00235         if (clear){
00236             mClearFlag |= GL_DEPTH_BUFFER_BIT;
00237         } else {
00238             mClearFlag &= ~GL_DEPTH_BUFFER_BIT;
00239         }
00240     }
00241     
00242     bool Camera::clearDepthBuffer(){
00243         return (bool) (mClearFlag & GL_DEPTH_BUFFER_BIT);
00244     }
00245     
00246     void Camera::setClearStencilBuffer(bool clear){
00247         if (clear){
00248             mClearFlag |= GL_STENCIL_BUFFER_BIT;
00249         } else {
00250             mClearFlag &= ~GL_STENCIL_BUFFER_BIT;
00251         }
00252     }
00253     
00254     bool Camera::clearStencilBuffer(){
00255         return (bool) (mClearFlag & GL_STENCIL_BUFFER_BIT);
00256     }
00257 
00258     glm::mat4 Camera::projectionMatrix() {
00259         return mProjectionMatrix;
00260     }
00261 
00262     void Camera::setProjectionMatrix(glm::mat4 projectionMatrix) {
00263         this->mProjectionMatrix = projectionMatrix;
00264     }
00265 
00266     void Camera::resetProjectionMatrix(){
00267     }
00268 
00269     bool Camera::shadow() const {
00270         return mShadow;
00271     }
00272 
00273     void Camera::setShadow(bool renderShadow) {
00274         if (Camera::mShadow != renderShadow) {
00275             Camera::mShadow = renderShadow;
00276             if (renderShadow){
00277                 initShadowMap();
00278             } else {
00279                 destroyShadowMap();
00280             }
00281         }
00282     }
00283 
00284     void Camera::initShadowMap() {
00285         mShadowMapShader = Project::loadShader("assets/shaders/__shadowmap.shader");
00286         mShadowMapMaterial = new Material();
00287         mShadowMapMaterial->setShader(mShadowMapShader);
00288     }
00289 
00290     void Camera::destroyShadowMap() {
00291     }
00292 
00293     int Camera::cullingMask() const {
00294         return mCullingMask;
00295     }
00296 
00297     void Camera::setCullingMask(int cullingMask) {
00298         Camera::mCullingMask = cullingMask;
00299     }
00300 
00301     TextureRenderTarget *Camera::target() const {
00302         return mTarget;
00303     }
00304 
00305     void Camera::setTarget(TextureRenderTarget *target) {
00306         Camera::mTarget = target;
00307     }
00308 
00309     void Camera::pick(glm::ivec2 point, std::function<void(GameObject*,int)> onPicked, glm::ivec2 size, bool returnNullptrOnNoHit){
00310         mPickQueue.push_back({point, size, onPicked, returnNullptrOnNoHit});
00311     }
00312 
00313     std::shared_ptr<Material> const &Camera::replacementMaterial() const {
00314         return mReplacementMaterial;
00315     }
00316 
00317     void Camera::setReplacementMaterial(std::shared_ptr<Material> const &replacementMaterial) {
00318         Camera::mReplacementMaterial = replacementMaterial;
00319     }
00320 
00321     glm::vec2 const &Camera::viewportOffset() const {
00322         return mNormalizedViewportOffset;
00323     }
00324 
00325     void Camera::setViewportOffset(glm::vec2 const &normalizedViewportOffset) {
00326         Camera::mNormalizedViewportOffset = normalizedViewportOffset;
00327     }
00328 
00329     glm::vec2 const &Camera::viewportDim() const {
00330         return mNormalizedViewportDim;
00331     }
00332 
00333     void Camera::setViewportDim(glm::vec2 const &normalizedViewportDim) {
00334         Camera::mNormalizedViewportDim = normalizedViewportDim;
00335     }
00336 
00337     Ray Camera::screenPointToRay(glm::vec2 point){
00338 
00339         vec3 zoomDirection = transform()->forward();
00340 
00341         vec2 surfaceDim = (vec2)(Engine::context()->getContextSurfaceDim());
00342         vec3 mousePosNormalizedNear{(vec2(point) / surfaceDim)*2.0f-vec2(1.0f),1.0f};
00343         vec3 mousePosNormalizedFar{(vec2(point) / surfaceDim)*2.0f-vec2(1.0f),-1.0f};
00344         // inverse
00345         mousePosNormalizedNear.y *=-1;
00346         mousePosNormalizedFar.y *=-1;
00347 
00348         mat4 invProjection = inverse(projectionMatrix());
00349         mat4 invView = transform()->globalMatrix();
00350 
00351         vec4 mousePosViewNear = invProjection * vec4(mousePosNormalizedNear, 1.0);
00352         vec4 mousePosViewFar = invProjection * vec4(mousePosNormalizedFar, 1.0);
00353         mousePosViewNear /= 1.0f/mousePosViewNear.w;
00354         mousePosViewFar /= 1.0f/mousePosViewFar.w;
00355         mousePosViewNear.w = 1;
00356         mousePosViewFar.w = 1;
00357 
00358         vec4 mousePosWorldNear = invView * mousePosViewNear;
00359         vec4 mousePosWorldFar = invView * mousePosViewFar;
00360 
00361         return Ray{(vec3)mousePosWorldNear, normalize((vec3)mousePosWorldFar - (vec3)mousePosWorldNear)};
00362     }
00363 
00364     bool Camera::main() {return mMainCamera;}
00365 
00366     void Camera::setMain(bool main) { mMainCamera = main;}
00367 
00368     int Camera::index() {return mIndex;}
00369 
00370     void Camera::setIndex(int index) {mIndex = index;}
00371 
00372     std::vector<ComponentRenderable *> Camera::cull() {
00373         std::vector<ComponentRenderable *> res;
00374         for (auto c : mRenderableComponents){
00375             if (c->gameObject()->layer() & mCullingMask) {
00376                 res.push_back(c.get());
00377             }
00378         }
00379         return res;
00380     }
00381 
00382     std::shared_ptr<Camera> Camera::mainCamera() {
00383         return Engine::activeScene()->mainCamera();
00384     }
00385 }
 All Classes Functions Variables