Skip to content

Commit

Permalink
feat: dropshadow for text in lesson16
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Jan 27, 2025
1 parent b663769 commit 6aa085f
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 18 deletions.
30 changes: 25 additions & 5 deletions packages/core/src/drawcalls/SDFText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export class SDFText extends Drawcall {
}

private hash(shape: Text) {
const { metrics, bitmapFont } = shape as Text;
return `${metrics?.font}-${bitmapFont?.fontFamily}`;
const { metrics, bitmapFont, dropShadowBlurRadius } = shape as Text;
return `${metrics?.font}-${bitmapFont?.fontFamily}-${dropShadowBlurRadius}`;
}

private get useBitmapFont() {
Expand Down Expand Up @@ -198,6 +198,8 @@ export class SDFText extends Drawcall {
}

createMaterial(defines: string, uniformBuffer: Buffer): void {
const { content, dropShadowBlurRadius } = this.shapes[0] as Text;

let glyphAtlasTexture: Texture;
if (this.useBitmapFont) {
const { bitmapFont } = this.shapes[0] as Text;
Expand All @@ -214,8 +216,6 @@ export class SDFText extends Drawcall {
}
} else {
defines += '#define USE_SDF\n';

const { content } = this.shapes[0] as Text;
const hasEmoji = containsEmoji(content);
if (hasEmoji) {
defines += '#define USE_EMOJI\n';
Expand All @@ -224,14 +224,18 @@ export class SDFText extends Drawcall {
glyphAtlasTexture = this.#glyphManager.getAtlasTexture();
}

if (dropShadowBlurRadius > 0) {
defines += '#define USE_SHADOW\n';
}

this.device.setResourceName(glyphAtlasTexture, 'SDFText Texture');

this.createProgram(vert, frag, defines);

if (!this.#uniformBuffer) {
this.#uniformBuffer = this.device.createBuffer({
viewOrSize:
Float32Array.BYTES_PER_ELEMENT * (16 + 4 + 4 + 4 + 4 + 4 + 4),
Float32Array.BYTES_PER_ELEMENT * (16 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4),
usage: BufferUsage.UNIFORM,
hint: BufferFrequencyHint.DYNAMIC,
});
Expand Down Expand Up @@ -376,6 +380,10 @@ export class SDFText extends Drawcall {
strokeOpacity,
sizeAttenuation,
fontSize,
dropShadowColorRGB: { r: dsR, g: dsG, b: dsB, opacity: dsO },
dropShadowOffsetX,
dropShadowOffsetY,
dropShadowBlurRadius,
} = shape;

const { width: atlasWidth, height: atlasHeight } = image;
Expand All @@ -399,6 +407,14 @@ export class SDFText extends Drawcall {
sizeAttenuation ? 1 : 0,
];

const u_DropShadowColor = [dsR / 255, dsG / 255, dsB / 255, dsO];
const u_DropShadow = [
dropShadowOffsetX,
dropShadowOffsetY,
dropShadowBlurRadius,
0,
];

const u_AtlasSize = [atlasWidth, atlasHeight];

return [
Expand All @@ -407,13 +423,17 @@ export class SDFText extends Drawcall {
...u_StrokeColor,
...u_ZIndexStrokeWidth,
...u_Opacity,
...u_DropShadowColor,
...u_DropShadow,
...u_AtlasSize,
],
{
u_FillColor,
u_StrokeColor,
u_ZIndexStrokeWidth,
u_Opacity,
u_DropShadowColor,
u_DropShadow,
u_AtlasSize,
},
];
Expand Down
30 changes: 28 additions & 2 deletions packages/core/src/shaders/sdf_text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ layout(std140) uniform ShapeUniforms {
vec4 u_StrokeColor;
vec4 u_ZIndexStrokeWidth;
vec4 u_Opacity;
vec4 u_DropShadowColor;
vec4 u_DropShadow;
vec2 u_AtlasSize;
};
Expand Down Expand Up @@ -78,6 +80,8 @@ layout(std140) uniform ShapeUniforms {
vec4 u_StrokeColor;
vec4 u_ZIndexStrokeWidth;
vec4 u_Opacity;
vec4 u_DropShadowColor;
vec4 u_DropShadow;
vec2 u_AtlasSize;
};
Expand All @@ -87,12 +91,12 @@ ${wireframe_frag_declaration}
in vec2 v_Uv;
uniform sampler2D u_Texture;
float epsilon = 0.000001;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
float epsilon = 0.000001;
#define SDF_PX 8.0
void main() {
Expand All @@ -103,24 +107,39 @@ void main() {
float fillOpacity = u_Opacity.y;
float strokeOpacity = u_Opacity.z;
float shapeSizeAttenuation = u_Opacity.w;
vec4 dropShadow = u_DropShadow;
vec4 dropShadowColor = u_DropShadowColor;
float shadowDist;
float shadowBlurRadius = u_DropShadow.z;
#ifdef USE_SDF_NONE
outputColor = texture(SAMPLER_2D(u_Texture), v_Uv);
#else
float dist;
lowp float buff;
vec2 shadowOffset = u_DropShadow.xy / u_AtlasSize;
#ifdef USE_SDF
#ifdef USE_EMOJI
fillColor = texture(SAMPLER_2D(u_Texture), v_Uv);
#endif
dist = texture(SAMPLER_2D(u_Texture), v_Uv).a;
buff = (256.0 - 64.0) / 256.0;
#ifdef USE_SHADOW
shadowDist = texture(SAMPLER_2D(u_Texture), v_Uv - shadowOffset).a;
#endif
#endif
#ifdef USE_MSDF
vec3 s = texture(SAMPLER_2D(u_Texture), v_Uv).rgb;
dist = median(s.r, s.g, s.b);
buff = 0.5;
#ifdef USE_SHADOW
vec3 shadowSample = texture(SAMPLER_2D(u_Texture), v_Uv - shadowOffset).rgb;
shadowDist = median(shadowSample.r, shadowSample.g, shadowSample.b);
#endif
#endif
float fontSize = u_ZIndexStrokeWidth.z;
Expand All @@ -142,6 +161,13 @@ void main() {
outputColor.a *= opacity;
#ifdef USE_SHADOW
gamma_scaled = fwidth(shadowDist) * 128.0 / shadowBlurRadius;
alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, shadowDist);
dropShadowColor.a *= alpha;
outputColor = mix(dropShadowColor, outputColor, outputColor.a);
#endif
${wireframe_frag}
if (outputColor.a < epsilon)
Expand Down
101 changes: 100 additions & 1 deletion packages/core/src/shapes/Text.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as d3 from 'd3-color';
import {
getOrCreateCanvasTextMetrics,
TextMetrics,
Expand Down Expand Up @@ -142,6 +143,31 @@ export interface TextAttributes extends ShapeAttributes {
* BiDi chars after doing metrics.
*/
bidiChars: string;

/**
* Specifies color for the shadow.
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow#color
*/
dropShadowColor: string;

/**
* Horizontal offset
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow
*/
dropShadowOffsetX: number;

/**
* Vertical offset
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow
*/
dropShadowOffsetY: number;

/**
* The larger this value, the bigger the blur, so the shadow becomes bigger and lighter.
* Negative values are not allowed. If not specified, it will be set to `0`.
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow
*/
dropShadowBlurRadius: number;
}

// @ts-ignore
Expand Down Expand Up @@ -169,6 +195,12 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {
#leading: number;
#textAlign: CanvasTextAlign;
#textBaseline: CanvasTextBaseline;
#dropShadowColor: string;
#dropShadowColorRGB: d3.RGBColor;
#dropShadowOffsetX: number;
#dropShadowOffsetY: number;
#dropShadowBlurRadius: number;

bitmapFont: BitmapFont;
bitmapFontKerning: boolean;
esdt: boolean;
Expand Down Expand Up @@ -233,6 +265,10 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {
bitmapFont,
bitmapFontKerning,
esdt,
dropShadowColor,
dropShadowOffsetX,
dropShadowOffsetY,
dropShadowBlurRadius,
} = attributes;

this.#x = x ?? 0;
Expand All @@ -256,6 +292,10 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {
this.bitmapFont = bitmapFont ?? null;
this.bitmapFontKerning = bitmapFontKerning ?? true;
this.esdt = esdt ?? true;
this.dropShadowColor = dropShadowColor ?? 'black';
this.dropShadowOffsetX = dropShadowOffsetX ?? 0;
this.dropShadowOffsetY = dropShadowOffsetY ?? 0;
this.dropShadowBlurRadius = dropShadowBlurRadius ?? 0;
}

containsPoint(x: number, y: number) {
Expand All @@ -273,7 +313,13 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {

getRenderBounds() {
if (this.renderBoundsDirtyFlag) {
const { strokeWidth, strokeAlignment } = this;
const {
strokeWidth,
strokeAlignment,
dropShadowOffsetX,
dropShadowOffsetY,
dropShadowBlurRadius,
} = this;
const offset = strokeOffset(strokeAlignment, strokeWidth);

this.renderBoundsDirtyFlag = false;
Expand All @@ -284,6 +330,14 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {
maxX + offset,
maxY + offset,
);
this.renderBounds.addBounds(
new AABB(
minX + dropShadowOffsetX - dropShadowBlurRadius,
minY + dropShadowOffsetY - dropShadowBlurRadius,
maxX + dropShadowOffsetX + dropShadowBlurRadius,
maxY + dropShadowOffsetY + dropShadowBlurRadius,
),
);
}
return this.renderBounds;
}
Expand Down Expand Up @@ -548,5 +602,50 @@ export function TextWrapper<TBase extends GConstructor>(Base: TBase) {
this.materialDirtyFlag = true;
}
}

get dropShadowColor() {
return this.#dropShadowColor;
}
set dropShadowColor(dropShadowColor: string) {
if (this.#dropShadowColor !== dropShadowColor) {
this.#dropShadowColor = dropShadowColor;
this.#dropShadowColorRGB = d3.rgb(dropShadowColor);
this.renderDirtyFlag = true;
}
}

get dropShadowColorRGB() {
return this.#dropShadowColorRGB;
}

get dropShadowOffsetX() {
return this.#dropShadowOffsetX;
}
set dropShadowOffsetX(dropShadowOffsetX: number) {
if (this.#dropShadowOffsetX !== dropShadowOffsetX) {
this.#dropShadowOffsetX = dropShadowOffsetX;
this.renderDirtyFlag = true;
}
}

get dropShadowOffsetY() {
return this.#dropShadowOffsetY;
}
set dropShadowOffsetY(dropShadowOffsetY: number) {
if (this.#dropShadowOffsetY !== dropShadowOffsetY) {
this.#dropShadowOffsetY = dropShadowOffsetY;
this.renderDirtyFlag = true;
}
}

get dropShadowBlurRadius() {
return this.#dropShadowBlurRadius;
}
set dropShadowBlurRadius(dropShadowBlurRadius: number) {
if (this.#dropShadowBlurRadius !== dropShadowBlurRadius) {
this.#dropShadowBlurRadius = dropShadowBlurRadius;
this.renderDirtyFlag = true;
}
}
};
}
4 changes: 4 additions & 0 deletions packages/site/docs/.vitepress/config/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ export const en = defineConfig({
text: 'Text Baseline',
link: 'text-baseline',
},
{
text: 'Text DropShadow',
link: 'text-dropshadow',
},
{
text: 'Load web font',
link: 'web-font-loader',
Expand Down
4 changes: 4 additions & 0 deletions packages/site/docs/.vitepress/config/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ export const zh = defineConfig({
text: '文本基线',
link: 'text-baseline',
},
{
text: '文本阴影',
link: 'text-dropshadow',
},
{
text: '加载 Web 字体',
link: 'web-font-loader',
Expand Down
Loading

0 comments on commit 6aa085f

Please sign in to comment.