Files
rrttm/src/renderers.py
2026-09-11 19:08:17 +02:00

171 lines
4.7 KiB
Python

import arcade
import assets
# !!! CHATGPT !!!
class TextureRenderer:
def __init__(self, ctx):
self.ctx = ctx
self.program = ctx.program(
vertex_shader="""
#version 330
in vec2 in_vert;
in vec2 in_uv;
out vec2 uv;
uniform vec2 screen_size;
uniform vec4 bounds;
void main() {
// Convert quad coordinates from [-1, 1] to [0, 1]
vec2 local = in_vert * 0.5 + 0.5;
// bounds = x, y, width, height in pixels
vec2 pixel_pos = bounds.xy + local * bounds.zw;
// Convert pixels to NDC
vec2 ndc = pixel_pos / screen_size * 2.0 - 1.0;
gl_Position = vec4(ndc, 0.0, 1.0);
uv = in_uv;
}
""",
fragment_shader="""
#version 330
uniform sampler2D tex;
in vec2 uv;
out vec4 color;
void main() {
color = texture(tex, uv);
}
""",
)
self.quad = arcade.gl.geometry.quad_2d_fs()
def render(self, texture, x, y, width, height):
self.program["screen_size"] = (self.ctx.screen.width,
self.ctx.screen.height)
self.program["bounds"] = (x, y, width, height)
texture.use(0)
self.program["tex"] = 0
self.quad.render(self.program)
# !!! CHATGPT !!!
class NineSlicesPanel:
SLICE_SIZE = 16
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
self.sprites = []
self.rebuild()
def rebuild(self):
self.sprites.clear()
sheet = assets.sprites["panel"]
s = self.SLICE_SIZE
# Crop a specific sub-region from the spritesheet
def tex(col, row, w=s, h=s):
return sheet.get_texture(
arcade.LBWH(col * s, row * s, w, h)
)
# Base 9-slice textures
textures = {
"bl": tex(0, 2),
"b": tex(1, 0),
"br": tex(2, 2),
"l": tex(0, 1),
"c": tex(1, 1),
"r": tex(2, 1),
"tl": tex(0, 0),
"t": tex(1, 2),
"tr": tex(2, 0),
}
def add(texture, x, y, w, h):
if w > 0 and h > 0:
self.sprites.append((
texture,
arcade.XYWH(x + w / 2, y + h / 2, w, h)
))
# Corners
add(textures["bl"], self.x, self.y, s, s)
add(textures["br"], self.x + self.w - s, self.y, s, s)
add(textures["tl"], self.x, self.y + self.h - s, s, s)
add(textures["tr"], self.x + self.w - s, self.y + self.h - s, s, s)
middle_w = self.w - s * 2
middle_h = self.h - s * 2
# Tile horizontal edges
def tile_horizontal(col, row, x, y, width):
curr_x = x
rem_w = width
while rem_w > 0:
tile_w = min(s, rem_w)
t = tex(col, row, tile_w, s)
add(t, curr_x, y, tile_w, s)
curr_x += tile_w
rem_w -= tile_w
# Tile vertical edges
def tile_vertical(col, row, x, y, height):
curr_y = y
rem_h = height
while rem_h > 0:
tile_h = min(s, rem_h)
# Crop from top of sprite when filling upwards
t = tex(col, row, s, tile_h)
add(t, x, curr_y, s, tile_h)
curr_y += tile_h
rem_h -= tile_h
# Render borders
tile_horizontal(1, 2, self.x + s, self.y, middle_w) # Bottom
tile_horizontal(1, 0, self.x + s, self.y + self.h - s, middle_w) # Top
tile_vertical(0, 1, self.x, self.y + s, middle_h) # Left
tile_vertical(2, 1, self.x + self.w - s, self.y + s, middle_h) # Right
# Render center grid
curr_y = self.y + s
rem_h = middle_h
while rem_h > 0:
tile_h = min(s, rem_h)
curr_x = self.x + s
rem_w = middle_w
while rem_w > 0:
tile_w = min(s, rem_w)
t = tex(1, 1, tile_w, tile_h)
add(t, curr_x, curr_y, tile_w, tile_h)
curr_x += tile_w
rem_w -= tile_w
curr_y += tile_h
rem_h -= tile_h
def render(self):
for texture, rect in self.sprites:
arcade.draw_texture_rect(
texture,
rect,
pixelated=True
)