#pragma once #include #include #include #include // XZ floor grid, centered at origin // SIZE = half-extent (25 means grid goes -25 to +25) // STEP = spacing between lines static constexpr int GRID_SIZE = 25; static constexpr float GRID_STEP = 1.0f; struct GridRenderer { unsigned int VAO, VBO; unsigned int shader; int vertex_count; }; static const char *GRID_VERT_SRC = R"( #version 330 core layout(location = 0) in vec3 aPos; uniform mat4 uMVP; void main() { gl_Position = uMVP * vec4(aPos, 1.0); } )"; static const char *GRID_FRAG_SRC = R"( #version 330 core out vec4 FragColor; void main() { FragColor = vec4(0.35, 0.35, 0.35, 1.0); } )"; inline GridRenderer grid_init() { GridRenderer r; // Build vertices on the CPU — two endpoints per line, X-parallel and Z-parallel std::vector verts; verts.reserve(4 * 3 * (GRID_SIZE * 2 + 1) * 2); // rough upper bound float lo = -GRID_SIZE * GRID_STEP; float hi = GRID_SIZE * GRID_STEP; for (int i = -GRID_SIZE; i <= GRID_SIZE; i++) { float t = i * GRID_STEP; // Line parallel to X axis (varies X, fixed Z=t) verts.insert(verts.end(), { lo, 0.0f, t, hi, 0.0f, t }); // Line parallel to Z axis (fixed X=t, varies Z) verts.insert(verts.end(), { t, 0.0f, lo, t, 0.0f, hi }); } r.vertex_count = (int)(verts.size() / 3); // Compile shaders int success; char log[512]; unsigned int vert = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vert, 1, &GRID_VERT_SRC, NULL); glCompileShader(vert); glGetShaderiv(vert, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vert, 512, NULL, log); fprintf(stderr, "Grid vert: %s\n", log); } unsigned int frag = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(frag, 1, &GRID_FRAG_SRC, NULL); glCompileShader(frag); glGetShaderiv(frag, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(frag, 512, NULL, log); fprintf(stderr, "Grid frag: %s\n", log); } r.shader = glCreateProgram(); glAttachShader(r.shader, vert); glAttachShader(r.shader, frag); glLinkProgram(r.shader); glGetProgramiv(r.shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(r.shader, 512, NULL, log); fprintf(stderr, "Grid link: %s\n", log); } glDeleteShader(vert); glDeleteShader(frag); // Upload geometry glGenVertexArrays(1, &r.VAO); glGenBuffers(1, &r.VBO); glBindVertexArray(r.VAO); glBindBuffer(GL_ARRAY_BUFFER, r.VBO); glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindVertexArray(0); return r; } inline void grid_draw(const GridRenderer &r, const glm::mat4 &mvp) { glUseProgram(r.shader); glUniformMatrix4fv(glGetUniformLocation(r.shader, "uMVP"), 1, GL_FALSE, glm::value_ptr(mvp)); glBindVertexArray(r.VAO); glLineWidth(1.0f); glDrawArrays(GL_LINES, 0, r.vertex_count); glBindVertexArray(0); } inline void grid_destroy(GridRenderer &r) { glDeleteVertexArrays(1, &r.VAO); glDeleteBuffers(1, &r.VBO); glDeleteProgram(r.shader); }