#include "gl_graphics.h" #define ATTR_COLOR 0x1 // 0001 #define ATTR_TEX 0x2 // 0010 // ============== Loading functions are not subject to change ================= void LoadUniformInt(u32 SP, const char *Uniform, i32 Val) { glUniform1i(glGetUniformLocation(SP, Uniform), Val); } void LoadUniformFloat(u32 SP, const char *Uniform, r32 Val) { glUniform1f(glGetUniformLocation(SP, Uniform), Val); } void LoadUniformVec3(u32 SP, const char *Uniform, Vec3 Val) { glUniform3f(glGetUniformLocation(SP, Uniform), Val.x, Val.y, Val.z); } void LoadUniformMat4(u32 SP, const char *Uniform, const r32 *Val) { glUniformMatrix4fv(glGetUniformLocation(SP, Uniform), 1, GL_TRUE, Val); } u32 CreateVertexShader(const char *VertexShaderSource) { u32 VertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(VertexShader, 1, &VertexShaderSource, NULL); glCompileShader(VertexShader); i32 Success; char InfoLog[512]; glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &Success); if (!Success) { glGetShaderInfoLog(VertexShader, 512, NULL, InfoLog); // todo(talha): error logging // vertex shader compilation failed printf("================================\n"); printf("vertex shader compilation failed:\n%s\n", InfoLog); } return VertexShader; } u32 CreateFragmentShader(const char *FragmentShaderSource) { u32 FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(FragmentShader, 1, &FragmentShaderSource, NULL); glCompileShader(FragmentShader); i32 Success; char InfoLog[512]; glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &Success); if (!Success) { glGetShaderInfoLog(FragmentShader, 512, NULL, InfoLog); // todo(talha): error logging // fragment shader compilation failed printf("================================\n"); printf("fragment shader compilation failed:\n%s\n", InfoLog); } return FragmentShader; } u32 CreateShaderProgram(unsigned int VertexShader, unsigned int FragmentShader) { u32 ShaderProgram = glCreateProgram(); glAttachShader(ShaderProgram, VertexShader); glAttachShader(ShaderProgram, FragmentShader); glLinkProgram(ShaderProgram); i32 Success; char InfoLog[512]; glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); if (!Success) { glGetProgramInfoLog(ShaderProgram, 512, NULL, InfoLog); // todo(talha): error logging // program linking failed printf("================================\n"); printf("program linking failed:\n%s\n", InfoLog); } glDeleteShader(VertexShader); glDeleteShader(FragmentShader); return ShaderProgram; } // --------------------------------------------------------------------------- u32 CreateTriangle(r32 vertices[], i32 sz) { u32 VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind to setup triangle attributes u32 VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sz, vertices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); // color attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)(3*sizeof(r32))); glEnableVertexAttribArray(1); // unbind post setup glBindVertexArray(0); return VAO; } void DrawTriangle(u32 VAO) { glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); } u32 CreateRectangle(r32 vertices[], i32 v_sz, u32 indices[], i32 i_sz) { u32 VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind to setup triangle attributes u32 VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, v_sz, vertices, GL_STATIC_DRAW); u32 EBO; glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, i_sz, indices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); // color attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)(3*sizeof(float))); glEnableVertexAttribArray(1); // unbind post setup glBindVertexArray(0); return VAO; } BufferO CreateRectangleTextured(r32 vertices[], i32 v_sz, u32 indices[], i32 i_sz, u32 attr) { /* * This will setup options and buffer objects to create a rectangle based on a texture * The actual assigning of a texture will happen outside of this function * Call BindGlTexture/GenAndBindGlTexture for assigning textures */ u32 VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind to setup triangle attributes u32 VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, v_sz, vertices, GL_STATIC_DRAW); u32 EBO; glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, i_sz, indices, GL_STATIC_DRAW); // default is 3 for position u32 stride = 3; i32 color_offset = 3; i32 tex_offset = 3; if (attr & ATTR_COLOR) { stride += 3; tex_offset += 3; } if (attr & ATTR_TEX) { stride += 2; } u8 attr_pos = 1; // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); if (attr & ATTR_COLOR) { // color attribute glVertexAttribPointer(attr_pos, 3, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)(color_offset*sizeof(r32))); glEnableVertexAttribArray(attr_pos); attr_pos += 1; } if (attr & ATTR_TEX) { // texture attribute glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)(tex_offset*sizeof(r32))); glEnableVertexAttribArray(attr_pos); } // unbind post setup glBindVertexArray(0); BufferO BO = {0}; BO.VAO=VAO; BO.VBO=VBO; BO.EBO=EBO; return BO; } void MakeRectangleTextured(BufferO *bo, r32 vertices[], i32 v_sz, u32 indices[], i32 i_sz, u32 attr) { /* * This will setup options and buffer objects to create a rectangle based on a texture * The actual assigning of a texture will happen outside of this function */ glGenVertexArrays(1, &bo->VAO); glBindVertexArray(bo->VAO); // bind to setup triangle attributes glGenBuffers(1, &bo->VBO); glBindBuffer(GL_ARRAY_BUFFER, bo->VBO); glBufferData(GL_ARRAY_BUFFER, v_sz, vertices, GL_STATIC_DRAW); glGenBuffers(1, &bo->EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo->EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, i_sz, indices, GL_STATIC_DRAW); // default is 3 for position u32 stride = 3; i32 color_offset = 3; i32 tex_offset = 3; if (attr & ATTR_COLOR) { stride += 3; tex_offset += 3; } if (attr & ATTR_TEX) { stride += 2; } u8 attr_pos = 1; // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); if (attr & ATTR_COLOR) { // color attribute glVertexAttribPointer(attr_pos, 3, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)(color_offset*sizeof(r32))); glEnableVertexAttribArray(attr_pos); attr_pos += 1; } if (attr & ATTR_TEX) { // texture attribute glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, stride*sizeof(r32), (void*)(tex_offset*sizeof(r32))); glEnableVertexAttribArray(attr_pos); } // unbind post setup glBindVertexArray(0); } void DrawRectangle(u32 VAO) { glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); } void DrawRectangleTextured(u32 VAO, u32 TexO) { glBindTexture(GL_TEXTURE_2D, TexO); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } BufferO CreateCube(r32 vertices[], i32 v_sz) { u32 VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind to setup triangle attributes u32 VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, v_sz, vertices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); // normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(r32), (void*)(3*sizeof(r32))); glEnableVertexAttribArray(1); // unbind post setup glBindVertexArray(0); BufferO BO = {0}; BO.VAO=VAO; BO.VBO=VBO; return BO; } BufferO CreateCubeTextured(r32 vertices[], i32 v_sz) { /* * This will setup options and buffer objects to create a rectangle based on a texture * The actual assigning of a texture will happen outside of this function */ u32 VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // bind to setup triangle attributes u32 VBO; glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, v_sz, vertices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(r32), (void*)0); glEnableVertexAttribArray(0); // normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(r32), (void*)(3*sizeof(r32))); glEnableVertexAttribArray(1); // texture attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(r32), (void*)(6*sizeof(r32))); glEnableVertexAttribArray(2); // unbind post setup glBindVertexArray(0); BufferO BO = {0}; BO.VAO=VAO; BO.VBO=VBO; return BO; } void DrawCube(u32 VAO) { glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 36); } GLint GetColorAttrib(u32 nrChannels) { GLint color_attrib; switch (nrChannels) { case 1: { color_attrib = GL_RED; } break; case 3: { color_attrib = GL_RGB; } break; case 4: { color_attrib = GL_RGBA; } break; default: { assert(1 == 0); break; } } return color_attrib; } /* * Defines texture loaded from a Texture2D object into opengl. * Texture wrapping and filtering options are defined. Should they need be altered * define a new function or change them inside. It depends on the art style, but * I think it should remain the same for everything * * Parameters: * 1. Texture2D Tex: Contains information about the loaded texture * 2. u32 VAO: Contains the VertexArrayObject index for the VAO to attach the texture to * 3. u32 *TexO: Pointer to a TextureObject. This needs to be adtivated by glActiveTexture * in order to define texture properties */ void GenAndBindGlTexture(Texture2D Tex, u32 VAO, u32 *TexO) { glBindVertexArray(VAO); glGenTextures(1, TexO); glBindTexture(GL_TEXTURE_2D, *TexO); // defining texture wrapping options glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLint color_attrib = GetColorAttrib(Tex.nrChannels); glTexImage2D(GL_TEXTURE_2D, 0, color_attrib, Tex.width, Tex.height, 0, color_attrib, GL_UNSIGNED_BYTE, Tex.data); glGenerateMipmap(GL_TEXTURE_2D); glBindVertexArray(0); } /* * Similar to GenAndBindGlTexture but it only binds a texture object * must be passed a generated tex_obj */ void BindGlTexture(Texture2D Tex, u32 VAO, u32 TexO) { glBindVertexArray(VAO); glBindTexture(GL_TEXTURE_2D, TexO); // defining texture wrapping options glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLint color_attrib = GetColorAttrib(Tex.nrChannels); glTexImage2D(GL_TEXTURE_2D, 0, color_attrib, Tex.width, Tex.height, 0, color_attrib, GL_UNSIGNED_BYTE, Tex.data); glGenerateMipmap(GL_TEXTURE_2D); glBindVertexArray(0); }