2022-09-05 20:17:25 +02:00
# ifndef DRAW_CPP
# define DRAW_CPP
# include <glad/glad.h>
# include <GLFW/glfw3.h>
# include <iostream>
2022-10-19 15:51:07 +02:00
# include <cmath>
2023-03-11 17:26:16 +01:00
# include <filesystem>
2022-09-05 20:17:25 +02:00
# include "draw.hpp"
# include "renderLoop.hpp"
# include "shaders.hpp"
# include "constants.hpp"
# include "misc.hpp"
2022-12-11 19:52:49 +01:00
# include "shader.hpp"
2023-03-05 20:02:41 +01:00
# include "textures.hpp"
2023-03-11 17:26:16 +01:00
# include "stb_image.h"
2022-09-05 20:17:25 +02:00
2022-09-10 13:40:58 +02:00
int drawFigure ( const int whatToDraw )
2022-09-05 20:17:25 +02:00
{
2022-09-10 13:40:58 +02:00
switch ( whatToDraw )
2022-09-05 20:17:25 +02:00
{
2022-09-10 13:40:58 +02:00
case 0 :
2023-01-27 21:29:04 +01:00
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) ;
2022-09-10 13:40:58 +02:00
case 1 :
2023-03-11 16:58:17 +01:00
return drawSquare ( constants : : SQUARE_VERTICES , constants : : SQUARE_VERTICES_SIZE , constants : : SQUARE_INDICES , constants : : SQUARE_INDICES_SIZE , constants : : VERTEX_SHADER_SOURCE , constants : : FRAGMENT_SHADER_SOURCE ) ;
2022-09-17 14:14:08 +02:00
case 2 :
// Try to draw 2 triangles next to each other using glDrawArrays by adding more vertices to your data.
2023-01-27 21:29:04 +01:00
return drawTriangleClass ( constants : : TRIANGLES_VERTICES , constants : : TRIANGLES_VERTICES_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) ;
2022-09-17 14:14:08 +02:00
case 3 :
// Now create the same 2 triangles using two different VAOs and VBOs for their data
2023-01-27 21:29:04 +01:00
return ( drawTriangleClass ( constants : : TRIANGLE_ONE , constants : : TRIANGLE_ONE_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) = = - 1 | | drawTriangleClass ( constants : : TRIANGLE_TWO , constants : : TRIANGLE_TWO_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) = = - 1 ) ;
2022-10-19 15:51:07 +02:00
case 4 :
2022-10-19 15:46:29 +02:00
// 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
2023-01-27 21:29:04 +01:00
return ( drawTriangleClass ( constants : : TRIANGLE_ONE , constants : : TRIANGLE_ONE_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) = = - 1 | | drawTriangleClass ( constants : : TRIANGLE_TWO , constants : : TRIANGLE_TWO_SIZE , constants : : VERTEX_SHADER_SOURCE_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_YELLOW_FILENAME ) = = - 1 ) ;
2022-10-19 15:51:07 +02:00
case 5 :
// Get color from vertex shader to fragment shader
2023-01-27 21:29:04 +01:00
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_COLOR_FILENAME , constants : : FRAGMENT_SHADER_COLOR_FROM_VERTEX_FILENAME ) ;
2022-10-19 15:51:07 +02:00
case 6 :
// set color from opengl code to uniform value in fragment shader
2023-01-27 21:29:04 +01:00
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_COLOR_FILENAME , constants : : FRAGMENT_SHADER_UNIFORMS_FILENAME ) ;
2022-11-20 23:14:59 +01:00
case 7 :
2022-10-19 15:51:07 +02:00
// set color from opengl code to uniform value in fragment shader
2023-01-18 17:51:24 +01:00
return drawTriangleClass ( constants : : TRIANGLE_COLORS , constants : : TRIANGLE_COLORS_SIZE , constants : : VERTEX_SHADER_VERTICE_COLOR_FILENAME , constants : : FRAGMENT_SHADER_COLOR_FROM_VERTEX_FILENAME , true ) ;
2023-01-27 21:29:04 +01:00
case 8 :
// upside down triangle
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_UPSIDE_DOWN_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME ) ;
case 9 :
{
// offset triangle
offsetsStruct offsets = offsetsStruct ( ) ;
offsets . xOffset = 0.5f ;
2023-03-05 20:02:41 +01:00
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_OFFSET_FILENAME , constants : : FRAGMENT_SHADER_SOURCE_FILENAME , false , false , offsets ) ;
2023-01-27 21:29:04 +01:00
}
2023-03-05 20:02:41 +01:00
case 10 :
2023-01-27 21:29:04 +01:00
return drawTriangleClass ( constants : : TRIANGLE_VERTICES , constants : : TRIANGLE_VERTICES_SIZE , constants : : VERTEX_SHADER_TASK_THREE_FILENAME , constants : : FRAGMENT_SHADER_TASK_THREE_FILENAME ) ;
2023-03-05 20:02:41 +01:00
case constants : : MAX_DRAW_CALL :
2023-03-11 16:58:17 +01:00
return drawDebilMode ( ) ;
2022-09-10 13:40:58 +02:00
default :
throw " No function for this draw call " ;
2022-09-07 18:54:59 +02:00
}
2022-09-05 20:17:25 +02:00
}
2022-12-11 18:49:16 +01:00
unsigned int getShaderProgram ( const char * vertexShaderSource , const char * fragmentShaderSource )
{
const std : : pair < unsigned int , unsigned int > shaders = compileShaders ( vertexShaderSource , fragmentShaderSource ) ;
if ( shaders . first = = 0 | | shaders . second = = 0 )
return 0 ;
const unsigned int shaderProgram = linkShaderObjectsShaderProgram ( shaders . first , shaders . second ) ;
if ( shaderProgram = = 0 )
return 0 ;
return shaderProgram ;
}
2023-01-27 21:29:04 +01:00
void setOffsets ( Shader shader , const offsetsStruct offsets ) {
shader . setFloat ( " xOffset " , offsets . xOffset ) ;
shader . setFloat ( " yOffset " , offsets . yOffset ) ;
shader . setFloat ( " zOffset " , offsets . zOffset ) ;
}
2023-03-05 20:02:41 +01:00
int drawTriangleClass ( const float triangleVertices [ ] , const size_t triangleVerticesSize , const char * vertexPath , const char * fragmentPath , const bool colorIncluded , const bool textureIncluded , const offsetsStruct offsets )
2022-11-20 23:14:59 +01:00
{
2023-01-27 21:29:04 +01:00
// In your CPP file:
// ======================
// float offset = 0.5f;
2022-11-20 23:14:59 +01:00
Shader ourShader ( vertexPath , fragmentPath ) ;
ourShader . use ( ) ;
2023-01-27 21:29:04 +01:00
setOffsets ( ourShader , offsets ) ;
2022-11-20 23:14:59 +01:00
const unsigned int vertexBufferObject = copyVerticesMemory ( triangleVertices , triangleVerticesSize , GL_ARRAY_BUFFER ) ;
const unsigned int vertexArrayObject = generateBindVAO ( ) ;
copyVerticesArray ( vertexBufferObject , triangleVertices , triangleVerticesSize , GL_ARRAY_BUFFER ) ;
// set vertex attribute pointers
2023-03-05 20:02:41 +01:00
configureVertexAttribute ( colorIncluded , textureIncluded ) ;
2022-11-20 23:14:59 +01:00
doDrawArrays ( ourShader . ID , vertexArrayObject , GL_TRIANGLES , 0 , triangleVerticesSize ) ;
return 0 ;
}
2023-03-05 20:02:41 +01:00
int drawTriangle ( const float triangleVertices [ ] , const size_t triangleVerticesSize , const char * vertexShaderSource , const char * fragmentShaderSource , const bool colorIncluded , const bool textureIncluded )
2022-09-05 20:17:25 +02:00
{
2022-12-11 18:49:16 +01:00
const unsigned int shaderProgram = getShaderProgram ( vertexShaderSource , fragmentShaderSource ) ;
2022-10-19 15:51:39 +02:00
if ( shaderProgram = = 0 )
2022-12-11 18:49:16 +01:00
return - 1 ;
const unsigned int vertexBufferObject = copyVerticesMemory ( triangleVertices , triangleVerticesSize , GL_ARRAY_BUFFER ) ;
const unsigned int vertexArrayObject = generateBindVAO ( ) ;
copyVerticesArray ( vertexBufferObject , triangleVertices , triangleVerticesSize , GL_ARRAY_BUFFER ) ;
// set vertex attribute pointers
2023-03-05 20:02:41 +01:00
configureVertexAttribute ( colorIncluded , textureIncluded ) ;
2022-12-11 18:49:16 +01:00
doDrawArrays ( shaderProgram , vertexArrayObject , GL_TRIANGLES , 0 , triangleVerticesSize ) ;
return 0 ;
2022-11-20 23:14:59 +01:00
}
2022-09-05 20:17:25 +02:00
2023-03-11 16:58:17 +01:00
int drawSquare ( const float squareVertices [ ] , const size_t squareVerticesSize , const unsigned int squareIndices [ ] , const size_t squareIndicesSize , const char * vertexShaderSource , const char * fragmentShaderSource , const bool colorIncluded , const bool textureIncluded , const offsetsStruct offsets )
2022-11-20 23:14:59 +01:00
{
const unsigned int shaderProgram = getShaderProgram ( vertexShaderSource , fragmentShaderSource ) ;
if ( shaderProgram = = 0 )
return - 1 ;
2022-09-07 18:54:59 +02:00
const unsigned int VAO = generateBindVAO ( ) ;
2023-03-11 16:58:17 +01:00
copyVerticesMemory ( squareVertices , squareVerticesSize , GL_ARRAY_BUFFER ) ;
copyVerticesMemory ( squareIndices , squareIndicesSize , GL_ELEMENT_ARRAY_BUFFER ) ;
2022-09-05 20:17:25 +02:00
2022-09-07 18:54:59 +02:00
// set vertex attribute pointers
2023-03-11 16:58:17 +01:00
configureVertexAttribute ( colorIncluded , textureIncluded ) ;
2022-09-05 20:17:25 +02:00
2023-03-11 16:58:17 +01:00
doDrawElements ( shaderProgram , VAO , GL_TRIANGLES , GL_UNSIGNED_INT , squareIndicesSize ) ;
2022-09-05 20:17:25 +02:00
return 0 ;
}
2023-03-11 16:58:17 +01:00
int drawSquareClass ( const char * vertexPath , const char * fragmentPath , const bool colorIncluded , const bool textureIncluded , const offsetsStruct offsets )
2023-01-18 17:51:24 +01:00
{
Shader ourShader ( vertexPath , fragmentPath ) ;
ourShader . use ( ) ;
const unsigned int vertexBufferObject = copyVerticesMemory ( constants : : SQUARE_VERTICES , constants : : SQUARE_VERTICES_SIZE , GL_ARRAY_BUFFER ) ;
const unsigned int vertexArrayObject = generateBindVAO ( ) ;
copyVerticesArray ( vertexBufferObject , constants : : SQUARE_VERTICES , constants : : SQUARE_VERTICES_SIZE , GL_ARRAY_BUFFER ) ;
// set vertex attribute pointers
2023-03-05 20:02:41 +01:00
configureVertexAttribute ( false , false ) ;
2023-01-18 17:51:24 +01:00
doDrawArrays ( ourShader . ID , vertexArrayObject , GL_TRIANGLES , 0 , constants : : SQUARE_VERTICES_SIZE ) ;
return 0 ;
}
2023-03-11 16:58:17 +01:00
int drawDebilMode ( ) {
// https://stackoverflow.com/questions/33883609/opengl-linker-error-linking-with-uncompiled-shader
Shader ourShader ( constants : : VERTEX_SHADER_TEXTURE_FILENAME , constants : : FRAGMENT_SHADER_TEXTURE_FILENAME ) ;
2023-03-11 17:26:16 +01:00
float vertices [ ] = {
// positions // colors // texture coords
0.5f , 0.5f , 0.0f , 1.0f , 0.0f , 0.0f , 1.0f , 1.0f , // top right
0.5f , - 0.5f , 0.0f , 0.0f , 1.0f , 0.0f , 1.0f , 0.0f , // bottom right
- 0.5f , - 0.5f , 0.0f , 0.0f , 0.0f , 1.0f , 0.0f , 0.0f , // bottom left
- 0.5f , 0.5f , 0.0f , 1.0f , 1.0f , 0.0f , 0.0f , 1.0f // top left
} ;
unsigned int indices [ ] = {
0 , 1 , 3 , // first triangle
1 , 2 , 3 // second triangle
} ;
unsigned int VBO , VAO , EBO ;
glGenVertexArrays ( 1 , & VAO ) ;
glGenBuffers ( 1 , & VBO ) ;
glGenBuffers ( 1 , & EBO ) ;
glBindVertexArray ( VAO ) ;
glBindBuffer ( GL_ARRAY_BUFFER , VBO ) ;
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ) , vertices , GL_STATIC_DRAW ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , EBO ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( indices ) , indices , GL_STATIC_DRAW ) ;
// position attribute
glVertexAttribPointer ( 0 , 3 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) 0 ) ;
glEnableVertexAttribArray ( 0 ) ;
// color attribute
glVertexAttribPointer ( 1 , 3 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) ( 3 * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( 1 ) ;
// texture coord attribute
glVertexAttribPointer ( 2 , 2 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) ( 6 * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( 2 ) ;
// load and create a texture
// -------------------------
unsigned int texture1 , texture2 ;
// texture 1
// ---------
glGenTextures ( 1 , & texture1 ) ;
glBindTexture ( GL_TEXTURE_2D , texture1 ) ;
// set the texture wrapping parameters
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT ) ; // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT ) ;
// set texture filtering parameters
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
// load image, create texture and generate mipmaps
int width = 430 , height = 288 , nrChannels ;
stbi_set_flip_vertically_on_load ( true ) ; // tell stb_image.h to flip loaded texture's on the y-axis.
// The FileSystem::getPath(...) is part of the GitHub repository so we can find files on any IDE/platform; replace it with your own image path.
unsigned char * data = stbi_load ( " assets/Preview.png " , & width , & height , & nrChannels , 0 ) ;
if ( data )
{
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , data ) ;
glGenerateMipmap ( GL_TEXTURE_2D ) ;
}
else
{
stbi_image_free ( data ) ;
std : : cout < < " Failed to load texture " < < std : : endl ;
}
stbi_image_free ( data ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , texture1 ) ;
ourShader . use ( ) ; // don't forget to activate/use the shader before setting uniforms!
// or set it via the texture class
ourShader . setInt ( " texture1 " , 1 ) ;
glBindVertexArray ( VAO ) ;
glDrawElements ( GL_TRIANGLES , 6 , GL_UNSIGNED_INT , 0 ) ;
glDeleteVertexArrays ( 1 , & VAO ) ;
glDeleteBuffers ( 1 , & VBO ) ;
glDeleteBuffers ( 1 , & EBO ) ;
2023-03-11 16:58:17 +01:00
return 0 ;
}
2022-10-19 15:51:39 +02:00
void doDrawElements ( const unsigned int shaderProgram , const unsigned int vertexArrayObject , const GLenum drawArrayMode , const GLenum drawType , const int numberOfElementsToDraw )
2022-09-05 20:17:25 +02:00
{
2022-10-19 15:51:39 +02:00
glUseProgram ( shaderProgram ) ;
2022-09-05 20:17:25 +02:00
glBindVertexArray ( vertexArrayObject ) ;
glDrawElements ( drawArrayMode , numberOfElementsToDraw , drawType , 0 ) ;
glBindVertexArray ( 0 ) ;
2022-09-07 18:54:59 +02:00
}
2022-09-05 20:17:25 +02:00
2022-10-19 15:51:39 +02:00
void updateUniformColor ( const unsigned int shaderProgram , const GLchar * uniformName )
2022-10-19 15:51:07 +02:00
{
// 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
2022-10-19 15:51:39 +02:00
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 .
*/
}
2022-10-19 15:51:07 +02:00
}
2022-10-19 15:51:39 +02:00
void doDrawArrays ( const unsigned int shaderProgram , const unsigned int vertexArrayObject , const GLenum drawArrayMode , const int firstIndex , const unsigned int numberOfIndicesToBeRendered )
2022-09-05 20:17:25 +02:00
{
// use shader program to render an object
2022-10-19 15:51:39 +02:00
glUseProgram ( shaderProgram ) ;
updateUniformColor ( shaderProgram , " ourColor " ) ;
2023-03-11 16:58:17 +01:00
const unsigned int texture = generateTexture ( " ./assets/Preview.png " , 430 , 288 , 3 ) ;
2023-03-05 20:02:41 +01:00
glBindTexture ( GL_TEXTURE_2D , texture ) ;
2022-09-05 20:17:25 +02:00
glBindVertexArray ( vertexArrayObject ) ;
// From left:
// primitive type we want to draw
2022-09-07 18:54:59 +02:00
// starting index of vertex array
2022-09-05 20:17:25 +02:00
// how many vertices we want to draw
glDrawArrays ( drawArrayMode , firstIndex , numberOfIndicesToBeRendered ) ;
}
2023-03-05 20:02:41 +01:00
int drawTexture ( ) {
// we added new vertex attribute and need to inform opengl that we done so
glVertexAttribPointer ( 2 , 2 , GL_FLOAT , GL_FALSE , 8 * sizeof ( float ) , ( void * ) ( 6 * sizeof ( float ) ) ) ;
glEnableVertexAttribArray ( 2 ) ;
return - 1 ;
}
2022-09-07 18:54:59 +02:00
# endif