mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-06-08 03:13:52 +00:00
Added 51-gpufont example. (#3641)
This commit is contained in:
committed by
GitHub
parent
3118337be2
commit
a7016487e5
254
examples/51-gpufont/fs_slug.sc
Normal file
254
examples/51-gpufont/fs_slug.sc
Normal file
@@ -0,0 +1,254 @@
|
||||
$input v_texcoord0, v_banding, v_glyph
|
||||
|
||||
// ===================================================
|
||||
// Reference pixel shader for the Slug algorithm.
|
||||
// This code is made available under the MIT License.
|
||||
// Copyright 2017, by Eric Lengyel.
|
||||
// ===================================================
|
||||
|
||||
#include "../common/common.sh"
|
||||
|
||||
// The curve and band textures use a fixed width of 4096 texels.
|
||||
|
||||
#define kLogBandTextureWidth 12
|
||||
|
||||
SAMPLER2D(s_curveData, 0);
|
||||
SAMPLER2D(s_bandData, 1);
|
||||
|
||||
uniform vec4 u_params;
|
||||
|
||||
int calcRootCode(float _y1, float _y2, float _y3)
|
||||
{
|
||||
// Calculate the root eligibility code for a sample-relative quadratic Bezier curve.
|
||||
// Extract the signs of the y coordinates of the three control points.
|
||||
|
||||
int i1 = (_y1 < 0.0) ? 1 : 0;
|
||||
int i2 = (_y2 < 0.0) ? 2 : 0;
|
||||
int i3 = (_y3 < 0.0) ? 4 : 0;
|
||||
int shift = i1 + i2 + i3;
|
||||
|
||||
// Eligibility is returned in bits 0 and 8.
|
||||
|
||||
return (0x2E74 >> shift) & 0x0101;
|
||||
}
|
||||
|
||||
vec2 solveHorizPoly(vec4 _p12, vec2 _p3)
|
||||
{
|
||||
// Solve for the values of t where the curve crosses y = 0.
|
||||
// The quadratic polynomial in t is given by
|
||||
//
|
||||
// a t^2 - 2b t + c,
|
||||
//
|
||||
// where a = p1.y - 2 p2.y + p3.y, b = p1.y - p2.y, and c = p1.y.
|
||||
// The discriminant b^2 - ac is clamped to zero, and imaginary
|
||||
// roots are treated as a double root at the global minimum
|
||||
// where t = b / a.
|
||||
|
||||
vec2 a = _p12.xy - _p12.zw * 2.0 + _p3;
|
||||
vec2 b = _p12.xy - _p12.zw;
|
||||
float ra = 1.0 / a.y;
|
||||
float rb = 0.5 / b.y;
|
||||
|
||||
float d = sqrt(max(b.y * b.y - a.y * _p12.y, 0.0) );
|
||||
float t1 = (b.y - d) * ra;
|
||||
float t2 = (b.y + d) * ra;
|
||||
|
||||
// If the polynomial is nearly linear, then solve -2b t + c = 0.
|
||||
|
||||
if (abs(a.y) < 1.0 / 65536.0)
|
||||
{
|
||||
t1 = t2 = _p12.y * rb;
|
||||
}
|
||||
|
||||
// Return the x coordinates where C(t) = 0.
|
||||
|
||||
return vec2( (a.x * t1 - b.x * 2.0) * t1 + _p12.x, (a.x * t2 - b.x * 2.0) * t2 + _p12.x);
|
||||
}
|
||||
|
||||
vec2 solveVertPoly(vec4 _p12, vec2 _p3)
|
||||
{
|
||||
// Solve for the values of t where the curve crosses x = 0.
|
||||
|
||||
vec2 a = _p12.xy - _p12.zw * 2.0 + _p3;
|
||||
vec2 b = _p12.xy - _p12.zw;
|
||||
float ra = 1.0 / a.x;
|
||||
float rb = 0.5 / b.x;
|
||||
|
||||
float d = sqrt(max(b.x * b.x - a.x * _p12.x, 0.0) );
|
||||
float t1 = (b.x - d) * ra;
|
||||
float t2 = (b.x + d) * ra;
|
||||
|
||||
if (abs(a.x) < 1.0 / 65536.0) t1 = t2 = _p12.x * rb;
|
||||
|
||||
return vec2(
|
||||
(a.y * t1 - b.y * 2.0) * t1 + _p12.y
|
||||
, (a.y * t2 - b.y * 2.0) * t2 + _p12.y
|
||||
);
|
||||
}
|
||||
|
||||
ivec2 calcBandLoc(ivec2 glyphLoc, int offset)
|
||||
{
|
||||
// If the offset causes the x coordinate to exceed the texture width, then wrap to the next line.
|
||||
|
||||
ivec2 bandLoc = ivec2(glyphLoc.x + offset, glyphLoc.y);
|
||||
bandLoc.y += bandLoc.x >> kLogBandTextureWidth;
|
||||
bandLoc.x &= (1 << kLogBandTextureWidth) - 1;
|
||||
return bandLoc;
|
||||
}
|
||||
|
||||
float calcCoverage(float xcov, float ycov, float xwgt, float ywgt)
|
||||
{
|
||||
// Combine coverages from the horizontal and vertical rays using their weights.
|
||||
// Absolute values ensure that either winding direction convention works.
|
||||
|
||||
float coverage = max(abs(xcov * xwgt + ycov * ywgt) / max(xwgt + ywgt, 1.0 / 65536.0), min(abs(xcov), abs(ycov) ));
|
||||
|
||||
// Using nonzero fill rule here.
|
||||
|
||||
coverage = clamp(coverage, 0.0, 1.0);
|
||||
return coverage;
|
||||
}
|
||||
|
||||
float slugRender(vec2 _renderCoord, vec4 _bandTransform, ivec2 _glyphLoc, ivec2 _bandMax)
|
||||
{
|
||||
int curveIndex;
|
||||
|
||||
// The effective pixel dimensions of the em square are computed
|
||||
// independently for x and y directions with texcoord derivatives.
|
||||
|
||||
vec2 emsPerPixel = fwidth(_renderCoord);
|
||||
vec2 pixelsPerEm = 1.0 / emsPerPixel;
|
||||
|
||||
// Determine what bands the current pixel lies in by applying a scale and offset
|
||||
// to the render coordinates. The scales are given by _bandTransform.xy, and the
|
||||
// offsets are given by _bandTransform.zw. Band indexes are clamped to [0, _bandMax.xy].
|
||||
|
||||
ivec2 bandIndex = clamp(ivec2(_renderCoord * _bandTransform.xy + _bandTransform.zw), ivec2(0, 0), _bandMax);
|
||||
|
||||
float xcov = 0.0;
|
||||
float xwgt = 0.0;
|
||||
|
||||
// Fetch data for the horizontal band from the index texture. The number
|
||||
// of curves intersecting the band is in the x component, and the offset
|
||||
// to the list of locations for those curves is in the y component.
|
||||
|
||||
vec4 hbandRaw = texelFetch(s_bandData, ivec2(_glyphLoc.x + bandIndex.y, _glyphLoc.y), 0);
|
||||
int hbandCount = int(hbandRaw.x + 0.5);
|
||||
int hbandOffset = int(hbandRaw.y + 0.5);
|
||||
ivec2 hbandLoc = calcBandLoc(_glyphLoc, hbandOffset);
|
||||
|
||||
// Loop over all curves in the horizontal band.
|
||||
|
||||
for (curveIndex = 0; curveIndex < hbandCount; curveIndex++)
|
||||
{
|
||||
// Fetch the location of the current curve from the index texture.
|
||||
|
||||
vec4 locRaw = texelFetch(s_bandData, ivec2(hbandLoc.x + curveIndex, hbandLoc.y), 0);
|
||||
ivec2 curveLoc = ivec2(int(locRaw.x + 0.5), int(locRaw.y + 0.5) );
|
||||
|
||||
// Fetch the three 2D control points for the current curve from the curve texture.
|
||||
// The first texel contains both p1 and p2 in the (x,y) and (z,w) components, respectively,
|
||||
// and the the second texel contains p3 in the (x,y) components. Subtracting the render
|
||||
// coordinates makes the curve relative to the sample position. The quadratic Bezier curve
|
||||
// C(t) is given by
|
||||
//
|
||||
// C(t) = (1 - t)^2 p1 + 2t(1 - t) p2 + t^2 p3
|
||||
|
||||
vec4 p12 = texelFetch(s_curveData, curveLoc, 0) - vec4(_renderCoord, _renderCoord);
|
||||
vec2 p3 = texelFetch(s_curveData, ivec2(curveLoc.x + 1, curveLoc.y), 0).xy - _renderCoord;
|
||||
|
||||
// If the largest x coordinate among all three control points falls
|
||||
// left of the current pixel, then there are no more curves in the
|
||||
// horizontal band that can influence the result, so exit the loop.
|
||||
// (The curves are sorted in descending order by max x coordinate.)
|
||||
|
||||
if (max(max(p12.x, p12.z), p3.x) * pixelsPerEm.x < -0.5) break;
|
||||
|
||||
int code = calcRootCode(p12.y, p12.w, p3.y);
|
||||
if (code != 0)
|
||||
{
|
||||
vec2 r = solveHorizPoly(p12, p3) * pixelsPerEm.x;
|
||||
|
||||
if ( (code & 1) != 0)
|
||||
{
|
||||
xcov += clamp(r.x + 0.5, 0.0, 1.0);
|
||||
xwgt = max(xwgt, clamp(1.0 - abs(r.x) * 2.0, 0.0, 1.0) );
|
||||
}
|
||||
|
||||
if (code > 1)
|
||||
{
|
||||
xcov -= clamp(r.y + 0.5, 0.0, 1.0);
|
||||
xwgt = max(xwgt, clamp(1.0 - abs(r.y) * 2.0, 0.0, 1.0) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float ycov = 0.0;
|
||||
float ywgt = 0.0;
|
||||
|
||||
// Fetch data for the vertical band from the index texture. This follows
|
||||
// the data for all horizontal bands, so we have to add _bandMax.y + 1.
|
||||
|
||||
vec4 vbandRaw = texelFetch(s_bandData, ivec2(_glyphLoc.x + _bandMax.y + 1 + bandIndex.x, _glyphLoc.y), 0);
|
||||
int vbandCount = int(vbandRaw.x + 0.5);
|
||||
int vbandOffset = int(vbandRaw.y + 0.5);
|
||||
ivec2 vbandLoc = calcBandLoc(_glyphLoc, vbandOffset);
|
||||
|
||||
// Loop over all curves in the vertical band.
|
||||
|
||||
for (curveIndex = 0; curveIndex < vbandCount; curveIndex++)
|
||||
{
|
||||
vec4 locRaw = texelFetch(s_bandData, ivec2(vbandLoc.x + curveIndex, vbandLoc.y), 0);
|
||||
ivec2 curveLoc = ivec2(int(locRaw.x + 0.5), int(locRaw.y + 0.5) );
|
||||
|
||||
vec4 p12 = texelFetch(s_curveData, curveLoc, 0) - vec4(_renderCoord, _renderCoord);
|
||||
vec2 p3 = texelFetch(s_curveData, ivec2(curveLoc.x + 1, curveLoc.y), 0).xy - _renderCoord;
|
||||
|
||||
if (max(max(p12.y, p12.w), p3.y) * pixelsPerEm.y < -0.5) break;
|
||||
|
||||
int code = calcRootCode(p12.x, p12.z, p3.x);
|
||||
if (code != 0)
|
||||
{
|
||||
vec2 r = solveVertPoly(p12, p3) * pixelsPerEm.y;
|
||||
|
||||
if ( (code & 1) != 0)
|
||||
{
|
||||
ycov -= clamp(r.x + 0.5, 0.0, 1.0);
|
||||
ywgt = max(ywgt, clamp(1.0 - abs(r.x) * 2.0, 0.0, 1.0) );
|
||||
}
|
||||
|
||||
if (code > 1)
|
||||
{
|
||||
ycov += clamp(r.y + 0.5, 0.0, 1.0);
|
||||
ywgt = max(ywgt, clamp(1.0 - abs(r.y) * 2.0, 0.0, 1.0) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return calcCoverage(xcov, ycov, xwgt, ywgt);
|
||||
}
|
||||
|
||||
vec4 unpackRGBA8(float _packed)
|
||||
{
|
||||
uint rgba = floatBitsToUint(_packed);
|
||||
return vec4(
|
||||
(rgba >> 24) & 0xffu
|
||||
, (rgba >> 16) & 0xffu
|
||||
, (rgba >> 8) & 0xffu
|
||||
, (rgba ) & 0xffu
|
||||
) / 255.0
|
||||
;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 glyphLoc = ivec2(v_glyph.xy);
|
||||
ivec2 bandMax = ivec2(v_glyph.zw);
|
||||
bandMax.y &= 0x00FF;
|
||||
|
||||
float coverage = slugRender(v_texcoord0, v_banding, glyphLoc, bandMax);
|
||||
vec4 fg = unpackRGBA8(u_params.x);
|
||||
vec4 bg = unpackRGBA8(u_params.y);
|
||||
|
||||
gl_FragColor = mix(bg, fg, coverage);
|
||||
}
|
||||
1427
examples/51-gpufont/gpufont.cpp
Normal file
1427
examples/51-gpufont/gpufont.cpp
Normal file
File diff suppressed because it is too large
Load Diff
10
examples/51-gpufont/makefile
Normal file
10
examples/51-gpufont/makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2011-2026 Branimir Karadzic. All rights reserved.
|
||||
# License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
|
||||
#
|
||||
|
||||
BGFX_DIR=../..
|
||||
RUNTIME_DIR=$(BGFX_DIR)/examples/runtime
|
||||
BUILD_DIR=../../.build
|
||||
|
||||
include $(BGFX_DIR)/scripts/shader.mk
|
||||
BIN
examples/51-gpufont/screenshot.png
Normal file
BIN
examples/51-gpufont/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 337 KiB |
9
examples/51-gpufont/varying.def.sc
Normal file
9
examples/51-gpufont/varying.def.sc
Normal file
@@ -0,0 +1,9 @@
|
||||
vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
|
||||
flat vec4 v_banding : TEXCOORD1 = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
flat vec4 v_glyph : TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec2 v_position : TEXCOORD3 = vec2(0.0, 0.0);
|
||||
|
||||
vec4 a_position : POSITION;
|
||||
vec4 a_texcoord0 : TEXCOORD0;
|
||||
vec4 a_texcoord1 : TEXCOORD1;
|
||||
vec2 a_texcoord2 : TEXCOORD2;
|
||||
95
examples/51-gpufont/vs_slug.sc
Normal file
95
examples/51-gpufont/vs_slug.sc
Normal file
@@ -0,0 +1,95 @@
|
||||
$input a_position, a_texcoord0, a_texcoord1
|
||||
$output v_texcoord0, v_banding, v_glyph
|
||||
|
||||
// ===================================================
|
||||
// Reference vertex shader for the Slug algorithm.
|
||||
// This code is made available under the MIT License.
|
||||
// Copyright 2017, by Eric Lengyel.
|
||||
// ===================================================
|
||||
|
||||
#include "../common/common.sh"
|
||||
|
||||
uniform vec4 u_params;
|
||||
|
||||
// The per-vertex input data consists of 5 attributes all having 4 floating-point components:
|
||||
//
|
||||
// 0 - pos
|
||||
// 1 - tex
|
||||
// 2 - jac
|
||||
// 3 - bnd
|
||||
// 4 - col
|
||||
|
||||
// pos.xy = object-space vertex coordinates.
|
||||
// pos.zw = object-space normal vector.
|
||||
|
||||
// tex.xy = em-space sample coordinates.
|
||||
|
||||
// tex.z = location of glyph data in band texture (interpreted as integer):
|
||||
|
||||
// | 31 24 | 23 16 | 15 8 | 7 0 |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | y coordinate of glyph data in band texture | x coordinate of glyph data in band texture |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
// tex.w = max band indexes and flags (interpreted as integer):
|
||||
|
||||
// | 31 24 | 23 16 | 15 8 | 7 0 |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | 0 0 0 | E | 0 0 0 0 | band max y | 0 0 0 0 0 0 0 0 | band max x |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
// jac = inverse Jacobian matrix entries (00, 01, 10, 11).
|
||||
// bnd = (band scale x, band scale y, band offset x, band offset y).
|
||||
// col = vertex color (red, green, blue, alpha).
|
||||
|
||||
void slugUnpack(vec4 _bnd, vec2 _bits, out vec4 _outBanding, out vec4 _outGlyph)
|
||||
{
|
||||
uvec2 g = floatBitsToUint(_bits);
|
||||
_outGlyph = vec4(g.x & 0xffffu, g.x >> 16u, g.y & 0xffffu, g.y >> 16u);
|
||||
_outBanding = _bnd;
|
||||
}
|
||||
|
||||
vec2 slugDilate(vec2 _pos, vec2 _normal, vec2 _tex, vec4 _jac, vec2 _dim, out vec2 _outPos)
|
||||
{
|
||||
vec2 n = normalize(_normal);
|
||||
|
||||
vec4 pClip = mul(u_modelViewProj, vec4(_pos, 0.0, 1.0) );
|
||||
vec4 nClip = mul(u_modelViewProj, vec4(n, 0.0, 0.0) );
|
||||
|
||||
float s = pClip.w;
|
||||
float t = nClip.w;
|
||||
|
||||
float u = (s * nClip.x - t * pClip.x) * _dim.x;
|
||||
float v = (s * nClip.y - t * pClip.y) * _dim.y;
|
||||
|
||||
float s2 = s * s;
|
||||
float st = s * t;
|
||||
float uv = u * u + v * v;
|
||||
vec2 d = _normal * (s2 * (st + sqrt(uv) ) / (uv - st * st) );
|
||||
|
||||
_outPos = _pos + d;
|
||||
return vec2(_tex.x + dot(d, _jac.xy), _tex.y + dot(d, _jac.zw) );
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 p;
|
||||
vec4 jacobian = vec4(u_params.w, 0.0, 0.0, u_params.w);
|
||||
|
||||
// Apply dynamic dilation to vertex position. Returns new em-space sample position.
|
||||
|
||||
vec2 pos = a_position.xy;
|
||||
vec2 normal = a_position.zw;
|
||||
vec2 uv = a_texcoord0.xy;
|
||||
vec2 bits = a_texcoord0.zw;
|
||||
|
||||
v_texcoord0 = slugDilate(pos, normal, uv, jacobian, u_viewRect.zw, p);
|
||||
|
||||
// Apply MVP matrix to dilated vertex position.
|
||||
|
||||
gl_Position = mul(u_modelViewProj, vec4(p, 0.0, 1.0) );
|
||||
|
||||
// Unpack or pass through remaining vertex data.
|
||||
|
||||
slugUnpack(a_texcoord1, bits, v_banding, v_glyph);
|
||||
}
|
||||
@@ -471,8 +471,6 @@ void showExampleDialog(entry::AppI* _app, const char* _errorText)
|
||||
{
|
||||
if (ImGui::CollapsingHeader(ICON_FA_PUZZLE_PIECE " Resources") )
|
||||
{
|
||||
const bgfx::Caps* caps = bgfx::getCaps();
|
||||
|
||||
const float itemHeight = ImGui::GetTextLineHeightWithSpacing();
|
||||
const float maxWidth = 90.0f;
|
||||
|
||||
|
||||
BIN
examples/runtime/shaders/dxbc/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/dxbc/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/dxbc/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/dxbc/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/dxil/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/dxil/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/dxil/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/dxil/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/essl/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/essl/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/essl/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/essl/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/glsl/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/glsl/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/glsl/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/glsl/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/metal/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/metal/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/metal/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/metal/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/spirv/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/spirv/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/spirv/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/spirv/vs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/wgsl/fs_slug.bin
Normal file
BIN
examples/runtime/shaders/wgsl/fs_slug.bin
Normal file
Binary file not shown.
BIN
examples/runtime/shaders/wgsl/vs_slug.bin
Normal file
BIN
examples/runtime/shaders/wgsl/vs_slug.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user