Skip to content

Commit 96ac221

Browse files
committed
update to use per pixel update only
1 parent 11196b6 commit 96ac221

File tree

4 files changed

+139
-45
lines changed

4 files changed

+139
-45
lines changed

Diff for: CONSTS.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ class OnLoadMapError(Exception):
1515

1616
coordinate = tuple[int, int]
1717
DEFAULT_DENSITY = 20
18-
MAX_THREAD_BY_CALC = 58
18+
MAX_THREAD_BY_CALC = 1

Diff for: debug_utils.py

+42-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,53 @@
11
"""
22
Outil de debug divers
33
"""
4+
from time import time
5+
from typing import Callable
46

5-
def test_get_full_line():
7+
total_time = 0
8+
9+
10+
def get_time(function: Callable) -> Callable:
11+
def wrapper(*args, **kwargs):
12+
t1 = time()
13+
result = function(*args, **kwargs)
14+
t2 = time()
15+
print(f'Elapsed time of {function}: {t2 - t1}')
16+
return result
17+
18+
return wrapper
19+
20+
21+
def add_time_incache(function: Callable) -> Callable:
22+
global total_time
623

24+
def wrapper(*args, **kwargs):
25+
global total_time
26+
t1 = time()
27+
result = function(*args, **kwargs)
28+
t2 = time()
29+
total_time += t2 - t1
30+
return result
31+
32+
return wrapper
33+
34+
35+
def get_time_incache() -> int:
36+
print(f"Total time: {total_time}")
37+
return total_time
38+
39+
40+
def test_get_full_line():
741
from utils import get_full_line
842

943
assert get_full_line((10, 30), (-20, 69)) == [(-20, 69), (-19, 68), (-18, 67), (-18, 66), (-17, 65), (-16, 64),
10-
(-15, 63), (-15, 62), (-14, 61), (-13, 60), (-12, 59), (-12, 58),
11-
(-11, 57), (-10, 56), (-9, 55), (-8, 54), (-8, 53), (-7, 52), (-6, 51),
12-
(-5, 50), (-5, 49), (-4, 48), (-3, 47), (-2, 46), (-2, 45), (-1, 44),
13-
(0, 43), (1, 42), (2, 41), (2, 40), (3, 39), (4, 38), (5, 37), (5, 36),
14-
(6, 35), (7, 34), (8, 33), (8, 32), (9, 31), (10, 30)]
44+
(-15, 63), (-15, 62), (-14, 61), (-13, 60), (-12, 59), (-12, 58),
45+
(-11, 57), (-10, 56), (-9, 55), (-8, 54), (-8, 53), (-7, 52),
46+
(-6, 51),
47+
(-5, 50), (-5, 49), (-4, 48), (-3, 47), (-2, 46), (-2, 45), (-1, 44),
48+
(0, 43), (1, 42), (2, 41), (2, 40), (3, 39), (4, 38), (5, 37),
49+
(5, 36),
50+
(6, 35), (7, 34), (8, 33), (8, 32), (9, 31), (10, 30)]
1551

1652

1753
def have_duplicated_obj_in_list(master: list[list]) -> bool:

Diff for: main.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
Ce module devra également contenir
44
- Les instructions pour lancer la boucle principale (dans game_engine.MaitreDuJeu)
55
"""
6+
from threading import Thread
67

78
import pygame
89

910
from map import TileMap
1011
from debug_pygame import show_point, get_point_from_idx
12+
from debug_utils import get_time_incache
1113

1214
pygame.init()
1315

@@ -22,7 +24,11 @@
2224

2325
run = True
2426
debug_switch = False
27+
28+
map.blit_texture(SCREEN, all_pxs=True)
29+
2530
while run:
31+
destruction = ()
2632
if debug_switch:
2733
map.print_map(SCREEN)
2834
else:
@@ -32,13 +38,19 @@
3238
if event.type == pygame.KEYDOWN:
3339
if event.key == pygame.K_s:
3440
debug_switch = not debug_switch
35-
# if event.key == pygame.K_d:
41+
map.blit_texture(SCREEN, all_pxs=True)
42+
if event.key == pygame.K_d:
43+
get_time_incache()
3644
elif event.key == pygame.K_ESCAPE:
3745
run = False
3846
elif event.type == pygame.MOUSEBUTTONDOWN:
3947
print("Mouse point @", pygame.mouse.get_pos())
40-
map.destroy_map(pygame.mouse.get_pos(), 50.0)
48+
destruction = (pygame.mouse.get_pos(), 50.0)
4149
elif event.type == pygame.QUIT:
4250
pygame.quit()
4351
exit(1)
44-
# Oclock.tick(60)
52+
53+
if destruction != ():
54+
Thread(group=None, target=map.destroy_map, name=None, args=destruction).start()
55+
56+
Oclock.tick(60)

Diff for: map.py

+81-35
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
- Comment représenter dans le programme de la matière
66
"""
77

8-
from debug_pygame import show_point
8+
from functools import reduce
99
from sys import setrecursionlimit
1010
from threading import Thread
11-
from functools import reduce
1211

1312
import pygame
1413

15-
from CONSTS import coordinate, OnLoadMapError, DEFAULT_DENSITY, MAX_THREAD_BY_CALC
14+
from CONSTS import coordinate, OnLoadMapError, DEFAULT_DENSITY
15+
from debug_pygame import get_point_from_idx
1616
from utils import get_full_line, get_circle
1717

1818
setrecursionlimit(9000000)
@@ -35,12 +35,15 @@ def gen_segmented_map(vectmap: list[list[coordinate]]) -> list[list[coordinate]]
3535

3636

3737
def algo_peinture(segmap: list[list[coordinate]], fmap: list[list[bool]], centers: list[coordinate],
38-
base: bool = False):
38+
dim: list[int], base: bool = False):
3939
def fill_neighbours(point: coordinate, segform: set[coordinate]):
4040
# print(segform)
4141
fmap[point[0]][point[1]] = not base
4242
for (x, y) in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
43-
if (point not in segform) and fmap[point[0] + x][point[1] + y] == base:
43+
if (
44+
0 <= point[0] + x < dim[0] and 0 < point[1] + y <= dim[1] and
45+
(point not in segform) and fmap[point[0] + x][point[1] + y] == base
46+
):
4447
fill_neighbours((point[0] + x, point[1] + y), segform)
4548

4649
# print(centers)
@@ -58,10 +61,11 @@ def __init__(self, mappath: str):
5861
"""
5962
self.map: list[list[bool]] = [] # [x][y]
6063
self.texture: list[int] | None = None # Invalid texture is None - debug // list[int] is bytes to print img
61-
self.fond: pygame.Surface | None = None
64+
self.fond: list[int] | None = None
6265
self.dimensions: list[int] = [0, 0]
6366
self.form_borders: list[list[coordinate]] = []
64-
67+
self.reset_ONMAP_thread: Thread | None = None
68+
self.px_update_list: list[int] = []
6569
# Step 1: Extract vectorial map
6670

6771
"""
@@ -154,7 +158,7 @@ def __init__(self, mappath: str):
154158
else:
155159
if sp[0] == "empty":
156160
print("load fond")
157-
self.fond = pygame.image.load(sp[1])
161+
self.fond = list(pygame.image.tobytes(pygame.image.load(sp[1]), 'ARGB'))
158162
elif sp[0] == "full":
159163
print("load front")
160164
# pygame.image.tobytes returns [y] then [x]
@@ -167,6 +171,7 @@ def __init__(self, mappath: str):
167171
# print(vectmap)
168172

169173
### INTERLUDE ###
174+
self.TRUEMAP = [[True for y in range(self.dimensions[1])] for x in range(self.dimensions[0])]
170175
Thread(group=None, target=self.__reset_ONMAP, name=None).start()
171176
### ###
172177

@@ -305,7 +310,7 @@ def __init__(self, mappath: str):
305310
elif x not in Hdict[y]:
306311
self.map[x][y] = inside
307312

308-
self.__filter_image(0, len(self.texture))
313+
self.__filter_image(0, len(self.texture), arbitrary=True)
309314

310315
def clear_map(self):
311316
"""
@@ -328,15 +333,28 @@ def print_map(self, screen):
328333
else:
329334
screen.set_at((x, y), "black")
330335

331-
def blit_texture(self, screen):
336+
def blit_texture(self, screen, *, all_pxs: bool = False):
332337
"""
333338
Affiche la map dans le screen
334339
Utilise les textures internes
335340
:param screen: Le screen qu'on doit blit dessus
336341
"""
337-
screen.blit(self.fond, (0, 0))
338-
screen.blit(pygame.image.frombytes(bytes(self.texture), self.dimensions, 'ARGB'), (0, 0))
342+
if all_pxs:
343+
screen.blit(pygame.image.frombytes(bytes(self.fond), self.dimensions, 'ARGB'), (0, 0))
344+
screen.blit(pygame.image.frombytes(bytes(self.texture), self.dimensions, 'ARGB'), (0, 0))
345+
else:
346+
while len(self.px_update_list) > 0:
347+
self.update_px(self.px_update_list.pop(), screen)
348+
349+
def update_px(self, idx: int, screen) -> None:
350+
"""
351+
Blit the pixel given on screen
352+
:param idx: Pixel index in self.texture (should point on Alpha channel)
353+
:param screen: The screen to update
354+
"""
355+
screen.set_at(get_point_from_idx(idx), self.fond[idx + 1:idx + 4])
339356

357+
# @get_time
340358
def destroy_map(self, impact: coordinate, power: float):
341359
"""
342360
Destoy the map using an impact point and the power of the weapon
@@ -357,50 +375,78 @@ def destroy_map(self, impact: coordinate, power: float):
357375
# show_point(point, does_stop=False, one_pixel=True)
358376
# show_point(impact, color=(0,0,255))
359377

360-
algo_peinture(seg_circle, self.ONMAP, [impact], base=True)
378+
algo_peinture(seg_circle, self.ONMAP, [impact], self.dimensions, base=True)
361379

362-
self.map = [
363-
[self.map[x][y] and self.ONMAP[x][y] for y in range(len(self.map[x]))] for x in range(len(self.map))
364-
]
380+
for x in range(len(self.map)):
381+
for y in range(len(self.map[x])):
382+
self.map[x][y] = self.map[x][y] and self.ONMAP[x][y]
365383

366384
head = (xmini, ymini)
367-
queue = (xmaxi, ymaxi)
368-
starter = (head[0]+head[1]*self.dimensions[0])*4
369-
goal = (queue[0]+queue[1]*self.dimensions[0])*4
385+
# queue = (xmaxi, ymaxi)
386+
starter = (head[0] + head[1] * self.dimensions[0]) * 4
387+
# goal = (queue[0] + queue[1] * self.dimensions[0]) * 4
370388
# show_point(head, does_stop=False)
371389
# show_point(queue)
372390

391+
while self.reset_ONMAP_thread:
392+
pass
393+
373394
Thread(group=None, target=self.__reset_ONMAP, name=None).start()
395+
374396
# self.tt = 0
375-
parter = (goal-starter) // MAX_THREAD_BY_CALC
376-
print(parter, goal, starter)
377-
for i in range(MAX_THREAD_BY_CALC):
378-
Thread(group=None, target=self.__filter_image, name=None,
379-
kwargs={'_from': starter + parter * i, '_to': starter + parter * (i + 1)}
380-
).start()
381-
382-
def __filter_image(self, _from: int, _to: int):
397+
parter = (xmaxi - xmini) * 4
398+
# print(parter, goal, starter)
399+
launch_dicts = [{'_from': starter + self.dimensions[0] * i * 4,
400+
'_to': starter + parter + self.dimensions[0] * (i + 1) * 4}
401+
for i in range(ymaxi - ymini)]
402+
Thread(group=None, target=self.__start_filter_image, name=None, args=launch_dicts).start()
403+
# for dlign in launch_dicts:
404+
# self.__filter_image(**dlign)
405+
406+
# @add_time_incache
407+
def __start_filter_image(self, *launch_dict: dict[str, int]) -> None:
408+
for dict in launch_dict:
409+
self.__filter_image(**dict)
410+
411+
def __filter_image(self, _from: int, _to: int, *, arbitrary: bool = False) -> None:
383412
"""
384413
Filter the image to set alpha channel of hidden pixel to 0 and the other pixel to 1
385414
:param _from: Start processing at px _from (included)
386415
:param _to: Ends processing at px _to (excluded)
387416
"""
388-
print("go from",_from, "to", _to)
417+
# print("go from", _from, "to", _to)
389418
# t1 = time()
390419
# Make sure we are interacting with images
391420
assert self.texture != None
421+
if arbitrary:
422+
for idx in range(_from, _to, 4): # Catch only alpha channels
423+
# print((idx // 4) // self.dimensions[0], (idx // 4) // self.dimensions[1])
424+
if self.map[(idx // 4) % self.dimensions[0]][(idx // 4) // self.dimensions[0]]:
425+
self.texture[idx] = 255
426+
else:
427+
self.texture[idx] = 0
428+
else:
429+
for idx in range(_from, _to, 4): # Catch only alpha channels
430+
if (
431+
self.map[(idx // 4) % self.dimensions[0]][(idx // 4) // self.dimensions[0]]
432+
and self.texture[idx] != 255
433+
):
434+
self.texture[idx] = 255
435+
self.px_update_list.append(idx)
436+
elif (
437+
not self.map[(idx // 4) % self.dimensions[0]][(idx // 4) // self.dimensions[0]]
438+
and self.texture[idx] != 0
439+
):
440+
self.texture[idx] = 0
441+
self.px_update_list.append(idx)
392442

393-
for idx in range(_from, _to, 4): # Catch only alpha channels
394-
# print((idx // 4) // self.dimensions[0], (idx // 4) // self.dimensions[1])
395-
if self.map[(idx // 4) % self.dimensions[0]][(idx // 4) // self.dimensions[0]]:
396-
self.texture[idx] = 255
397-
else:
398-
self.texture[idx] = 0
399443
# t2 = time()
400444
# self.tt += t2 - t1
401445

402446
def __reset_ONMAP(self):
403-
self.ONMAP = [[True for y in range(self.dimensions[1])] for x in range(self.dimensions[0])]
447+
self.reset_ONMAP_thread = True
448+
self.ONMAP = self.TRUEMAP.copy()
449+
self.reset_ONMAP_thread = False
404450

405451

406452
if __name__ == "__main__":

0 commit comments

Comments
 (0)