diff --git a/src/main.c b/src/main.c index 8fb0f80..337e954 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,29 @@ #include "SDL3/SDL_init.h" #include "SDL3/SDL_log.h" -#include "SDL3/SDL_opengl.h" #include "SDL3/SDL_render.h" #include "SDL3/SDL_video.h" +#include #include +// settings +const unsigned int SCR_WIDTH = 800; +const unsigned int SCR_HEIGHT = 600; + +const char *vertexShaderSource = + "#version 330 core\n" + "layout (location = 0) in vec3 aPos;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" + "}\0"; +const char *fragmentShaderSource = + "#version 330 core\n" + "out vec4 FragColor;\n" + "void main()\n" + "{\n" + " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" + "}\n\0"; + int main(int argc, char *argv[]) { SDL_Window *window; SDL_Renderer *renderer; @@ -24,12 +43,111 @@ int main(int argc, char *argv[]) { window = SDL_CreateWindow("Hello SDL3", 320, 240, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!window) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create windowe: %s", + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s", SDL_GetError()); return EXIT_FAILURE; } - SDL_GLContext glcontext = SDL_GL_CreateContext(window); + if (!glcontext) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't create OpenGL Context: %s", SDL_GetError()); + return EXIT_FAILURE; + } + + GLenum glewError = glewInit(); + if (glewError != GLEW_OK) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error initializing GLEW! %s", + glewGetErrorString(glewError)); + } + + if (!SDL_GL_MakeCurrent(window, glcontext)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Couldn't make glcontext current: %s", SDL_GetError()); + } + + // vertex shader + unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + // check for shader compile errors + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to compile vertex shader: %s", infoLog); + } + // fragment shader + unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + // check for shader compile errors + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to compile fragment shader: %s", infoLog); + } + // link shaders + unsigned int shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); + glLinkProgram(shaderProgram); + // check for linking errors + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to link shader program: %s", infoLog); + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + // set up vertex data (and buffer(s)) and configure vertex attributes + float vertices[] = { + 0.5f, 0.5f, 0.0f, // top right + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f // top left + }; + unsigned int indices[] = { + // note that we start from 0! + 0, 1, 3, // first Triangle + 1, 2, 3 // second Triangle + }; + unsigned int VBO, VAO, EBO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + // bind the Vertex Array Object first, then bind and set vertex buffer(s), and + // then configure vertex attributes(s). + 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); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + glEnableVertexAttribArray(0); + + // 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); while (1) { // handle input @@ -39,11 +157,26 @@ int main(int argc, char *argv[]) { } // render - glClearColor(0, 0, 0, 1); + glClearColor(0.1f, 0.3f, 0.4f, 1.f); glClear(GL_COLOR_BUFFER_BIT); + + // draw our first triangle + glUseProgram(shaderProgram); + glBindVertexArray( + VAO); // 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 + // glDrawArrays(GL_TRIANGLES, 0, 6); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + // glBindVertexArray(0); // no need to unbind it every time + SDL_GL_SwapWindow(window); } + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + glDeleteProgram(shaderProgram); + SDL_GL_DestroyContext(glcontext); SDL_DestroyWindow(window);