feat: add shader class

This commit is contained in:
Krzysztof Rudnicki 2022-09-18 18:10:03 +02:00
parent df41a903f3
commit aef81a89c5
16 changed files with 259 additions and 49 deletions

View File

@ -33,6 +33,35 @@ namespace constants
GLfloat alpha = 1.0f;
} LEARN_OPEN_GL_COLOR;
inline const std::string_view VERTEX_SHADER_OUTPUT_FILE {
"./shaders/vertexShaderOutput.vs"
};
inline const std::string_view VERTEX_FIRST_SHADER {
"./shaders/firstShader.vs"
};
inline const std::string_view VERTEX_WITH_COLOR {
"./shaders/vertexWithColor.vs"
};
inline const std::string_view FRAGMENT_YELLOW {
"./shaders/yellow.fs"
};
inline const std::string_view FRAGMENT_ORANGE {
"./shaders/orange.fs"
};
inline const std::string_view FRAGMENT_COLOR_INPUT {
"./shaders/fragmentColorInput.fs"
};
inline const std::string_view FRAGMENT_UNIFORMS {
"./shaders/fragmentUniforms.fs"
};
// we send output from vertex shader (vertexColor)...
inline const char *VERTEX_SHADER_COLOR { "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"

View File

@ -15,41 +15,35 @@ int drawFigure(const int whatToDraw)
switch (whatToDraw)
{
case 0:
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false);
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false);
case 1:
return drawSquare(constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE);
return drawSquare(constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE);
case 2:
// Try to draw 2 triangles next to each other using glDrawArrays by adding more vertices to your data.
return drawTriangle(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false);
return drawTriangle(constants::TRIANGLES_VERTICES, constants::TRIANGLES_VERTICES_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false);
case 3:
// Now create the same 2 triangles using two different VAOs and VBOs for their data
return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1);
return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1);
case 4:
// Create two shader programs where the second program uses a different fragment shader that outputs the color yellow; draw both triangles again where one outputs the color yellow
return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_SHADER_SOURCE, constants::FRAGMENT_SHADER_SOURCE_YELLOW, false) == -1);
return (drawTriangle(constants::TRIANGLE_ONE, constants::TRIANGLE_ONE_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_ORANGE, false) == -1 || drawTriangle(constants::TRIANGLE_TWO, constants::TRIANGLE_TWO_SIZE, constants::VERTEX_FIRST_SHADER, constants::FRAGMENT_YELLOW, false) == -1);
case 5:
// Get color from vertex shader to fragment shader
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX, false);
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_COLOR_INPUT, false);
case 6:
// set color from opengl code to uniform value in fragment shader
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_SHADER_COLOR, constants::FRAGMENT_SHADER_UNIFORMS, false);
return drawTriangle(constants::TRIANGLE_VERTICES, constants::TRIANGLE_VERTICES_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_UNIFORMS, false);
case constants::MAX_DRAW_CALL:
// set color from opengl code to uniform value in fragment shader
return drawTriangle(constants::TRIANGLE_COLORS, constants::TRIANGLE_COLORS_SIZE, constants::VERTEX_SHADER_VERTICE_COLOR, constants::FRAGMENT_SHADER_COLOR_FROM_VERTEX, true);
return drawTriangle(constants::TRIANGLE_COLORS, constants::TRIANGLE_COLORS_SIZE, constants::VERTEX_WITH_COLOR, constants::FRAGMENT_COLOR_INPUT, true);
default:
throw "No function for this draw call";
}
}
int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource)
int drawSquare(const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource)
{
const std::pair<unsigned int, unsigned int> shaders = compileShaders(vertexShaderSource, fragmentShaderSource);
if (shaders.first == 0 || shaders.second == 0)
return -1;
const unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second);
if (shaderProgram == 0)
return -1;
Shader ourShader(vertexShaderSource, fragmentShaderSource);
const unsigned int VAO = generateBindVAO();
copyVerticesMemory(constants::SQUARE_VERTICES, constants::SQUARE_VERTICES_SIZE, GL_ARRAY_BUFFER);
@ -58,65 +52,48 @@ int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource)
// set vertex attribute pointers
configureVertexAttribute(false);
doDrawElements(shaderProgram, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES));
doDrawElements(ourShader, VAO, GL_TRIANGLES, GL_UNSIGNED_INT, std::size(constants::SQUARE_INDICES));
return 0;
}
void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw)
void doDrawElements(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw)
{
glUseProgram(shaderProgram);
Shader.use();
glBindVertexArray(vertexArrayObject);
glDrawElements(drawArrayMode, numberOfElementsToDraw, drawType, 0);
glBindVertexArray(0);
}
int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded)
int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource, const bool colorIncluded)
{
const unsigned int vertexBufferObject = copyVerticesMemory(triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER);
const std::pair<unsigned int, unsigned int> shaders = compileShaders(vertexShaderSource, fragmentShaderSource);
if (shaders.first == 0 || shaders.second == 0)
return -1;
const unsigned int shaderProgram = linkShaderObjectsShaderProgram(shaders.first, shaders.second);
if (shaderProgram == 0)
return -1;
Shader ourShader(vertexShaderSource, fragmentShaderSource);
const unsigned int vertexArrayObject = generateBindVAO();
copyVerticesArray(vertexBufferObject, triangleVertices, triangleVerticesSize, GL_ARRAY_BUFFER);
// set vertex attribute pointers
configureVertexAttribute(colorIncluded);
doDrawArrays(shaderProgram, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize);
doDrawArrays(ourShader, vertexArrayObject, GL_TRIANGLES, 0, triangleVerticesSize);
return 0;
}
void updateUniformColor(const unsigned int shaderProgram, const GLchar* uniformName)
GLfloat updateUniformColor()
{
// update the uniform color
const float timeValue = glfwGetTime(); // retrieve running time
const float greenValue = sin(timeValue) / 2.0f + 0.5f; // vary the color from 0.0 to 1.0 using sin
const int vertexColorLocation = glGetUniformLocation(shaderProgram, uniformName); // query the location of our uniform
if(vertexColorLocation != -1) // if glGetUniformLocation returns -1 it could not find the location
{
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); /* we set the uniform value using glUniform4f
4f means that it expects 4 floats
few of possible postfixes:
f: the function expects a float as its value.
i: the function expects an int as its value.
ui: the function expects an unsigned int as its value.
3f: the function expects 3 floats as its value.
fv: the function expects a float vector/array as its value.
*/
}
return greenValue;
}
void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered)
void doDrawArrays(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered)
{
// use shader program to render an object
glUseProgram(shaderProgram);
updateUniformColor(shaderProgram, "ourColor");
Shader.use();
Shader.setFloat("ourColor", updateUniformColor());
glBindVertexArray(vertexArrayObject);
// From left:
// primitive type we want to draw

View File

@ -4,10 +4,10 @@
#include <GLFW/glfw3.h>
int drawFigure(const int whatToDraw);
int drawSquare(const char* vertexShaderSource, const char* fragmentShaderSource);
int drawSquare(const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource);
void doDrawElements(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const GLenum drawType, const int numberOfElementsToDraw);
int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const char* vertexShaderSource, const char* fragmentShaderSource, const bool colorIncluded);
void updateUniformColor(const unsigned int shaderProgram, const GLchar* uniformName);
void doDrawArrays(const unsigned int shaderProgram, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered );
int drawTriangle(const float triangleVertices[], const size_t triangleVerticesSize, const std::string_view vertexShaderSource, const std::string_view fragmentShaderSource, const bool colorIncluded);
GLfloat updateUniformColor();
void doDrawArrays(const Shader Shader, const unsigned int vertexArrayObject, const GLenum drawArrayMode, const int firstIndex, const unsigned int numberOfIndicesToBeRendered );
#endif

BIN
Engine/engine/match Executable file → Normal file

Binary file not shown.

View File

@ -1,10 +1,26 @@
#ifndef MISC_CPP
#define MISC_CPP
#include <iostream>
#include <fstream>
#include <sstream>
#include "misc.hpp"
void print(const std::string s)
{
std::cout << s << std::endl;
}
std::string fileBufferToString(const std::string filePath, std::ifstream &file)
{
std::string sourceCode;
// open files
file.open(filePath); // read file's buffer contents into streams
std::stringstream fileStream;
fileStream << file.rdbuf();
// close file handlers
file.close();
// convert stream into string
sourceCode = fileStream.str();
return sourceCode;
}
#endif

View File

@ -3,4 +3,5 @@
#include <iostream>
void print(const std::string s);
std::string fileBufferToString(const std::string filePath, std::ifstream &file);
#endif

107
Engine/engine/shader.cpp Normal file
View File

@ -0,0 +1,107 @@
#ifndef SHADER_CPP
#define SHADER_CPP
#include <glad/glad.h>
#include <fstream>
#include "shader.hpp"
#include "misc.hpp"
unsigned int Shader::linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader) const
{
// link shader objects into shader program
// will store shader program id
// creates program
const unsigned int shaderProgram = glCreateProgram();
// attachShaders
glAttachShader(shaderProgram, vertexShaders);
glAttachShader(shaderProgram, fragmentShader);
// link shaders
glLinkProgram(shaderProgram);
if (!shaderSuccessful(shaderProgram, false))
return 0;
// delete shaders (they are linked into shaderProgram and we do not need them anymore)
glDeleteShader(vertexShaders);
glDeleteShader(fragmentShader);
if (shaderProgram == 0)
print("Shader Program Linking Failed");
return shaderProgram;
}
unsigned int Shader::compileShader(const GLenum shaderType, const char *shaderSource) const
{
// we create vertex shader and assign its id to shader variable
const unsigned int shaderID = glCreateShader(shaderType);
// attach shader source code to shader object
// from left: shader object to compile, how many strings as source code, actual source code (we leave the 4th as NULL)
glShaderSource(shaderID, 1, &shaderSource, NULL);
// compile shader
glCompileShader(shaderID);
if (!shaderSuccessful(shaderID, true))
return 0;
return shaderID;
}
const char* Shader::getSourceCode(const std::string_view sourcePath) const
{
// 1. retrieve the vertex/fragment source code from filePath
std::string sourceCode;
std::ifstream sourceFile;
// ensure ifstream objects can throw exceptions:
sourceFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
sourceCode = fileBufferToString(sourcePath, sourceFile);
}
// https://stackoverflow.com/a/62030396
catch(std::ifstream::failure const& e)
{
std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ for sourcePath: " << sourcePath << std::endl;
}
const char* cSourceCode = sourceCode.c_str();
return cSourceCode;
}
void Shader::use()
{
glUseProgram(ID);
}
void Shader::setBool(const std::string_view &name, const bool value) const
{
const int vertexColorLocation = glGetUniformLocation(ID, name.c_str());
if(vertexColorLocation != -1) {
glUniform1i(vertexColorLocation, (int)value);
}
}
void Shader::setInt(const std::string_view &name, const int value) const
{
const int vertexColorLocation = glGetUniformLocation(ID, name.c_str());
if(vertexColorLocation != -1) {
glUniform1i(vertexColorLocation, value);
}
}
void Shader::setFloat(const std::string_view &name, const float value) const
{
const int vertexColorLocation = glGetUniformLocation(ID, name.c_str());
if(vertexColorLocation != -1) {
glUniform1f(vertexColorLocation, value);
}
}
Shader::Shader(const std::string_view vertexPath, const std::string_view fragmentPath)
{
const char* vShaderCode = getSourceCode(vertexPath);
const char* fShaderCode = getSourceCode(fragmentPath);
const int vectorShaderID = compileShader(GL_VERTEX_SHADER, vShaderCode);
const int fragmentShaderID = compileShader(GL_FRAGMENT_SHADER, fShaderCode);
ID = linkShaderObjectsShaderProgram(vectorShaderID, fragmentShaderID);
}
#endif // SHADER_CPP

29
Engine/engine/shader.hpp Normal file
View File

@ -0,0 +1,29 @@
#ifndef SHADER_HPP
#define SHADER_HPP
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
// the program ID
unsigned int ID;
unsigned int linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader) const;
int shaderSuccessful(const unsigned int shader, const bool compilation) const;
unsigned int compileShader(const GLenum shaderType, const char *shaderSource) const;
const char *getSourceCode(const std::string_view sourcePath) const;
// constructor reads and builds the shader
Shader(const std::string_view vertexPath, const std::string_view fragmentPath);
// use/activate the shader
void use();
// utility uniform functions
void setBool(const std::string_view &name, const bool value) const;
void setInt(const std::string_view &name, const int value) const;
void setFloat(const std::string_view &name, const float value) const;
};
#endif

View File

@ -3,6 +3,7 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "misc.hpp"
unsigned int linkShaderObjectsShaderProgram(const unsigned int vertexShaders, const unsigned int fragmentShader);
std::pair<unsigned int, unsigned int> compileShaders(const char* vertexShaderSource, const char* fragmentShaderSource);

View File

@ -0,0 +1,6 @@
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

View File

@ -0,0 +1,7 @@
#version 330 core
out vec4 FragColor;
in vec3 vertexColor;
void main()
{
FragColor = vec4(vertexColor, 1.0);
}

View File

@ -0,0 +1,8 @@
#version 330 core
out vec4 FragColor;
uniform vec1 ourColor;
void main()
{
FragColor = (0.0f, ourColor, 0.0f, 1.0f);
}

View File

@ -0,0 +1,6 @@
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

View File

@ -0,0 +1,8 @@
#version 330 core\n
layout (location = 0) in vec3 aPos;
out vec3 vertexColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
vertexColor = vec3(0.5, 0.0, 0.0);
}

View File

@ -0,0 +1,9 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 vertexColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
vertexColor = aColor;
}

View File

@ -0,0 +1,6 @@
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);
}