Repository navigation
Fix create_text_sprite atlas sharing, anchors, position, and empty text - #2915
Merged
Merged
Conversation
- The texture was created with the text as its atlas name, so sprites with the same text shared one atlas image. Creating a second one in another color or size redrew the shared image (changing the first sprite) into the first sprite's region (stretching the second). Give each texture a unique name; the atlas frees it when the texture is garbage collected. - Only y was shifted before drawing into the texture, so with anchor_x="center" or "right" the text started at a negative x and was partly or completely clipped. Shift x too. - The sprite's center was read from the Text after shifting it, which put the sprite too high. Use the bounds from before the shift, so the sprite covers the same area as an equivalent Text object. - An empty string made a 0x0 texture and raised ValueError. Make the texture at least 1x1. - Round the texture size up instead of truncating it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-sprite # Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First of the text rendering fixes from the review.
arcade.create_text_sprite()had four bugs, all reproduced ondevelopmentbefore fixing.1. Sprites with the same text shared one atlas image
The texture was created with
Texture.create_empty(text, size), using the text as its name, which is also the atlas key. So a second sprite with the same text reused the first one's atlas region, andrender_intodrew over it:Fix: each texture gets a unique name (
create_text_sprite_<uuid>).create_emptydocuments its name as "the unique name for this texture". The atlas already frees an image when its texture is garbage collected (through its finalizers), so this doesn't leak atlas space.2.
anchor_x="center"and"right"clipped the textBefore drawing into the texture, only
ywas shifted to bring the text to (0, 0). With a center or right anchor, the text's left edge is negative, so it was drawn partly or completely outside the texture. For "Hello World" at 20pt, measured as total alpha in the texture:Fix: shift
xas well.3. The sprite was placed too high
The sprite's center was read from the
Textafter the shift, which put it about one text height too high: 14 px for 12pt text, and 47 px for 40pt. Fix: use the bounds from before the shift.The sprite now covers the same area as an
arcade.Text(text, 0, 0, anchor_y="baseline", ...)with the same arguments. Rendered side by side at the same position, their pixels match within 1 px, for every anchor, size, multiline and centered multiline case I tried. The 1 px is a faint edge column on multiline text; text sprites draw edges slightly lighter because of a separate blending issue from the review.4. An empty string raised
ValueErrorThe docstring says
text"can be an empty string", but that made a 0×0 texture and raisedValueError: height and width must be > 0. The texture is now at least 1×1, giving a transparent sprite.Also, the texture size is rounded up instead of truncated, so a fractional text width can't clip the last column. Widths are whole pixels on Windows, so this changes nothing here.
Behavior change
Sprites from
create_text_spriteare now positioned differently: lower by the text's height, and anchored likeText. Code that positions the sprite itself afterwards, which is the usual case, isn't affected. No examples or docs in the repo usecreate_text_sprite.Tests
New tests in
tests/unit/text/test_text_sprite.py:test_position_matches_text(6 cases: default, center and right anchors, 40pt, multiline, centered multiline): the sprite's bounds equal theTextobject's bounds. It compares against arcade's ownTextbounds, so it doesn't depend on which fonts are installed (CI is Linux).test_anchor_draws_all_text(left, center, right): the anchored sprite's image has as much ink as the left-anchored one. Each image is read right away, so this test doesn't depend on fix 1.test_same_text_different_style: each texture gets an atlas region of its own size, and creating a blue sprite doesn't change the red one's pixels.test_empty_text: a transparent texture of at least 1×1.On
development, 10 of these fail: all six position cases, the center and right anchors, the shared image, and the empty string. Only the left-anchor case and the existing loosetest_createcases pass there.Full suite on pyglet 3.0.dev11: 1472 passed. The 3 failures are the render tests that only fail on my machine. Ruff is clean, and mypy reports no errors in
arcade/text.py.🤖 Generated with Claude Code