|
|
@ -3,7 +3,9 @@ |
|
|
|
import glob |
|
|
|
import json |
|
|
|
import os |
|
|
|
import pygame |
|
|
|
import random |
|
|
|
import re |
|
|
|
import sys |
|
|
|
from PIL import Image |
|
|
|
|
|
|
@ -99,7 +101,7 @@ def unglob(list_of_globs): |
|
|
|
|
|
|
|
def input_wh(prompt): |
|
|
|
while True: |
|
|
|
geometry = input(prompt) |
|
|
|
geometry = input(prompt).strip() |
|
|
|
try: |
|
|
|
cols, rows = [int(x) for x in geometry.split(' ')] |
|
|
|
return cols, rows |
|
|
@ -107,9 +109,154 @@ def input_wh(prompt): |
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
# Returns True or False. |
|
|
|
def input_ok(prompt): |
|
|
|
while True: |
|
|
|
ok = input(prompt).strip() |
|
|
|
if ok.startswith('y'): |
|
|
|
return True |
|
|
|
if ok.startswith('n'): |
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
def draw_checkerboard(size): |
|
|
|
surface = pygame.display.get_surface() |
|
|
|
surface.fill((224, 224, 224)) |
|
|
|
for i in range(surface.get_width() // size + 1): |
|
|
|
for j in range(surface.get_height() // size + 1): |
|
|
|
if (i + j) % 2 == 0: |
|
|
|
continue |
|
|
|
rect = pygame.Rect(i * size, j * size, size, size) |
|
|
|
surface.fill((192, 192, 192), rect) |
|
|
|
|
|
|
|
|
|
|
|
def show_splits(image_width, image_height, cols, rows): |
|
|
|
surface = pygame.display.get_surface() |
|
|
|
split_width = image_width / cols |
|
|
|
split_height = image_height / rows |
|
|
|
for i in range(cols): |
|
|
|
for j in range(rows): |
|
|
|
rect = pygame.Rect( |
|
|
|
i * split_width, j * split_height, split_width + 1, split_height + 1) |
|
|
|
pygame.draw.rect(surface, (255, 0, 255), rect, 1) |
|
|
|
pygame.display.flip() |
|
|
|
|
|
|
|
|
|
|
|
def render_text(text, pos, color): |
|
|
|
surface = pygame.display.get_surface() |
|
|
|
font = pygame.font.SysFont('notomono', 16) |
|
|
|
image = font.render(text, True, color) |
|
|
|
surface.blit(image, pos) |
|
|
|
pygame.display.flip() |
|
|
|
|
|
|
|
|
|
|
|
def render_sprite(metadata): |
|
|
|
line_color = (255, 0, 255) |
|
|
|
|
|
|
|
surface = pygame.display.get_surface() |
|
|
|
draw_checkerboard(8) |
|
|
|
image = pygame.image.load(metadata['filename']) |
|
|
|
surface.blit(image, (0, 0)) |
|
|
|
|
|
|
|
if metadata.get('chunks'): |
|
|
|
for chunk in metadata['chunks']: |
|
|
|
rect = pygame.Rect( |
|
|
|
chunk['x'], chunk['y'], chunk['width'] + 1, chunk['height'] + 1) |
|
|
|
pygame.draw.rect(surface, line_color, rect, 1) |
|
|
|
label_pos = (chunk['x'] + 4, chunk['y']) |
|
|
|
render_text(str(chunk['index']), label_pos, line_color) |
|
|
|
caption_pos = (4, 4 + metadata['image_height'] + chunk['index'] * 20) |
|
|
|
caption = '%d: %s' % (chunk['index'], chunk.get('name', '')) |
|
|
|
render_text(caption, caption_pos, (0, 0, 0)) |
|
|
|
|
|
|
|
pygame.display.flip() |
|
|
|
|
|
|
|
|
|
|
|
def set_sprite_chunk_size(metadata): |
|
|
|
cols, rows = input_wh('how many columns & rows of sprites? ') |
|
|
|
metadata['chunk_columns'] = cols |
|
|
|
metadata['chunk_rows'] = rows |
|
|
|
metadata['chunk_width'] = metadata['image_width'] // cols |
|
|
|
metadata['chunk_height'] = metadata['image_height'] // rows |
|
|
|
metadata['chunks'] = [] |
|
|
|
for i in range(cols * rows): |
|
|
|
x = i % cols |
|
|
|
y = i // cols |
|
|
|
chunk_md = { |
|
|
|
'index': i, |
|
|
|
'x': x * metadata['chunk_width'], |
|
|
|
'y': y * metadata['chunk_height'], |
|
|
|
'width': metadata['chunk_width'], |
|
|
|
'height': metadata['chunk_height'] |
|
|
|
} |
|
|
|
metadata['chunks'].append(chunk_md) |
|
|
|
render_sprite(metadata) |
|
|
|
|
|
|
|
|
|
|
|
def edit_sprite_chunk_metadata(chunk): |
|
|
|
while True: |
|
|
|
name = input('name for chunk #%d: ' % chunk['index']).strip() |
|
|
|
print(name) |
|
|
|
if re.fullmatch(r'\w+', name): |
|
|
|
chunk['name'] = name |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
def edit_sprite_metadata(filename, metadata=None): |
|
|
|
if metadata is None: |
|
|
|
image = pygame.image.load(filename) |
|
|
|
metadata = { |
|
|
|
'filename': filename, |
|
|
|
'image_width': image.get_width(), |
|
|
|
'image_height': image.get_height(), |
|
|
|
} |
|
|
|
|
|
|
|
print('\nprocessing %s (%dx%d)' % ( |
|
|
|
filename, metadata['image_width'], metadata['image_height'])) |
|
|
|
|
|
|
|
render_sprite(metadata) |
|
|
|
|
|
|
|
if not metadata.get('chunk_width'): |
|
|
|
set_sprite_chunk_size(metadata) |
|
|
|
|
|
|
|
while True: |
|
|
|
render_sprite(metadata) |
|
|
|
prompt = 'edit (c)hunk sizes, type a chunk #, (n)ext, or (q)uit: ' |
|
|
|
choice = input(prompt).strip() |
|
|
|
if choice == 'n': |
|
|
|
return metadata, False |
|
|
|
elif choice == 'q': |
|
|
|
return metadata, True |
|
|
|
elif choice == 'c': |
|
|
|
set_sprite_chunk_size(metadata) |
|
|
|
elif re.fullmatch(r'\d+', choice): |
|
|
|
chunk_num = int(choice) |
|
|
|
if 0 <= chunk_num < len(metadata['chunks']): |
|
|
|
edit_sprite_chunk_metadata(metadata['chunks'][chunk_num]) |
|
|
|
else: |
|
|
|
print('invalid chunk #') |
|
|
|
else: |
|
|
|
print('invalid choice') |
|
|
|
|
|
|
|
|
|
|
|
def annotate_sprites(sprite_files, all_metadata): |
|
|
|
pygame.init() |
|
|
|
surface = pygame.display.set_mode((1200, 900), pygame.RESIZABLE) |
|
|
|
|
|
|
|
for filename in sprite_files: |
|
|
|
sprite_metadata, quit = edit_sprite_metadata( |
|
|
|
filename, all_metadata.get(filename)) |
|
|
|
all_metadata[filename] = sprite_metadata |
|
|
|
with open('metadata.json', 'w') as f: |
|
|
|
json.dump(all_metadata, f) |
|
|
|
if quit: |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
def main(args): |
|
|
|
os.chdir(os.path.expanduser('~/time_fantasy')) |
|
|
|
metadata = json.load(open('metadata.json')) |
|
|
|
with open('metadata.json') as f: |
|
|
|
all_metadata = json.load(f) |
|
|
|
|
|
|
|
sprite_files = unglob(SPRITE_FILES) |
|
|
|
tileset_files = unglob(TILESET_FILES) |
|
|
@ -120,22 +267,14 @@ def main(): |
|
|
|
(len(sprite_files), len(tileset_files), len(animation_files), |
|
|
|
len(icon_files), len(background_files))) |
|
|
|
|
|
|
|
for filename in sprite_files: |
|
|
|
with Image.open(filename) as image: |
|
|
|
x = image.show() |
|
|
|
cols, rows = input_wh('%s (%dx%d): ' % ( |
|
|
|
filename, image.size[0], image.size[1])) |
|
|
|
width = image.size[0] / cols |
|
|
|
height = image.size[1] / rows |
|
|
|
print(width, height) |
|
|
|
if rows == 1 and cols == 1: |
|
|
|
continue |
|
|
|
for i in range(rows): |
|
|
|
for j in range(cols): |
|
|
|
box = (j * width, i * height, (j + 1) * width, (i + 1) * height) |
|
|
|
sprites = image.crop(box) |
|
|
|
sprites.show() |
|
|
|
if len(args) < 1: |
|
|
|
return |
|
|
|
|
|
|
|
command = args[0] |
|
|
|
|
|
|
|
if command == 'annotate-sprites': |
|
|
|
annotate_sprites(sprite_files, all_metadata) |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
main() |
|
|
|
main(sys.argv[1:]) |