Files
kraken/KREngine/KREngine/Classes/KRCamera.cpp
2012-08-15 21:26:06 +00:00

899 lines
31 KiB
C++

//
// KRSettings.cpp
// KREngine
//
// Copyright 2012 Kearwood Gilbert. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Kearwood Gilbert.
//
#import <string>
#include <iostream>
#include <sstream>
#include <fstream>
#import "KRVector2.h"
#import "KRCamera.h"
#import "KRBoundingVolume.h"
KRCamera::KRCamera() {
double const PI = 3.141592653589793f;
double const D2R = PI * 2 / 360;
bShowShadowBuffer = false;
bEnablePerPixel = true;
bEnableDiffuseMap = true;
bEnableNormalMap = true;
bEnableSpecMap = true;
bEnableReflectionMap = true;
bDebugPSSM = false;
bEnableAmbient = true;
bEnableDiffuse = true;
bEnableSpecular = true;
bEnableLightMap = true;
bDebugSuperShiny = false;
bEnableDeferredLighting = true;
dAmbientR = 0.0f;
dAmbientG = 0.0f;
dAmbientB = 0.0f;
dSunR = 1.0f;
dSunG = 1.0f;
dSunB = 1.0f;
perspective_fov = 45.0 * D2R;
perspective_nearz = 5.0f;
perspective_farz = 100.0f;
dof_quality = 0;
dof_depth = 0.05f;
dof_falloff = 0.05f;
bEnableFlash = false;
flash_intensity = 1.0f;
flash_depth = 0.7f;
flash_falloff = 0.5f;
bEnableVignette = false;
vignette_radius = 0.4f;
vignette_falloff = 1.0f;
m_cShadowBuffers = 0;
memset(shadowFramebuffer, sizeof(GLuint) * 3, 0);
memset(shadowDepthTexture, sizeof(GLuint) * 3, 0);
m_postShaderProgram = 0;
m_iFrame = 0;
}
KRCamera::~KRCamera() {
invalidatePostShader();
destroyBuffers();
}
KRMat4 KRCamera::getProjectionMatrix() {
KRMat4 projectionMatrix;
projectionMatrix.perspective(perspective_fov, m_viewportSize.x / m_viewportSize.y, perspective_nearz, perspective_farz);
return projectionMatrix;
}
const KRVector2 &KRCamera::getViewportSize() {
return m_viewportSize;
}
void KRCamera::setViewportSize(const KRVector2 &size) {
m_viewportSize = size;
}
KRVector3 KRCamera::getPosition() const {
return m_position;
}
void KRCamera::setPosition(const KRVector3 &position) {
m_position = position;
}
void KRCamera::renderFrame(KRContext &context, KRScene &scene, KRMat4 &viewMatrix)
{
KRMat4 invViewMatrix = viewMatrix;
invViewMatrix.invert();
KRVector3 cameraPosition = KRMat4::Dot(invViewMatrix, KRVector3(0.0,0.0,0.0));
KRVector3 lightDirection(0.0, 0.0, 1.0);
// ----- Render Model -----
KRMat4 shadowvp;
shadowvp.rotate(scene.sun_pitch, X_AXIS);
shadowvp.rotate(scene.sun_yaw, Y_AXIS);
lightDirection = KRMat4::Dot(shadowvp, lightDirection);
shadowvp.invert();
lightDirection.normalize();
allocateShadowBuffers();
int iOffset=m_iFrame % m_cShadowBuffers;
for(int iShadow2=iOffset; iShadow2 < m_cShadowBuffers + iOffset; iShadow2++) {
int iShadow = iShadow2 % m_cShadowBuffers;
GLfloat shadowMinDepths[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.05, 0.3}};
GLfloat shadowMaxDepths[3][3] = {{0.0, 0.0, 1.0},{0.1, 0.0, 0.0},{0.1, 0.3, 1.0}};
KRMat4 newShadowMVP;
if(shadowMaxDepths[m_cShadowBuffers - 1][iShadow] == 0.0) {
KRBoundingVolume ext = KRBoundingVolume(scene.getExtents(&context));
newShadowMVP = ext.calcShadowProj(&scene, &context, scene.sun_yaw, scene.sun_pitch);
} else {
KRBoundingVolume frustrumSliceVolume = KRBoundingVolume(viewMatrix, perspective_fov, getViewportSize().x / getViewportSize().y, perspective_nearz + (perspective_farz - perspective_nearz) * shadowMinDepths[m_cShadowBuffers - 1][iShadow], perspective_nearz + (perspective_farz - perspective_nearz) * shadowMaxDepths[m_cShadowBuffers - 1][iShadow]);
newShadowMVP = frustrumSliceVolume.calcShadowProj(&scene, &context, scene.sun_yaw, scene.sun_pitch);
}
if(!(shadowmvpmatrix[iShadow] == newShadowMVP)) {
shadowValid[iShadow] = false;
}
if(!shadowValid[iShadow]) {
shadowValid[iShadow] = true;
shadowmvpmatrix[iShadow] = newShadowMVP;
renderShadowBuffer(context, scene, iShadow);
break;
}
}
renderFrame(context, scene, viewMatrix, lightDirection, cameraPosition);
renderPost(context);
m_iFrame++;
}
void KRCamera::renderFrame(KRContext &context, KRScene &scene, KRMat4 &viewMatrix, KRVector3 &lightDirection, KRVector3 &cameraPosition) {
setViewportSize(KRVector2(backingWidth, backingHeight));
KRBoundingVolume frustrumVolume = KRBoundingVolume(viewMatrix, perspective_fov, getViewportSize().x / getViewportSize().y, perspective_nearz, perspective_farz);
if(bEnableDeferredLighting) {
// ----====---- Opaque Geometry, Deferred rendering Pass 1 ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Enable backface culling
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
// Enable z-buffer write
glDepthMask(GL_TRUE);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthRangef(0.0, 1.0);
// Disable alpha blending
glDisable(GL_BLEND);
// Render the geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_GBUFFER);
// ----====---- Opaque Geometry, Deferred rendering Pass 2 ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, lightAccumulationBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Enable additive blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
// Disable z-buffer write
glDepthMask(GL_FALSE);
// Set source to buffers from pass 1
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, compositeColorTexture);
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, compositeDepthTexture);
// Render the geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, 0, KRNode::RENDER_PASS_DEFERRED_LIGHTS);
// ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
// Disable alpha blending
glDisable(GL_BLEND);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Set source to buffers from pass 2
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, lightAccumulationTexture);
// Enable backface culling
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthRangef(0.0, 1.0);
// Enable z-buffer write
glDepthMask(GL_TRUE);
// Render the geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_DEFERRED_OPAQUE);
// Deactivate source buffer texture units
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, 0);
} else {
// ----====---- Opaque Geometry, Forward Rendering ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
// Disable alpha blending
glDisable(GL_BLEND);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Enable backface culling
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
// Enable z-buffer write
glDepthMask(GL_TRUE);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthRangef(0.0, 1.0);
// Render the geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_OPAQUE);
}
// ----====---- Transparent Geometry, Forward Rendering ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
// Disable backface culling
glDisable(GL_CULL_FACE);
// Disable z-buffer write
glDepthMask(GL_FALSE);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthRangef(0.0, 1.0);
// Enable alpha blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Render all transparent geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FORWARD_TRANSPARENT);
// ----====---- Flares ----====----
// Set render target
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
// Disable backface culling
glDisable(GL_CULL_FACE);
// Disable z-buffer write
glDepthMask(GL_FALSE);
// Disable z-buffer test
glDisable(GL_DEPTH_TEST);
glDepthRangef(0.0, 1.0);
// Enable additive blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
// Render all transparent geometry
scene.render(this, &context, frustrumVolume, viewMatrix, cameraPosition, lightDirection, shadowmvpmatrix, shadowDepthTexture, m_cShadowBuffers, KRNode::RENDER_PASS_FLARES);
// Re-enable z-buffer write
glDepthMask(GL_TRUE);
}
void KRCamera::createBuffers() {
// ===== Create offscreen compositing framebuffer object =====
glGenFramebuffers(1, &compositeFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer);
// ----- Create texture color buffer for compositeFramebuffer -----
glGenTextures(1, &compositeColorTexture);
glBindTexture(GL_TEXTURE_2D, compositeColorTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, compositeColorTexture, 0);
// ----- Create Depth Texture for compositeFramebuffer -----
glGenTextures(1, &compositeDepthTexture);
glBindTexture(GL_TEXTURE_2D, compositeDepthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, backingWidth, backingHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, backingWidth, backingHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, backingWidth, backingHeight);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0);
// ===== Create offscreen compositing framebuffer object =====
glGenFramebuffers(1, &lightAccumulationBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, lightAccumulationBuffer);
// ----- Create texture color buffer for compositeFramebuffer -----
glGenTextures(1, &lightAccumulationTexture);
glBindTexture(GL_TEXTURE_2D, lightAccumulationTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // This is necessary for non-power-of-two textures
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, backingWidth, backingHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lightAccumulationTexture, 0);
allocateShadowBuffers();
}
void KRCamera::allocateShadowBuffers() {
// First deallocate buffers no longer needed
for(int iShadow = m_cShadowBuffers; iShadow < KRENGINE_MAX_SHADOW_BUFFERS; iShadow++) {
if (shadowDepthTexture[iShadow]) {
glDeleteTextures(1, shadowDepthTexture + iShadow);
shadowDepthTexture[iShadow] = 0;
}
if (shadowFramebuffer[iShadow]) {
glDeleteFramebuffers(1, shadowFramebuffer + iShadow);
shadowFramebuffer[iShadow] = 0;
}
}
// Allocate newly required buffers
for(int iShadow = 0; iShadow < m_cShadowBuffers; iShadow++) {
if(!shadowDepthTexture[iShadow]) {
shadowValid[iShadow] = false;
glGenFramebuffers(1, shadowFramebuffer + iShadow);
glGenTextures(1, shadowDepthTexture + iShadow);
// ===== Create offscreen shadow framebuffer object =====
glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]);
// ----- Create Depth Texture for shadowFramebuffer -----
glBindTexture(GL_TEXTURE_2D, shadowDepthTexture[iShadow]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0);
}
}
}
void KRCamera::destroyBuffers()
{
m_cShadowBuffers = 0;
allocateShadowBuffers();
if (compositeDepthTexture) {
glDeleteTextures(1, &compositeDepthTexture);
compositeDepthTexture = 0;
}
if (compositeColorTexture) {
glDeleteTextures(1, &compositeColorTexture);
compositeColorTexture = 0;
}
if (lightAccumulationTexture) {
glDeleteTextures(1, &lightAccumulationTexture);
lightAccumulationTexture = 0;
}
if (compositeFramebuffer) {
glDeleteFramebuffers(1, &compositeFramebuffer);
compositeFramebuffer = 0;
}
if (lightAccumulationBuffer) {
glDeleteFramebuffers(1, &lightAccumulationBuffer);
lightAccumulationBuffer = 0;
}
}
void KRCamera::renderShadowBuffer(KRContext &context, KRScene &scene, int iShadow)
{
glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow]);
glClearDepthf(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
//glViewport(1, 1, 2046, 2046);
glDisable(GL_DITHER);
glCullFace(GL_BACK); // Enable frontface culling, which eliminates some self-cast shadow artifacts
glEnable(GL_CULL_FACE);
// Enable z-buffer test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthRangef(0.0, 1.0);
// Disable alpha blending as we are using alpha channel for packed depth info
glDisable(GL_BLEND);
// Use shader program
glUseProgram(m_shadowShaderProgram);
// Sets the diffuseTexture variable to the first texture unit
/*
glUniform1i(glGetUniformLocation(m_shadowShaderProgram, "diffuseTexture"), 0);
*/
// Validate program before drawing. This is a good check, but only really necessary in a debug build.
// DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
if (!ValidateProgram(m_shadowShaderProgram)) {
fprintf(stderr, "Failed to validate program: %d", m_shadowShaderProgram);
return;
}
#endif
// Bind our modelmatrix variable to be a uniform called mvpmatrix in our shaderprogram
glUniformMatrix4fv(m_shadowUniforms[KRENGINE_UNIFORM_SHADOWMVP1], 1, GL_FALSE, shadowmvpmatrix[iShadow].getPointer());
// Calculate the bounding volume of the light map
KRMat4 matInvShadow = shadowmvpmatrix[iShadow];
matInvShadow.invert();
KRVector3 vertices[8];
vertices[0] = KRVector3(-1.0, -1.0, 0.0);
vertices[1] = KRVector3(1.0, -1.0, 0.0);
vertices[2] = KRVector3(1.0, 1.0, 0.0);
vertices[3] = KRVector3(-1.0, 1.0, 0.0);
vertices[4] = KRVector3(-1.0, -1.0, 1.0);
vertices[5] = KRVector3(1.0, -1.0, 1.0);
vertices[6] = KRVector3(1.0, 1.0, 1.0);
vertices[7] = KRVector3(-1.0, 1.0, 1.0);
for(int iVertex=0; iVertex < 8; iVertex++) {
vertices[iVertex] = KRMat4::Dot(matInvShadow, vertices[iVertex]);
}
KRVector3 cameraPosition;
KRVector3 lightDirection;
KRBoundingVolume shadowVolume = KRBoundingVolume(vertices);
scene.render(this, &context, shadowVolume, shadowmvpmatrix[iShadow], cameraPosition, lightDirection, shadowmvpmatrix, NULL, m_cShadowBuffers, KRNode::RENDER_PASS_SHADOWMAP);
glViewport(0, 0, backingWidth, backingHeight);
}
bool KRCamera::ValidateProgram(GLuint prog)
{
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
fprintf(stderr, "Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0)
return false;
return true;
}
void KRCamera::renderPost(KRContext &context)
{
glBindFramebuffer(GL_FRAMEBUFFER, 1); // renderFramebuffer
// Disable alpha blending
glDisable(GL_BLEND);
static const GLfloat squareVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
static const GLfloat squareVerticesShadow[3][8] = {{
-1.0f, -1.0f,
-0.60f, -1.0f,
-1.0f, -0.60f,
-0.60f, -0.60f,
},{
-0.50f, -1.0f,
-0.10f, -1.0f,
-0.50f, -0.60f,
-0.10f, -0.60f,
},{
0.00f, -1.0f,
0.40f, -1.0f,
0.00f, -0.60f,
0.40f, -0.60f,
}};
static const GLfloat textureVertices[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
glDisable(GL_DEPTH_TEST);
bindPostShader(context);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, compositeDepthTexture);
glUniform1i(glGetUniformLocation(m_postShaderProgram, "depthFrame"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, compositeColorTexture);
//glBindTexture(GL_TEXTURE_2D, lightAccumulationTexture);
glUniform1i(glGetUniformLocation(m_postShaderProgram, "renderFrame"), 1);
// Update attribute values.
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_VERTEX);
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_TEXUVA, 2, GL_FLOAT, 0, 0, textureVertices);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_TEXUVA);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
if(bShowShadowBuffer) {
glDisable(GL_DEPTH_TEST);
glUseProgram(m_postShaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, compositeDepthTexture);
glUniform1i(glGetUniformLocation(m_postShaderProgram, "depthFrame"), 0);
glUniform1i(glGetUniformLocation(m_postShaderProgram, "renderFrame"), 1);
// Update attribute values.
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_TEXUVA, 2, GL_FLOAT, 0, 0, textureVertices);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_TEXUVA);
for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowDepthTexture[iShadow]);
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVerticesShadow[iShadow]);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_VERTEX);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
const char *szText = m_debug_text.c_str();
if(*szText) {
KRTexture *pFontTexture = context.getTextureManager()->getTexture("font");
glDisable(GL_DEPTH_TEST);
glUseProgram(m_postShaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, compositeDepthTexture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, pFontTexture->getName());
glUniform1i(glGetUniformLocation(m_postShaderProgram, "depthFrame"), 0);
glUniform1i(glGetUniformLocation(m_postShaderProgram, "renderFrame"), 1);
const char *pChar = szText;
int iPos=0;
double dScale = 1.0 / 24.0;
double dTexScale = 1.0 / 16.0;
while(*pChar) {
int iChar = *pChar++ - '\0';
int iCol = iChar % 16;
int iRow = 15 - (iChar - iCol) / 16;
GLfloat charVertices[] = {
-1.0f, dScale * iPos - 1.0,
-1.0 + dScale, dScale * iPos - 1.0,
-1.0f, dScale * iPos + dScale - 1.0,
-1.0 + dScale, dScale * iPos + dScale - 1.0,
};
GLfloat charTexCoords[] = {
dTexScale * iCol, dTexScale * iRow + dTexScale,
dTexScale * iCol, dTexScale * iRow,
dTexScale * iCol + dTexScale, dTexScale * iRow + dTexScale,
dTexScale * iCol + dTexScale, dTexScale * iRow
};
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_TEXUVA, 2, GL_FLOAT, 0, 0, charTexCoords);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_TEXUVA);
glVertexAttribPointer(KRShader::KRENGINE_ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, charVertices);
glEnableVertexAttribArray(KRShader::KRENGINE_ATTRIB_VERTEX);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
iPos++;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void KRCamera::bindPostShader(KRContext &context)
{
if(!m_postShaderProgram) {
std::stringstream stream;
stream.precision(std::numeric_limits<long double>::digits10);
stream << "#define DOF_QUALITY " << dof_quality;
stream << "\n#define ENABLE_FLASH " << (bEnableFlash ? "1" : "0");
stream << "\n#define ENABLE_VIGNETTE " << (bEnableVignette ? "1" : "0");
stream.setf(std::ios::fixed,std::ios::floatfield);
stream << "\n#define DOF_DEPTH " << dof_depth;
stream << "\n#define DOF_FALLOFF " << dof_falloff;
stream << "\n#define FLASH_DEPTH " << flash_depth;
stream << "\n#define FLASH_FALLOFF " << flash_falloff;
stream << "\n#define FLASH_INTENSITY " << flash_intensity;
stream << "\n#define VIGNETTE_RADIUS " << vignette_radius;
stream << "\n#define VIGNETTE_FALLOFF " << vignette_falloff;
stream << "\n";
LoadShader(context, "PostShader", &m_postShaderProgram, stream.str());
}
glUseProgram(m_postShaderProgram);
}
void KRCamera::invalidatePostShader()
{
if(m_postShaderProgram) {
glDeleteProgram(m_postShaderProgram);
m_postShaderProgram = 0;
}
}
void KRCamera::invalidateShadowBuffers() {
for(int i=0; i < m_cShadowBuffers; i++) {
shadowValid[i] = false;
}
}
bool KRCamera::LoadShader(KRContext &context, const std::string &name, GLuint *programPointer, const std::string &options)
{
GLuint vertexShader, fragShader;
// Create shader program.
*programPointer = glCreateProgram();
// Create and compile vertex shader.
if(!CompileShader(&vertexShader, GL_VERTEX_SHADER, context.getShaderManager()->getVertShaderSource(name), options)) {
fprintf(stderr, "Failed to compile vertex shader");
return false;
}
// Create and compile fragment shader.
if(!CompileShader(&fragShader, GL_FRAGMENT_SHADER, context.getShaderManager()->getFragShaderSource(name), options)) {
fprintf(stderr, "Failed to compile fragment shader");
return false;
}
// Attach vertex shader to program.
glAttachShader(*programPointer, vertexShader);
// Attach fragment shader to program.
glAttachShader(*programPointer, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(*programPointer, KRShader::KRENGINE_ATTRIB_TEXUVB, "vertex_lightmap_uv");
glBindAttribLocation(*programPointer, KRShader::KRENGINE_ATTRIB_VERTEX, "vertex_position");
glBindAttribLocation(*programPointer, KRShader::KRENGINE_ATTRIB_NORMAL, "vertex_normal");
glBindAttribLocation(*programPointer, KRShader::KRENGINE_ATTRIB_TANGENT, "vertex_tangent");
glBindAttribLocation(*programPointer, KRShader::KRENGINE_ATTRIB_TEXUVA, "vertex_uv");
// Link program.
if(!LinkProgram(*programPointer)) {
fprintf(stderr, "Failed to link program: %d", *programPointer);
if (vertexShader) {
glDeleteShader(vertexShader);
vertexShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (*programPointer) {
glDeleteProgram(*programPointer);
*programPointer = 0;
}
return false;
}
// Release vertex and fragment shaders.
if (vertexShader)
{
glDeleteShader(vertexShader);
}
if (fragShader)
{
glDeleteShader(fragShader);
}
return true;
}
bool KRCamera::CompileShader(GLuint *shader, GLenum type, const std::string &shader_source, const std::string &options)
{
GLint status;
const GLchar *source[2];
source[0] = (GLchar *)shader_source.c_str();
if (!source[0])
{
fprintf(stderr, "Failed to load vertex shader");
return false;
}
if(options.length()) {
source[1] = source[0];
source[0] = options.c_str();
}
*shader = glCreateShader(type);
glShaderSource(*shader, options.length() ? 2 : 1, source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
fprintf(stderr, "Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return false;
}
return true;
}
bool KRCamera::LinkProgram(GLuint prog)
{
GLint status;
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
fprintf(stderr, "Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0)
return false;
return true;
}
void KRCamera::loadShaders(KRContext &context)
{
LoadShader(context, "ShadowShader", &m_shadowShaderProgram, "");
m_shadowUniforms[KRENGINE_UNIFORM_SHADOWMVP1] = glGetUniformLocation(m_shadowShaderProgram, "shadow_mvp1");
}