/
ArtemNech
/
simpleOpenGL
Обзор
Документация
Войти
/
ArtemNech
/
simpleOpenGL
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
devOpt
backend/ogl_sys/CGlTransformator.cpp
637 строк
23 KB
Artem Nechitaylenko
Тупиковая ветка. Оптимизация только от контекста
31 май 2026, 15:27
31 май 2026, 15:27
8136c99
Код
Авторство
О чём код?
#include "CGlTransformator.h" void CGlTransformator::addLineAsLine(COglLayer *set, const ngraph::NLineF &line, const ngraph::NColor &color) { auto [x1,y1] = set->worldToGL(line.p1()); auto [x2,y2] = set->worldToGL(line.p2()); // 4. Цвет float r = color.redF(); float g = color.greenF(); float b = color.blueF(); float a = color.alphaF(); std::vector<vertex_t> &vertices = set->vertices(); // Line vertices.insert(vertices.end(), { {x1, y1, set->get_layer_Z(),r, g, b, a}, {x2, y2, set->get_layer_Z(),r, g, b, a} }); } void CGlTransformator::addLineAsQuad(COglLayer *set, const ngraph::NLineF &line, const ngraph::NColor &color, float width) { float x1 = line.p1().x(); float y1 = line.p1().y(); float x2 = line.p2().x(); float y2 = line.p2().y(); // Толщина в нормализованных координатах float thickness = calculateLineWidth(set, {line.p1().x(), line.p1().y()}, {line.p2().x(), line.p2().y()}, width); // 3. Вектор линии и перпендикуляр float dx = (x2 - x1); float dy = (y2 - y1); float length = std::sqrt(dx*dx + dy*dy); if (length < 0.0001f) return; // Слишком короткая линия const float EPSILON = 1e-4f; float px, py; if (std::abs(dy) <= EPSILON) { px = 0.0f; py = thickness; } else if (std::abs(dx) <= EPSILON) { px = thickness; py = 0.0f; } else { px = -dy / length * thickness; py = dx / length * thickness; } // Цвет float r = color.redF(); float g = color.greenF(); float b = color.blueF(); float a = color.alphaF(); float z = set->get_layer_Z(); // Квад из двух треугольников auto &vertices = set->vertices(); vertices.insert(vertices.end(), { // Треугольник 1 {x1 + px, y1 + py, z, r, g, b, a}, {x1 - px, y1 - py, z, r, g, b, a}, {x2 + px, y2 + py, z, r, g, b, a}, // Треугольник 2 {x1 - px, y1 - py, z, r, g, b, a}, {x2 - px, y2 - py, z, r, g, b, a}, {x2 + px, y2 + py, z, r, g, b, a} }); } float CGlTransformator::calculateLineWidth(COglLayer *set, const glm::vec2 &start, const glm::vec2 &end, float desiredPixelWidth) { (void)set; (void)start; (void)end; (void )desiredPixelWidth; return 0.01; /* float dx = std::abs(end.x - start.x); float dy = std::abs(end.y - start.y); auto size = set->viewport_size(); const float EPSILON = 1e-6f; if (dy <= EPSILON) { // Горизонтальная линия - толщина по Y return (2.0f * desiredPixelWidth) / (float )size.height(); } else if (dx <= EPSILON) { // Вертикальная линия - толщина по X return (2.0f * desiredPixelWidth) / (float )size.width(); } else { // Наклонная линия - используем общую формулу float aspect = static_cast<float>(size.width()) / size.height(); if (dx > dy) { // Линия ближе к горизонтальной float t = dy / dx; // тангенс угла (0-1) float thickY = 2.0f * desiredPixelWidth / size.height(); float thickDiag = 2.0f * desiredPixelWidth / (size.width() * std::sqrt(1.0f + 1.0f / (aspect * aspect))); return thickY * (1.0f - t) + thickDiag * t; } else { // Линия ближе к вертикальной float t = dx / dy; // котангенс угла (0-1) float thickX = 2.0f * desiredPixelWidth / size.width(); float thickDiag = 2.0f * desiredPixelWidth / (size.height() * std::sqrt(1.0f + aspect * aspect)); return thickX * (1.0f - t) + thickDiag * t; } }*/ } void CGlTransformator::addLineToBuffer(COglLayer *set, const ngraph::NLineF &line, const ngraph::NColor &color, float width) { if (width <= 1.0f + 1e-6) { addLineAsLine(set, line, color); } else { addLineAsQuad(set, line, color, width); } } void CGlTransformator::addRectToBuffer(COglLayer *set, const ngraph::NRectF &rect, const ngraph::NColor &fillColor) { auto &vertices = set->vertices(); const auto x1 = (float)rect.left(); const auto y1 = (float)rect.top(); const auto x2 = (float)rect.right(); const auto y2 = (float)rect.bottom(); const float r = fillColor.redF(); const float g = fillColor.greenF(); const float b = fillColor.blueF(); const float a = fillColor.alphaF(); vertices.reserve(vertices.size() + 6); float z = set->get_layer_Z(); vertices.emplace_back(x1, y1, z, r, g, b, a); // левый верх vertices.emplace_back(x2, y1, z, r, g, b, a); // правый верх vertices.emplace_back(x1, y2, z, r, g, b, a); // левый низ vertices.emplace_back(x1, y2, z, r, g, b, a); // левый низ vertices.emplace_back(x2, y1, z, r, g, b, a); // правый верх vertices.emplace_back(x2, y2, z, r, g, b, a); // правый низ } void CGlTransformator::drawLine(COglLayer *set, const ngraph::NLineF &line, const ngraph::NColor &color, float width) { if (width <= 1.0f + 1e-6) { set->startBatch(GL_LINES); CGlTransformator::addLineAsLine(set, line, color); } else { set->startBatch(GL_LINES); CGlTransformator::addLineAsQuad(set, line, color, width); } set->endBatch(); } void CGlTransformator::drawRect(COglLayer *set, const ngraph::NRectF &rect, const ngraph::NColor &fillColor, const ngraph::NColor &borderColor, float borderWidth) { set->startBatch(GL_TRIANGLES); addRectToBuffer(set, rect, fillColor); set->endBatch(); // Если есть граница, рисуем линии if (borderColor.red() != 0 || borderColor.green() != 0 || borderColor.blue() != 0) { ngraph::NLineF top(rect.left_top(), ngraph::NPointF(rect.right(), rect.top())); ngraph::NLineF right(ngraph::NPointF(rect.right(), rect.top()), rect.bottom_right()); ngraph::NLineF bottom(rect.bottom_right(), ngraph::NPointF(rect.left(), rect.bottom())); ngraph::NLineF left(ngraph::NPointF(rect.left(), rect.bottom()), rect.left_top()); set->startBatch(GL_TRIANGLES); addLineToBuffer(set, top, borderColor, borderWidth); addLineToBuffer(set, right, borderColor, borderWidth); addLineToBuffer(set, bottom, borderColor, borderWidth); addLineToBuffer(set, left, borderColor, borderWidth); set->endBatch(); } } void CGlTransformator::drawPoint(COglLayer *set, const ngraph::NPointF &point, const ngraph::NColor &color, float size) { set->startBatch(GL_TRIANGLES); auto &vertices = set->vertices(); auto view_size = set->viewport_size(); int segments = std::max(8, static_cast<int>(std::round(8 * size))); float centerX = (2.0f * float(point.x()) / static_cast<float>(view_size.width())) - 1.0f; float centerY = 1.0f - (2.0f * float(point.y()) / float(view_size.height())); // Важно: использовать одинаковые коэффициенты для радиуса по X и Y // или компенсировать aspect ratio //float aspectRatio = static_cast<float>(view_size.width()) / float(view_size.height()); // Радиус в нормализованных координатах float radiusX = (size / static_cast<float>(view_size.width())); float radiusY = (size / static_cast<float>(view_size.height())); float r = color.redF(); float g = color.greenF(); float b = color.blueF(); float a = color.alphaF(); float z = set->get_layer_Z(); vertex center(centerX, centerY, z, r, g, b, a); for (int i = 0; i < segments; i++) { float angle1 = 2.0f * M_PI * (i / segments); float angle2 = 2.0f * M_PI * (i + 1) / segments; // Компенсируем aspect ratio для получения круга вместо эллипса vertex v1(centerX + radiusX * cos(angle1), centerY + radiusY * sin(angle1), z, r, g, b, a); vertex v2(centerX + radiusX * cos(angle2), centerY + radiusY * sin(angle2), z, r, g, b, a); vertices.insert(vertices.end(), {center, v1, v2}); } set->endBatch(); } void CGlTransformator::drawRectGradient(COglLayer *set, const ngraph::NRectF &rect, GradientType gradientType, const ngraph::NColor &startColor, const ngraph::NColor &endColor, const ngraph::NPointF &startPos, const ngraph::NPointF &endPos, float angleDegrees) { (void)angleDegrees; auto[gl_x0,gl_y0] = set->worldToGL(rect.left_top()); auto[gl_x1,gl_y1] = set->worldToGL(rect.bottom_right()); ngraph::NRectF oRect(ngraph::NPointF(gl_x0,gl_y0), ngraph::NPointF(gl_x1,gl_y1)); auto[x_start, y_start] = set->worldToGL(startPos); auto[x_end, y_end] = set->worldToGL(endPos); gradData_t grad_data; grad_data.gradient_type = gradientType; // 1. Сохраняем параметры градиента для uniform'ов grad_data.colGradStart = glm::vec4( (float)startColor.redF(), (float)startColor.greenF(), (float)startColor.blueF(), (float)startColor.alphaF() ); grad_data.colGradEnd = glm::vec4( (float)endColor.redF(), (float)endColor.greenF(), (float)endColor.blueF(), (float)endColor.alphaF() ); grad_data.posGradStart = glm::vec2(x_start, y_start); grad_data.posGradEnd = glm::vec2(x_end, y_end); // Для радиального градиента: центр = середина rect, радиус = половина диагонали grad_data.posGradMid = glm::vec2(oRect.centerX(), oRect.centerY()); /* auto *gradLayer = dynamic_cast<CLayerMainCaps*>(set); gradLayer->add_gradient_data(grad_data);*/ // 3. Преобразование в OpenGL координаты auto x1 = oRect.left(); auto y1 = oRect.top(); auto x2 = oRect.right(); auto y2 = oRect.bottom(); // 4. Цвет в вершинах не важен (будет переопределён градиентом) ngraph::NColor dummyColor(255, 255, 255, 255); // 5. Для каждой вершины вычисляем gx, gy - позицию в градиенте (0..1) // Для прямоугольника: gx = горизонтальная позиция (0 слева, 1 справа) // gy = вертикальная позиция (0 сверху, 1 снизу) // Левый верх float gx1 = 0.0f; float gy1 = 0.0f; // Правый верх float gx2 = 1.0f; float gy2 = 0.0f; // Левый низ float gx3 = 0.0f; float gy3 = 1.0f; // Правый низ float gx4 = 1.0f; float gy4 = 1.0f; // 2. Создаём батч с флагом градиента set->startBatch(GL_TRIANGLES, 12,false, 0, false, true); auto &vertices = set->vertices(); // 6. Добавляем прямоугольник (2 треугольника) float z = set->get_layer_Z(); vertices.insert(vertices.end(), { // Треугольник 1 vertex(x1, y1, z, dummyColor, 0, 0, gradientType, gx1, gy1), vertex(x2, y1, z, dummyColor, 0, 0, gradientType, gx2, gy2), vertex(x1, y2, z, dummyColor, 0, 0, gradientType, gx3, gy3), // Треугольник 2 vertex(x2, y1, z, dummyColor, 0, 0, gradientType, gx2, gy2), vertex(x2, y2, z, dummyColor, 0, 0, gradientType, gx4, gy4), vertex(x1, y2, z, dummyColor, 0, 0, gradientType, gx3, gy3) }); set->endBatch(); } void CGlTransformator::drawRectGradient(COglLayer *set, const ngraph::NRectF &rect, GradientType gradientType, const ngraph::NColor &startColor, const ngraph::NColor &middleColor, const ngraph::NColor &endColor, const ngraph::NPointF &startPos, const ngraph::NPointF &endPos, float angleDegrees) { if (gradientType != GradientType::Pipe) { // fallback на 2-цветный градиент drawRectGradient(set, rect, gradientType, startColor, endColor, startPos, endPos); return; } GradientUniforms gradUniforms; gradUniforms.m_gradientStart = glm::vec4( (float)startColor.red() / 255.0f, (float)startColor.green() / 255.0f, (float)startColor.blue() / 255.0f, (float)startColor.alpha() / 255.0f ); gradUniforms.m_gradientMiddle = glm::vec4( (float)middleColor.red() / 255.0f, (float)middleColor.green() / 255.0f, (float)middleColor.blue() / 255.0f, (float)middleColor.alpha() / 255.0f ); gradUniforms.m_gradientEnd = glm::vec4( (float)endColor.red() / 255.0f, (float)endColor.green() / 255.0f, (float)endColor.blue() / 255.0f, (float)endColor.alpha() / 255.0f ); gradUniforms.m_gradientAngleDeg = angleDegrees; gradUniforms.m_gradientStartPos = glm::vec2(startPos.x(), startPos.y()); auto m_gradientEndPos = glm::vec2(endPos.x(), endPos.y()); gradUniforms.m_hasGradientStart = true; gradUniforms.m_hasGradientMiddle = true; gradUniforms.m_hasGradientEnd = true; set->startBatch(GL_TRIANGLES, 12,false, 0, false, true, gradUniforms); auto [x1, y1] = set->worldToGL(rect.left_top()); auto [x2, y2] = set->worldToGL(rect.bottom_right()); ngraph::NColor dummyColor(255, 255, 255, 255); // gx, gy как в предыдущем методе float gx1 = 0.0f, gy1 = 0.0f; float gx2 = 1.0f, gy2 = 0.0f; float gx3 = 0.0f, gy3 = 1.0f; float gx4 = 1.0f, gy4 = 1.0f; float z = set->get_layer_Z(); auto & m_vertices = set->vertices(); m_vertices.insert(m_vertices.end(), { vertex(x1, y1, z, dummyColor, 0, 0, gradientType, gx1, gy1), vertex(x2, y1, z, dummyColor, 0, 0, gradientType, gx2, gy2), vertex(x1, y2, z, dummyColor, 0, 0, gradientType, gx3, gy3), vertex(x2, y1, z, dummyColor, 0, 0, gradientType, gx2, gy2), vertex(x2, y2, z, dummyColor, 0, 0, gradientType, gx4, gy4), vertex(x1, y2, z, dummyColor, 0, 0, gradientType, gx3, gy3) }); set->endBatch(); } void CGlTransformator::drawRectRadialGradient(COglLayer *set, const ngraph::NRectF &rect, const ngraph::NColor ¢erColor, const ngraph::NColor &edgeColor) { // Uniform'ы градиента GradientUniforms gradUniforms; gradUniforms.m_gradientStart = glm::vec4( centerColor.redF(), centerColor.greenF(), centerColor.blueF(), centerColor.alphaF() ); gradUniforms.m_gradientEnd = glm::vec4( edgeColor.redF(), edgeColor.greenF(), edgeColor.blueF(), edgeColor.alphaF() ); gradUniforms.m_hasGradientStart = true; gradUniforms.m_hasGradientEnd = true; // Батч с radial градиентом set->startBatch(GL_TRIANGLES, 12,false, 0, false, true, gradUniforms); auto [x1, y1] = set->worldToGL(rect.left_top()); auto [x2, y2] = set->worldToGL(rect.bottom_right()); float z = set->get_layer_Z(); ngraph::NColor dummyColor(255, 255, 255, 255); // Вычисляем gradientData.xy для каждой вершины auto & m_vertices = set->vertices(); m_vertices.insert(m_vertices.end(), { vertex(x1, y1, z, dummyColor, 0, 0, GradientType::Radial, 0.0f, 0.0f), vertex(x2, y1, z, dummyColor, 0, 0, GradientType::Radial, 1.0f, 0.0f), vertex(x1, y2, z, dummyColor, 0, 0, GradientType::Radial, 0.0f, 1.0f), vertex(x2, y1, z, dummyColor, 0, 0, GradientType::Radial, 1.0f, 0.0f), vertex(x2, y2, z, dummyColor, 0, 0, GradientType::Radial, 1.0f, 1.0f), vertex(x1, y2, z, dummyColor, 0, 0, GradientType::Radial, 0.0f, 1.0f) }); set->endBatch(); } void CGlTransformator::drawRectConicalGradient(COglLayer *set, const ngraph::NRectF &rect, const ngraph::NColor &startColor, const ngraph::NColor &endColor, float startAngleDeg) { (void)startAngleDeg; // Uniform'ы градиента GradientUniforms gradUniforms; gradUniforms.m_gradientStart = glm::vec4( startColor.redF(), startColor.greenF(), startColor.blueF(), startColor.alphaF() ); gradUniforms.m_gradientEnd = glm::vec4( endColor.redF(), endColor.greenF(), endColor.blueF(), endColor.alphaF() ); gradUniforms.m_hasGradientStart = true; gradUniforms.m_hasGradientEnd = true; auto [x1, y1] = set->worldToGL(rect.left_top()); auto [x2, y2] = set->worldToGL(rect.bottom_right()); float z = set->get_layer_Z(); ngraph::NColor dummyColor(255, 255, 255, 255); set->startBatch(GL_TRIANGLES, 12,false, 0, false, true, gradUniforms); auto & m_vertices = set->vertices(); m_vertices.insert(m_vertices.end(), { // Треугольник 1 vertex(x1, y1, z, dummyColor, 0, 0, GradientType::Conical, 0.0f, 0.0f), vertex(x2, y1, z, dummyColor, 0, 0, GradientType::Conical, 1.0f, 0.0f), vertex(x1, y2, z, dummyColor, 0, 0, GradientType::Conical, 0.0f, 1.0f), // Треугольник 2 vertex(x2, y1, z, dummyColor, 0, 0, GradientType::Conical, 1.0f, 0.0f), vertex(x2, y2, z, dummyColor, 0, 0, GradientType::Conical, 1.0f, 1.0f), vertex(x1, y2, z, dummyColor, 0, 0, GradientType::Conical, 0.0f, 1.0f) }); set->endBatch(); } void CGlTransformator::drawCircle(COglLayer *set, const ngraph::NPointF ¢er, double radius, double horizonRad, const ngraph::NColor &fillColor, const ngraph::NColor &borderColor) { auto &vertices = set->vertices(); auto view_size = set->viewport_size(); float radiusX = static_cast<float>(horizonRad > 0 ? horizonRad : radius); float radiusY = static_cast<float>(radius); float centerX = center.x(); float centerY = center.y(); float normRadiusX = radiusX; float normRadiusY = radiusY; // Определяем количество сегментов для гладкости float avgRadius = (radiusX + radiusY) / 2.0f; int segments = std::max(12, static_cast<int>(std::round(16 * avgRadius / 100.0f))); segments = std::min(segments, 360); // ограничиваем максимум // Цвета float rFill = fillColor.redF(); float gFill = fillColor.greenF(); float bFill = fillColor.blueF(); float aFill = fillColor.alphaF(); float rBorder = borderColor.redF(); float gBorder = borderColor.greenF(); float bBorder = borderColor.blueF(); float aBorder = borderColor.alphaF(); float z = set->get_layer_Z(); vertex centerVert(centerX, centerY, z, rFill, gFill, bFill, aFill); set->startBatch(GL_TRIANGLES); for (int i = 0; i < segments; ++i) { float angle1 = 2.0f * M_PI * static_cast<float>(i) / static_cast<float>(segments); float angle2 = 2.0f * M_PI * static_cast<float>(i + 1) / static_cast<float>(segments); vertex v1(centerX + normRadiusX * cos(angle1), centerY + normRadiusY * sin(angle1), z, rFill, gFill, bFill, aFill); vertex v2(centerX + normRadiusX * cos(angle2), centerY + normRadiusY * sin(angle2), z, rFill, gFill, bFill, aFill); vertices.insert(vertices.end(), {centerVert, v1, v2}); } set->endBatch(); if (borderColor.alpha() > 0 && borderColor != fillColor) { set->startBatch(GL_LINES); for (int i = 0; i < segments; ++i) { float angle1 = 2.0f * M_PI * static_cast<float>(i) / static_cast<float>(segments); float angle2 = 2.0f * M_PI * static_cast<float>(i + 1) / static_cast<float>(segments); vertex v1(centerX + normRadiusX * cos(angle1), centerY + normRadiusY * sin(angle1), z, rBorder, gBorder, bBorder, aBorder); vertex v2(centerX + normRadiusX * cos(angle2), centerY + normRadiusY * sin(angle2), z, rBorder, gBorder, bBorder, aBorder); vertices.insert(vertices.end(), {v1, v2}); } set->endBatch(); } } void CGlTransformator::drawTriangle(COglLayer *set, const ngraph::NPointF ¢er, float baseLen, float lateralSide, const ngraph::NColor &fillColor, const ngraph::NColor &borderColor) { auto &vertices = set->vertices(); float z = set->get_layer_Z(); float halfBase = baseLen / 2.0f; float height = std::sqrt(lateralSide * lateralSide - halfBase * halfBase); float x1 = center.x() - halfBase; float y1 = center.y() + height / 3.0f; // Центр масс отступает от основания // Нижняя правая вершина float x2 = center.x() + halfBase; float y2 = center.y() + height / 3.0f; // Верхняя вершина float x3 = center.x(); float y3 = center.y() - height * 2.0f / 3.0f; // Центр масс на 1/3 от основания float rFill = fillColor.redF(); float gFill = fillColor.greenF(); float bFill = fillColor.blueF(); float aFill = fillColor.alphaF(); float rBorder = borderColor.redF(); float gBorder = borderColor.greenF(); float bBorder = borderColor.blueF(); float aBorder = borderColor.alphaF(); vertex v1(x1, y1, z, rFill, gFill, bFill, aFill); vertex v2(x2, y2, z, rFill, gFill, bFill, aFill); vertex v3(x3, y3, z, rFill, gFill, bFill, aFill); set->startBatch(GL_TRIANGLES); vertices.insert(vertices.end(), {v1, v2, v3}); set->endBatch(); // Рисуем границу (три отрезка) if (borderColor.alpha() > 0 && borderColor != fillColor) { set->startBatch(GL_LINES); // Сторона 1: от v1 к v2 (основание) vertices.insert(vertices.end(), {v1, v2}); // Сторона 2: от v2 к v3 (правая боковая) vertex v2_border(x2, y2, z, rBorder, gBorder, bBorder, aBorder); vertex v3_border(x3, y3, z, rBorder, gBorder, bBorder, aBorder); vertices.insert(vertices.end(), {v2_border, v3_border}); // Сторона 3: от v3 к v1 (левая боковая) vertex v1_border(x1, y1, z, rBorder, gBorder, bBorder, aBorder); vertices.insert(vertices.end(), {v3_border, v1_border}); set->endBatch(); } }