Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mado-perf
font-edit
.font-edit
src/composite-decls.h
src/shadow-gaussian-lut.h

# Swap
[._]*.s[a-v][a-z]
Expand Down
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ src/composite-decls.h: scripts/gen-composite-decls.py
@echo " GEN $@"
@$< > $@

src/shadow-gaussian-lut.h: scripts/gen-shadow-lut.py
@echo " GEN $@"
@./scripts/gen-shadow-lut.py $@

# Optional features

libtwin.a_files-$(CONFIG_LOGGING) += src/log.c
Expand Down Expand Up @@ -277,6 +281,9 @@ ifeq ($(filter config defconfig clean,$(MAKECMDGOALS)),)
ifeq ($(wildcard src/composite-decls.h),)
$(shell scripts/gen-composite-decls.py > src/composite-decls.h)
endif
ifeq ($(wildcard src/shadow-gaussian-lut.h),)
$(shell ./scripts/gen-shadow-lut.py src/shadow-gaussian-lut.h)
endif
endif

# Only skip build rules when running ONLY config/defconfig (no other targets)
Expand Down
19 changes: 16 additions & 3 deletions configs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -191,32 +191,45 @@ config DROP_SHADOW

config HORIZONTAL_OFFSET
int "Horizontal offset"
default 1
default 6
range 1 10
depends on DROP_SHADOW
help
Horizontal shadow offset in pixels.
Default matches a CSS-style soft shadow (≈6 px offset).
Larger values push shadow further right.

config VERTICAL_OFFSET
int "Vertical offset"
default 1
default 6
range 1 10
depends on DROP_SHADOW
help
Vertical shadow offset in pixels.
Default matches a CSS-style soft shadow (≈6 px offset).
Larger values push shadow further down.

config SHADOW_BLUR
int "Shadow blur radius"
default 10
default 12
range 1 15
depends on DROP_SHADOW
help
Shadow blur kernel size (radius).
Default 12 approximates common CSS box-shadow softness.
Larger values create softer, more diffuse shadows.
Higher values increase rendering cost.

config SHADOW_FADE_TAIL
int "Shadow fade tail"
default 2
range 0 3
depends on DROP_SHADOW
help
Additional zero-alpha pixels appended to the shadow mask.
Default adds ~2 px of clear space to match CSS feathering.
Higher values slightly enlarge the off-screen buffer usage.

endmenu

menu "Image Loaders"
Expand Down
64 changes: 64 additions & 0 deletions scripts/gen-shadow-lut.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""
Generate precomputed Gaussian-style weights for the drop shadow LUT.

The curve approximates (1 - t^2)^2 * 0.92 + 0.08 sampled at 17 points
between 0 and 1 (inclusive). Values are emitted in 16.16 fixed-point so
the renderer can remain purely fixed-point.
"""

import math
import pathlib
import sys


def compute_weights(samples: int = 16) -> list[int]:
weights = []
for idx in range(samples + 1):
t = idx / samples
value = ((1.0 - t * t) ** 2) * 0.92 + 0.08
fixed = int(round(value * 65536)) # 16.16 fixed-point
fixed = max(0, min(fixed, 0xFFFFFFFF))
weights.append(fixed)
return weights


HEADER_TEMPLATE = """\
/*
* This file is auto-generated by scripts/gen-shadow-lut.py.
* Do not edit manually.
*/
#ifndef SHADOW_GAUSSIAN_LUT_H
#define SHADOW_GAUSSIAN_LUT_H

#include "twin.h"

static const twin_fixed_t shadow_gaussian_lut[{count}] = {{
{body}
}};

#endif /* SHADOW_GAUSSIAN_LUT_H */
"""


def emit_header(path: pathlib.Path) -> None:
weights = compute_weights()
lines = []
for idx, value in enumerate(weights):
suffix = "," if idx < len(weights) - 1 else ""
lines.append(f" 0x{value:05x}{suffix}")
header = HEADER_TEMPLATE.format(count=len(weights), body="\n".join(lines))
path.write_text(header, encoding="utf-8")


def main(argv: list[str]) -> int:
if len(argv) != 2:
sys.stderr.write("Usage: gen-shadow-lut.py <output>\n")
return 1
output_path = pathlib.Path(argv[1])
emit_header(output_path)
return 0


if __name__ == "__main__":
raise SystemExit(main(sys.argv))
Loading