Files
SDBA/tigl.cpp
2021-05-18 10:33:08 +02:00

466 lines
14 KiB
C++

#include "tigl.h"
#include <glm/gtc/type_ptr.hpp>
#include <string>
#include <iostream>
namespace tigl
{
class ShaderImpl : public internal::Shader
{
public:
ShaderImpl();
~ShaderImpl();
void use();
void setProjectionMatrix(const glm::mat4& matrix);
void setViewMatrix(const glm::mat4& matrix);
void setModelMatrix(const glm::mat4& matrix);
void enableColor(bool enabled) { setUniform(Uniform::useColor, enabled); }
void enableTexture(bool enabled) { setUniform(Uniform::useTexture, enabled); }
void enableLighting(bool enabled) { setUniform(Uniform::useLighting, enabled); }
void setLightCount(int count) { setUniform(Uniform::lightCount, count); }
void setLightDirectional(int lightNr, bool isDirectional) { setUniform("lights[" + std::to_string(lightNr) + "].directional", isDirectional); }
void setLightPosition(int lightNr, const glm::vec3& position) { setUniform("lights[" + std::to_string(lightNr) + "].position", position); }
void setLightAmbient(int lightNr, const glm::vec3& color) { setUniform("lights[" + std::to_string(lightNr) + "].ambient", color); }
void setLightDiffuse(int lightNr, const glm::vec3& color) { setUniform("lights[" + std::to_string(lightNr) + "].diffuse", color); }
void setLightSpecular(int lightNr, const glm::vec3& color) { setUniform("lights[" + std::to_string(lightNr) + "].specular", color); }
void setShinyness(float shinyness) { setUniform(Uniform::shinyness, shinyness); }
void enableColorMult(bool enabled) { setUniform(Uniform::useColorMult, enabled); }
void setColorMult(const glm::vec4& color) { setUniform(Uniform::colorMult, color); }
void enableAlphaTest(bool enabled) { setUniform(Uniform::useAlphaTest, enabled); }
void enableFog(bool enabled) { setUniform(Uniform::useFog, enabled); }
void setFogLinear(float begin, float end) {
setUniform(Uniform::fogType, 0);
setUniform(Uniform::fogLinNear, begin);
setUniform(Uniform::fogLinFar, end);
}
void setFogExp(float density) {
setUniform(Uniform::fogType, 1);
setUniform(Uniform::fogExpDensity, density);
}
void setFogExp2(float density) {
setUniform(Uniform::fogType, 2);
setUniform(Uniform::fogExpDensity, density);
}
private:
void addShader(int shaderProgram, GLenum shaderType, const std::string& shader);
GLuint programId;
enum Uniform
{
//matrices
ProjectionMatrix,
ViewMatrix,
ModelMatrix,
NormalMatrix,
//flags
useColor,
useColorMult,
useTexture,
useLighting,
useAlphaTest,
useFog,
//parameters
colorMult,
lightCount,
shinyness,
cameraPosition,
fogType,
fogLinNear,
fogLinFar,
fogExpDensity,
UniformMax
};
int uniforms[UniformMax];
void setUniform(Uniform uniform, const glm::mat4& value);
void setUniform(Uniform uniform, const glm::mat3& value);
void setUniform(Uniform uniform, const glm::vec4& value);
void setUniform(Uniform uniform, const glm::vec3& value);
void setUniform(Uniform uniform, const glm::vec2& value);
void setUniform(Uniform uniform, float value);
void setUniform(Uniform uniform, int value);
void setUniform(Uniform uniform, bool value);
//slower
void setUniform(const std::string& uniform, const glm::mat4& value);
void setUniform(const std::string& uniform, const glm::mat3& value);
void setUniform(const std::string& uniform, const glm::vec4& value);
void setUniform(const std::string& uniform, const glm::vec3& value);
void setUniform(const std::string& uniform, const glm::vec2& value);
void setUniform(const std::string& uniform, float value);
void setUniform(const std::string& uniform, int value);
void setUniform(const std::string& uniform, bool value);
glm::mat4 modelMatrix;
glm::mat4 projectionMatrix;
glm::mat4 viewMatrix;
};
std::unique_ptr<internal::Shader> shader;
int attributePosition = 0;
int attributeColor = 1;
int attributeTexcoord = 2;
int attributeNormal = 3;
// Initializes shader used
void init()
{
glewInit();
shader.reset(new ShaderImpl());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
}
std::vector<Vertex> vertices;
GLenum shape = 0;
void begin(GLenum shape)
{
assert(tigl::shape == 0);
tigl::shape = shape;
vertices.clear();
}
void addVertex(const Vertex& vertex)
{
vertices.push_back(vertex);
}
void end()
{
assert(shape != 0);
drawVertices(shape, vertices);
shape = 0;
}
void drawVertices(GLenum shape, const std::vector<Vertex>& vertices)
{
if (vertices.size() > 0)
{
glVertexAttribPointer(tigl::attributePosition, 3, GL_FLOAT, false, sizeof(Vertex), &vertices[0].position);
glVertexAttribPointer(tigl::attributeColor, 4, GL_FLOAT, false, sizeof(Vertex), &vertices[0].color);
glVertexAttribPointer(tigl::attributeTexcoord, 2, GL_FLOAT, false, sizeof(Vertex), &vertices[0].texcoord);
glVertexAttribPointer(tigl::attributeNormal, 3, GL_FLOAT, false, sizeof(Vertex), &vertices[0].normal);
glDrawArrays(shape, 0, (GLsizei)vertices.size());
}
}
ShaderImpl::ShaderImpl()
{
this->programId = glCreateProgram();
addShader(this->programId, GL_VERTEX_SHADER, R"ESC(#version 330
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec4 a_color;
layout (location = 2) in vec2 a_texcoord;
layout (location = 3) in vec3 a_normal;
uniform mat4 modelMatrix = mat4(1.0);
uniform mat4 viewMatrix = mat4(1.0);
uniform mat4 projectionMatrix = mat4(1.0);
uniform mat3 normalMatrix = mat3(1.0);
out vec4 color;
out vec2 texCoord;
out vec3 normal;
out vec3 position;
void main()
{
texCoord = a_texcoord;
color = a_color;
normal = normalMatrix * a_normal;
position = vec3(modelMatrix * vec4(a_position,1));
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(a_position,1);
}
)ESC");
addShader(this->programId, GL_FRAGMENT_SHADER, R"ESC(#version 330
layout(location = 0) out vec4 fragColor;
uniform sampler2D s_texture;
//flags
uniform bool useColor = false;
uniform bool useColorMult = false;
uniform bool useTexture = false;
uniform bool useLighting = false;
uniform bool useAlphaTest = false;
uniform bool useFog = false;
//parameters
uniform vec4 colorMult = vec4(1,1,1,1);
uniform vec3 fogColor = vec3(1.0);
uniform vec3 cameraPosition;
uniform int fogType = 0;
uniform float fogLinNear = 0;
uniform float fogLinFar = 100;
uniform float fogExpDensity = 0;
uniform float shinyness = 0;
struct Light
{
bool directional;
vec3 position;
vec3 diffuse;
vec3 ambient;
vec3 specular;
};
uniform Light lights[5];
uniform int lightCount = 1;
in vec4 color;
in vec2 texCoord;
in vec3 normal;
in vec3 position;
float fogFactorLinear(const float dist, const float start, const float end) {
return 1.0 - clamp((end - dist) / (end - start), 0.0, 1.0);
}
float fogFactorExp2(const float dist, const float density) {
const float LOG2 = -1.442695;
float d = density * dist;
return 1.0 - clamp(exp2(d * d * LOG2), 0.0, 1.0);
}
float fogFactorExp(const float dist, const float density) {
return 1.0 - clamp(exp(-density * dist), 0.0, 1.0);
}
void main()
{
vec4 outputColor = vec4(1,1,1,1);
if(useColor)
outputColor *= color;
if(useColorMult)
outputColor *= colorMult;
if(useTexture)
outputColor *= texture2D(s_texture, texCoord);
if(useLighting) {
vec3 ambient;
vec3 specular;
vec3 diffuse;
for(int i = 0; i < lightCount; i++) {
vec3 lightDir = normalize(lights[i].position - position);
ambient += lights[i].ambient;
float diffuseFactor = max(0, dot(lightDir, normalize(normal)));
diffuse += diffuseFactor * lights[i].diffuse;
vec3 reflectDir = reflect(-lightDir, normalize(normal));
float specularFactor = pow(max(dot(normalize(cameraPosition-position), reflectDir), 0.0), shinyness);
specular += specularFactor * lights[i].specular;
}
outputColor.rgb = (ambient + specular + diffuse) * outputColor.rgb;
}
if(useFog) {
float fogDistance = gl_FragCoord.z / gl_FragCoord.w;
if(fogType == 0)
outputColor.rgb = mix(outputColor.rgb, fogColor, fogFactorLinear(fogDistance, fogLinNear,fogLinFar));
else if(fogType == 1)
outputColor.rgb = mix(outputColor.rgb, fogColor, fogFactorExp(fogDistance, fogExpDensity));
else if(fogType == 2)
outputColor.rgb = mix(outputColor.rgb, fogColor, fogFactorExp2(fogDistance, fogExpDensity));
}
if(useAlphaTest && outputColor.a < 0.01)
discard;
fragColor = outputColor;
}
)ESC");
glLinkProgram(programId);
GLint status;
glGetProgramiv(programId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int length, charsWritten;
glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &length);
char* infolog = new char[length + 1];
memset(infolog, 0, length + 1);
glGetProgramInfoLog(programId, length, &charsWritten, infolog);
std::cout << "Error compiling shader:\n" << infolog << std::endl;
delete[] infolog;
return;
}
uniforms[Uniform::ModelMatrix] = glGetUniformLocation(programId, "modelMatrix");
uniforms[Uniform::ViewMatrix] = glGetUniformLocation(programId, "viewMatrix");
uniforms[Uniform::ProjectionMatrix] = glGetUniformLocation(programId, "projectionMatrix");
uniforms[Uniform::NormalMatrix] = glGetUniformLocation(programId, "normalMatrix");
uniforms[Uniform::useColor] = glGetUniformLocation(programId, "useColor");
uniforms[Uniform::useColorMult] = glGetUniformLocation(programId, "useColorMult");
uniforms[Uniform::useTexture] = glGetUniformLocation(programId, "useTexture");
uniforms[Uniform::useLighting] = glGetUniformLocation(programId, "useLighting");
uniforms[Uniform::useAlphaTest] = glGetUniformLocation(programId, "useAlphaTest");
uniforms[Uniform::useFog] = glGetUniformLocation(programId, "useFog");
uniforms[Uniform::colorMult] = glGetUniformLocation(programId, "colorMult");
uniforms[Uniform::cameraPosition] = glGetUniformLocation(programId, "cameraPosition");
uniforms[Uniform::shinyness] = glGetUniformLocation(programId, "shinyness");
uniforms[Uniform::fogType] = glGetUniformLocation(programId, "fogType");
uniforms[Uniform::fogLinNear] = glGetUniformLocation(programId, "fogLinNear");
uniforms[Uniform::fogLinFar] = glGetUniformLocation(programId, "fogLinFar");
uniforms[Uniform::fogExpDensity] = glGetUniformLocation(programId, "fogExpDensity");
use();
}
ShaderImpl::~ShaderImpl()
{
}
void ShaderImpl::use()
{
glUseProgram(programId);
}
void ShaderImpl::addShader(int shaderProgram, GLenum shaderType, const std::string& shader)
{
GLuint shaderId = glCreateShader(shaderType);
const char* shaderSource = shader.c_str();
glShaderSource(shaderId, 1, &shaderSource, NULL);
glCompileShader(shaderId);
GLint status;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
int length, charsWritten;
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length);
char* infolog = new char[length + 1];
memset(infolog, 0, length + 1);
glGetShaderInfoLog(shaderId, length, &charsWritten, infolog);
std::cout << "Error compiling shader:\n" << infolog << std::endl;
delete[] infolog;
return;
}
glAttachShader(programId, shaderId);
}
void ShaderImpl::setProjectionMatrix(const glm::mat4& matrix)
{
this->projectionMatrix = matrix;
setUniform(Uniform::ProjectionMatrix, matrix);
}
void ShaderImpl::setViewMatrix(const glm::mat4& matrix)
{
this->viewMatrix = matrix;
setUniform(Uniform::ViewMatrix, matrix);
glm::vec4 cameraPosition = glm::inverse(matrix) * glm::vec4(0, 0, 0, 1);
setUniform(Uniform::cameraPosition, glm::vec3(cameraPosition));
}
void ShaderImpl::setModelMatrix(const glm::mat4& matrix)
{
this->modelMatrix = matrix;
setUniform(Uniform::ModelMatrix, matrix);
setUniform(Uniform::NormalMatrix, glm::mat3(glm::transpose(glm::inverse(modelMatrix))));
}
void ShaderImpl::setUniform(Uniform uniform, const glm::mat4& value)
{
glUniformMatrix4fv(uniforms[uniform], 1, false, glm::value_ptr(value));
}
void ShaderImpl::setUniform(Uniform uniform, const glm::mat3& value)
{
glUniformMatrix3fv(uniforms[uniform], 1, false, glm::value_ptr(value));
}
void ShaderImpl::setUniform(Uniform uniform, const glm::vec4& value)
{
glUniform4fv(uniforms[uniform], 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(Uniform uniform, const glm::vec3& value)
{
glUniform3fv(uniforms[uniform], 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(Uniform uniform, const glm::vec2& value)
{
glUniform2fv(uniforms[uniform], 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(Uniform uniform, bool value)
{
glUniform1i(uniforms[uniform], value ? GL_TRUE : GL_FALSE);
}
void ShaderImpl::setUniform(Uniform uniform, int value)
{
glUniform1i(uniforms[uniform], value);
}
void ShaderImpl::setUniform(Uniform uniform, float value)
{
glUniform1f(uniforms[uniform], value);
}
void ShaderImpl::setUniform(const std::string& uniform, const glm::mat4& value)
{
glUniformMatrix4fv(glGetUniformLocation(programId, uniform.c_str()), 1, false, glm::value_ptr(value));
}
void ShaderImpl::setUniform(const std::string& uniform, const glm::mat3& value)
{
glUniformMatrix3fv(glGetUniformLocation(programId, uniform.c_str()), 1, false, glm::value_ptr(value));
}
void ShaderImpl::setUniform(const std::string& uniform, const glm::vec4& value)
{
glUniform4fv(glGetUniformLocation(programId, uniform.c_str()), 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(const std::string& uniform, const glm::vec3& value)
{
glUniform3fv(glGetUniformLocation(programId, uniform.c_str()), 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(const std::string& uniform, const glm::vec2& value)
{
glUniform2fv(glGetUniformLocation(programId, uniform.c_str()), 1, glm::value_ptr(value));
}
void ShaderImpl::setUniform(const std::string& uniform, bool value)
{
glUniform1i(glGetUniformLocation(programId, uniform.c_str()), value ? GL_TRUE : GL_FALSE);
}
void ShaderImpl::setUniform(const std::string& uniform, int value)
{
glUniform1i(glGetUniformLocation(programId, uniform.c_str()), value);
}
void ShaderImpl::setUniform(const std::string& uniform, float value)
{
glUniform1f(glGetUniformLocation(programId, uniform.c_str()), value);
}
}