Skip to content

Commit 36bd517

Browse files
authored
Atlas resize shader without geometry shader (#2698)
1 parent d3e1c95 commit 36bd517

File tree

7 files changed

+109
-13
lines changed

7 files changed

+109
-13
lines changed

arcade/context.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,13 @@ def __init__(
131131
)
132132
# Atlas shaders
133133
self.atlas_resize_program: Program = self.load_program(
134-
vertex_shader=":system:shaders/atlas/resize_vs.glsl",
135-
geometry_shader=":system:shaders/atlas/resize_gs.glsl",
136-
fragment_shader=":system:shaders/atlas/resize_fs.glsl",
134+
# NOTE: This is the geo shader version of the atlas resize program.
135+
# vertex_shader=":system:shaders/atlas/resize_vs.glsl",
136+
# geometry_shader=":system:shaders/atlas/resize_gs.glsl",
137+
# fragment_shader=":system:shaders/atlas/resize_fs.glsl",
138+
# Vertex and fragment shader version
139+
vertex_shader=":system:shaders/atlas/resize_simple_vs.glsl",
140+
fragment_shader=":system:shaders/atlas/resize_simple_fs.glsl",
137141
)
138142
self.atlas_resize_program["atlas_old"] = 0 # Configure texture channels
139143
self.atlas_resize_program["atlas_new"] = 1

arcade/resources/system/shaders/atlas/resize_fs.glsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#version 330
22

3-
// The old atlas texture.
3+
// The old atlas texture. We copy sections to the new atlas texture
4+
// by render into an fbo with the target texture as the color attachment.
45
uniform sampler2D atlas_old;
56

67
out vec4 fragColor;

arcade/resources/system/shaders/atlas/resize_gs.glsl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
#include :system:shaders/lib/sprite.glsl
66

7-
// Old and new texture coordiantes
7+
// Old and new texture coordinates
88
uniform sampler2D atlas_old;
99
uniform sampler2D atlas_new;
10+
1011
uniform sampler2D texcoords_old;
1112
uniform sampler2D texcoords_new;
13+
1214
uniform mat4 projection;
1315
uniform float border;
1416

@@ -33,7 +35,7 @@ void main() {
3335
// absolute value of the diagonal * size + border * 2
3436
vec2 size = abs(new_uv3 - new_uv0) * vec2(size_new) + vec2(border * 2.0);
3537

36-
// We need to offset the old coordiantes by border size
38+
// We need to offset the old coordinates by border size
3739
vec2 pix_offset = vec2(border) / vec2(size_old);
3840
// (
3941
// 0.015625, 0.015625, # minus, minus
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#version 330
2+
// Atlas resize without geometry shader
3+
4+
// The old atlas texture. We copy sections to the new atlas texture
5+
// by render into an fbo with the target texture as the color attachment.
6+
uniform sampler2D atlas_old;
7+
8+
out vec4 fragColor;
9+
in vec2 uv;
10+
11+
void main() {
12+
fragColor = texture(atlas_old, uv);
13+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#version 330
2+
// Atlas resize without geometry shader
3+
4+
// The render target for this program is the new
5+
// texture atlas texture
6+
7+
#include :system:shaders/lib/sprite.glsl
8+
9+
// Old and new texture coordinates
10+
uniform sampler2D atlas_old;
11+
uniform sampler2D atlas_new;
12+
13+
uniform sampler2D texcoords_old;
14+
uniform sampler2D texcoords_new;
15+
16+
uniform mat4 projection;
17+
uniform float border;
18+
19+
out vec2 uv;
20+
21+
void main() {
22+
// Get the texture sizes
23+
ivec2 size_old = textureSize(atlas_old, 0).xy;
24+
ivec2 size_new = textureSize(atlas_new, 0).xy;
25+
26+
// Read texture coordinates from UV texture here
27+
int texture_id = gl_VertexID / 6;
28+
vec2 old_uv0, old_uv1, old_uv2, old_uv3;
29+
getSpriteUVs(texcoords_old, texture_id, old_uv0, old_uv1, old_uv2, old_uv3);
30+
vec2 new_uv0, new_uv1, new_uv2, new_uv3;
31+
getSpriteUVs(texcoords_new, texture_id, new_uv0, new_uv1, new_uv2, new_uv3);
32+
33+
// Lower left corner flipped * size - border
34+
vec2 pos = vec2(new_uv2.x, 1.0 - new_uv2.y) * vec2(size_new) - vec2(border);
35+
// absolute value of the diagonal * size + border * 2
36+
vec2 size = abs(new_uv3 - new_uv0) * vec2(size_new) + vec2(border * 2.0);
37+
38+
// We need to offset the old coordinates by border size
39+
vec2 pix_offset = vec2(border) / vec2(size_old);
40+
41+
// Emit two triangles over 6 vertices
42+
switch (gl_VertexID % 6) {
43+
// First triangle
44+
case 0:
45+
// upper left
46+
uv = old_uv0 - pix_offset;
47+
gl_Position = projection * vec4(pos + vec2(0.0, size.y), 0.0, 1.0);
48+
break;
49+
case 1:
50+
// lower left
51+
uv = old_uv2 + vec2(-pix_offset.x, pix_offset.y);
52+
gl_Position = projection * vec4(pos, 0.0, 1.0);
53+
break;
54+
case 2:
55+
// upper right
56+
uv = old_uv1 + vec2(pix_offset.x, -pix_offset.y);
57+
gl_Position = projection * vec4(pos + vec2(size.x, size.y), 0.0, 1.0);
58+
break;
59+
// Second triangle
60+
case 3:
61+
// lower left
62+
uv = old_uv2 + vec2(-pix_offset.x, pix_offset.y);
63+
gl_Position = projection * vec4(pos, 0.0, 1.0);
64+
break;
65+
case 4:
66+
// upper right
67+
uv = old_uv1 + vec2(pix_offset.x, -pix_offset.y);
68+
gl_Position = projection * vec4(pos + vec2(size.x, size.y), 0.0, 1.0);
69+
break;
70+
case 5:
71+
// lower right
72+
uv = old_uv3 + pix_offset;
73+
gl_Position = projection * vec4(pos + vec2(size.x, 0.0), 0.0, 1.0);
74+
break;
75+
}
76+
}

arcade/texture_atlas/atlas_default.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def __init__(
103103
self,
104104
size: tuple[int, int],
105105
*,
106-
border: int = 1,
106+
border: int = 2,
107107
textures: Sequence[Texture] | None = None,
108108
auto_resize: bool = True,
109109
ctx: ArcadeContext | None = None,
@@ -667,8 +667,7 @@ def resize(self, size: tuple[int, int], force=False) -> None:
667667
force:
668668
Force a resize even if the size is the same
669669
"""
670-
# LOG.info("[%s] Resizing atlas from %s to %s", id(self), self._size, size)
671-
# print("Resizing atlas from", self._size, "to", size)
670+
print("Resizing atlas from", self._size, "to", size)
672671

673672
# Only resize if the size actually changed
674673
if size == self._size and not force:
@@ -732,8 +731,9 @@ def resize(self, size: tuple[int, int], force=False) -> None:
732731
with self._ctx.enabled_only():
733732
self._ctx.geometry_empty.render(
734733
self._ctx.atlas_resize_program,
735-
mode=self._ctx.POINTS,
736-
vertices=self.max_width,
734+
mode=self._ctx.TRIANGLES,
735+
# Two triangles per texture
736+
vertices=UV_TEXTURE_WIDTH * self._capacity * 6,
737737
)
738738

739739
# duration = time.perf_counter() - resize_start
@@ -746,7 +746,7 @@ def rebuild(self) -> None:
746746
This method also tries to organize the textures more efficiently ordering them by size.
747747
The texture ids will persist so the sprite list doesn't need to be rebuilt.
748748
"""
749-
# LOG.info("Rebuilding atlas")
749+
print("Rebuilding atlas")
750750

751751
# Hold a reference to the old textures
752752
textures = self.textures

tests/unit/atlas/test_basics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def test_create(ctx, common):
1111
assert atlas.width == 100
1212
assert atlas.height == 200
1313
assert atlas.size == (100, 200)
14-
assert atlas.border == 1
14+
assert atlas.border == 2
1515
assert atlas.auto_resize is True
1616
assert isinstance(atlas.max_size, tuple)
1717
assert atlas.max_size > (0, 0)

0 commit comments

Comments
 (0)