Separated OpenGL specific code into its own "compilation unit"

This commit is contained in:
2015-10-06 19:11:19 +02:00
parent 116cfb5759
commit 13360856f9
28 changed files with 258 additions and 152 deletions
-3
View File
@@ -1,3 +0,0 @@
#include "PrecompiledHeader.h"
#include "Core/BGFXRenderer.h"
-124
View File
@@ -1,124 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/Camera.h"
dd::Camera::Camera(float aspectRatio, float yFOV, float nearClip, float farClip)
{
m_AspectRatio = aspectRatio;
m_FOV = yFOV;
m_NearClip = nearClip;
m_FarClip = farClip;
m_Position = glm::vec3(0.0);
UpdateProjectionMatrix();
UpdateViewMatrix();
}
glm::vec3 dd::Camera::Forward()
{
return m_Orientation * glm::vec3(0, 0, -1);
}
//
//glm::vec3 Camera::Right()
//{
// return glm::rotate(glm::vec3(1.f, 0.f, 0.f), -m_Yaw, glm::vec3(0.f, 1.f, 0.f));
//}
//glm::mat4 Camera::Orientation()
//{
// glm::mat4 orientation(1.f);
// orientation = glm::rotate(orientation, m_Pitch, glm::vec3(1.f, 0.f, 0.f));
// orientation = glm::rotate(orientation, m_Yaw, glm::vec3(0.f, 1.f, 0.f));
// return orientation;
//}
void dd::Camera::SetPosition(glm::vec3 val)
{
m_Position = val;
UpdateViewMatrix();
}
void dd::Camera::SetOrientation(glm::quat val)
{
m_Orientation = val;
UpdateViewMatrix();
}
//void Camera::Pitch(float val)
//{
// m_Pitch = val;
// UpdateViewMatrix();
//}
//
//void Camera::Yaw(float val)
//{
// m_Yaw = val;
// UpdateViewMatrix();
//}
void dd::Camera::UpdateProjectionMatrix()
{
// m_ProjectionMatrix = glm::ortho(
// -16.f,
// 16.f,
// -9.f,
// 9.f,
// m_NearClip,
// m_FarClip
// );
m_ProjectionMatrix = glm::perspective(
m_FOV,
m_AspectRatio,
m_NearClip,
m_FarClip
);
}
void dd::Camera::UpdateViewMatrix()
{
m_ViewMatrix = glm::toMat4(glm::inverse(m_Orientation))
* glm::translate(-m_Position);
}
void dd::Camera::SetAspectRatio(float val)
{
m_AspectRatio = val;
UpdateProjectionMatrix();
}
void dd::Camera::SetFOV(float val)
{
m_FOV = val;
UpdateProjectionMatrix();
}
void dd::Camera::SetNearClip(float val)
{
m_NearClip = val;
UpdateProjectionMatrix();
}
void dd::Camera::SetFarClip(float val)
{
m_FarClip = val;
UpdateProjectionMatrix();
}
-386
View File
@@ -1,386 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/Model.h"
dd::Model::Model(std::string fileName)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(fileName, aiProcess_CalcTangentSpace | aiProcess_Triangulate);
if (scene == nullptr) {
LOG_ERROR("Failed to load model \"%s\"", fileName.c_str());
LOG_ERROR("Assimp error: %s", importer.GetErrorString());
return;
}
auto m = scene->mRootNode->mTransformation;
m_Matrix = glm::mat4(
m.a1, m.a2, m.a3, m.a4,
m.b1, m.b2, m.b3, m.b4,
m.c1, m.c2, m.c3, m.c4,
m.d1, m.d2, m.d3, m.d4
);
m_Matrix = glm::transpose(m_Matrix);
auto meshes = scene->mMeshes;
// Pre-count vertices
int numVertices = 0;
int numIndices = 0;
for (int i = 0; i < scene->mNumMeshes; ++i) {
numVertices += meshes[i]->mNumVertices;
// Faces
for (int j = 0; j < meshes[i]->mNumFaces; ++j) {
auto face = meshes[i]->mFaces[j];
numIndices += face.mNumIndices;
}
}
LOG_DEBUG("Vertex count %i", numVertices);
LOG_DEBUG("Index count %i", numIndices);
LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures);
std::vector<std::tuple<std::string, glm::mat4>> boneInfo;
std::map<std::string, int> boneNameMapping;
for (int i = 0; i < scene->mNumMeshes; ++i) {
auto mesh = meshes[i];
auto material = scene->mMaterials[mesh->mMaterialIndex];
unsigned int indexOffset = m_Vertices.size();
// Vertices, normals and texture coordinates
for (int vertexIndex = 0; vertexIndex < mesh->mNumVertices; ++vertexIndex) {
Vertex desc;
// Position
auto position = mesh->mVertices[vertexIndex];
desc.Position = glm::vec3(position.x, position.y, position.z);
// Normal
auto normal = mesh->mNormals[vertexIndex];
desc.Normal = glm::vec3(normal.x, normal.y, normal.z);
//if (mesh->HasTangentsAndBitangents()) {
// // Tangent
// auto tangent = mesh->mTangents[vertexIndex];
// desc.Tangent = glm::vec3(tangent.x, tangent.y, tangent.z);
// // Bi-tangent
// auto bitangent = mesh->mBitangents[vertexIndex];
// desc.BiTangent = glm::vec3(bitangent.x, bitangent.y, bitangent.z);
//}
// UV
if (mesh->HasTextureCoords(0)) {
auto uv = mesh->mTextureCoords[0][vertexIndex];
desc.TextureCoords = glm::vec2(uv.x, uv.y);
}
// Material diffuse color
aiColor4D diffuse;
material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, diffuse.a);
// Material specular color
aiColor4D specular;
material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
desc.SpecularVertexColor = glm::vec4(specular.r, specular.g, specular.b, specular.a);
m_Vertices.push_back(desc);
}
// Faces
for (int j = 0; j < mesh->mNumFaces; ++j) {
auto face = mesh->mFaces[j];
for (int k = 0; k < face.mNumIndices; ++k) {
unsigned int index = face.mIndices[k];
m_Indices.push_back(indexOffset + index);
}
}
// Calculate normal mapping tangents
for (int i = 0; i < m_Indices.size(); i += 3) {
Vertex& v0 = m_Vertices[m_Indices[i]];
Vertex& v1 = m_Vertices[m_Indices[i + 1]];
Vertex& v2 = m_Vertices[m_Indices[i + 2]];
glm::vec3 edge1 = v1.Position - v0.Position;
glm::vec3 edge2 = v2.Position - v0.Position;
float deltaU1 = v1.TextureCoords.x - v0.TextureCoords.x;
float deltaV1 = v1.TextureCoords.y - v0.TextureCoords.y;
float deltaU2 = v2.TextureCoords.x - v0.TextureCoords.x;
float deltaV2 = v2.TextureCoords.y - v0.TextureCoords.y;
float f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1);
glm::vec3 tangent;
tangent.x = f * (deltaV2 * edge1.x - deltaV1 * edge2.x);
tangent.y = f * (deltaV2 * edge1.y - deltaV1 * edge2.y);
tangent.z = f * (deltaV2 * edge1.z - deltaV1 * edge2.z);
v0.Tangent += tangent;
v1.Tangent += tangent;
v2.Tangent += tangent;
}
for (auto& vertex : m_Vertices) {
vertex.Tangent = glm::normalize(vertex.Tangent);
vertex.BiTangent = glm::normalize(glm::cross(vertex.Tangent, glm::normalize(vertex.Normal)));
}
// Material info
MaterialGroup matGroup;
matGroup.StartIndex = indexOffset;
matGroup.EndIndex = m_Indices.size() - 1;
// Material shininess
material->Get(AI_MATKEY_SHININESS, matGroup.Shininess);
LOG_DEBUG("Shininess: %f", matGroup.Shininess);
// Diffuse texture
LOG_DEBUG("%i diffuse textures found", material->GetTextureCount(aiTextureType_DIFFUSE));
if (material->GetTextureCount(aiTextureType_DIFFUSE)) {
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_DIFFUSE, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str());
matGroup.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
}
// Normal map
LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT));
if (material->GetTextureCount(aiTextureType_HEIGHT)) {
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_HEIGHT, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
LOG_DEBUG("Normal map: %s", absolutePath.c_str());
matGroup.NormalMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
}
// Specular map
LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR));
if (material->GetTextureCount(aiTextureType_SPECULAR)) {
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_SPECULAR, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
LOG_DEBUG("Specular map: %s", absolutePath.c_str());
matGroup.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
}
TextureGroups.push_back(matGroup);
// Bones
std::map<int, std::vector<std::tuple<int, float>>> vertexWeights;
for (int j = 0; j < mesh->mNumBones; ++j) {
auto bone = mesh->mBones[j];
std::string boneName = bone->mName.C_Str();
auto mat = bone->mOffsetMatrix;
glm::mat4 glmMat(mat.a1, mat.b1, mat.c1, mat.d1,
mat.a2, mat.b2, mat.c2, mat.d2,
mat.a3, mat.b3, mat.c3, mat.d3,
mat.a4, mat.b4, mat.c4, mat.d4);
int boneIndex;
if (boneNameMapping.find(boneName) != boneNameMapping.end()) {
boneIndex = boneNameMapping[boneName];
} else {
boneIndex = boneInfo.size();
boneInfo.push_back(std::make_tuple(boneName, glmMat));
boneNameMapping[boneName] = boneIndex;
}
for (int k = 0; k < bone->mNumWeights; ++k) {
auto weight = bone->mWeights[k];
unsigned int offsetVertexId = weight.mVertexId + indexOffset;
vertexWeights[offsetVertexId].push_back(std::make_tuple(boneIndex, weight.mWeight));
}
}
for (auto &pair : vertexWeights) {
auto weights = pair.second;
Vertex& desc = m_Vertices[pair.first];
const int maxWeights = 8;
if (weights.size() > maxWeights) {
LOG_WARNING("Vertex weights (%i) greater than max weights per vertex (%i)", weights.size(), maxWeights);
}
for (int weightIndex = 0; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 4; ++weightIndex) {
std::tie(desc.BoneIndices1[weightIndex], desc.BoneWeights1[weightIndex]) = weights[weightIndex];
}
for (int weightIndex = 4; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 8; ++weightIndex) {
std::tie(desc.BoneIndices2[weightIndex - 4], desc.BoneWeights2[weightIndex - 4]) = weights[weightIndex];
}
}
//break;
}
// Traverse the node tree and build a skeleton
if (!boneInfo.empty()) {
m_Skeleton = new Skeleton();
CreateSkeleton(boneInfo, boneNameMapping, scene->mRootNode, -1);
int numBones = m_Skeleton->Bones.size();
LOG_DEBUG("Bone count: %i", numBones);
if (numBones > 0) {
m_Skeleton->PrintSkeleton();
}
}
// Animations
LOG_DEBUG("Animation count: %i", scene->mNumAnimations);
for (int i = 0; i < scene->mNumAnimations; ++i) {
auto animation = scene->mAnimations[i];
std::string animationName = animation->mName.C_Str();
LOG_DEBUG("Animation: %s", animationName.c_str());
LOG_DEBUG("Duration: %f", animation->mDuration);
LOG_DEBUG("Ticks per second: %f", animation->mTicksPerSecond);
Skeleton::Animation skelAnim;
skelAnim.Name = animationName;
skelAnim.Duration = animation->mDuration / animation->mTicksPerSecond;
std::map<int, double> frameTimes;
std::map<int, std::map<int, Skeleton::Animation::Keyframe::BoneProperty>> frameBoneProperties;
// For each animation channel (bone)
for (int channelIndex = 0; channelIndex < animation->mNumChannels; ++channelIndex) {
auto channel = animation->mChannels[channelIndex];
std::string boneName = channel->mNodeName.C_Str();
int boneID = m_Skeleton->GetBoneID(boneName);
if (boneID == -1) {
LOG_ERROR("Animation referenced a bone that doesn't exist: %s", boneName.c_str());
continue;
}
// If you don't have the same amount of keyframes for every transformation type you're dumb.
if (channel->mNumPositionKeys != channel->mNumRotationKeys || channel->mNumPositionKeys != channel->mNumScalingKeys) {
LOG_ERROR("Hey, animation! You're dumb!", animationName.c_str());
continue;
}
for (int keyframe = 0; keyframe < channel->mNumPositionKeys; ++keyframe) {
auto posKey = channel->mPositionKeys[keyframe];
auto rotKey = channel->mRotationKeys[keyframe];
auto scaleKey = channel->mScalingKeys[keyframe];
frameTimes[keyframe] = posKey.mTime;
auto &property = frameBoneProperties[keyframe][boneID];
property.ID = keyframe;
property.Position = glm::vec3(posKey.mValue.x, posKey.mValue.y, posKey.mValue.z);
property.Rotation = glm::quat(rotKey.mValue.w, rotKey.mValue.x, rotKey.mValue.y, rotKey.mValue.z);
property.Scale = glm::vec3(scaleKey.mValue.x, scaleKey.mValue.y, scaleKey.mValue.z);
}
}
// Create keyframes from bone properties
for (auto &kv : frameBoneProperties) {
int keyframe = kv.first;
Skeleton::Animation::Keyframe animationFrame;
animationFrame.Index = keyframe;
animationFrame.Time = frameTimes[keyframe] / animation->mTicksPerSecond;
for (auto &kv2 : kv.second) {
int boneID = kv2.first;
auto &property = kv2.second;
animationFrame.BoneProperties[boneID] = property;
}
skelAnim.Keyframes.push_back(animationFrame);
}
m_Skeleton->Animations[animationName] = skelAnim;
}
// Generate GL buffers
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &ElementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_Indices.size() * sizeof(unsigned int), &m_Indices[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLERROR("GLEW: BufferFail4");
glBindBuffer(GL_ARRAY_BUFFER, buffer);
std::vector<int> structSizes = { 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4 };
int stride = 0;
for (int size : structSizes)
stride += size;
stride *= sizeof(GLfloat);
int offset = 0;
{
int element = 0;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * offset)); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
}
GLERROR("GLEW: BufferFail5");
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glEnableVertexAttribArray(7);
glEnableVertexAttribArray(8);
glEnableVertexAttribArray(9);
glEnableVertexAttribArray(10);
GLERROR("GLEW: BufferFail5");
//CreateBuffers();
}
dd::Model::~Model()
{
if (m_Skeleton) {
delete m_Skeleton;
}
}
void dd::Model::CreateSkeleton(std::vector<std::tuple<std::string, glm::mat4>> &boneInfo, std::map<std::string, int> &boneNameMapping, aiNode* node, int parentID)
{
std::string nodeName = node->mName.C_Str();
// Find the bone by name in the bone info list
if (boneNameMapping.find(nodeName) == boneNameMapping.end()) {
LOG_DEBUG("Node \"%s\" was not a bone", nodeName.c_str());
} else {
glm::mat4 offsetMatrix;
int ID = boneNameMapping[nodeName];
std::tie(std::ignore, offsetMatrix) = boneInfo[ID];
m_Skeleton->CreateBone(ID, parentID, nodeName, offsetMatrix);
parentID = ID;
}
for (int childIndex = 0; childIndex < node->mNumChildren; ++childIndex) {
aiNode* child = node->mChildren[childIndex];
CreateSkeleton(boneInfo, boneNameMapping, child, parentID);
}
}
-427
View File
@@ -1,427 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/OBJ.h"
bool dd::OBJ::LoadFromFile(std::string filename)
{
m_Path = boost::filesystem::path(filename);
// http://paulbourke.net/dataformats/obj/
std::ifstream file(m_Path.string());
if (!file.is_open())
{
LOG_ERROR("Failed to open .obj \"%s\": %s", m_Path.string().c_str(), strerror(errno));
return false;
}
//LOG_INFO("Parsing .obj \"%s\"", m_Path.string().c_str());
std::string line;
while (std::getline(file, line))
{
if (line.length() == 0)
continue;
std::stringstream ss(line);
std::string prefix;
ss >> prefix;
// Ignore comments
if (prefix == "#")
continue;
// Material files
if (prefix == "mtllib")
{
std::string materialFilename;
ss >> materialFilename;
m_MaterialPath = m_Path.branch_path() / materialFilename;
ParseMaterial();
continue;
}
// Material statement
if (prefix == "usemtl")
{
std::string material;
ss >> material;
m_CurrentMaterial = &Materials[material];
continue;
}
// Vertices
if (prefix == "v")
{
float x, y, z;
ss >> x >> y >> z;
Vertices.push_back(std::make_tuple(x, y, z));
continue;
}
// Normals
if (prefix == "vn")
{
float x, y, z;
ss >> x >> y >> z;
Normals.push_back(std::make_tuple(x, y, z));
}
// Texture coordinates
if (prefix == "vt")
{
float u, v, w;
ss >> u >> v >> w;
TextureCoords.push_back(std::make_tuple(u, v, w));
}
// Face definitions
if (prefix == "f")
{
Face face;
face.Material = m_CurrentMaterial;
std::string faceDefString;
while (ss >> faceDefString)
{
std::stringstream ss2(faceDefString);
FaceDefinition faceDef = { 0, 0, 0 };
ss2 >> faceDef.VertexIndex;
ss2.ignore(); // Ignore first delimiter
if (!ss2)
continue;
if (ss2.peek() == '/')
{
ss2.ignore();
ss2 >> faceDef.NormalIndex;
}
else
{
ss2 >> faceDef.TextureCoordIndex;
ss2.ignore();
ss2 >> faceDef.NormalIndex;
}
face.Definitions.push_back(faceDef);
}
Faces.push_back(face);
}
}
return true;
}
void dd::OBJ::ParseMaterial()
{
// http://paulbourke.net/dataformats/mtl/
std::ifstream file(m_MaterialPath.string());
if (!file.is_open())
{
LOG_ERROR("Failed to open .mtl \"%s\"", m_MaterialPath.string().c_str());
return;
}
//LOG_INFO("Parsing .mtl \"%s\"", m_MaterialPath.string().c_str());
std::string currentMaterialName;
MaterialInfo* currentMaterial = nullptr;
unsigned int currentLine = 0;
std::string line;
while (std::getline(file, line))
{
currentLine++;
if (line.length() == 0)
continue;
std::stringstream ss(line);
std::string prefix;
ss >> prefix;
// Create a new material definition
if (prefix == "newmtl")
{
MaterialInfo mat;
ss >> currentMaterialName;
//LOG_INFO("Parsing material %s", currentMaterialName.c_str());
Materials[currentMaterialName] = mat;
currentMaterial = &Materials[currentMaterialName];
continue;
}
if (!currentMaterial)
continue;
// Ambient color
if (prefix == "Ka")
{
float r, g, b;
ss >> r >> g >> b;
currentMaterial->AmbientColor = std::make_tuple(r, g, b);
continue;
}
// Diffuse color
if (prefix == "Kd")
{
float r, g, b;
ss >> r >> g >> b;
currentMaterial->DiffuseColor = std::make_tuple(r, g, b);
continue;
}
// Specular color
if (prefix == "Ks")
{
float r, g, b;
ss >> r >> g >> b;
currentMaterial->SpecularColor = std::make_tuple(r, g, b);
continue;
}
// Transmission filter
if (prefix == "Tf")
{
std::stringstream ss2;
ss2 << ss.str();
std::string command;
ss2 >> command;
if (command == "xyz")
{
// TODO: "The "Ks xyz" statement specifies the specular reflectivity using CIEXYZ values."
}
else if (command == "spectral")
{
// TODO: "The "Tf spectral" statement specifies the transmission filter using a spectral curve."
}
else
{
float r, g, b;
ss >> r;
// G and B are optional
if (!(ss >> g >> b))
{
g = r;
b = r;
}
currentMaterial->TransmissionFilter = std::make_tuple(r, g, b);
}
continue;
}
// Optical density
if (prefix == "Ni")
{
ss >> currentMaterial->OpticalDensity;
continue;
}
// Alpha
if (prefix == "d" || prefix == "Tr")
{
ss >> currentMaterial->Alpha;
continue;
}
// Shininess
if (prefix == "Ns")
{
ss >> currentMaterial->Shininess;
continue;
}
// Illumination model
if (prefix == "illum")
{
int illum = 0;
ss >> illum;
currentMaterial->IlluminationModel = illum;
continue;
}
// Diffuse texture
if (prefix == "map_Kd")
{
MaterialInfo::ColorMap colorMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseColorMap(currentLine, ss, prefix, arg, colorMap);
}
// HACK: Should we really have to specify the full FilePath here?
colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string();
currentMaterial->DiffuseTexture = colorMap;
continue;
}
// Specular map
if (prefix == "map_Ks")
{
MaterialInfo::ColorMap colorMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseColorMap(currentLine, ss, prefix, arg, colorMap);
}
// HACK: Should we really have to specify the full FilePath here?
colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string();
currentMaterial->SpecularMap = colorMap;
continue;
}
// Normal map (bump map)
if (prefix == "bump" || prefix == "map_Bump" )
{
MaterialInfo::BumpMap bumpMap;
std::string fileName;
std::string arg;
while (ss >> arg)
{
ParseBumpMap(currentLine, ss, prefix, arg, bumpMap);
}
// HACK: Should we really have to specify the full FilePath here?
bumpMap.FileName = (m_MaterialPath.branch_path() / bumpMap.FileName).string();
currentMaterial->NormalMap = bumpMap;
continue;
}
}
}
void dd::OBJ::ParseTextureMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::TextureMap &textureMap)
{
if (arg == "-blendu")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.blendu = false;
else if (val == "on")
textureMap.blendu = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-blendv")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.blendv = false;
else if (val == "on")
textureMap.blendv = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-clamp")
{
std::string val;
ss >> val;
if (val == "off")
textureMap.clamp = false;
else if (val == "on")
textureMap.clamp = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else if (arg == "-o")
{
float u, v, w;
if (ss >> u >> v >> w)
{
textureMap.o = std::make_tuple(u, v, w);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
else if (arg == "-s")
{
float u, v, w;
if (ss >> u >> v >> w)
{
textureMap.s = std::make_tuple(u, v, w);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
// Assume unrecognized options is part of the file name
else
{
if (!textureMap.FileName.empty())
textureMap.FileName += " ";
textureMap.FileName += arg;
}
}
void dd::OBJ::ParseColorMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::ColorMap &colorMap)
{
if (arg == "-cc")
{
if (prefix != "map_Kd" || prefix != "map_Ks")
{
LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line);
return;
}
std::string val;
if (ss >> val)
{
if (val == "off")
colorMap.cc = false;
else if (val == "on")
colorMap.cc = true;
else
LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line);
}
else
{
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
}
else
{
ParseTextureMap(line, ss, prefix, arg, colorMap);
}
}
void dd::OBJ::ParseBumpMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::BumpMap &bumpMap)
{
if (arg == "-bm")
{
if (prefix != "bump")
{
LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line);
return;
}
float val;
if (ss >> val)
bumpMap.bm = val;
else
LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line);
}
else
{
ParseTextureMap(line, ss, prefix, arg, bumpMap);
}
}
-125
View File
@@ -1,125 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/PNG.h"
dd::PNG::PNG(std::string path)
{
FILE* file = fopen(path.c_str(), "rb");
if (!file) {
LOG_ERROR("Failed to open texture file \"%s\": %s", path.c_str(), const_cast<const char*>(strerror(errno)));
return;
}
png_byte header[8];
fread(header, 1, 8, file);
bool isPNG = !png_sig_cmp(header, 0, 8);
if (!isPNG) {
LOG_ERROR("Failed to load texture file \"%s\": File isn't PNG", path.c_str());
fclose(file);
return;
}
// Initialize libpng
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, (png_error_ptr)&PNG::pngErrorFunction, (png_error_ptr)&PNG::pngErrorFunction);
if (!png_ptr) {
LOG_ERROR("libpng: Failed to initialze png_struct");
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
fclose(file);
return;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
LOG_ERROR("libpng: Failed to initialze png_info");
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
fclose(file);
return;
}
png_infop info_end_ptr = png_create_info_struct(png_ptr);
if (!info_end_ptr) {
LOG_ERROR("libpng: Failed to initialze second png_info");
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
fclose(file);
return;
}
png_init_io(png_ptr, file);
// We already read the first 8 bytes of the header
png_set_sig_bytes(png_ptr, 8);
// Read all the info up to the image data
png_read_info(png_ptr, info_ptr);
// Get info
int bit_depth, color_type;
unsigned int width, height;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
if (bit_depth != 8) {
LOG_ERROR("libpng: Unsupported bit depth \"%i\" of image \"%s\", must be 8", bit_depth, path.c_str());
return;
}
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
Format = Image::ImageFormat::RGB;
break;
case PNG_COLOR_TYPE_RGBA:
Format = Image::ImageFormat::RGBA;
break;
default:
LOG_ERROR("libpng: Unsupported color format \"%i\" of image \"%s\"", color_type, path.c_str());
return;
}
unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
this->Data = new unsigned char[height * row_bytes];
png_bytep* row_pointers = new png_bytep[height];
// Point each row to the continuous data array
for (int i = 0; i < height; ++i) {
// Invert Y for OpenGL
row_pointers[height - 1 - i] = this->Data + i * row_bytes;
}
// Read in the data
png_read_image(png_ptr, row_pointers);
delete[] row_pointers;
this->Width = width;
this->Height = height;
png_destroy_read_struct(&png_ptr, &info_ptr, &info_end_ptr);
fclose(file);
}
dd::PNG::~PNG()
{
if (this->Data != nullptr) {
delete[] this->Data;
this->Data = nullptr;
}
}
void dd::PNG::pngErrorFunction(png_structp png_ptr, png_const_charp error_msg)
{
LOG_WARNING("%s", error_msg);
}
void dd::PNG::pngWarningFunction(png_structp png_ptr, png_const_charp warning_msg)
{
LOG_WARNING("%s", warning_msg);
}
-716
View File
@@ -1,716 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/Renderer.h"
void dd::Renderer::Initialize()
{
// Initialize GLFW
if (!glfwInit()) {
LOG_ERROR("GLFW: Initialization failed");
exit(EXIT_FAILURE);
}
// Create a window
GLFWmonitor* monitor = nullptr;
if (m_Fullscreen) {
monitor = glfwGetPrimaryMonitor();
}
glfwWindowHint(GLFW_SAMPLES, 8);
m_Window = glfwCreateWindow(m_Resolution.Width, m_Resolution.Height, "daydream", monitor, nullptr);
if (!m_Window) {
LOG_ERROR("GLFW: Failed to create window");
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(m_Window);
// GL version info
glGetIntegerv(GL_MAJOR_VERSION, &m_GLVersion[0]);
glGetIntegerv(GL_MINOR_VERSION, &m_GLVersion[1]);
m_GLVendor = (GLchar*)glGetString(GL_VENDOR);
std::stringstream ss;
ss << m_GLVendor << " OpenGL " << m_GLVersion[0] << "." << m_GLVersion[1];
#ifdef DEBUG
ss << " DEBUG";
#endif
LOG_INFO(ss.str().c_str());
glfwSetWindowTitle(m_Window, ss.str().c_str());
// Initialize GLEW
if (glewInit() != GLEW_OK) {
LOG_ERROR("GLEW: Initialization failed");
exit(EXIT_FAILURE);
}
// Create default camera
m_DefaultCamera = std::unique_ptr<dd::Camera>(new dd::Camera((float)m_Resolution.Width / m_Resolution.Height, 45.f, 0.01f, 5000.f));
m_DefaultCamera->SetPosition(glm::vec3(0, 0, 0));
if (m_Camera == nullptr) {
m_Camera = m_DefaultCamera.get();
}
glfwSwapInterval(m_VSYNC);
LoadShaders();
CreateBuffers();
m_CurrentScreenBuffer = m_TFinal;
}
void dd::Renderer::LoadShaders()
{
/*
Deferred rendering
*/
// Pass #1: Fill G-buffers
m_SpDeferred1 = ResourceManager::Load<ShaderProgram>("Shaders/Deferred/1/");
m_SpDeferred1->BindFragDataLocation(0, "GDiffuse");
m_SpDeferred1->BindFragDataLocation(1, "GPosition");
m_SpDeferred1->BindFragDataLocation(2, "GNormal");
m_SpDeferred1->BindFragDataLocation(3, "GSpecular");
m_SpDeferred1->Link();
// Pass #2: Lighting
m_SpDeferred2 = ResourceManager::Load<ShaderProgram>("Shaders/Deferred/2/");
//glBindFragDataLocation(m_SPDeferred2, 0, "FragmentLighting");
m_SpDeferred2->Link();
//Water Pass
m_SpWater = ResourceManager::Load<ShaderProgram>("Shaders/Deferred/water/");
m_SpWater->Link();
m_SpWater2 = ResourceManager::Load<ShaderProgram>("Shaders/Deferred/water2/");
m_SpWater2->Link();
// Pass #3: Combining into final image
m_SpDeferred3 = ResourceManager::Load<ShaderProgram>("Shaders/Deferred/3/");
m_SpDeferred3->Link();
/*
Forward rendering
*/
m_SpForward = ResourceManager::Load<ShaderProgram>("Shaders/Forward/");
m_SpForward->Link();
/*
Screen draw
*/
m_SpScreen = ResourceManager::Load<ShaderProgram>("Shaders/Screen/");
m_SpScreen->Link();
}
void dd::Renderer::CreateBuffers()
{
//TODO: Make the most common cases of texture create and FBO create into a function so it's not so cluttered in here.
m_ScreenQuad = CreateQuad();
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
m_StandardNormal = ResourceManager::Load<Texture>("Textures/Core/NeutralNormalMap.png");
m_StandardSpecular = ResourceManager::Load<Texture>("Textures/Core/NeutralSpecularMap.png");
m_WhiteSphereTexture = ResourceManager::Load<Texture>("Textures/Test/Water.png");
glGenRenderbuffers(1, &m_RbDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_RbDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Resolution.Width, m_Resolution.Height);
// Generate G-buffer textures
glGenTextures(1, &m_GDiffuse);
glBindTexture(GL_TEXTURE_2D, m_GDiffuse);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenTextures(1, &m_GPosition);
glBindTexture(GL_TEXTURE_2D, m_GPosition);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, m_Resolution.Width, m_Resolution.Height, 0, GL_RGB, GL_FLOAT, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenTextures(1, &m_GNormal);
glBindTexture(GL_TEXTURE_2D, m_GNormal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, m_Resolution.Width, m_Resolution.Height, 0, GL_RGB, GL_FLOAT, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenTextures(1, &m_GSpecular);
glBindTexture(GL_TEXTURE_2D, m_GSpecular);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_FLOAT, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenTextures(1, &m_Gwater);
glBindTexture(GL_TEXTURE_2D, m_Gwater);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_FLOAT, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Create first pass framebuffer
glGenFramebuffers(1, &m_FbDeferred1);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_RbDepthBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_GDiffuse, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_GPosition, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, m_GNormal, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, m_GSpecular, 0);
GLenum firstPassDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
glDrawBuffers(4, firstPassDrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred1 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
// Generate lighting texture
glGenTextures(1, &m_TLighting);
glBindTexture(GL_TEXTURE_2D, m_TLighting);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// Create second pass framebuffer
glGenFramebuffers(1, &m_FbDeferred2);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TLighting, 0);
GLenum secondPassDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, secondPassDrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred2 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
//Fill Water Texture
glGenTextures(1, &m_Gwater);
glBindTexture(GL_TEXTURE_2D, m_Gwater);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Fill water pass
glGenFramebuffers(1, &m_FbWater);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbWater);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_Gwater, 0);
GLenum waterPassDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, waterPassDrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred2 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
//water Blur texture
glGenTextures(1, &m_BWater);
glBindTexture(GL_TEXTURE_2D, m_BWater);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Fill waterBlur pass
glGenFramebuffers(1, &m_FbWaterBlur);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbWaterBlur);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_BWater, 0);
GLenum waterBlurDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, waterBlurDrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred2 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
//water Blur texture2
glGenTextures(1, &m_BWater2);
glBindTexture(GL_TEXTURE_2D, m_BWater2);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_RbDepthBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Fill waterBlur pass2
glGenFramebuffers(1, &m_FbWaterBlur2);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbWaterBlur2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_BWater2, 0);
GLenum waterBlur2DrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, waterBlur2DrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred2 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
// Generate final deferred texture
glGenTextures(1, &m_TFinal);
glBindTexture(GL_TEXTURE_2D, m_TFinal);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create third pass framebuffer
glGenFramebuffers(1, &m_FbDeferred3);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred3);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_RbDepthBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_TFinal, 0);
GLenum thirdPassDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, thirdPassDrawBuffers);
if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("m_FbDeferred3 incomplete: 0x%x\n", fbStatus);
exit(EXIT_FAILURE);
}
}
void dd::Renderer::Draw(RenderQueueCollection& rq)
{
rq.Forward.Jobs.sort(dd::Renderer::DepthSort);
DrawDeferred(rq.Deferred, rq.Lights);
DrawForward(rq.Forward, rq.Lights);
DrawGUI(rq.GUI);
// Finally: Draw the deferred+forward combined texture to the screen
glDisable(GL_CULL_FACE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
m_SpScreen->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_CurrentScreenBuffer);
glBindVertexArray(m_ScreenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(m_Window);
DebugKeys();
}
void dd::Renderer::DrawDeferred(RenderQueue &objects, RenderQueue &lights)
{
// Pass #1: Fill G-buffers
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred1);
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_SpDeferred1->Bind();
DrawScene(objects, *m_SpDeferred1);
// Pass #2: Lighting
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred2);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
m_SpDeferred2->Bind();
DrawLightSpheres(lights);
// Pass #3: Combine into final deferred image
glCullFace(GL_BACK);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred3);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
m_SpDeferred3->Bind();
glUniform3fv(glGetUniformLocation(*m_SpDeferred3, "La"), 1, glm::value_ptr(glm::vec3(0.5f)));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_GDiffuse);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_TLighting);
glBindVertexArray(m_ScreenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void dd::Renderer::DrawForward(RenderQueue &objects, RenderQueue &lights)
{
// Forward-render semi-transparent objects on top of the current framebuffer
glDisable(GL_CULL_FACE);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred3);
// glClearColor(1, 0.9, 0.8f, 1);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_SpForward->Bind();
DrawScene(objects, *m_SpForward);
//WaterPass
glDisable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbWater);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
m_SpWater->Bind();
DrawWater(objects);
}
void dd::Renderer::PlaceCamera(glm::vec3 position)
{
m_DefaultCamera->SetPosition(position);
}
void dd::Renderer::DrawScene(RenderQueue &objects, ShaderProgram &program)
{
GLuint shaderProgramHandle = program;
glm::mat4 viewMatrix = m_Camera->ViewMatrix();
glm::mat4 PV = m_Camera->ProjectionMatrix() * viewMatrix;
glm::mat4 MVP;
for (auto &job : objects) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if (modelJob) {
glm::mat4 modelMatrix = modelJob->ModelMatrix;
MVP = PV * modelMatrix;
glUniform4fv(glGetUniformLocation(shaderProgramHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "V"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightPosition"), 1, glm::value_ptr(glm::vec3(0.f,0.f,-9.f)));
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightSpecular"), 1, glm::value_ptr(glm::vec3(1.f)));
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightDiffuse"), 1, glm::value_ptr(glm::vec3(1.f)));
glUniform1f(glGetUniformLocation(shaderProgramHandle, "LightRadius"), 40.0f);
glUniform1f(glGetUniformLocation(shaderProgramHandle, "MaterialShininess"), modelJob->Shininess);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, modelJob->DiffuseTexture);
if (modelJob->NormalTexture != 0) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, modelJob->NormalTexture);
} else {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, *m_StandardNormal);
}
if (modelJob->SpecularTexture != 0) {
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, modelJob->SpecularTexture);
} else {
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, *m_StandardSpecular);
}
if (modelJob->Skeleton != nullptr) {
auto animation = modelJob->Skeleton->GetAnimation(modelJob->AnimationName);
if (animation != nullptr) {
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(
*animation,
modelJob->AnimationTime,
modelJob->NoRootMotion
);
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
LOG_WARNING("Tried to play unknown animation \"%s\"", modelJob->AnimationName.c_str());
}
}
glBindVertexArray(modelJob->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
continue;
}
auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(job);
if (spriteJob)
{
glm::mat4 modelMatrix = spriteJob->ModelMatrix;
MVP = PV * modelMatrix;
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "V"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniform4fv(glGetUniformLocation(shaderProgramHandle, "Color"), 1, glm::value_ptr(spriteJob->Color));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, spriteJob->DiffuseTexture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, spriteJob->NormalTexture);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, spriteJob->SpecularTexture);
glBindVertexArray(m_UnitQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_UnitQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_UnitQuad->m_Indices.size(), GL_UNSIGNED_INT, 0, 0);
continue;
}
}
}
void dd::Renderer::DrawLightSpheres(RenderQueue &lights)
{
GLuint shaderProgramHandle = *m_SpDeferred2;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_GPosition);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_GNormal);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m_GSpecular);
glm::mat4 projectionMatrix = m_Camera->ProjectionMatrix();
glm::mat4 viewMatrix = m_Camera->ViewMatrix();
glm::mat4 PV = projectionMatrix * viewMatrix;
glm::mat4 MVP;
for (auto &job : lights) {
auto pointLightJob = std::dynamic_pointer_cast<PointLightJob>(job);
if (pointLightJob) {
glm::mat4 modelMatrix = glm::translate(pointLightJob->Position) * glm::scale(glm::vec3(pointLightJob->Radius * 2.f));
MVP = PV * modelMatrix;
glUniform2fv(glGetUniformLocation(shaderProgramHandle, "ViewportSize"), 1, glm::value_ptr(glm::vec2(m_Resolution.Width, m_Resolution.Height)));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "V"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "P"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightPosition"), 1, glm::value_ptr(pointLightJob->Position));
glUniform1f(glGetUniformLocation(shaderProgramHandle, "LightRadius"), pointLightJob->Radius);
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightDiffuse"), 1, glm::value_ptr(pointLightJob->DiffuseColor));
glUniform3fv(glGetUniformLocation(shaderProgramHandle, "LightSpecular"), 1, glm::value_ptr(pointLightJob->SpecularColor));
glBindVertexArray(m_UnitSphere->VAO);
glDrawArrays(GL_TRIANGLES, 0, m_UnitSphere->m_Vertices.size());
}
}
}
void dd::Renderer::DrawWater(RenderQueue &rq)
{
GLuint shaderProgramHandle = *m_SpWater;
glm::mat4 projectionMatrix = m_Camera->ProjectionMatrix();
glm::mat4 viewMatrix = m_Camera->ViewMatrix();
glm::mat4 PV = projectionMatrix * viewMatrix;
glm::mat4 MVP;
for ( auto &job : rq ) {
auto waterJob = std::dynamic_pointer_cast<WaterParticleJob>(job);
if (waterJob) {
glm::mat4 modelMatrix = waterJob->ModelMatrix;
MVP = PV * modelMatrix;
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "M"), 1, GL_FALSE,
glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgramHandle, "V"), 1, GL_FALSE,
glm::value_ptr(viewMatrix));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *m_WhiteSphereTexture);
glBindVertexArray(m_UnitQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_UnitQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_UnitQuad->m_Indices.size(), GL_UNSIGNED_INT, 0, 0);
}
}
//blur1
shaderProgramHandle = *m_SpWater2;
glDisable(GL_CULL_FACE);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbWaterBlur);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
m_SpWater2->Bind();
//TODO: Add this in water particle component. Blurradius
float radius = 3.f;
glUniform2fv(glGetUniformLocation(shaderProgramHandle, "dir"), 1, glm::value_ptr(glm::vec2(1.0f, 0.0f)));
glUniform1f(glGetUniformLocation(shaderProgramHandle, "res"), m_Resolution.Width);
glUniform1f(glGetUniformLocation(shaderProgramHandle, "radius"), radius);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Gwater);
glBindVertexArray(m_ScreenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
//blur2
shaderProgramHandle = *m_SpWater2;
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred3);
m_SpWater2->Bind();
glUniform2fv(glGetUniformLocation(shaderProgramHandle, "dir"), 1, glm::value_ptr(glm::vec2(0.0f, 1.0f)));
glUniform1f(glGetUniformLocation(shaderProgramHandle, "res"), m_Resolution.Height);
glUniform1f(glGetUniformLocation(shaderProgramHandle, "radius"), radius);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_BWater);
glBindVertexArray(m_ScreenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
GLuint dd::Renderer::CreateQuad()
{
float quadVertices[] =
{
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
float quadTexCoords[] =
{
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
GLuint vbo[2], vao;
glGenBuffers(2, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, 3 * 6 * sizeof(float), quadVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, 2 * 6 * sizeof(float), quadTexCoords, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(4);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return vao;
}
void dd::Renderer::DebugKeys()
{
if (glfwGetKey(m_Window, GLFW_KEY_F1)) {
m_CurrentScreenBuffer = m_TFinal;
}
if (glfwGetKey(m_Window, GLFW_KEY_F2)) {
m_CurrentScreenBuffer = m_GDiffuse;
}
if (glfwGetKey(m_Window, GLFW_KEY_F3)) {
m_CurrentScreenBuffer = m_GPosition;
}
if (glfwGetKey(m_Window, GLFW_KEY_F4)) {
m_CurrentScreenBuffer = m_GNormal;
}
if (glfwGetKey(m_Window, GLFW_KEY_F5)) {
m_CurrentScreenBuffer = m_GSpecular;
}
if (glfwGetKey(m_Window, GLFW_KEY_F6)) {
m_CurrentScreenBuffer = m_TLighting;
}
if (glfwGetKey(m_Window, GLFW_KEY_F7)) {
m_CurrentScreenBuffer = m_Gwater;
}
if (glfwGetKey(m_Window, GLFW_KEY_F8)) {
m_CurrentScreenBuffer = m_BWater;
}
}
void dd::Renderer::DrawGUI(dd::RenderQueue& rq)
{
glBindFramebuffer(GL_FRAMEBUFFER, m_FbDeferred3);
glDisable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
//glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
m_SpScreen->Bind();
glm::mat4 MVP;
for (auto &job : rq) {
auto frameJob = std::dynamic_pointer_cast<FrameJob>(job);
if (frameJob) {
FrameJob jobCopy = *(frameJob.get());
glm::mat4 viewMatrix = glm::mat4(1); //frameJob->ViewMatrix;
glm::mat4 PV = glm::mat4(1); //frameJob->ProjectionMatrix * viewMatrix;
glm::mat4 modelMatrix = glm::mat4(1); //frameJob->ModelMatrix;
MVP = PV * modelMatrix;
glUniformMatrix4fv(glGetUniformLocation(*m_SpScreen, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glUniformMatrix4fv(glGetUniformLocation(*m_SpScreen, "M"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(*m_SpScreen, "V"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniform4fv(glGetUniformLocation(*m_SpScreen, "Color"), 1, glm::value_ptr(frameJob->Color));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, frameJob->DiffuseTexture);
//glActiveTexture(GL_TEXTURE1);
//glBindTexture(GL_TEXTURE_2D, frameJob->NormalTexture);
//glActiveTexture(GL_TEXTURE2);
//glBindTexture(GL_TEXTURE_2D, frameJob->SpecularTexture);
Rectangle& vp = frameJob->Viewport;
glViewport(vp.X, m_Resolution.Height - vp.Y - vp.Height, vp.Width, vp.Height);
Rectangle& sc = frameJob->Scissor;
if (sc == Rectangle()) {
glDisable(GL_SCISSOR_TEST);
} else {
glEnable(GL_SCISSOR_TEST);
glScissor(sc.X, m_Resolution.Height - sc.Y - sc.Height, sc.Width, sc.Height);
}
glBindVertexArray(m_ScreenQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
continue;
}
}
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, m_Resolution.Width, m_Resolution.Height);
}
-192
View File
@@ -1,192 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/ShaderProgram.h"
void dd::Shader::Compile()
{
LOG_INFO("Compiling shader \"%s\"", m_FileName.c_str());
std::string shaderFile;
std::ifstream in(m_FileName, std::ios::in);
if (!in)
{
LOG_ERROR("Error: Failed to open shader file \"%s\"", m_FileName.c_str());
return;
}
in.seekg(0, std::ios::end);
shaderFile.resize((int)in.tellg());
in.seekg(0, std::ios::beg);
in.read(&shaderFile[0], shaderFile.size());
in.close();
const GLchar* shaderFileC = shaderFile.c_str();
const GLint length = shaderFile.length();
glShaderSource(m_ShaderHandle, 1, &shaderFileC, &length);
if(GLERROR("glShaderSource"))
return;
glCompileShader(m_ShaderHandle);
GLint compileStatus;
glGetShaderiv(m_ShaderHandle, GL_COMPILE_STATUS, &compileStatus);
if(compileStatus != GL_TRUE)
{
LOG_ERROR("Shader compilation failed");
GLsizei infoLogLength;
glGetShaderiv(m_ShaderHandle, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* infolog = new GLchar[infoLogLength];
glGetShaderInfoLog(m_ShaderHandle, infoLogLength, &infoLogLength, infolog);
LOG_ERROR(infolog);
delete[] infolog;
}
if(GLERROR("glCompileShader"))
return;
}
dd::Shader::Shader(GLenum shaderType, std::string resourceName)
: m_ShaderType(shaderType)
, m_FileName(resourceName)
{
m_ShaderHandle = glCreateShader(shaderType);
if (GLERROR("glCreateShader"))
return;
Compile();
}
dd::Shader::~Shader()
{
if (m_ShaderHandle != 0)
{
glDeleteShader(m_ShaderHandle);
}
}
GLenum dd::Shader::GetType() const
{
return m_ShaderType;
}
std::string dd::Shader::GetFileName() const
{
return m_FileName;
}
GLuint dd::Shader::GetHandle() const
{
return m_ShaderHandle;
}
dd::ShaderProgram::ShaderProgram(std::string resourceName)
{
auto path = boost::filesystem::path(resourceName);
if (!boost::filesystem::is_directory(path))
{
LOG_ERROR("Failed to load shader program: \"%s\" is not a directory", resourceName.c_str());
return;
}
for (auto it = boost::filesystem::directory_iterator(path); it != boost::filesystem::directory_iterator(); it++)
{
std::string filename = it->path().filename().string();
std::string filepath = it->path().string();
if (filename == "Vertex.glsl")
{
m_Shaders.push_back(ResourceManager::Load<VertexShader>(filepath, this));
}
else if (filename == "Fragment.glsl")
{
m_Shaders.push_back(ResourceManager::Load<FragmentShader>(filepath, this));
}
else if (filename == "Geometry.glsl")
{
m_Shaders.push_back(ResourceManager::Load<GeometryShader>(filepath, this));
}
}
}
dd::ShaderProgram::~ShaderProgram()
{
if (m_ShaderProgramHandle != 0)
{
glDeleteProgram(m_ShaderProgramHandle);
}
}
GLuint dd::ShaderProgram::Link()
{
if (m_Shaders.size() == 0)
{
LOG_ERROR("Failed to link shader program: No shaders bound");
return 0;
}
if (m_ShaderProgramHandle == 0)
{
m_ShaderProgramHandle = glCreateProgram();
}
LOG_INFO("Linking shader program");
for (auto &shader : m_Shaders)
{
glAttachShader(m_ShaderProgramHandle, shader->GetHandle());
}
glLinkProgram(m_ShaderProgramHandle);
if (GLERROR("glLinkProgram"))
return 0;
return m_ShaderProgramHandle;
}
GLuint dd::ShaderProgram::GetHandle()
{
return m_ShaderProgramHandle;
}
void dd::ShaderProgram::Bind()
{
if (m_ShaderProgramHandle == 0)
return;
glUseProgram(m_ShaderProgramHandle);
}
void dd::ShaderProgram::Unbind()
{
glActiveShaderProgram(0, 0);
}
void dd::ShaderProgram::BindFragDataLocation(int colorNumber, std::string name)
{
if (m_ShaderProgramHandle == 0)
return;
glBindFragDataLocation(m_ShaderProgramHandle, colorNumber, name.c_str());
}
void dd::ShaderProgram::OnChildReloaded(dd::Resource* child) {
LOG_INFO("Re-linking shader program");
glLinkProgram(m_ShaderProgramHandle);
if (GLERROR("glLinkProgram"))
return;
}
-161
View File
@@ -1,161 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/Skeleton.h"
int dd::Skeleton::CreateBone(int ID, int parentID, std::string name, glm::mat4 offsetMatrix)
{
if (m_BonesByName.find(name) != m_BonesByName.end()) {
return m_BonesByName.at(name)->ID;
} else {
Bone* bone;
if (parentID == -1) {
bone = new Bone(ID, nullptr, name, offsetMatrix);
RootBone = bone;
} else {
Bone* parent = Bones[parentID];
bone = new Bone(ID, parent, name, offsetMatrix);
parent->Children.push_back(bone);
}
Bones[ID] = bone;
m_BonesByName[name] = bone;
return ID;
}
}
dd::Skeleton::~Skeleton()
{
for (auto &kv : Bones) {
delete kv.second;
}
}
const dd::Skeleton::Animation* dd::Skeleton::GetAnimation(std::string name)
{
auto it = Animations.find(name);
if (it != Animations.end()) {
return const_cast<const Animation*>(&it->second);
} else {
return nullptr;
}
}
std::vector<glm::mat4> dd::Skeleton::GetFrameBones(const Animation& animation, double time, bool noRootMotion /*= false*/)
{
// HACK: Animation wrap-around
while (time < 0)
time += animation.Duration;
while (time > animation.Duration)
time -= animation.Duration;
int currentKeyframeIndex = GetKeyframe(animation, time);
const Animation::Keyframe& currentFrame = animation.Keyframes[currentKeyframeIndex];
const Animation::Keyframe& nextFrame = animation.Keyframes[currentKeyframeIndex + 1];
float alpha = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
//auto animationFrame = Animations[""].Keyframes[frame];
std::map<int, glm::mat4> frameBones;
AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, alpha, frameBones, RootBone, glm::mat4(1));
std::vector<glm::mat4> finalMatrices;
for (auto &kv : frameBones) {
finalMatrices.push_back(kv.second);
}
return finalMatrices;
}
void dd::Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe &currentFrame, const Animation::Keyframe &nextFrame, float progress, std::map<int, glm::mat4> &boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
if (currentFrame.BoneProperties.find(bone->ID) != currentFrame.BoneProperties.end() || nextFrame.BoneProperties.find(bone->ID) != nextFrame.BoneProperties.end()) {
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties.at(bone->ID);
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties.at(bone->ID);
glm::vec3 positionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
glm::quat rotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
glm::vec3 scaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
positionInterp.x = 0;
positionInterp.z = 0;
}
boneMatrix = parentMatrix * (glm::translate(positionInterp) * glm::toMat4(rotationInterp) * glm::scale(scaleInterp));
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = parentMatrix * bone->Parent->OffsetMatrix; // * glm::inverse(bone->OffsetMatrix);
boneMatrices[bone->ID] = boneMatrix; // * bone->OffsetMatrix;
}
for (auto &child : bone->Children) {
std::string name = child->Name;
AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, progress, boneMatrices, child, boneMatrix);
}
}
int dd::Skeleton::GetBoneID(std::string name)
{
if (m_BonesByName.find(name) == m_BonesByName.end()) {
return -1;
} else {
return m_BonesByName.at(name)->ID;
}
}
void dd::Skeleton::PrintSkeleton()
{
if (LOG_LEVEL < LOG_LEVEL_DEBUG) {
return;
}
PrintSkeleton(RootBone, 0);
}
void dd::Skeleton::PrintSkeleton(const Bone* bone, int depthCount)
{
std::stringstream ss;
ss << std::string(depthCount, ' ');
ss << bone->ID << ": " << bone->Name;
std::cout << ss.str() << std::endl;
depthCount++;
for (auto &child : bone->Children) {
PrintSkeleton(child, depthCount);
}
}
int dd::Skeleton::GetKeyframe(const Animation& animation, double time)
{
if (time < 0)
time = 0;
if (time > animation.Duration)
return animation.Keyframes.size() - 1;
for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) {
if (animation.Keyframes[keyframe].Time > time)
return glm::max(0, keyframe - 1); // HACK: If the time is less than the first keyframe, don
}
return 0;
}
-68
View File
@@ -1,68 +0,0 @@
/*
This file is part of Daydream Engine.
Copyright 2014 Adam Byléhn, Tobias Dahl, Simon Holmberg, Viktor Ljung
Daydream Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Daydream Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Daydream Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Core/Texture.h"
dd::Texture::Texture(std::string path)
{
PNG image(path);
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
image = PNG("Textures/Core/ErrorTexture.png");
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
LOG_ERROR("Couldn't even load the error texture. This is a dark day indeed.");
return;
}
}
this->Width = image.Width;
this->Height = image.Height;
GLint format;
switch (image.Format) {
case Image::ImageFormat::RGB:
format = GL_RGB;
break;
case Image::ImageFormat::RGBA:
format = GL_RGBA;
break;
}
// Construct the OpenGL texture
glGenTextures(1, &m_Texture);
glBindTexture(GL_TEXTURE_2D, m_Texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, image.Width, image.Height, 0, format, GL_UNSIGNED_BYTE, image.Data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLERROR("Texture load");
}
dd::Texture::~Texture()
{
glDeleteTextures(1, &m_Texture);
}
void dd::Texture::Bind(GLenum textureUnit /* = GL_TEXTURE0 */)
{
glActiveTexture(textureUnit);
glBindTexture(GL_TEXTURE_2D, m_Texture);
}