I'm trying to apply a square texture to a trapezoid-like shape in OpenGL but I get some distortion. I've been reading a lot on possible solutions and the one that seems most convenient requires modifying the "q" texture coordinates. This is done using GlTexCoord functions in the solution; however, I'm using vertex buffers and I don't know how I can use them to change this coordinate this way. The texture init in GLSL takes a vec2; so I have no idea how I would pass anything but two-dimensional texture coordinates to it.
main.c
//C libs
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//GL libs (Need to have set up to run this)
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//Libs in folder
#include "shader.h"
#include "image.h"
//Window consts
#define WINDOW_HEIGHT 500
#define WINDOW_WIDTH 500
#define WINDOW_NAME "ForStackOverflow"
//Shader consts
#define VERTEX_SHADER_FILE "vertex_shader.glsl"
#define FRAGMENT_SHADER_FILE "fragment_shader.glsl"
//Vertex constants
#define POSITION_ATTRIBUTE_LOC 0
#define TEXTURE_COORD_ATTRIBUTE_LOC 1
#define POSITION_SIZE 2
#define TEXTURE_COORD_SIZE 2
#define VERTEX_SIZE (POSITION_SIZE + TEXTURE_COORD_SIZE) //Amount of floats per vertex
#define POSITION_OFFSET 0
#define TEXTURE_COORD_OFFSET (POSITION_SIZE * sizeof(float))
#define STRIDE (sizeof(float) * VERTEX_SIZE)
//Functions
static void framebuffer_size_callback(GLFWwindow*, int, int);
static unsigned int load_bmp_texture(const char* name);
int main() 
{
    printf("Running!\n");
    //*GLFW
    if (!glfwInit())
    {
        printf("GLFW init fail\n");
        return -1;
    }
    //3.3 core
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //*Window object
    GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_NAME, NULL, NULL);
    if (window == NULL) 
    {
        printf("GLFW window fail\n");
        return -1;
    }
    glfwMakeContextCurrent(window);
    //*GLAD
    if (!gladLoadGLLoader((GLADloadproc) &glfwGetProcAddress))
    {
        printf("GLAD init fail");
        glfwTerminate();
        return -1;
    }
    
    //*Window
    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
    glfwSetFramebufferSizeCallback(window, &framebuffer_size_callback);
    //*Shaders
    ShaderProgram shader_program;
    if (!shader_program_init(&shader_program, VERTEX_SHADER_FILE, FRAGMENT_SHADER_FILE)) {
        glfwTerminate();
        return -1;
    }
    //*Triangle rendering
    //Vertices
    float tri_vertices[4 * VERTEX_SIZE] = { //FORM A TRAPEZOID
        //Position       //Texture coordinates
        -0.5f,   0.5f,   0.0f, 1.0f,               //Top-left
        -0.5f,  -0.5f,   0.0f, 0.0f,               //Bottom-left
         0.5f,   0.75f,  1.0f, 1.0f,               //Top-right
         0.5f,  -0.75f,  1.0f, 0.0f                //Bottom-right
    };
    //Indices
    unsigned int tri_indices[6] = {
        2, 0, 1, //Top-right, top-left, bottom-left
        2, 3, 1  //Top-right, bottom-right, bottom-left
    };
    //VAO
    unsigned int tri_vao;
    glGenVertexArrays(1, &tri_vao);
    glBindVertexArray(tri_vao);
    //VBO
    unsigned int tri_vbo;
    glGenBuffers(1, &tri_vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, tri_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(tri_vertices), tri_vertices, GL_STATIC_DRAW);
    //EBO
    unsigned int tri_ebo;
    glGenBuffers(1, &tri_ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tri_ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(tri_indices), tri_indices, GL_STATIC_DRAW);
    
    //Config
    //Position
    glVertexAttribPointer(POSITION_ATTRIBUTE_LOC, POSITION_SIZE, GL_FLOAT, GL_FALSE, STRIDE, (void*) POSITION_OFFSET);
    glEnableVertexAttribArray(POSITION_ATTRIBUTE_LOC);
    //Texture coordinates
    glVertexAttribPointer(TEXTURE_COORD_ATTRIBUTE_LOC, TEXTURE_COORD_SIZE, GL_FLOAT, GL_FALSE, STRIDE, (void*) TEXTURE_COORD_OFFSET); 
    glEnableVertexAttribArray(TEXTURE_COORD_ATTRIBUTE_LOC);
    //*Textures
    unsigned int brick_tex = load_bmp_texture("purple_bricks.bmp");
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, brick_tex);
    //Attaching to uniform
    glUseProgram(shader_program);
    glUniform1i(glGetUniformLocation(shader_program, "brick"), 0);
    //*Rendering setup
    //Shader
    glUseProgram(shader_program);
    //*Main loop
    while (!glfwWindowShouldClose(window)) 
    {
        //*Blittering
        //Background
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        //Triangles
        glBindVertexArray(tri_vao);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tri_ebo);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*) 0);
        //*Buffer, events
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    //*End program
    glDeleteVertexArrays(1, &tri_vao);
    glDeleteBuffers(1, &tri_vbo);
    glDeleteBuffers(1, &tri_ebo);
    glfwTerminate();
    return 0;
}
//Centers the OpenGL part of the window and keeps the same width and height
static void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport((width - WINDOW_WIDTH) / 2, (height - WINDOW_HEIGHT) / 2, WINDOW_WIDTH, WINDOW_HEIGHT);
} 
//Loads and sets up a BMP texture
static unsigned int load_bmp_texture(const char* name) {
    //Loading into array
    RGBImage image;
    read_bmp(name, &image);
    //Generating texture in GL
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    //Setting mapping
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //X 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //Y
    //Setting filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    //Setting texture and mipmap
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image.data);
    glGenerateMipmap(GL_TEXTURE_2D);
    //Freeing image array
    free_RGBImage(image);
    return texture;
}
image.h
//Code for loading a bmp file as an array
//Definitely not part of the problem
//24 bit bmps
//C libs
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
//Prevent struct packing
#pragma pack(1)
typedef struct RGB {
    unsigned char R;
    unsigned char G;
    unsigned char B;
} RGB;
typedef struct RGBImage {
    int width;
    int height;
    RGB* data;
} RGBImage;
typedef struct BMPFileHeader {
    char name[2];
    uint32_t size;
    uint32_t garbage;
    uint32_t image_offset;
} BMPFileHeader;
typedef struct BMPInfoHeader {
    uint32_t header_size;
    uint32_t width;
    uint32_t height;
    uint16_t color_planes;
    uint16_t bits_per_pixel;
    uint32_t compression;
    uint32_t image_size;
} BMPInfoHeader;
void free_RGBImage(RGBImage image) {
    free(image.data);
}
bool read_bmp(const char* file_name, RGBImage* image) {
    FILE* fp = fopen(file_name, "rb");
    if (fp == NULL) {
        printf("Couldn't open %s\n", file_name);
        return false;
    }
    BMPFileHeader file_header;
    fread(file_header.name, sizeof(BMPFileHeader), 1, fp);
    if ((file_header.name[0] != 'B') || (file_header.name[1] != 'M')) {
        fclose(fp);
        return false;
    }
    BMPInfoHeader info_header;
    fread(&info_header, sizeof(BMPInfoHeader), 1, fp);
    if ((info_header.header_size != 40) || (info_header.compression != 0) || (info_header.bits_per_pixel != 24)) {
        fclose(fp);
        return false;
    }
    fseek(fp, file_header.image_offset, SEEK_SET);
    image->width = info_header.width;
    image->height = info_header.height;
    image->data = (RGB*) malloc(image->height * image->width * sizeof(RGB));
    for (int i = 0; i < image->height; i++) {
        fread(&image->data[i * image->width], sizeof(RGB), image->width, fp);
    }
    int R;
    for (int i = 0; i < image->height * image->width; i++) {
        R = image->data[i].R;
        image->data[i].R = image->data[i].B;
        image->data[i].B = R;
    }
    fclose(fp);
    return true;
}
shader.h
//Code for compiling and linking a shader
//Definitely not part of the problem
//C libs
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//GL libs
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//Consts
#define INFO_LOG_SIZE 512
static bool _glad_is_init();
static bool _glfw_is_init();
typedef unsigned int ShaderProgram;
bool shader_program_init(ShaderProgram* shader_program, char* vertex_shader_file_name, char* fragment_shader_file_name) 
{
    if (!_glfw_is_init()) {
        printf("Shader: glfw uninitialized\n");
        return 0;
    }
    else if (!_glad_is_init()) {
        printf("Shader: glad uninitialized\n");
        return 0;
    }
    long int file_size;
    size_t new_source_length;
    FILE* fp;
    //*Reading vertex shader file
    //Open
    fp = fopen(vertex_shader_file_name, "r");
    if (fp == NULL) {
        printf("Couldn't open vertex shader file\n");
        return 0;
    }
    //Find length for buffer
    fseek(fp, 0L, SEEK_END);
    file_size = ftell(fp);
    if (file_size == -1) {
        printf("Couldn't seek end of file\n");
        return 0;
    }
    rewind(fp);
    char vertex_shader_source[(file_size + 1) * sizeof(char)];
    //Read
    new_source_length = fread(vertex_shader_source, sizeof(char), file_size, fp);
    if (ferror(fp) != 0) {
        printf("Error when reading file\n");
        return 0;
    }
    //Add string termination
    vertex_shader_source[new_source_length] = '\0';
    //Close
    fclose(fp);
    
    //*Reading fragment shader
    //Open
    fp = fopen(fragment_shader_file_name, "r");
    if (fp == NULL) {
        printf("Couldn't open fragment shader file\n");
        return 0;
    }
    //Find length for buffer
    fseek(fp, 0L, SEEK_END);
    file_size = ftell(fp);
    if (file_size == -1) {
        printf("Couldn't seek end of file\n");
        return 0;
    }
    rewind(fp);
    char fragment_shader_source[(file_size + 1) * sizeof(char)];
    //Read
    new_source_length = fread(fragment_shader_source, sizeof(char), file_size, fp);
    if (ferror(fp) != 0) {
        printf("Error reading file\n");
        return 0;
    }
    //Add string termination
    fragment_shader_source[new_source_length] = '\0';
    //Close
    fclose(fp);
    //*Compiling
    //For error checking
    int success;
    char infolog[INFO_LOG_SIZE];
    
    const char* vertex_shader_code = vertex_shader_source; //vertex_shader_source is of type char foo[n], a VLA.
    const char* fragment_shader_code = fragment_shader_source;
    
    //Vertex
    unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_code, NULL);
    glCompileShader(vertex_shader);
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertex_shader, INFO_LOG_SIZE, NULL, infolog);
        printf("Vertex shader compile fail: \n%s\n", infolog);
        return 0;
    }
    //Fragment
    unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_code, NULL);
    glCompileShader(fragment_shader);
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragment_shader, INFO_LOG_SIZE, NULL, infolog);
        printf("Fragment shader compile fail: \n%s\n", infolog);
        return 0;
    }
    //Program
    *shader_program = glCreateProgram();
    glAttachShader(*shader_program, vertex_shader);
    glAttachShader(*shader_program, fragment_shader);
    glLinkProgram(*shader_program);
    glGetProgramiv(*shader_program, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(*shader_program, INFO_LOG_SIZE, NULL, infolog);
        printf("Shader program compile fail: \n%s\n", infolog);
        return 0;
    }
    //Deleting
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    return 1;
}
bool _glfw_is_init() {
    if (!glfwInit())
    {
        return false;
    }
    return true;
}
bool _glad_is_init() {
    if (!gladLoadGLLoader((GLADloadproc) &glfwGetProcAddress))
    {
        return false;
    }
    return true;
}
vertex_shader.glsl
#version 330 core
layout (location = 0) in vec2 vertex_position;
layout (location = 1) in vec2 vertex_texture_coordinate;
out vec2 texture_coordinate;
void main()
{
    gl_Position = vec4(vertex_position, 1.0, 1.0);
    texture_coordinate = vertex_texture_coordinate;
};
fragment_shader.glsl
#version 330 core
in vec4 color;
in vec2 texture_coordinate;
out vec4 FragColor;
uniform sampler2D brick;
void main()
{
    FragColor = texture(brick, texture_coordinate);
};
Texture used
Result of program
Edit: for those reading in the future, this link helped a lot with implementing the method described in the answer below: https://www.cs.cmu.edu/~16385/s17/Slides/10.2_2D_Alignment__DLT.pdf


 