add tool for annotating sprite metadata
This commit is contained in:
parent
3bb110172f
commit
46e5a34120
@ -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:])
|
||||
|
Loading…
Reference in New Issue
Block a user