Skip to content

Commit c61f661

Browse files
committed
fix vertex shader dilation and rotation
+ tests in main.cpp
1 parent 5ecc78a commit c61f661

File tree

2 files changed

+162
-15
lines changed

2 files changed

+162
-15
lines changed

62_CAD/HatchGlyphBuilder.h

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Debug tool to Visualize Freetype Glyphs by turning them into Polyline objects
2+
3+
class FreetypeHatchBuilder
4+
{
5+
public:
6+
// Start a new line from here
7+
void moveTo(const float64_t2 to)
8+
{
9+
lastPosition = to;
10+
}
11+
12+
// Continue the last line started with moveTo (could also use the last
13+
// position from a lineTo)
14+
void lineTo(const float64_t2 to)
15+
{
16+
if (to != lastPosition) {
17+
std::vector<float64_t2> linePoints;
18+
linePoints.push_back(lastPosition);
19+
linePoints.push_back(to);
20+
currentPolyline.addLinePoints(linePoints);
21+
22+
lastPosition = to;
23+
}
24+
}
25+
26+
// Continue the last moveTo or lineTo with a quadratic bezier:
27+
// [last position, control, end]
28+
void quadratic(const float64_t2 control, const float64_t2 to)
29+
{
30+
shapes::QuadraticBezier<double> bezier = shapes::QuadraticBezier<double>::construct(
31+
lastPosition,
32+
control,
33+
to
34+
);
35+
currentPolyline.addQuadBeziers({ &bezier, 1 });
36+
lastPosition = to;
37+
}
38+
39+
// Continue the last moveTo or lineTo with a cubic bezier:
40+
// [last position, control1, control2, end]
41+
void cubic(const float64_t2 control1, const float64_t2 control2, const float64_t2 to)
42+
{
43+
std::vector<shapes::QuadraticBezier<double>> quadBeziers;
44+
curves::CubicCurve myCurve(
45+
float64_t4(lastPosition.x, lastPosition.y, control1.x, control1.y),
46+
float64_t4(control2.x, control2.y, to.x, to.y)
47+
);
48+
49+
curves::Subdivision::AddBezierFunc addToBezier = [&](shapes::QuadraticBezier<double>&& info) -> void
50+
{
51+
quadBeziers.push_back(info);
52+
};
53+
54+
curves::Subdivision::adaptive(myCurve, 0.0, 1.0, 1e-5, addToBezier, 10u);
55+
currentPolyline.addQuadBeziers(quadBeziers);
56+
57+
lastPosition = to;
58+
}
59+
60+
void finish()
61+
{
62+
if (currentPolyline.getSectionsCount() > 0)
63+
polylines.push_back(currentPolyline);
64+
}
65+
66+
std::vector<CPolyline> polylines;
67+
CPolyline currentPolyline = {};
68+
// Set with move to and line to
69+
float64_t2 lastPosition = float64_t2(0.0);
70+
};
71+
72+
// TODO: Figure out what this is supposed to do
73+
static double f26dot6ToDouble(float x)
74+
{
75+
return (1 / 64. * double(x));
76+
}
77+
78+
static float64_t2 ftPoint2(const FT_Vector& vector) {
79+
return float64_t2(f26dot6ToDouble(vector.x), f26dot6ToDouble(vector.y));
80+
}
81+
82+
static int ftMoveTo(const FT_Vector* to, void* user) {
83+
FreetypeHatchBuilder* context = reinterpret_cast<FreetypeHatchBuilder*>(user);
84+
context->moveTo(ftPoint2(*to));
85+
return 0;
86+
}
87+
static int ftLineTo(const FT_Vector* to, void* user) {
88+
FreetypeHatchBuilder* context = reinterpret_cast<FreetypeHatchBuilder*>(user);
89+
context->lineTo(ftPoint2(*to));
90+
return 0;
91+
}
92+
93+
static int ftConicTo(const FT_Vector* control, const FT_Vector* to, void* user) {
94+
FreetypeHatchBuilder* context = reinterpret_cast<FreetypeHatchBuilder*>(user);
95+
context->quadratic(ftPoint2(*control), ftPoint2(*to));
96+
return 0;
97+
}
98+
99+
static int ftCubicTo(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user) {
100+
FreetypeHatchBuilder* context = reinterpret_cast<FreetypeHatchBuilder*>(user);
101+
context->cubic(ftPoint2(*control1), ftPoint2(*control2), ftPoint2(*to));
102+
return 0;
103+
}
104+
105+
static int ftMoveToMSDF(const FT_Vector* to, void* user) {
106+
nbl::ext::TextRendering::GlyphShapeBuilder* context = reinterpret_cast<nbl::ext::TextRendering::GlyphShapeBuilder*>(user);
107+
context->moveTo(ftPoint2(*to));
108+
return 0;
109+
}
110+
static int ftLineToMSDF(const FT_Vector* to, void* user) {
111+
nbl::ext::TextRendering::GlyphShapeBuilder* context = reinterpret_cast<nbl::ext::TextRendering::GlyphShapeBuilder*>(user);
112+
context->lineTo(ftPoint2(*to));
113+
return 0;
114+
}
115+
116+
static int ftConicToMSDF(const FT_Vector* control, const FT_Vector* to, void* user) {
117+
nbl::ext::TextRendering::GlyphShapeBuilder* context = reinterpret_cast<nbl::ext::TextRendering::GlyphShapeBuilder*>(user);
118+
context->quadratic(ftPoint2(*control), ftPoint2(*to));
119+
return 0;
120+
}
121+
122+
static int ftCubicToMSDF(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user) {
123+
nbl::ext::TextRendering::GlyphShapeBuilder* context = reinterpret_cast<nbl::ext::TextRendering::GlyphShapeBuilder*>(user);
124+
context->cubic(ftPoint2(*control1), ftPoint2(*control2), ftPoint2(*to));
125+
return 0;
126+
}
127+
128+
bool drawFreetypeGlyph(msdfgen::Shape& shape, FT_Library library, FT_Face face)
129+
{
130+
nbl::ext::TextRendering::GlyphShapeBuilder builder(shape);
131+
FT_Outline_Funcs ftFunctions;
132+
ftFunctions.move_to = &ftMoveToMSDF;
133+
ftFunctions.line_to = &ftLineToMSDF;
134+
ftFunctions.conic_to = &ftConicToMSDF;
135+
ftFunctions.cubic_to = &ftCubicToMSDF;
136+
ftFunctions.shift = 0;
137+
ftFunctions.delta = 0;
138+
FT_Error error = FT_Outline_Decompose(&face->glyph->outline, &ftFunctions, &builder);
139+
if (error)
140+
return false;
141+
builder.finish();
142+
return true;
143+
}

62_CAD/vertex_shader.hlsl

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -471,31 +471,35 @@ PSInput main(uint vertexID : SV_VertexID)
471471
const float2 screenDirU = (float2) transformVectorNdc(clipProjectionData.projectionToNDC, glyphInfo.dirU);
472472
const float2 screenDirV = (float2) transformVectorNdc(clipProjectionData.projectionToNDC, dirV);
473473

474-
float2 corner = float2(bool2(vertexIdx & 0x1u, vertexIdx >> 1));
474+
const float2 corner = float2(bool2(vertexIdx & 0x1u, vertexIdx >> 1)); // corners of square from (0, 0) to (1, 1)
475+
const float2 undilatedCornerNDC = corner * 2.0 - 1.0; // corners of square from (-1, -1) to (1, 1)
475476

476-
const float2 screenSpaceAabbExtents = float2(length(screenDirU), length(screenDirV)) * float2(globals.resolution);
477-
477+
const double2 screenSpaceAabbExtents = double2(length(screenDirU * double2(globals.resolution)) / 2.0, length(screenDirV * double2(globals.resolution)) / 2.0);
478478
const float pixelsToIncreaseOnEachSide = globals.antiAliasingFactor + 1.0;
479-
const double2 dilateRate = pixelsToIncreaseOnEachSide / screenSpaceAabbExtents;
480-
const double2 dilatationFactor = 1.0 + 2.0 * dilateRate;
481-
482-
const float2 undilatedCornerNDC = corner * 2.0 - 1.0;
483-
// Dilate the UVs
484-
const float2 maxCorner = float2((undilatedCornerNDC * dilatationFactor + 1.0) * 0.5);
479+
const float2 dilateRate = (float2)(pixelsToIncreaseOnEachSide / screenSpaceAabbExtents);
485480

486481
const float2 vx = screenDirU * dilateRate.x;
487482
const float2 vy = screenDirV * dilateRate.y;
488483
const float2 offsetVec = vx * undilatedCornerNDC.x + vy * undilatedCornerNDC.y;
489-
490484
const float2 coord = screenTopLeft + corner.x * screenDirU + corner.y * screenDirV + offsetVec;
491485

492-
const float2 maxUV = float2(1.0, 1.0) - minUV;
493-
const float2 uvs = minUV + corner * (maxUV - minUV);
494-
495-
const float screenPxRange = max(screenSpaceAabbExtents.x / ((maxUV.x - minUV.x) * MSDFSize), 1.0);
486+
// If aspect ratio of the dimensions and glyph inside the texture are the same -->
487+
// it doesn't matter which component (x or y) to use to compute screenPxRange.
488+
// but if the glyph box is stretched in any way then we won't get correct msdf
489+
// We compute this value using the ration of our screenspace extent to the texel space our glyph takes inside the texture
490+
// Our glyph is centered inside the texture, so `maxUV = 1.0 - minUV` and `glyphTexelSize = (1.0-2.0*minUV) * MSDFSize
491+
const float screenPxRange = max(screenSpaceAabbExtents.x / ((1.0 - 2.0 * minUV.x) * MSDFSize), 1.0);
492+
493+
// In order to keep the shape scale constant with any dilation values:
494+
// We compute the new dilated minUV that gets us minUV when interpolated on the previous undilated top left
495+
const float2 topLeftInterpolationValue = (dilateRate/(1.0+2.0*dilateRate));
496+
const float2 dilatedMinUV = (topLeftInterpolationValue - minUV) / (2.0 * topLeftInterpolationValue - 1.0);
497+
const float2 dilatedMaxUV = float2(1.0, 1.0) - dilatedMinUV;
498+
499+
const float2 uv = dilatedMinUV + corner * (dilatedMaxUV - dilatedMinUV);
496500

497501
outV.position = float4(coord, 0.f, 1.f);
498-
outV.setFontGlyphUV(uvs);
502+
outV.setFontGlyphUV(uv);
499503
outV.setFontGlyphTextureId(textureID);
500504
outV.setFontGlyphScreenPxRange(screenPxRange);
501505
}

0 commit comments

Comments
 (0)