From 58801bfab3feb5be5e82f1417715097683a223b3 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 20 Feb 2026 02:43:27 +0300 Subject: [PATCH 1/5] Add one more example --- examples/CMakeLists.txt | 9 + examples/example_barycentric.cpp | 283 +++++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 examples/example_barycentric.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a2b7136f..3e078ced 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -26,6 +26,15 @@ set_target_properties( LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") +add_executable(example_barycentric example_barycentric.cpp) +set_target_properties( + example_barycentric + PROPERTIES CXX_STANDARD 23 + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") +target_link_libraries(example_barycentric PRIVATE omath::omath GLEW::GLEW glfw OpenGL::GL) + find_package(OpenGL) find_package(GLEW REQUIRED) find_package(glfw3 CONFIG REQUIRED) diff --git a/examples/example_barycentric.cpp b/examples/example_barycentric.cpp new file mode 100644 index 00000000..e87cee9b --- /dev/null +++ b/examples/example_barycentric.cpp @@ -0,0 +1,283 @@ +#include +#include +#include +#include +#include +#include "omath/linear_algebra/vector3.hpp" +#include "omath/linear_algebra/triangle.hpp" + +using omath::Vector3; +using omath::Triangle; + +static const char* vertexShaderSource = R"( +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; +layout (location = 2) in float aPointSize; + +out vec3 vColor; + +void main() { + gl_Position = vec4(aPos, 1.0); + vColor = aColor; + gl_PointSize = aPointSize; +} +)"; + +static const char* fragmentShaderSource = R"( +#version 330 core +in vec3 vColor; +out vec4 FragColor; + +void main() { + FragColor = vec4(vColor, 1.0); +} +)"; + +GLuint compileShader(GLenum type, const char* src) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, nullptr); + glCompileShader(shader); + GLint ok; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (!ok) { + char log[1024]; + glGetShaderInfoLog(shader, sizeof(log), nullptr, log); + std::cerr << "Shader error: " << log << std::endl; + } + return shader; +} + +void drawChar(char c, float x, float y, float scale, const Vector3& color, std::vector& lines) { + float w = 0.5f * scale; + float h = 1.0f * scale; + + auto add = [&](float x1, float y1, float x2, float y2) { + lines.push_back(x + x1*w); lines.push_back(y + y1*h); lines.push_back(0.0f); + lines.push_back(color.x); lines.push_back(color.y); lines.push_back(color.z); + lines.push_back(1.0f); // size + + lines.push_back(x + x2*w); lines.push_back(y + y2*h); lines.push_back(0.0f); + lines.push_back(color.x); lines.push_back(color.y); lines.push_back(color.z); + lines.push_back(1.0f); // size + }; + + switch(c) { + case '0': add(0,0, 1,0); add(1,0, 1,1); add(1,1, 0,1); add(0,1, 0,0); break; + case '1': add(0.5f,0, 0.5f,1); add(0.25f,0.75f, 0.5f,1); add(0.25f,0, 0.75f,0); break; + case '2': add(0,1, 1,1); add(1,1, 1,0.5f); add(1,0.5f, 0,0.5f); add(0,0.5f, 0,0); add(0,0, 1,0); break; + case '3': add(0,1, 1,1); add(1,1, 1,0); add(1,0, 0,0); add(0,0.5f, 1,0.5f); break; + case '4': add(0,1, 0,0.5f); add(0,0.5f, 1,0.5f); add(1,1, 1,0); break; + case '5': add(1,1, 0,1); add(0,1, 0,0.5f); add(0,0.5f, 1,0.5f); add(1,0.5f, 1,0); add(1,0, 0,0); break; + case '6': add(1,1, 0,1); add(0,1, 0,0); add(0,0, 1,0); add(1,0, 1,0.5f); add(1,0.5f, 0,0.5f); break; + case '7': add(0,1, 1,1); add(1,1, 0.5f,0); break; + case '8': add(0,0, 1,0); add(1,0, 1,1); add(1,1, 0,1); add(0,1, 0,0); add(0,0.5f, 1,0.5f); break; + case '9': add(1,0.5f, 0,0.5f); add(0,0.5f, 0,1); add(0,1, 1,1); add(1,1, 1,0); add(1,0, 0,0); break; + case '.': add(0.4f,0, 0.6f,0); add(0.6f,0, 0.6f,0.2f); add(0.6f,0.2f, 0.4f,0.2f); add(0.4f,0.2f, 0.4f,0); break; + } +} + +void drawText(const std::string& text, float x, float y, float scale, const Vector3& color, std::vector& lines) { + float cursor = x; + for (char c : text) { + drawChar(c, cursor, y, scale, color, lines); + cursor += (c == '.' ? 0.3f : 0.7f) * scale; + } +} + +int main() { + if (!glfwInit()) { + std::cerr << "Failed to initialize GLFW\n"; + return -1; + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + GLFWwindow* window = glfwCreateWindow(800, 800, "Barycentric Coordinates", NULL, NULL); + if (!window) { + std::cerr << "Failed to create GLFW window\n"; + glfwTerminate(); + return -1; + } + glfwMakeContextCurrent(window); + + // Check if context is valid using standard GL + const GLubyte* renderer = glGetString(GL_RENDERER); + const GLubyte* version = glGetString(GL_VERSION); + if (renderer && version) { + std::cout << "Renderer: " << renderer << "\n"; + std::cout << "OpenGL version supported: " << version << "\n"; + } else { + std::cerr << "Failed to get GL_RENDERER or GL_VERSION. Context might be invalid.\n"; + } + + glewExperimental = GL_TRUE; + GLenum glewErr = glewInit(); + if (glewErr != GLEW_OK) { + // Ignore GLEW_ERROR_NO_GLX_DISPLAY if we have a valid context (e.g. Wayland) + if (glewErr == GLEW_ERROR_NO_GLX_DISPLAY && renderer) { + std::cerr << "GLEW warning: " << glewGetErrorString(glewErr) << " (Ignored because context seems valid)\n"; + } else { + std::cerr << "Failed to initialize GLEW: " << glewGetErrorString(glewErr) << "\n"; + glfwTerminate(); + return -1; + } + } + + GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSource); + GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); + GLuint shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vs); + glAttachShader(shaderProgram, fs); + glLinkProgram(shaderProgram); + + // Triangle vertices as shown in the picture (Red, Green, Blue) + // Scaled down slightly to leave room for text + Vector3 A(0.0f, 0.6f, 0.0f); // Red dot (top) + Vector3 B(-0.6f, -0.6f, 0.0f); // Green dot (bottom left) + Vector3 C(0.6f, -0.6f, 0.0f); // Blue dot (bottom right) + + std::vector pointCloud; + + // Iterating over barycentric coordinates (u, v, w) from 0.0 to 1.0 + for (float u = 0.0f; u <= 1.0f; u += 0.015f) { + for (float v = 0.0f; v <= 1.0f - u; v += 0.015f) { + float w = 1.0f - u - v; + if (w >= 0.0f && w <= 1.0f) { + Vector3 P = A * u + B * v + C * w; + pointCloud.push_back(P.x); pointCloud.push_back(P.y); pointCloud.push_back(P.z); + pointCloud.push_back(u); pointCloud.push_back(v); pointCloud.push_back(w); + pointCloud.push_back(2.0f); // size + } + } + } + + GLuint VAO_cloud, VBO_cloud; + glGenVertexArrays(1, &VAO_cloud); + glGenBuffers(1, &VBO_cloud); + glBindVertexArray(VAO_cloud); + glBindBuffer(GL_ARRAY_BUFFER, VBO_cloud); + glBufferData(GL_ARRAY_BUFFER, pointCloud.size() * sizeof(float), pointCloud.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + + GLuint VAO_dyn, VBO_dyn; + glGenVertexArrays(1, &VAO_dyn); + glGenBuffers(1, &VBO_dyn); + glBindVertexArray(VAO_dyn); + glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn); + glBufferData(GL_ARRAY_BUFFER, 1000 * 7 * sizeof(float), NULL, GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + + glEnable(GL_PROGRAM_POINT_SIZE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + while (!glfwWindowShouldClose(window)) { + glClearColor(0.02f, 0.02f, 0.02f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(shaderProgram); + + // Draw the point cloud (the iterated points) + glBindVertexArray(VAO_cloud); + glDrawArrays(GL_POINTS, 0, pointCloud.size() / 7); + + // Animate the white dot to simulate dragging + float t = glfwGetTime(); + float u = (std::sin(t * 1.5f) * 0.5f + 0.5f); + float v = (std::cos(t * 1.1f) * 0.5f + 0.5f); + + if (u + v > 1.0f) { + u = 1.0f - u; + v = 1.0f - v; + } + float w = 1.0f - u - v; + + if (w > 1.0f) { + float diff = w - 1.0f; + w = 1.0f; + u += diff / 2.0f; + v += diff / 2.0f; + } else if (w < 0.0f) { + float diff = -w; + w = 0.0f; + u -= diff / 2.0f; + v -= diff / 2.0f; + } + + Vector3 P = A * u + B * v + C * w; + + float sizeA = 10.0f + u * 30.0f; + float sizeB = 10.0f + v * 30.0f; + float sizeC = 10.0f + w * 30.0f; + float sizeP = 12.0f; + + std::vector dynData = { + // Lines from P to A, B, C + P.x, P.y, P.z, u, v, w, 1.0f, + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, + + P.x, P.y, P.z, u, v, w, 1.0f, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, + + P.x, P.y, P.z, u, v, w, 1.0f, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, + + // The animated dot itself (White) + P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, + + // The 3 corner dots + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, sizeC + }; + + char bufA[16], bufB[16], bufC[16]; + snprintf(bufA, sizeof(bufA), "%.2f", u); + snprintf(bufB, sizeof(bufB), "%.2f", v); + snprintf(bufC, sizeof(bufC), "%.2f", w); + + // Keep text at a fixed distance from the dots + float distA = 0.13f; + float distB = 0.13f; + float distC = 0.13f; + + drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Vector3(1,0,0), dynData); + drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Vector3(0,1,0), dynData); + drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Vector3(0,0,1), dynData); + + glBindVertexArray(VAO_dyn); + glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn); + glBufferSubData(GL_ARRAY_BUFFER, 0, dynData.size() * sizeof(float), dynData.data()); + + // Draw lines + glDrawArrays(GL_LINES, 0, 6); + + // Draw text lines + int numTextVertices = (dynData.size() / 7) - 10; + if (numTextVertices > 0) { + glDrawArrays(GL_LINES, 10, numTextVertices); + } + + // Draw dots + glDrawArrays(GL_POINTS, 6, 4); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + return 0; +} From 05462724935c7b919f8d97dd8718edafd18ff25c Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 20 Feb 2026 02:50:55 +0300 Subject: [PATCH 2/5] Use dot not quad --- examples/example_barycentric.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/example_barycentric.cpp b/examples/example_barycentric.cpp index e87cee9b..cf8a1c6b 100644 --- a/examples/example_barycentric.cpp +++ b/examples/example_barycentric.cpp @@ -30,6 +30,11 @@ in vec3 vColor; out vec4 FragColor; void main() { + // Calculate distance from center of the point + vec2 coord = gl_PointCoord - vec2(0.5); + if(length(coord) > 0.5) + discard; + FragColor = vec4(vColor, 1.0); } )"; From f363fa6f1a3c2bc235698f338d8510997784c09a Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 20 Feb 2026 02:53:20 +0300 Subject: [PATCH 3/5] Fix text --- examples/example_barycentric.cpp | 59 +++++++++++++++++++------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/examples/example_barycentric.cpp b/examples/example_barycentric.cpp index cf8a1c6b..4df49952 100644 --- a/examples/example_barycentric.cpp +++ b/examples/example_barycentric.cpp @@ -14,26 +14,32 @@ static const char* vertexShaderSource = R"( layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; layout (location = 2) in float aPointSize; +layout (location = 3) in float aIsLine; out vec3 vColor; +out float vIsLine; void main() { gl_Position = vec4(aPos, 1.0); vColor = aColor; gl_PointSize = aPointSize; + vIsLine = aIsLine; } )"; static const char* fragmentShaderSource = R"( #version 330 core in vec3 vColor; +in float vIsLine; out vec4 FragColor; void main() { - // Calculate distance from center of the point - vec2 coord = gl_PointCoord - vec2(0.5); - if(length(coord) > 0.5) - discard; + if (vIsLine < 0.5) { + // Calculate distance from center of the point + vec2 coord = gl_PointCoord - vec2(0.5); + if(length(coord) > 0.5) + discard; + } FragColor = vec4(vColor, 1.0); } @@ -61,10 +67,12 @@ void drawChar(char c, float x, float y, float scale, const Vector3& color lines.push_back(x + x1*w); lines.push_back(y + y1*h); lines.push_back(0.0f); lines.push_back(color.x); lines.push_back(color.y); lines.push_back(color.z); lines.push_back(1.0f); // size + lines.push_back(1.0f); // isLine lines.push_back(x + x2*w); lines.push_back(y + y2*h); lines.push_back(0.0f); lines.push_back(color.x); lines.push_back(color.y); lines.push_back(color.z); lines.push_back(1.0f); // size + lines.push_back(1.0f); // isLine }; switch(c) { @@ -155,6 +163,7 @@ int main() { pointCloud.push_back(P.x); pointCloud.push_back(P.y); pointCloud.push_back(P.z); pointCloud.push_back(u); pointCloud.push_back(v); pointCloud.push_back(w); pointCloud.push_back(2.0f); // size + pointCloud.push_back(0.0f); // isLine } } } @@ -165,25 +174,29 @@ int main() { glBindVertexArray(VAO_cloud); glBindBuffer(GL_ARRAY_BUFFER, VBO_cloud); glBufferData(GL_ARRAY_BUFFER, pointCloud.size() * sizeof(float), pointCloud.data(), GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(6 * sizeof(float))); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float))); + glEnableVertexAttribArray(3); GLuint VAO_dyn, VBO_dyn; glGenVertexArrays(1, &VAO_dyn); glGenBuffers(1, &VBO_dyn); glBindVertexArray(VAO_dyn); glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn); - glBufferData(GL_ARRAY_BUFFER, 1000 * 7 * sizeof(float), NULL, GL_DYNAMIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); + glBufferData(GL_ARRAY_BUFFER, 1000 * 8 * sizeof(float), NULL, GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float))); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(6 * sizeof(float))); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float))); + glEnableVertexAttribArray(3); glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_BLEND); @@ -197,7 +210,7 @@ int main() { // Draw the point cloud (the iterated points) glBindVertexArray(VAO_cloud); - glDrawArrays(GL_POINTS, 0, pointCloud.size() / 7); + glDrawArrays(GL_POINTS, 0, pointCloud.size() / 8); // Animate the white dot to simulate dragging float t = glfwGetTime(); @@ -231,22 +244,22 @@ int main() { std::vector dynData = { // Lines from P to A, B, C - P.x, P.y, P.z, u, v, w, 1.0f, - A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - P.x, P.y, P.z, u, v, w, 1.0f, - B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, - P.x, P.y, P.z, u, v, w, 1.0f, - C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // The animated dot itself (White) - P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, + P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, 0.0f, // The 3 corner dots - A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, - B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, - C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, sizeC + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, 0.0f, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, 0.0f, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, sizeC, 0.0f }; char bufA[16], bufB[16], bufC[16]; @@ -271,7 +284,7 @@ int main() { glDrawArrays(GL_LINES, 0, 6); // Draw text lines - int numTextVertices = (dynData.size() / 7) - 10; + int numTextVertices = (dynData.size() / 8) - 10; if (numTextVertices > 0) { glDrawArrays(GL_LINES, 10, numTextVertices); } From b8323d3bc0951a058922405dd7ac7c171d3363d5 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 20 Feb 2026 02:56:27 +0300 Subject: [PATCH 4/5] simplify complexity --- examples/example_barycentric.cpp | 128 ++++++++++++++++++------------- 1 file changed, 75 insertions(+), 53 deletions(-) diff --git a/examples/example_barycentric.cpp b/examples/example_barycentric.cpp index 4df49952..f4fb6ab7 100644 --- a/examples/example_barycentric.cpp +++ b/examples/example_barycentric.cpp @@ -98,21 +98,21 @@ void drawText(const std::string& text, float x, float y, float scale, const Vect } } -int main() { +GLFWwindow* initWindow(int width, int height, const char* title) { if (!glfwInit()) { std::cerr << "Failed to initialize GLFW\n"; - return -1; + return nullptr; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - GLFWwindow* window = glfwCreateWindow(800, 800, "Barycentric Coordinates", NULL, NULL); + GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL); if (!window) { std::cerr << "Failed to create GLFW window\n"; glfwTerminate(); - return -1; + return nullptr; } glfwMakeContextCurrent(window); @@ -135,25 +135,23 @@ int main() { } else { std::cerr << "Failed to initialize GLEW: " << glewGetErrorString(glewErr) << "\n"; glfwTerminate(); - return -1; + return nullptr; } } + return window; +} +GLuint createShaderProgram() { GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShaderSource); GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); GLuint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vs); glAttachShader(shaderProgram, fs); glLinkProgram(shaderProgram); + return shaderProgram; +} - // Triangle vertices as shown in the picture (Red, Green, Blue) - // Scaled down slightly to leave room for text - Vector3 A(0.0f, 0.6f, 0.0f); // Red dot (top) - Vector3 B(-0.6f, -0.6f, 0.0f); // Green dot (bottom left) - Vector3 C(0.6f, -0.6f, 0.0f); // Blue dot (bottom right) - - std::vector pointCloud; - +void generatePointCloud(std::vector& pointCloud, const Vector3& A, const Vector3& B, const Vector3& C) { // Iterating over barycentric coordinates (u, v, w) from 0.0 to 1.0 for (float u = 0.0f; u <= 1.0f; u += 0.015f) { for (float v = 0.0f; v <= 1.0f - u; v += 0.015f) { @@ -167,8 +165,9 @@ int main() { } } } +} - GLuint VAO_cloud, VBO_cloud; +void setupBuffers(GLuint& VAO_cloud, GLuint& VBO_cloud, const std::vector& pointCloud, GLuint& VAO_dyn, GLuint& VBO_dyn) { glGenVertexArrays(1, &VAO_cloud); glGenBuffers(1, &VBO_cloud); glBindVertexArray(VAO_cloud); @@ -183,7 +182,6 @@ int main() { glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float))); glEnableVertexAttribArray(3); - GLuint VAO_dyn, VBO_dyn; glGenVertexArrays(1, &VAO_dyn); glGenBuffers(1, &VBO_dyn); glBindVertexArray(VAO_dyn); @@ -197,6 +195,66 @@ int main() { glEnableVertexAttribArray(2); glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(7 * sizeof(float))); glEnableVertexAttribArray(3); +} + +void updateDynamicData(std::vector& dynData, float u, float v, float w, const Vector3& P, const Vector3& A, const Vector3& B, const Vector3& C) { + float sizeA = 10.0f + u * 30.0f; + float sizeB = 10.0f + v * 30.0f; + float sizeC = 10.0f + w * 30.0f; + float sizeP = 12.0f; + + dynData = { + // Lines from P to A, B, C + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, + + P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + + // The animated dot itself (White) + P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, 0.0f, + + // The 3 corner dots + A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, 0.0f, + B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, 0.0f, + C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, sizeC, 0.0f + }; + + char bufA[16], bufB[16], bufC[16]; + snprintf(bufA, sizeof(bufA), "%.2f", u); + snprintf(bufB, sizeof(bufB), "%.2f", v); + snprintf(bufC, sizeof(bufC), "%.2f", w); + + // Keep text at a fixed distance from the dots + float distA = 0.13f; + float distB = 0.13f; + float distC = 0.13f; + + drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Vector3(1,0,0), dynData); + drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Vector3(0,1,0), dynData); + drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Vector3(0,0,1), dynData); +} + +int main() { + GLFWwindow* window = initWindow(800, 800, "Barycentric Coordinates"); + if (!window) return -1; + + GLuint shaderProgram = createShaderProgram(); + + // Triangle vertices as shown in the picture (Red, Green, Blue) + // Scaled down slightly to leave room for text + Vector3 A(0.0f, 0.6f, 0.0f); // Red dot (top) + Vector3 B(-0.6f, -0.6f, 0.0f); // Green dot (bottom left) + Vector3 C(0.6f, -0.6f, 0.0f); // Blue dot (bottom right) + + std::vector pointCloud; + generatePointCloud(pointCloud, A, B, C); + + GLuint VAO_cloud, VBO_cloud, VAO_dyn, VBO_dyn; + setupBuffers(VAO_cloud, VBO_cloud, pointCloud, VAO_dyn, VBO_dyn); glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_BLEND); @@ -237,44 +295,8 @@ int main() { Vector3 P = A * u + B * v + C * w; - float sizeA = 10.0f + u * 30.0f; - float sizeB = 10.0f + v * 30.0f; - float sizeC = 10.0f + w * 30.0f; - float sizeP = 12.0f; - - std::vector dynData = { - // Lines from P to A, B, C - P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, - A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - - P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, - B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, - - P.x, P.y, P.z, u, v, w, 1.0f, 1.0f, - C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, - - // The animated dot itself (White) - P.x, P.y, P.z, 1.0f, 1.0f, 1.0f, sizeP, 0.0f, - - // The 3 corner dots - A.x, A.y, A.z, 1.0f, 0.0f, 0.0f, sizeA, 0.0f, - B.x, B.y, B.z, 0.0f, 1.0f, 0.0f, sizeB, 0.0f, - C.x, C.y, C.z, 0.0f, 0.0f, 1.0f, sizeC, 0.0f - }; - - char bufA[16], bufB[16], bufC[16]; - snprintf(bufA, sizeof(bufA), "%.2f", u); - snprintf(bufB, sizeof(bufB), "%.2f", v); - snprintf(bufC, sizeof(bufC), "%.2f", w); - - // Keep text at a fixed distance from the dots - float distA = 0.13f; - float distB = 0.13f; - float distC = 0.13f; - - drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Vector3(1,0,0), dynData); - drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Vector3(0,1,0), dynData); - drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Vector3(0,0,1), dynData); + std::vector dynData; + updateDynamicData(dynData, u, v, w, P, A, B, C); glBindVertexArray(VAO_dyn); glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn); From 66debb46fa511b1c46382742df90015f21c7aba9 Mon Sep 17 00:00:00 2001 From: Saikari Date: Fri, 20 Feb 2026 03:01:34 +0300 Subject: [PATCH 5/5] Refactor to use Color class and Triangle structure for better clarity in drawing functions --- examples/example_barycentric.cpp | 39 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/examples/example_barycentric.cpp b/examples/example_barycentric.cpp index f4fb6ab7..9c9a3808 100644 --- a/examples/example_barycentric.cpp +++ b/examples/example_barycentric.cpp @@ -3,11 +3,11 @@ #include #include #include -#include "omath/linear_algebra/vector3.hpp" -#include "omath/linear_algebra/triangle.hpp" +#include using omath::Vector3; using omath::Triangle; +using omath::Color; static const char* vertexShaderSource = R"( #version 330 core @@ -59,7 +59,7 @@ GLuint compileShader(GLenum type, const char* src) { return shader; } -void drawChar(char c, float x, float y, float scale, const Vector3& color, std::vector& lines) { +void drawChar(char c, float x, float y, float scale, const Color& color, std::vector& lines) { float w = 0.5f * scale; float h = 1.0f * scale; @@ -90,7 +90,7 @@ void drawChar(char c, float x, float y, float scale, const Vector3& color } } -void drawText(const std::string& text, float x, float y, float scale, const Vector3& color, std::vector& lines) { +void drawText(const std::string& text, float x, float y, float scale, const Color& color, std::vector& lines) { float cursor = x; for (char c : text) { drawChar(c, cursor, y, scale, color, lines); @@ -151,7 +151,10 @@ GLuint createShaderProgram() { return shaderProgram; } -void generatePointCloud(std::vector& pointCloud, const Vector3& A, const Vector3& B, const Vector3& C) { +void generatePointCloud(std::vector& pointCloud, const Triangle>& triangle) { + const auto& A = triangle.m_vertex1; + const auto& B = triangle.m_vertex2; + const auto& C = triangle.m_vertex3; // Iterating over barycentric coordinates (u, v, w) from 0.0 to 1.0 for (float u = 0.0f; u <= 1.0f; u += 0.015f) { for (float v = 0.0f; v <= 1.0f - u; v += 0.015f) { @@ -197,7 +200,11 @@ void setupBuffers(GLuint& VAO_cloud, GLuint& VBO_cloud, const std::vector glEnableVertexAttribArray(3); } -void updateDynamicData(std::vector& dynData, float u, float v, float w, const Vector3& P, const Vector3& A, const Vector3& B, const Vector3& C) { +void updateDynamicData(std::vector& dynData, float u, float v, float w, const Vector3& P, const Triangle>& triangle) { + const auto& A = triangle.m_vertex1; + const auto& B = triangle.m_vertex2; + const auto& C = triangle.m_vertex3; + float sizeA = 10.0f + u * 30.0f; float sizeB = 10.0f + v * 30.0f; float sizeC = 10.0f + w * 30.0f; @@ -233,9 +240,9 @@ void updateDynamicData(std::vector& dynData, float u, float v, float w, c float distB = 0.13f; float distC = 0.13f; - drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Vector3(1,0,0), dynData); - drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Vector3(0,1,0), dynData); - drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Vector3(0,0,1), dynData); + drawText(bufA, A.x - 0.05f, A.y + distA, 0.1f, Color(1,0,0,1), dynData); + drawText(bufB, B.x - 0.15f - distB, B.y - 0.05f - distB, 0.1f, Color(0,1,0,1), dynData); + drawText(bufC, C.x + 0.05f + distC, C.y - 0.05f - distC, 0.1f, Color(0,0,1,1), dynData); } int main() { @@ -246,12 +253,14 @@ int main() { // Triangle vertices as shown in the picture (Red, Green, Blue) // Scaled down slightly to leave room for text - Vector3 A(0.0f, 0.6f, 0.0f); // Red dot (top) - Vector3 B(-0.6f, -0.6f, 0.0f); // Green dot (bottom left) - Vector3 C(0.6f, -0.6f, 0.0f); // Blue dot (bottom right) + Triangle> triangle( + Vector3(0.0f, 0.6f, 0.0f), // Red dot (top) + Vector3(-0.6f, -0.6f, 0.0f), // Green dot (bottom left) + Vector3(0.6f, -0.6f, 0.0f) // Blue dot (bottom right) + ); std::vector pointCloud; - generatePointCloud(pointCloud, A, B, C); + generatePointCloud(pointCloud, triangle); GLuint VAO_cloud, VBO_cloud, VAO_dyn, VBO_dyn; setupBuffers(VAO_cloud, VBO_cloud, pointCloud, VAO_dyn, VBO_dyn); @@ -293,10 +302,10 @@ int main() { v -= diff / 2.0f; } - Vector3 P = A * u + B * v + C * w; + Vector3 P = triangle.m_vertex1 * u + triangle.m_vertex2 * v + triangle.m_vertex3 * w; std::vector dynData; - updateDynamicData(dynData, u, v, w, P, A, B, C); + updateDynamicData(dynData, u, v, w, P, triangle); glBindVertexArray(VAO_dyn); glBindBuffer(GL_ARRAY_BUFFER, VBO_dyn);