171 lines
4.7 KiB
Python
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
|
|
)
|