#include #include "SDL3/SDL_surface.h" #include "SDL3_image/SDL_image.h" #include "arena_allocator.h" #include "mesh.h" wn_mesh *wn_mesh_init(Arena *arena, wn_shader *shader) { // set up vertex data (and buffer(s)) and configure vertex attributes wn_mesh *mesh = (wn_mesh *)arena_init(arena, sizeof(wn_mesh)); arena_deinit_task_push(arena, (ArenaDeinitTask){.func_ptr = *wn_mesh_deinit, .func_param = mesh, .next = NULL}); mesh->shader = shader; float vertices[] = { 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left }; unsigned int indices[] = { 0, 1, 3, // first Triangle 1, 2, 3 // second Triangle }; glGenVertexArrays(1, &mesh->VAO); glGenBuffers(1, &mesh->VBO); glGenBuffers(1, &mesh->EBO); // bind the Vertex Array Object first, then bind and set vertex buffer(s), and // then configure vertex attributes(s). glBindVertexArray(mesh->VAO); glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); glEnableVertexAttribArray(1); // note that this is allowed, the call to glVertexAttribPointer registered VBO // as the vertex attribute's bound vertex buffer object so afterwards we can // safely unbind // glBindBuffer(GL_ARRAY_BUFFER, 0); // remember: do NOT unbind the EBO while a VAO is active as the bound element // buffer object IS stored in the VAO; keep the EBO bound. // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // You can unbind the VAO afterwards so other VAO calls won't accidentally // modify this VAO, but this rarely happens. Modifying other VAOs requires a // call to glBindVertexArray anyways so we generally don't unbind VAOs (nor // VBOs) when it's not directly necessary. // glBindVertexArray(0); // Texture Load SDL_Surface *image = IMG_Load("./data/testxure.png"); if (image == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load texture"); return NULL; } SDL_FlipSurface(image, SDL_FLIP_VERTICAL); GLuint texture; glActiveTexture(GL_TEXTURE0); glGenTextures(1, &texture); // Handle different SDL Surface data types // int mode = GL_RGB; // if (image->format->BytesPerPixel == 4) { int mode = GL_RGBA; // mode = GL_RGBA; // } glBindTexture(GL_TEXTURE_2D, texture); // 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); glTexImage2D(GL_TEXTURE_2D, 0, mode, image->w, image->h, 0, mode, GL_UNSIGNED_BYTE, image->pixels); glGenerateMipmap(GL_TEXTURE_2D); SDL_DestroySurface(image); return mesh; } void wn_mesh_draw(wn_mesh *mesh) { // draw our first triangle glUseProgram(mesh->shader->shaderProgram); // seeing as we only have a single VAO there's no need to bind it // every time, but we'll do so to keep things a bit more organized glBindVertexArray(mesh->VAO); // glDrawArrays(GL_TRIANGLES, 0, 6); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // glBindVertexArray(0); // no need to unbind it every time } void wn_mesh_deinit(void *mesh) { wn_mesh *cast_mesh = (wn_mesh *)mesh; glDeleteVertexArrays(1, &cast_mesh->VAO); glDeleteBuffers(1, &cast_mesh->VBO); glDeleteBuffers(1, &cast_mesh->EBO); }