kopia lustrzana https://github.com/jameshball/osci-render
Completely remove custom SVG implementation and pugixml library in favour of JUCE classes
rodzic
4a3ba6c99c
commit
c9a46c29d0
|
@ -97,9 +97,12 @@ Vector2 Shape::maxVector(std::vector<std::unique_ptr<Shape>>& shapes) {
|
|||
}
|
||||
|
||||
void Shape::removeOutOfBounds(std::vector<std::unique_ptr<Shape>>& shapes) {
|
||||
std::vector<int> toRemove;
|
||||
|
||||
for (int i = 0; i < shapes.size(); i++) {
|
||||
Vector2 start = shapes[i]->nextVector(0);
|
||||
Vector2 end = shapes[i]->nextVector(1);
|
||||
bool keep = false;
|
||||
|
||||
if ((start.x < 1 && start.x > -1) || (start.y < 1 && start.y > -1)) {
|
||||
if ((end.x < 1 && end.x > -1) || (end.y < 1 && end.y > -1)) {
|
||||
|
@ -108,7 +111,16 @@ void Shape::removeOutOfBounds(std::vector<std::unique_ptr<Shape>>& shapes) {
|
|||
Vector2 newEnd(std::min(std::max(end.x, -1.0), 1.0), std::min(std::max(end.y, -1.0), 1.0));
|
||||
shapes[i] = std::make_unique<Line>(newStart.x, newStart.y, newEnd.x, newEnd.y);
|
||||
}
|
||||
keep = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
toRemove.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = toRemove.size() - 1; i >= 0; i--) {
|
||||
shapes.erase(shapes.begin() + toRemove[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#include "ClosePath.h"
|
||||
#include "../shape/Line.h"
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> ClosePath::absolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseClosePath(state, args);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> ClosePath::relative(SvgState& state, std::vector<float>& args) {
|
||||
return parseClosePath(state, args);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> ClosePath::parseClosePath(SvgState& state, std::vector<float>& args) {
|
||||
auto shapes = std::vector<std::unique_ptr<Shape>>();
|
||||
if (state.currPoint.x != state.initialPoint.x || state.currPoint.y != state.initialPoint.y) {
|
||||
state.currPoint = state.initialPoint;
|
||||
shapes.push_back(std::make_unique<Line>(state.currPoint.x, state.currPoint.y, state.initialPoint.x, state.initialPoint.y));
|
||||
}
|
||||
return shapes;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
|
||||
class ClosePath {
|
||||
public:
|
||||
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
|
||||
private:
|
||||
static std::vector<std::unique_ptr<Shape>> parseClosePath(SvgState& state, std::vector<float>& args);
|
||||
};
|
|
@ -1,107 +0,0 @@
|
|||
#include "CurveTo.h"
|
||||
#include "../shape/CubicBezierCurve.h"
|
||||
#include "../shape/QuadraticBezierCurve.h"
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::absolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, true, true, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::relative(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, false, true, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::smoothAbsolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, true, true, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::smoothRelative(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, false, true, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::quarticAbsolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, true, false, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::quarticRelative(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, false, false, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::quarticSmoothAbsolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, true, false, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::quarticSmoothRelative(SvgState& state, std::vector<float>& args) {
|
||||
return parseCurveTo(state, args, false, false, true);
|
||||
}
|
||||
|
||||
|
||||
// Parses curveto commands (C, c, S, s, Q, q, T, and t commands)
|
||||
// isCubic should be true for parsing C, c, S, and s commands
|
||||
// isCubic should be false for parsing Q, q, T, and t commands
|
||||
// isSmooth should be true for parsing S, s, T, and t commands
|
||||
// isSmooth should be false for parsing C, c, Q, and q commands
|
||||
std::vector<std::unique_ptr<Shape>> CurveTo::parseCurveTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isCubic, bool isSmooth) {
|
||||
int expectedArgs = isCubic ? 4 : 2;
|
||||
if (!isSmooth) {
|
||||
expectedArgs += 2;
|
||||
}
|
||||
|
||||
if (args.size() % expectedArgs != 0 || args.size() < expectedArgs) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto curves = std::vector<std::unique_ptr<Shape>>();
|
||||
|
||||
for (int i = 0; i < args.size(); i += expectedArgs) {
|
||||
Vector2 controlPoint1;
|
||||
Vector2 controlPoint2;
|
||||
|
||||
if (isSmooth) {
|
||||
if (isCubic) {
|
||||
if (!state.prevCubicControlPoint.has_value()) {
|
||||
controlPoint1 = state.currPoint;
|
||||
} else {
|
||||
controlPoint1 = state.prevCubicControlPoint.value();
|
||||
}
|
||||
} else {
|
||||
if (!state.prevQuadraticControlPoint.has_value()) {
|
||||
controlPoint1 = state.currPoint;
|
||||
} else {
|
||||
controlPoint1 = state.prevQuadraticControlPoint.value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
controlPoint1 = Vector2(args[i], args[i + 1]);
|
||||
}
|
||||
|
||||
if (isCubic) {
|
||||
controlPoint2 = Vector2(args[i + expectedArgs - 4], args[i + expectedArgs - 3]);
|
||||
}
|
||||
|
||||
Vector2 newPoint(args[i + expectedArgs - 2], args[i + expectedArgs - 1]);
|
||||
|
||||
if (!isAbsolute) {
|
||||
if (!isSmooth) {
|
||||
controlPoint1.translate(state.currPoint.x, state.currPoint.y);
|
||||
}
|
||||
controlPoint2.translate(state.currPoint.x, state.currPoint.y);
|
||||
newPoint.translate(state.currPoint.x, state.currPoint.y);
|
||||
}
|
||||
|
||||
if (isSmooth) {
|
||||
controlPoint1.reflectRelativeToVector(state.currPoint.x, state.currPoint.y);
|
||||
}
|
||||
|
||||
if (isCubic) {
|
||||
curves.push_back(std::make_unique<CubicBezierCurve>(state.currPoint.x, state.currPoint.y, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, newPoint.x, newPoint.y));
|
||||
state.currPoint = newPoint;
|
||||
state.prevCubicControlPoint = controlPoint2;
|
||||
} else {
|
||||
curves.push_back(std::make_unique<QuadraticBezierCurve>(state.currPoint.x, state.currPoint.y, controlPoint1.x, controlPoint1.y, newPoint.x, newPoint.y));
|
||||
state.currPoint = newPoint;
|
||||
state.prevQuadraticControlPoint = controlPoint1;
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
|
||||
class CurveTo {
|
||||
public:
|
||||
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> smoothAbsolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> smoothRelative(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> quarticAbsolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> quarticRelative(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> quarticSmoothAbsolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> quarticSmoothRelative(SvgState& state, std::vector<float>& args);
|
||||
private:
|
||||
static std::vector<std::unique_ptr<Shape>> parseCurveTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isCubic, bool isSmooth);
|
||||
};
|
|
@ -1,125 +0,0 @@
|
|||
#include "EllipticalArcTo.h"
|
||||
#include "../shape/Line.h"
|
||||
#include <numbers>
|
||||
#include "../shape/CircleArc.h"
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::absolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseEllipticalArc(state, args, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::relative(SvgState& state, std::vector<float>& args) {
|
||||
return parseEllipticalArc(state, args, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> EllipticalArcTo::parseEllipticalArc(SvgState& state, std::vector<float>& args, bool isAbsolute) {
|
||||
if (args.size() % 7 != 0 || args.size() < 7) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> shapes;
|
||||
for (int i = 0; i < args.size(); i += 7) {
|
||||
Vector2 newPoint(args[i + 5], args[i + 6]);
|
||||
if (!isAbsolute) {
|
||||
newPoint.translate(state.currPoint.x, state.currPoint.y);
|
||||
}
|
||||
|
||||
createArc(shapes, state.currPoint, args[i], args[i + 1], args[i + 2], args[i + 3] == 1, args[i + 4] == 1, newPoint);
|
||||
state.currPoint = newPoint;
|
||||
}
|
||||
|
||||
return shapes;
|
||||
}
|
||||
|
||||
// The following algorithm is completely based on https://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
||||
void EllipticalArcTo::createArc(std::vector<std::unique_ptr<Shape>>& shapes, Vector2 start, float rx, float ry, float theta, bool largeArcFlag, bool sweepFlag, Vector2 end) {
|
||||
double x2 = end.x;
|
||||
double y2 = end.y;
|
||||
// Ensure radii are valid
|
||||
if (rx == 0 || ry == 0) {
|
||||
shapes.push_back(std::make_unique<Line>(start.x, start.y, end.x, end.y));
|
||||
return;
|
||||
}
|
||||
double x1 = start.x;
|
||||
double y1 = start.y;
|
||||
// Compute the half distance between the current and the final point
|
||||
double dx2 = (x1 - x2) / 2.0;
|
||||
double dy2 = (y1 - y2) / 2.0;
|
||||
// Convert theta from degrees to radians
|
||||
|
||||
theta = std::fmod(theta, 360.0) * (std::numbers::pi / 180.0);
|
||||
|
||||
//
|
||||
// Step 1 : Compute (x1', y1')
|
||||
//
|
||||
double x1prime = std::cos(theta) * dx2 + std::sin(theta) * dy2;
|
||||
double y1prime = -std::sin(theta) * dx2 + std::cos(theta) * dy2;
|
||||
// Ensure radii are large enough
|
||||
rx = std::abs(rx);
|
||||
ry = std::abs(ry);
|
||||
double Prx = rx * rx;
|
||||
double Pry = ry * ry;
|
||||
double Px1prime = x1prime * x1prime;
|
||||
double Py1prime = y1prime * y1prime;
|
||||
double d = Px1prime / Prx + Py1prime / Pry;
|
||||
if (d > 1) {
|
||||
rx = std::abs(std::sqrt(d) * rx);
|
||||
ry = std::abs(std::sqrt(d) * ry);
|
||||
Prx = rx * rx;
|
||||
Pry = ry * ry;
|
||||
}
|
||||
|
||||
//
|
||||
// Step 2 : Compute (cx', cy')
|
||||
//
|
||||
double sign = (largeArcFlag == sweepFlag) ? -1.0 : 1.0;
|
||||
// Forcing the inner term to be positive. It should be >= 0 but can sometimes be negative due
|
||||
// to double precision.
|
||||
double coef = sign *
|
||||
std::sqrt(std::abs((Prx * Pry) - (Prx * Py1prime) - (Pry * Px1prime)) / ((Prx * Py1prime) + (Pry * Px1prime)));
|
||||
double cxprime = coef * ((rx * y1prime) / ry);
|
||||
double cyprime = coef * -((ry * x1prime) / rx);
|
||||
|
||||
//
|
||||
// Step 3 : Compute (cx, cy) from (cx', cy')
|
||||
//
|
||||
double sx2 = (x1 + x2) / 2.0;
|
||||
double sy2 = (y1 + y2) / 2.0;
|
||||
double cx = sx2 + std::cos(theta) * cxprime - std::sin(theta) * cyprime;
|
||||
double cy = sy2 + std::sin(theta) * cxprime + std::cos(theta) * cyprime;
|
||||
|
||||
//
|
||||
// Step 4 : Compute the angleStart (theta1) and the angleExtent (dtheta)
|
||||
//
|
||||
double ux = (x1prime - cxprime) / rx;
|
||||
double uy = (y1prime - cyprime) / ry;
|
||||
double vx = (-x1prime - cxprime) / rx;
|
||||
double vy = (-y1prime - cyprime) / ry;
|
||||
double p, n;
|
||||
// Compute the angle start
|
||||
n = std::sqrt((ux * ux) + (uy * uy));
|
||||
p = ux; // (1 * ux) + (0 * uy)
|
||||
sign = (uy < 0) ? -1.0 : 1.0;
|
||||
double angleStart = sign * std::acos(p / n);
|
||||
// Compute the angle extent
|
||||
n = std::sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
||||
p = ux * vx + uy * vy;
|
||||
sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
|
||||
double angleExtent = sign * std::acos(p / n);
|
||||
if (!sweepFlag && angleExtent > 0) {
|
||||
angleExtent -= 2 * std::numbers::pi;
|
||||
} else if (sweepFlag && angleExtent < 0) {
|
||||
angleExtent += 2 * std::numbers::pi;
|
||||
}
|
||||
angleExtent = std::fmod(angleExtent, 2 * std::numbers::pi);
|
||||
angleStart = std::fmod(angleStart, 2 * std::numbers::pi);
|
||||
|
||||
auto arc = std::make_unique<CircleArc>(cx, cy, rx, ry, angleStart, angleExtent);
|
||||
arc->translate(-cx, -cy);
|
||||
arc->rotate(theta);
|
||||
arc->translate(cx, cy);
|
||||
|
||||
Vector2 startPoint = arc->nextVector(0);
|
||||
Vector2 endPoint = arc->nextVector(1);
|
||||
|
||||
shapes.push_back(std::move(arc));
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
|
||||
class EllipticalArcTo {
|
||||
public:
|
||||
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
|
||||
private:
|
||||
static std::vector<std::unique_ptr<Shape>> parseEllipticalArc(SvgState& state, std::vector<float>& args, bool isAbsolute);
|
||||
static void createArc(std::vector<std::unique_ptr<Shape>>& shapes, Vector2 start, float rx, float ry, float theta, bool largeArcFlag, bool sweepFlag, Vector2 end);
|
||||
};
|
|
@ -1,74 +0,0 @@
|
|||
#include "LineTo.h"
|
||||
#include "../shape/Line.h"
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::absolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, true, true, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::relative(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, false, true, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::horizontalAbsolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, true, true, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::horizontalRelative(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, false, true, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::verticalAbsolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, true, false, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::verticalRelative(SvgState& state, std::vector<float>& args) {
|
||||
return parseLineTo(state, args, false, false, true);
|
||||
}
|
||||
|
||||
|
||||
// Parses lineto commands (L, l, H, h, V, and v commands)
|
||||
// isHorizontal and isVertical should be true for parsing L and l commands
|
||||
// Only isHorizontal should be true for parsing H and h commands
|
||||
// Only isVertical should be true for parsing V and v commands
|
||||
std::vector<std::unique_ptr<Shape>> LineTo::parseLineTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isHorizontal, bool isVertical) {
|
||||
int expectedArgs = isHorizontal && isVertical ? 2 : 1;
|
||||
|
||||
if (args.size() % expectedArgs != 0 || args.size() < expectedArgs) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto lines = std::vector<std::unique_ptr<Shape>>();
|
||||
|
||||
for (int i = 0; i < args.size(); i += expectedArgs) {
|
||||
Vector2 newPoint;
|
||||
|
||||
if (expectedArgs == 1) {
|
||||
newPoint = Vector2(args[i], args[i]);
|
||||
} else {
|
||||
newPoint = Vector2(args[i], args[i + 1]);
|
||||
}
|
||||
|
||||
if (isHorizontal && !isVertical) {
|
||||
if (isAbsolute) {
|
||||
newPoint.y = state.currPoint.y;
|
||||
} else {
|
||||
newPoint.y = 0;
|
||||
}
|
||||
} else if (isVertical && !isHorizontal) {
|
||||
if (isAbsolute) {
|
||||
newPoint.x = state.currPoint.x;
|
||||
} else {
|
||||
newPoint.x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAbsolute) {
|
||||
newPoint.translate(state.currPoint.x, state.currPoint.y);
|
||||
}
|
||||
|
||||
lines.push_back(std::make_unique<Line>(state.currPoint.x, state.currPoint.y, newPoint.x, newPoint.y));
|
||||
state.currPoint = newPoint;
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
|
||||
class LineTo {
|
||||
public:
|
||||
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> horizontalAbsolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> horizontalRelative(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> verticalAbsolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> verticalRelative(SvgState& state, std::vector<float>& args);
|
||||
private:
|
||||
static std::vector<std::unique_ptr<Shape>> parseLineTo(SvgState& state, std::vector<float>& args, bool isAbsolute, bool isHorizontal, bool isVertical);
|
||||
};
|
|
@ -1,36 +0,0 @@
|
|||
#include "MoveTo.h"
|
||||
#include "LineTo.h"
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> MoveTo::absolute(SvgState& state, std::vector<float>& args) {
|
||||
return parseMoveTo(state, args, true);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> MoveTo::relative(SvgState& state, std::vector<float>& args) {
|
||||
return parseMoveTo(state, args, false);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> MoveTo::parseMoveTo(SvgState& state, std::vector<float>& args, bool isAbsolute) {
|
||||
if (args.size() % 2 != 0 || args.size() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Vector2 vec(args[0], args[1]);
|
||||
|
||||
if (isAbsolute) {
|
||||
state.currPoint = vec;
|
||||
state.initialPoint = state.currPoint;
|
||||
if (args.size() > 2) {
|
||||
std::vector<float> newArgs = std::vector<float>(args.begin() + 2, args.end());
|
||||
return LineTo::absolute(state, newArgs);
|
||||
}
|
||||
} else {
|
||||
state.currPoint.translate(vec.x, vec.y);
|
||||
state.initialPoint = state.currPoint;
|
||||
if (args.size() > 2) {
|
||||
std::vector<float> newArgs = std::vector<float>(args.begin() + 2, args.end());
|
||||
return LineTo::relative(state, newArgs);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
|
||||
class MoveTo {
|
||||
public:
|
||||
static std::vector<std::unique_ptr<Shape>> absolute(SvgState& state, std::vector<float>& args);
|
||||
static std::vector<std::unique_ptr<Shape>> relative(SvgState& state, std::vector<float>& args);
|
||||
private:
|
||||
static std::vector<std::unique_ptr<Shape>> parseMoveTo(SvgState& state, std::vector<float>& args, bool isAbsolute);
|
||||
};
|
|
@ -1,46 +1,64 @@
|
|||
#include "SvgParser.h"
|
||||
#include <regex>
|
||||
#include "MoveTo.h"
|
||||
#include "LineTo.h"
|
||||
#include "CurveTo.h"
|
||||
#include "EllipticalArcTo.h"
|
||||
#include "ClosePath.h"
|
||||
#include "../shape/Line.h"
|
||||
#include "../shape/QuadraticBezierCurve.h"
|
||||
|
||||
|
||||
SvgParser::SvgParser(juce::String svgFile) {
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_string(svgFile.toStdString().c_str());
|
||||
|
||||
if (result) {
|
||||
pugi::xml_node svg = doc.select_node("//svg").node();
|
||||
pugi::xpath_node_set paths = svg.select_nodes("//path");
|
||||
auto doc = juce::XmlDocument::parse(svgFile);
|
||||
std::unique_ptr<juce::Drawable> svg = juce::Drawable::createFromSVG(*doc);
|
||||
juce::DrawableComposite* composite = dynamic_cast<juce::DrawableComposite*>(svg.get());
|
||||
auto contentArea = composite->getContentArea();
|
||||
auto path = svg->getOutlineAsPath();
|
||||
// apply transform to path to get the content area in the bounds -1 to 1
|
||||
path.applyTransform(juce::AffineTransform::translation(-contentArea.getX(), -contentArea.getY()));
|
||||
path.applyTransform(juce::AffineTransform::scale(2 / contentArea.getWidth(), 2 / contentArea.getHeight()));
|
||||
path.applyTransform(juce::AffineTransform::translation(-1, -1));
|
||||
|
||||
shapes = std::vector<std::unique_ptr<Shape>>();
|
||||
|
||||
for (pugi::xpath_node xPath : paths) {
|
||||
pugi::xml_node path = xPath.node();
|
||||
for (pugi::xml_attribute attr : path.attributes()) {
|
||||
if (std::strcmp(attr.name(), "d") == 0) {
|
||||
auto path = parsePath(juce::String(attr.value()));
|
||||
shapes.insert(shapes.end(), std::make_move_iterator(path.begin()), std::make_move_iterator(path.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<double, double> dimensions = getDimensions(svg);
|
||||
|
||||
if (dimensions.first != -1.0 && dimensions.second != -1.0) {
|
||||
double width = dimensions.first;
|
||||
double height = dimensions.second;
|
||||
|
||||
Shape::normalize(shapes, width, height);
|
||||
} else {
|
||||
Shape::normalize(shapes);
|
||||
}
|
||||
}
|
||||
pathToShapes(path, shapes);
|
||||
Shape::removeOutOfBounds(shapes);
|
||||
}
|
||||
|
||||
SvgParser::~SvgParser() {
|
||||
SvgParser::~SvgParser() {}
|
||||
|
||||
void SvgParser::pathToShapes(juce::Path& path, std::vector<std::unique_ptr<Shape>>& shapes) {
|
||||
juce::Path::Iterator pathIterator(path);
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double startX = 0;
|
||||
double startY = 0;
|
||||
|
||||
while (pathIterator.next()) {
|
||||
auto type = pathIterator.elementType;
|
||||
|
||||
switch (type) {
|
||||
case juce::Path::Iterator::PathElementType::startNewSubPath:
|
||||
x = pathIterator.x1;
|
||||
y = pathIterator.y1;
|
||||
startX = x;
|
||||
startY = y;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::lineTo:
|
||||
shapes.push_back(std::make_unique<Line>(x, -y, pathIterator.x1, -pathIterator.y1));
|
||||
x = pathIterator.x1;
|
||||
y = pathIterator.y1;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::quadraticTo:
|
||||
shapes.push_back(std::make_unique<QuadraticBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2));
|
||||
x = pathIterator.x2;
|
||||
y = pathIterator.y2;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::cubicTo:
|
||||
shapes.push_back(std::make_unique<CubicBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2, pathIterator.x3, -pathIterator.y3));
|
||||
x = pathIterator.x3;
|
||||
y = pathIterator.y3;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::closePath:
|
||||
shapes.push_back(std::make_unique<Line>(x, -y, startX, -startY));
|
||||
x = startX;
|
||||
y = startY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> SvgParser::draw() {
|
||||
|
@ -51,185 +69,4 @@ std::vector<std::unique_ptr<Shape>> SvgParser::draw() {
|
|||
tempShapes.push_back(shape->clone());
|
||||
}
|
||||
return tempShapes;
|
||||
}
|
||||
|
||||
std::vector<std::string> SvgParser::preProcessPath(std::string path) {
|
||||
std::regex re1(",");
|
||||
std::regex re2("-(?!e)");
|
||||
std::regex re3("\\s+");
|
||||
std::regex re4("(^\\s|\\s$)");
|
||||
|
||||
path = std::regex_replace(path, re1, " ");
|
||||
// reverse path and use a negative lookahead
|
||||
std::reverse(path.begin(), path.end());
|
||||
path = std::regex_replace(path, re2, "- ");
|
||||
std::reverse(path.begin(), path.end());
|
||||
path = std::regex_replace(path, re3, " ");
|
||||
path = std::regex_replace(path, re4, "");
|
||||
|
||||
std::regex commands("(?=[mlhvcsqtazMLHVCSQTAZ])");
|
||||
std::vector<std::string> commandsVector;
|
||||
|
||||
std::sregex_token_iterator iter(path.begin(), path.end(), commands, -1);
|
||||
|
||||
for (; iter != std::sregex_token_iterator(); ++iter) {
|
||||
commandsVector.push_back(iter->str());
|
||||
}
|
||||
|
||||
return commandsVector;
|
||||
}
|
||||
|
||||
juce::String SvgParser::simplifyLength(juce::String length) {
|
||||
return length.replace("em|ex|px|in|cm|mm|pt|pc", "");
|
||||
}
|
||||
|
||||
std::pair<double, double> SvgParser::getDimensions(pugi::xml_node& svg) {
|
||||
double width = -1.0;
|
||||
double height = -1.0;
|
||||
|
||||
if (!svg.attribute("viewBox").empty()) {
|
||||
juce::String viewBox = juce::String(svg.attribute("viewBox").as_string());
|
||||
juce::StringArray viewBoxValues = juce::StringArray::fromTokens(viewBox, " ", "");
|
||||
|
||||
if (viewBoxValues.size() == 4) {
|
||||
width = viewBoxValues[2].getDoubleValue();
|
||||
height = viewBoxValues[3].getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
std::regex re("em|ex|px|in|cm|mm|pt|pc");
|
||||
|
||||
if (!svg.attribute("width").empty()) {
|
||||
std::string widthString = svg.attribute("width").as_string();
|
||||
widthString = std::regex_replace(widthString, re, "");
|
||||
width = juce::String(widthString).getDoubleValue();
|
||||
}
|
||||
|
||||
if (!svg.attribute("height").empty()) {
|
||||
std::string heightString = svg.attribute("height").as_string();
|
||||
heightString = std::regex_replace(heightString, re, "");
|
||||
height = juce::String(heightString).getDoubleValue();
|
||||
}
|
||||
|
||||
return std::make_pair<>(width, height);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> SvgParser::parsePath(juce::String path) {
|
||||
if (path.isEmpty()) {
|
||||
return std::vector<std::unique_ptr<Shape>>();
|
||||
}
|
||||
|
||||
state.currPoint = Vector2();
|
||||
state.prevCubicControlPoint = std::nullopt;
|
||||
state.prevQuadraticControlPoint = std::nullopt;
|
||||
|
||||
std::vector<std::string> commands = preProcessPath(path.toStdString());
|
||||
std::vector<std::unique_ptr<Shape>> pathShapes;
|
||||
|
||||
for (auto& stdCommand : commands) {
|
||||
if (!stdCommand.empty()) {
|
||||
juce::String command(stdCommand);
|
||||
char commandChar = command[0];
|
||||
std::vector<float> nums;
|
||||
|
||||
if (commandChar != 'z' && commandChar != 'Z') {
|
||||
juce::StringArray tokens = juce::StringArray::fromTokens(command.substring(1), " ", "");
|
||||
|
||||
for (juce::String token : tokens) {
|
||||
token = token.trim();
|
||||
if (token.isNotEmpty()) {
|
||||
juce::StringArray decimalSplit = juce::StringArray::fromTokens(token, ".", "");
|
||||
if (decimalSplit.size() == 1) {
|
||||
auto num = decimalSplit[0].getFloatValue();
|
||||
nums.push_back(num);
|
||||
} else {
|
||||
juce::String decimal = decimalSplit[0] + "." + decimalSplit[1];
|
||||
nums.push_back(decimal.getFloatValue());
|
||||
|
||||
for (int i = 2; i < decimalSplit.size(); i++) {
|
||||
decimal = "." + decimalSplit[i];
|
||||
nums.push_back(decimal.getFloatValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> commandShapes;
|
||||
|
||||
switch (commandChar) {
|
||||
case 'M':
|
||||
commandShapes = MoveTo::absolute(state, nums);
|
||||
break;
|
||||
case 'm':
|
||||
commandShapes = MoveTo::relative(state, nums);
|
||||
break;
|
||||
case 'L':
|
||||
commandShapes = LineTo::absolute(state, nums);
|
||||
break;
|
||||
case 'l':
|
||||
commandShapes = LineTo::relative(state, nums);
|
||||
break;
|
||||
case 'H':
|
||||
commandShapes = LineTo::horizontalAbsolute(state, nums);
|
||||
break;
|
||||
case 'h':
|
||||
commandShapes = LineTo::horizontalRelative(state, nums);
|
||||
break;
|
||||
case 'V':
|
||||
commandShapes = LineTo::verticalAbsolute(state, nums);
|
||||
break;
|
||||
case 'v':
|
||||
commandShapes = LineTo::verticalRelative(state, nums);
|
||||
break;
|
||||
case 'C':
|
||||
commandShapes = CurveTo::absolute(state, nums);
|
||||
break;
|
||||
case 'c':
|
||||
commandShapes = CurveTo::relative(state, nums);
|
||||
break;
|
||||
case 'S':
|
||||
commandShapes = CurveTo::smoothAbsolute(state, nums);
|
||||
break;
|
||||
case 's':
|
||||
commandShapes = CurveTo::smoothRelative(state, nums);
|
||||
break;
|
||||
case 'Q':
|
||||
commandShapes = CurveTo::quarticAbsolute(state, nums);
|
||||
break;
|
||||
case 'q':
|
||||
commandShapes = CurveTo::quarticRelative(state, nums);
|
||||
break;
|
||||
case 'T':
|
||||
commandShapes = CurveTo::quarticSmoothAbsolute(state, nums);
|
||||
break;
|
||||
case 't':
|
||||
commandShapes = CurveTo::quarticSmoothRelative(state, nums);
|
||||
break;
|
||||
case 'A':
|
||||
commandShapes = EllipticalArcTo::absolute(state, nums);
|
||||
break;
|
||||
case 'a':
|
||||
commandShapes = EllipticalArcTo::relative(state, nums);
|
||||
break;
|
||||
case 'Z':
|
||||
commandShapes = ClosePath::absolute(state, nums);
|
||||
break;
|
||||
case 'z':
|
||||
commandShapes = ClosePath::relative(state, nums);
|
||||
break;
|
||||
}
|
||||
|
||||
pathShapes.insert(pathShapes.end(), std::make_move_iterator(commandShapes.begin()), std::make_move_iterator(commandShapes.end()));
|
||||
|
||||
if (commandChar != 'c' && commandChar != 'C' && commandChar != 's' && commandChar != 'S') {
|
||||
state.prevCubicControlPoint = std::nullopt;
|
||||
}
|
||||
if (commandChar != 'q' && commandChar != 'Q' && commandChar != 't' && commandChar != 'T') {
|
||||
state.prevQuadraticControlPoint = std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pathShapes;
|
||||
}
|
||||
}
|
|
@ -2,21 +2,16 @@
|
|||
#include "../shape/Vector2.h"
|
||||
#include <JuceHeader.h>
|
||||
#include "../shape/Shape.h"
|
||||
#include "SvgState.h"
|
||||
#include "../xml/pugixml.hpp"
|
||||
|
||||
class SvgParser {
|
||||
public:
|
||||
SvgParser(juce::String svgFile);
|
||||
~SvgParser();
|
||||
|
||||
static void pathToShapes(juce::Path& path, std::vector<std::unique_ptr<Shape>>& shapes);
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> draw();
|
||||
private:
|
||||
std::vector<std::string> preProcessPath(std::string path);
|
||||
juce::String simplifyLength(juce::String length);
|
||||
std::pair<double, double> getDimensions(pugi::xml_node&);
|
||||
std::vector<std::unique_ptr<Shape>> parsePath(juce::String);
|
||||
|
||||
std::vector<std::unique_ptr<Shape>> shapes;
|
||||
SvgState state = SvgState();
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
#include "SvgState.h"
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
#include "../shape/Vector2.h"
|
||||
#include <optional>
|
||||
|
||||
struct SvgState {
|
||||
Vector2 currPoint;
|
||||
Vector2 initialPoint;
|
||||
std::optional<Vector2> prevCubicControlPoint;
|
||||
std::optional<Vector2> prevQuadraticControlPoint;
|
||||
};
|
|
@ -1,6 +1,5 @@
|
|||
#include "TextParser.h"
|
||||
#include "../shape/Line.h"
|
||||
#include "../shape/QuadraticBezierCurve.h"
|
||||
#include "../svg/SvgParser.h"
|
||||
|
||||
|
||||
TextParser::TextParser(juce::String text, juce::Font font) {
|
||||
|
@ -9,44 +8,7 @@ TextParser::TextParser(juce::String text, juce::Font font) {
|
|||
glyphs.addFittedText(font, text, -2, -2, 4, 4, juce::Justification::centred, 2);
|
||||
glyphs.createPath(textPath);
|
||||
|
||||
juce::Path::Iterator pathIterator(textPath);
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double startX = 0;
|
||||
double startY = 0;
|
||||
|
||||
while (pathIterator.next()) {
|
||||
auto type = pathIterator.elementType;
|
||||
|
||||
switch (type) {
|
||||
case juce::Path::Iterator::PathElementType::startNewSubPath:
|
||||
x = pathIterator.x1;
|
||||
y = pathIterator.y1;
|
||||
startX = x;
|
||||
startY = y;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::lineTo:
|
||||
shapes.push_back(std::make_unique<Line>(x, -y, pathIterator.x1, -pathIterator.y1));
|
||||
x = pathIterator.x1;
|
||||
y = pathIterator.y1;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::quadraticTo:
|
||||
shapes.push_back(std::make_unique<QuadraticBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2));
|
||||
x = pathIterator.x2;
|
||||
y = pathIterator.y2;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::cubicTo:
|
||||
shapes.push_back(std::make_unique<CubicBezierCurve>(x, -y, pathIterator.x1, -pathIterator.y1, pathIterator.x2, -pathIterator.y2, pathIterator.x3, -pathIterator.y3));
|
||||
x = pathIterator.x3;
|
||||
y = pathIterator.y3;
|
||||
break;
|
||||
case juce::Path::Iterator::PathElementType::closePath:
|
||||
shapes.push_back(std::make_unique<Line>(x, -y, startX, -startY));
|
||||
x = startX;
|
||||
y = startY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SvgParser::pathToShapes(textPath, shapes);
|
||||
}
|
||||
|
||||
TextParser::~TextParser() {
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
* pugixml parser - version 1.13
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at https://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
// Uncomment this to disable STL
|
||||
// #define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
// #define PUGIXML_NO_EXCEPTIONS
|
||||
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Tune this constant to adjust max nesting for XPath queries
|
||||
// #define PUGIXML_XPATH_DEPTH_LIMIT 1024
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
// #define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2022 Arseny Kapoulkine
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
13158
Source/xml/pugixml.cpp
13158
Source/xml/pugixml.cpp
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -428,32 +428,13 @@
|
|||
<FILE id="NmptSY" name="Shape.h" compile="0" resource="0" file="Source/shape/Shape.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{56A27063-1FE7-31C3-8263-98389240A8CB}" name="svg">
|
||||
<FILE id="FVWkba" name="ClosePath.cpp" compile="1" resource="0" file="Source/svg/ClosePath.cpp"/>
|
||||
<FILE id="pJz3ek" name="ClosePath.h" compile="0" resource="0" file="Source/svg/ClosePath.h"/>
|
||||
<FILE id="PS8Qfk" name="CurveTo.cpp" compile="1" resource="0" file="Source/svg/CurveTo.cpp"/>
|
||||
<FILE id="Sjh7ne" name="CurveTo.h" compile="0" resource="0" file="Source/svg/CurveTo.h"/>
|
||||
<FILE id="DQJJdr" name="EllipticalArcTo.cpp" compile="1" resource="0"
|
||||
file="Source/svg/EllipticalArcTo.cpp"/>
|
||||
<FILE id="iVMpEw" name="EllipticalArcTo.h" compile="0" resource="0"
|
||||
file="Source/svg/EllipticalArcTo.h"/>
|
||||
<FILE id="DSmqNL" name="LineTo.cpp" compile="1" resource="0" file="Source/svg/LineTo.cpp"/>
|
||||
<FILE id="fjo7Oy" name="LineTo.h" compile="0" resource="0" file="Source/svg/LineTo.h"/>
|
||||
<FILE id="c2y2ap" name="MoveTo.cpp" compile="1" resource="0" file="Source/svg/MoveTo.cpp"/>
|
||||
<FILE id="SfIJEj" name="MoveTo.h" compile="0" resource="0" file="Source/svg/MoveTo.h"/>
|
||||
<FILE id="cTec1H" name="SvgParser.cpp" compile="1" resource="0" file="Source/svg/SvgParser.cpp"/>
|
||||
<FILE id="gvkrDH" name="SvgParser.h" compile="0" resource="0" file="Source/svg/SvgParser.h"/>
|
||||
<FILE id="OvloZU" name="SvgState.cpp" compile="1" resource="0" file="Source/svg/SvgState.cpp"/>
|
||||
<FILE id="GCBO9x" name="SvgState.h" compile="0" resource="0" file="Source/svg/SvgState.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{E81B1D7B-B0F7-1967-B271-71B3F838720F}" name="txt">
|
||||
<FILE id="vIYWRG" name="TextParser.cpp" compile="1" resource="0" file="Source/txt/TextParser.cpp"/>
|
||||
<FILE id="LlefOK" name="TextParser.h" compile="0" resource="0" file="Source/txt/TextParser.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{022CB910-9A16-C4AE-4C3B-9CB57BE87FC2}" name="xml">
|
||||
<FILE id="pW7WRh" name="pugiconfig.hpp" compile="0" resource="0" file="Source/xml/pugiconfig.hpp"/>
|
||||
<FILE id="CnkgyF" name="pugixml.cpp" compile="1" resource="0" file="Source/xml/pugixml.cpp"/>
|
||||
<FILE id="SrvH3B" name="pugixml.hpp" compile="0" resource="0" file="Source/xml/pugixml.hpp"/>
|
||||
</GROUP>
|
||||
</GROUP>
|
||||
</MAINGROUP>
|
||||
<JUCEOPTIONS JUCE_STRICT_REFCOUNTEDPOINTER="1" JUCE_VST3_CAN_REPLACE_VST2="0"/>
|
||||
|
|
Ładowanie…
Reference in New Issue