trianglengin 1.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tests/__init__.py +0 -0
- tests/conftest.py +108 -0
- tests/core/__init__.py +2 -0
- tests/core/environment/README.md +47 -0
- tests/core/environment/__init__.py +2 -0
- tests/core/environment/test_action_codec.py +50 -0
- tests/core/environment/test_game_state.py +483 -0
- tests/core/environment/test_grid_data.py +205 -0
- tests/core/environment/test_grid_logic.py +362 -0
- tests/core/environment/test_shape_logic.py +171 -0
- tests/core/environment/test_step.py +372 -0
- tests/core/structs/__init__.py +0 -0
- tests/core/structs/test_shape.py +83 -0
- tests/core/structs/test_triangle.py +97 -0
- tests/utils/__init__.py +0 -0
- tests/utils/test_geometry.py +93 -0
- trianglengin/__init__.py +18 -0
- trianglengin/app.py +110 -0
- trianglengin/cli.py +134 -0
- trianglengin/config/__init__.py +9 -0
- trianglengin/config/display_config.py +47 -0
- trianglengin/config/env_config.py +103 -0
- trianglengin/core/__init__.py +8 -0
- trianglengin/core/environment/__init__.py +31 -0
- trianglengin/core/environment/action_codec.py +37 -0
- trianglengin/core/environment/game_state.py +217 -0
- trianglengin/core/environment/grid/README.md +46 -0
- trianglengin/core/environment/grid/__init__.py +18 -0
- trianglengin/core/environment/grid/grid_data.py +140 -0
- trianglengin/core/environment/grid/line_cache.py +189 -0
- trianglengin/core/environment/grid/logic.py +131 -0
- trianglengin/core/environment/logic/__init__.py +3 -0
- trianglengin/core/environment/logic/actions.py +38 -0
- trianglengin/core/environment/logic/step.py +134 -0
- trianglengin/core/environment/shapes/__init__.py +19 -0
- trianglengin/core/environment/shapes/logic.py +84 -0
- trianglengin/core/environment/shapes/templates.py +587 -0
- trianglengin/core/structs/__init__.py +27 -0
- trianglengin/core/structs/constants.py +28 -0
- trianglengin/core/structs/shape.py +61 -0
- trianglengin/core/structs/triangle.py +48 -0
- trianglengin/interaction/README.md +45 -0
- trianglengin/interaction/__init__.py +17 -0
- trianglengin/interaction/debug_mode_handler.py +96 -0
- trianglengin/interaction/event_processor.py +43 -0
- trianglengin/interaction/input_handler.py +82 -0
- trianglengin/interaction/play_mode_handler.py +141 -0
- trianglengin/utils/__init__.py +9 -0
- trianglengin/utils/geometry.py +73 -0
- trianglengin/utils/types.py +10 -0
- trianglengin/visualization/README.md +44 -0
- trianglengin/visualization/__init__.py +61 -0
- trianglengin/visualization/core/README.md +52 -0
- trianglengin/visualization/core/__init__.py +12 -0
- trianglengin/visualization/core/colors.py +117 -0
- trianglengin/visualization/core/coord_mapper.py +73 -0
- trianglengin/visualization/core/fonts.py +55 -0
- trianglengin/visualization/core/layout.py +101 -0
- trianglengin/visualization/core/visualizer.py +232 -0
- trianglengin/visualization/drawing/README.md +45 -0
- trianglengin/visualization/drawing/__init__.py +30 -0
- trianglengin/visualization/drawing/grid.py +156 -0
- trianglengin/visualization/drawing/highlight.py +30 -0
- trianglengin/visualization/drawing/hud.py +39 -0
- trianglengin/visualization/drawing/previews.py +172 -0
- trianglengin/visualization/drawing/shapes.py +36 -0
- trianglengin-1.0.6.dist-info/METADATA +367 -0
- trianglengin-1.0.6.dist-info/RECORD +72 -0
- trianglengin-1.0.6.dist-info/WHEEL +5 -0
- trianglengin-1.0.6.dist-info/entry_points.txt +2 -0
- trianglengin-1.0.6.dist-info/licenses/LICENSE +22 -0
- trianglengin-1.0.6.dist-info/top_level.txt +2 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# trianglengin/visualization/drawing/__init__.py
|
2
|
+
"""Drawing functions for specific visual elements."""
|
3
|
+
|
4
|
+
from .grid import (
|
5
|
+
draw_debug_grid_overlay, # Keep if used elsewhere
|
6
|
+
draw_grid_background,
|
7
|
+
# draw_grid_indices, # Removed - integrated into background
|
8
|
+
draw_grid_state, # Renamed from draw_grid_triangles
|
9
|
+
)
|
10
|
+
from .highlight import draw_debug_highlight
|
11
|
+
from .hud import render_hud
|
12
|
+
from .previews import (
|
13
|
+
draw_floating_preview,
|
14
|
+
draw_placement_preview,
|
15
|
+
render_previews,
|
16
|
+
)
|
17
|
+
from .shapes import draw_shape
|
18
|
+
|
19
|
+
__all__ = [
|
20
|
+
"draw_grid_background",
|
21
|
+
"draw_grid_state", # Export renamed function
|
22
|
+
"draw_debug_grid_overlay",
|
23
|
+
# "draw_grid_indices", # Removed
|
24
|
+
"draw_shape",
|
25
|
+
"render_previews",
|
26
|
+
"draw_placement_preview",
|
27
|
+
"draw_floating_preview",
|
28
|
+
"render_hud",
|
29
|
+
"draw_debug_highlight",
|
30
|
+
]
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# File: trianglengin/visualization/drawing/grid.py
|
2
|
+
import logging
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
|
5
|
+
import pygame
|
6
|
+
|
7
|
+
from trianglengin.core.structs.triangle import Triangle
|
8
|
+
from trianglengin.visualization.core import colors
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from trianglengin.config import DisplayConfig, EnvConfig
|
12
|
+
from trianglengin.core.environment.grid.grid_data import GridData
|
13
|
+
|
14
|
+
|
15
|
+
log = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def draw_grid_background(
|
19
|
+
surface: pygame.Surface,
|
20
|
+
env_config: "EnvConfig",
|
21
|
+
display_config: "DisplayConfig",
|
22
|
+
cw: float,
|
23
|
+
ch: float,
|
24
|
+
ox: float,
|
25
|
+
oy: float,
|
26
|
+
game_over: bool = False,
|
27
|
+
debug_mode: bool = False,
|
28
|
+
) -> None:
|
29
|
+
"""Draws the background grid structure using pre-calculated render parameters."""
|
30
|
+
bg_color = colors.GRID_BG_GAME_OVER if game_over else colors.GRID_BG_DEFAULT
|
31
|
+
surface.fill(bg_color)
|
32
|
+
|
33
|
+
if cw <= 0 or ch <= 0:
|
34
|
+
log.warning("Cannot draw grid background with zero cell dimensions.")
|
35
|
+
return
|
36
|
+
|
37
|
+
for r in range(env_config.ROWS):
|
38
|
+
# Use PLAYABLE_RANGE_PER_ROW to determine death zones
|
39
|
+
start_col, end_col = env_config.PLAYABLE_RANGE_PER_ROW[r]
|
40
|
+
for c in range(env_config.COLS):
|
41
|
+
is_up = (r + c) % 2 != 0
|
42
|
+
is_death = not (start_col <= c < end_col) # Check if outside playable range
|
43
|
+
tri = Triangle(r, c, is_up, is_death)
|
44
|
+
|
45
|
+
if is_death:
|
46
|
+
cell_color = colors.DEATH_ZONE_COLOR
|
47
|
+
else:
|
48
|
+
cell_color = (
|
49
|
+
colors.GRID_BG_LIGHT if (r % 2 == c % 2) else colors.GRID_BG_DARK
|
50
|
+
)
|
51
|
+
|
52
|
+
points = tri.get_points(ox, oy, cw, ch)
|
53
|
+
pygame.draw.polygon(surface, cell_color, points)
|
54
|
+
pygame.draw.polygon(surface, colors.GRID_LINE_COLOR, points, 1)
|
55
|
+
|
56
|
+
if debug_mode:
|
57
|
+
font = display_config.DEBUG_FONT
|
58
|
+
text = f"{r},{c}"
|
59
|
+
text_surf = font.render(text, True, colors.DEBUG_TOGGLE_COLOR)
|
60
|
+
center_x = sum(p[0] for p in points) / 3
|
61
|
+
center_y = sum(p[1] for p in points) / 3
|
62
|
+
text_rect = text_surf.get_rect(center=(center_x, center_y))
|
63
|
+
surface.blit(text_surf, text_rect)
|
64
|
+
|
65
|
+
|
66
|
+
def draw_grid_state(
|
67
|
+
surface: pygame.Surface,
|
68
|
+
grid_data: "GridData",
|
69
|
+
cw: float,
|
70
|
+
ch: float,
|
71
|
+
ox: float,
|
72
|
+
oy: float,
|
73
|
+
) -> None:
|
74
|
+
"""Draws the occupied triangles with their colors using pre-calculated parameters."""
|
75
|
+
rows, cols = grid_data.rows, grid_data.cols
|
76
|
+
occupied_np = grid_data._occupied_np
|
77
|
+
color_id_np = grid_data._color_id_np
|
78
|
+
death_np = grid_data._death_np
|
79
|
+
|
80
|
+
if cw <= 0 or ch <= 0:
|
81
|
+
log.warning("Cannot draw grid state with zero cell dimensions.")
|
82
|
+
return
|
83
|
+
|
84
|
+
for r in range(rows):
|
85
|
+
for c in range(cols):
|
86
|
+
if death_np[r, c]:
|
87
|
+
continue
|
88
|
+
|
89
|
+
if occupied_np[r, c]:
|
90
|
+
color_id = int(color_id_np[r, c])
|
91
|
+
color = colors.ID_TO_COLOR_MAP.get(color_id)
|
92
|
+
|
93
|
+
is_up = (r + c) % 2 != 0
|
94
|
+
tri = Triangle(r, c, is_up, False)
|
95
|
+
points = tri.get_points(ox, oy, cw, ch)
|
96
|
+
|
97
|
+
if color is not None:
|
98
|
+
pygame.draw.polygon(surface, color, points)
|
99
|
+
elif color_id == colors.DEBUG_COLOR_ID:
|
100
|
+
pygame.draw.polygon(surface, colors.DEBUG_TOGGLE_COLOR, points)
|
101
|
+
else:
|
102
|
+
log.warning(
|
103
|
+
f"Occupied cell ({r},{c}) has invalid color ID: {color_id}"
|
104
|
+
)
|
105
|
+
pygame.draw.polygon(surface, colors.TRIANGLE_EMPTY_COLOR, points)
|
106
|
+
|
107
|
+
|
108
|
+
def draw_debug_grid_overlay(
|
109
|
+
surface: pygame.Surface,
|
110
|
+
grid_data: "GridData",
|
111
|
+
display_config: "DisplayConfig",
|
112
|
+
cw: float,
|
113
|
+
ch: float,
|
114
|
+
ox: float,
|
115
|
+
oy: float,
|
116
|
+
) -> None:
|
117
|
+
"""Draws debug information using pre-calculated render parameters."""
|
118
|
+
font = display_config.DEBUG_FONT
|
119
|
+
rows, cols = grid_data.rows, grid_data.cols
|
120
|
+
|
121
|
+
if cw <= 0 or ch <= 0:
|
122
|
+
log.warning("Cannot draw debug overlay with zero cell dimensions.")
|
123
|
+
return
|
124
|
+
|
125
|
+
for r in range(rows):
|
126
|
+
for c in range(cols):
|
127
|
+
is_up = (r + c) % 2 != 0
|
128
|
+
is_death = grid_data.is_death(r, c)
|
129
|
+
tri = Triangle(r, c, is_up, is_death)
|
130
|
+
points = tri.get_points(ox, oy, cw, ch)
|
131
|
+
|
132
|
+
text = f"{r},{c}"
|
133
|
+
text_surf = font.render(text, True, colors.DEBUG_TOGGLE_COLOR)
|
134
|
+
center_x = sum(p[0] for p in points) / 3
|
135
|
+
center_y = sum(p[1] for p in points) / 3
|
136
|
+
text_rect = text_surf.get_rect(center=(center_x, center_y))
|
137
|
+
surface.blit(text_surf, text_rect)
|
138
|
+
|
139
|
+
|
140
|
+
def draw_grid(
|
141
|
+
surface: pygame.Surface,
|
142
|
+
grid_data: "GridData",
|
143
|
+
env_config: "EnvConfig",
|
144
|
+
display_config: "DisplayConfig",
|
145
|
+
cw: float,
|
146
|
+
ch: float,
|
147
|
+
ox: float,
|
148
|
+
oy: float,
|
149
|
+
game_over: bool = False,
|
150
|
+
debug_mode: bool = False,
|
151
|
+
) -> None:
|
152
|
+
"""Main function to draw the entire grid including background and state."""
|
153
|
+
draw_grid_background(
|
154
|
+
surface, env_config, display_config, cw, ch, ox, oy, game_over, debug_mode
|
155
|
+
)
|
156
|
+
draw_grid_state(surface, grid_data, cw, ch, ox, oy)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# File: trianglengin/visualization/drawing/highlight.py
|
2
|
+
import pygame
|
3
|
+
|
4
|
+
# Use internal imports
|
5
|
+
from ...core.structs import Triangle
|
6
|
+
from ..core import colors
|
7
|
+
|
8
|
+
|
9
|
+
def draw_debug_highlight(
|
10
|
+
surface: pygame.Surface,
|
11
|
+
r: int,
|
12
|
+
c: int,
|
13
|
+
# config: EnvConfig, # Removed - use cw, ch, ox, oy
|
14
|
+
cw: float,
|
15
|
+
ch: float,
|
16
|
+
ox: float,
|
17
|
+
oy: float,
|
18
|
+
) -> None:
|
19
|
+
"""Highlights a specific triangle border for debugging using pre-calculated parameters."""
|
20
|
+
if surface.get_width() <= 0 or surface.get_height() <= 0:
|
21
|
+
return
|
22
|
+
|
23
|
+
if cw <= 0 or ch <= 0:
|
24
|
+
return
|
25
|
+
|
26
|
+
is_up = (r + c) % 2 != 0
|
27
|
+
temp_tri = Triangle(r, c, is_up)
|
28
|
+
pts = temp_tri.get_points(ox, oy, cw, ch)
|
29
|
+
|
30
|
+
pygame.draw.polygon(surface, colors.DEBUG_TOGGLE_COLOR, pts, 3)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# File: trianglengin/trianglengin/visualization/drawing/hud.py
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
import pygame
|
5
|
+
|
6
|
+
# Use internal imports
|
7
|
+
from ..core import colors
|
8
|
+
|
9
|
+
|
10
|
+
def render_hud(
|
11
|
+
surface: pygame.Surface,
|
12
|
+
mode: str,
|
13
|
+
fonts: dict[str, pygame.font.Font | None],
|
14
|
+
_display_stats: dict[str, Any] | None = None, # Prefix with underscore
|
15
|
+
) -> None:
|
16
|
+
"""
|
17
|
+
Renders HUD elements for interactive modes (play/debug).
|
18
|
+
Displays only help text relevant to the mode.
|
19
|
+
Ignores _display_stats.
|
20
|
+
"""
|
21
|
+
screen_w, screen_h = surface.get_size()
|
22
|
+
help_font = fonts.get("help")
|
23
|
+
|
24
|
+
if not help_font:
|
25
|
+
return
|
26
|
+
|
27
|
+
bottom_y = screen_h - 10 # Position from bottom
|
28
|
+
|
29
|
+
# --- Render Help Text Only ---
|
30
|
+
help_text = "[ESC] Quit"
|
31
|
+
if mode == "play":
|
32
|
+
help_text += " | [Click] Select/Place Shape"
|
33
|
+
elif mode == "debug":
|
34
|
+
help_text += " | [Click] Toggle Cell"
|
35
|
+
|
36
|
+
help_surf = help_font.render(help_text, True, colors.LIGHT_GRAY)
|
37
|
+
# Position help text at the bottom right
|
38
|
+
help_rect = help_surf.get_rect(bottomright=(screen_w - 15, bottom_y))
|
39
|
+
surface.blit(help_surf, help_rect)
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# File: trianglengin/visualization/drawing/previews.py
|
2
|
+
import logging
|
3
|
+
|
4
|
+
import pygame
|
5
|
+
|
6
|
+
# Use internal imports
|
7
|
+
from trianglengin.config import DisplayConfig, EnvConfig
|
8
|
+
from trianglengin.core.environment import GameState
|
9
|
+
from trianglengin.core.structs import Shape, Triangle
|
10
|
+
from trianglengin.visualization.core import colors
|
11
|
+
|
12
|
+
from .shapes import draw_shape
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
def render_previews(
|
18
|
+
surface: pygame.Surface,
|
19
|
+
game_state: GameState,
|
20
|
+
area_topleft: tuple[int, int],
|
21
|
+
_mode: str,
|
22
|
+
env_config: EnvConfig,
|
23
|
+
display_config: DisplayConfig,
|
24
|
+
selected_shape_idx: int = -1,
|
25
|
+
) -> dict[int, pygame.Rect]:
|
26
|
+
"""Renders shape previews in their area. Returns dict {index: screen_rect}."""
|
27
|
+
surface.fill(colors.PREVIEW_BG_COLOR)
|
28
|
+
preview_rects_screen: dict[int, pygame.Rect] = {}
|
29
|
+
num_slots = env_config.NUM_SHAPE_SLOTS
|
30
|
+
pad = display_config.PREVIEW_PADDING
|
31
|
+
inner_pad = display_config.PREVIEW_INNER_PADDING
|
32
|
+
border = display_config.PREVIEW_BORDER_WIDTH
|
33
|
+
selected_border = display_config.PREVIEW_SELECTED_BORDER_WIDTH
|
34
|
+
|
35
|
+
if num_slots <= 0:
|
36
|
+
return {}
|
37
|
+
|
38
|
+
total_pad_h = (num_slots + 1) * pad
|
39
|
+
available_h = surface.get_height() - total_pad_h
|
40
|
+
slot_h = available_h / num_slots if num_slots > 0 else 0
|
41
|
+
slot_w = surface.get_width() - 2 * pad
|
42
|
+
|
43
|
+
current_y = float(pad)
|
44
|
+
|
45
|
+
for i in range(num_slots):
|
46
|
+
slot_rect_local = pygame.Rect(pad, int(current_y), int(slot_w), int(slot_h))
|
47
|
+
slot_rect_screen = slot_rect_local.move(area_topleft)
|
48
|
+
preview_rects_screen[i] = slot_rect_screen
|
49
|
+
|
50
|
+
shape: Shape | None = game_state.shapes[i]
|
51
|
+
is_selected = selected_shape_idx == i
|
52
|
+
|
53
|
+
border_width = selected_border if is_selected else border
|
54
|
+
border_color = (
|
55
|
+
colors.PREVIEW_SELECTED_BORDER if is_selected else colors.PREVIEW_BORDER
|
56
|
+
)
|
57
|
+
pygame.draw.rect(surface, border_color, slot_rect_local, border_width)
|
58
|
+
|
59
|
+
if shape:
|
60
|
+
draw_area_w = slot_w - 2 * (border_width + inner_pad)
|
61
|
+
draw_area_h = slot_h - 2 * (border_width + inner_pad)
|
62
|
+
|
63
|
+
if draw_area_w > 0 and draw_area_h > 0:
|
64
|
+
min_r, min_c, max_r, max_c = shape.bbox()
|
65
|
+
shape_rows = max_r - min_r + 1
|
66
|
+
shape_cols_eff = (
|
67
|
+
(max_c - min_c + 1) * 0.75 + 0.25 if shape.triangles else 1
|
68
|
+
)
|
69
|
+
|
70
|
+
scale_w = (
|
71
|
+
draw_area_w / shape_cols_eff if shape_cols_eff > 0 else draw_area_w
|
72
|
+
)
|
73
|
+
scale_h = draw_area_h / shape_rows if shape_rows > 0 else draw_area_h
|
74
|
+
cell_size = max(1.0, min(scale_w, scale_h))
|
75
|
+
|
76
|
+
shape_render_w = shape_cols_eff * cell_size
|
77
|
+
shape_render_h = shape_rows * cell_size
|
78
|
+
draw_topleft_x = (
|
79
|
+
slot_rect_local.left
|
80
|
+
+ border_width
|
81
|
+
+ inner_pad
|
82
|
+
+ (draw_area_w - shape_render_w) / 2
|
83
|
+
)
|
84
|
+
draw_topleft_y = (
|
85
|
+
slot_rect_local.top
|
86
|
+
+ border_width
|
87
|
+
+ inner_pad
|
88
|
+
+ (draw_area_h - shape_render_h) / 2
|
89
|
+
)
|
90
|
+
|
91
|
+
draw_shape(
|
92
|
+
surface,
|
93
|
+
shape,
|
94
|
+
(int(draw_topleft_x), int(draw_topleft_y)),
|
95
|
+
cell_size,
|
96
|
+
_is_selected=is_selected,
|
97
|
+
origin_offset=(-min_r, -min_c),
|
98
|
+
)
|
99
|
+
|
100
|
+
current_y += slot_h + pad
|
101
|
+
|
102
|
+
return preview_rects_screen
|
103
|
+
|
104
|
+
|
105
|
+
def draw_placement_preview(
|
106
|
+
surface: pygame.Surface,
|
107
|
+
shape: Shape,
|
108
|
+
r: int,
|
109
|
+
c: int,
|
110
|
+
is_valid: bool,
|
111
|
+
cw: float,
|
112
|
+
ch: float,
|
113
|
+
ox: float,
|
114
|
+
oy: float,
|
115
|
+
) -> None:
|
116
|
+
"""Draws a semi-transparent shape snapped to the grid using pre-calculated parameters."""
|
117
|
+
if not shape or not shape.triangles:
|
118
|
+
return
|
119
|
+
|
120
|
+
if cw <= 0 or ch <= 0:
|
121
|
+
return
|
122
|
+
|
123
|
+
alpha = 100
|
124
|
+
base_color = (
|
125
|
+
colors.PLACEMENT_VALID_COLOR if is_valid else colors.PLACEMENT_INVALID_COLOR
|
126
|
+
)
|
127
|
+
color: colors.ColorRGBA = (base_color[0], base_color[1], base_color[2], alpha)
|
128
|
+
|
129
|
+
temp_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA)
|
130
|
+
temp_surface.fill((0, 0, 0, 0))
|
131
|
+
|
132
|
+
for dr, dc, is_up in shape.triangles:
|
133
|
+
tri_r, tri_c = r + dr, c + dc
|
134
|
+
temp_tri = Triangle(tri_r, tri_c, is_up)
|
135
|
+
pts = temp_tri.get_points(ox, oy, cw, ch)
|
136
|
+
pygame.draw.polygon(temp_surface, color, pts)
|
137
|
+
|
138
|
+
surface.blit(temp_surface, (0, 0))
|
139
|
+
|
140
|
+
|
141
|
+
def draw_floating_preview(
|
142
|
+
surface: pygame.Surface,
|
143
|
+
shape: Shape,
|
144
|
+
screen_pos: tuple[int, int],
|
145
|
+
# _config: EnvConfig, # Removed - not needed with fixed cell_size
|
146
|
+
# _mapper_module: "coord_mapper_module", # Removed
|
147
|
+
) -> None:
|
148
|
+
"""Draws a semi-transparent shape floating at the screen position."""
|
149
|
+
if not shape or not shape.triangles:
|
150
|
+
return
|
151
|
+
|
152
|
+
cell_size = 20.0 # Fixed size for floating preview
|
153
|
+
alpha = 100
|
154
|
+
color: colors.ColorRGBA = (shape.color[0], shape.color[1], shape.color[2], alpha)
|
155
|
+
|
156
|
+
temp_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA)
|
157
|
+
temp_surface.fill((0, 0, 0, 0))
|
158
|
+
|
159
|
+
min_r, min_c, max_r, max_c = shape.bbox()
|
160
|
+
center_r = (min_r + max_r) / 2.0
|
161
|
+
center_c = (min_c + max_c) / 2.0
|
162
|
+
|
163
|
+
for dr, dc, is_up in shape.triangles:
|
164
|
+
pt_x = screen_pos[0] + (dc - center_c) * (cell_size * 0.75)
|
165
|
+
pt_y = screen_pos[1] + (dr - center_r) * cell_size
|
166
|
+
|
167
|
+
temp_tri = Triangle(0, 0, is_up)
|
168
|
+
rel_pts = temp_tri.get_points(0, 0, cell_size, cell_size)
|
169
|
+
pts = [(px + pt_x, py + pt_y) for px, py in rel_pts]
|
170
|
+
pygame.draw.polygon(temp_surface, color, pts)
|
171
|
+
|
172
|
+
surface.blit(temp_surface, (0, 0))
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import pygame
|
2
|
+
|
3
|
+
# Use internal imports
|
4
|
+
from ...core.structs import Shape, Triangle
|
5
|
+
from ..core import colors
|
6
|
+
|
7
|
+
|
8
|
+
def draw_shape(
|
9
|
+
surface: pygame.Surface,
|
10
|
+
shape: Shape,
|
11
|
+
topleft: tuple[int, int],
|
12
|
+
cell_size: float,
|
13
|
+
_is_selected: bool = False,
|
14
|
+
origin_offset: tuple[int, int] = (0, 0),
|
15
|
+
) -> None:
|
16
|
+
"""Draws a single shape onto a surface."""
|
17
|
+
if not shape or not shape.triangles or cell_size <= 0:
|
18
|
+
return
|
19
|
+
|
20
|
+
shape_color = shape.color
|
21
|
+
border_color = colors.GRAY
|
22
|
+
|
23
|
+
cw = cell_size
|
24
|
+
ch = cell_size
|
25
|
+
|
26
|
+
for dr, dc, is_up in shape.triangles:
|
27
|
+
adj_r, adj_c = dr + origin_offset[0], dc + origin_offset[1]
|
28
|
+
|
29
|
+
tri_x = topleft[0] + adj_c * (cw * 0.75)
|
30
|
+
tri_y = topleft[1] + adj_r * ch
|
31
|
+
|
32
|
+
temp_tri = Triangle(0, 0, is_up)
|
33
|
+
pts = [(px + tri_x, py + tri_y) for px, py in temp_tri.get_points(0, 0, cw, ch)]
|
34
|
+
|
35
|
+
pygame.draw.polygon(surface, shape_color, pts)
|
36
|
+
pygame.draw.polygon(surface, border_color, pts, 1)
|