# HG changeset patch # User Neil Muller # Date 1328972872 -7200 # Node ID ebc48b397fd55e19228f38906b6f0bcb42bef2b7 # Parent 0571deb177e99885aa12b7432ae8c6aec0566c5b Turn rect_drawer into a command line option diff -r 0571deb177e9 -r ebc48b397fd5 pyntnclick/main.py --- a/pyntnclick/main.py Sat Feb 11 17:04:59 2012 +0200 +++ b/pyntnclick/main.py Sat Feb 11 17:07:52 2012 +0200 @@ -24,6 +24,9 @@ from pyntnclick.sound import Sound from pyntnclick import state +from pyntnclick.tools.rect_drawer import RectApp, make_rect_display +from pyntnclick.tools.utils import list_scenes + class MainShell(Shell): def __init__(self, display, game_description): @@ -86,6 +89,15 @@ dest="scene", help="initial scene") parser.add_option("--no-rects", action="store_false", default=True, dest="rects", help="disable debugging rects") + parser.add_option("--rect-drawer", action="store_true", + default=False, dest="rect_drawer", + help="Launch the rect drawing helper tool. Specify the" + " scene with --scene") + parser.add_option("--list-scenes", action="store_true", + default=False, dest='list_scenes', help="List all scenes" + " that can be used with --scene and exit.") + parser.add_option("--detail", type="str", default=None, + dest="detail", help="Detailed view for rect_drawer") return parser def main(self): @@ -102,12 +114,32 @@ # debug the specified scene self._initial_scene = opts.scene self._debug_rects = opts.rects - display = pygame.display.set_mode(self.constants.screen, - SWSURFACE) - pygame.display.set_icon(self.resource.get_image( - 'suspended_sentence24x24.png', basedir='icons')) - pygame.display.set_caption("Suspended Sentence") - shell = MainShell(display, self) + if opts.list_scenes: + # FIXME: Horrible hack to avoid image loading issues for + # now + display = pygame.display.set_mode(self.constants.screen, + SWSURFACE) + list_scenes(self.initial_state) + sys.exit(0) + if opts.rect_drawer: + if opts.scene is None: + print 'Need to supply a scene to use the rect drawer' + sys.exit(1) + display = make_rect_display() + try: + shell = RectApp(display, self.initial_state, opts.scene, + opts.detail) + except KeyError: + print 'Invalid scene: %s' % opts.scene + sys.exit(1) + else: + display = pygame.display.set_mode(self.constants.screen, + SWSURFACE) + pygame.display.set_icon(self.resource.get_image( + 'suspended_sentence24x24.png', basedir='icons')) + pygame.display.set_caption("Suspended Sentence") + + shell = MainShell(display, self) try: shell.run() except KeyboardInterrupt: diff -r 0571deb177e9 -r ebc48b397fd5 pyntnclick/tools/__init__.py diff -r 0571deb177e9 -r ebc48b397fd5 pyntnclick/tools/gen_sound.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyntnclick/tools/gen_sound.py Sat Feb 11 17:07:52 2012 +0200 @@ -0,0 +1,57 @@ +# Generate 'perfect' sine wave sounds + +# Design notes: produces ~= (use requested) s raw CDDA audio - 44100 Hz +# 16 bit signed values +# Input is freq in Hz - 440 for A, etc. - must be an integer +# Output is written the file beep.pcm +# Convert to ogg with oggenc -r + +import sys +import math +import struct + +CDDA_RATE = 44100 +MAX = 105 * 256 # Max value for sine wave + + +def gen_sine(freq, secs): + filename = 'beep%s.pcm' % freq + # We need to generate freq cycles and sample that CDDA_RATE times + samples_per_cycle = CDDA_RATE / freq + data = [] + for x in range(samples_per_cycle): + rad = float(x) / samples_per_cycle * 2 * math.pi + y = MAX * math.sin(rad) + data.append(struct.pack(' []' + print ' where is the frequency in Hz (integer)' + print ' and [] is the time is seconds (float)' + +if __name__ == "__main__": + try: + freq = int(sys.argv[1]) + except Exception, exc: + usage() + print 'Error was: %s' % exc + sys.exit(1) + + if len(sys.argv) > 2: + try: + secs = float(sys.argv[2]) + except Exception, exc: + usage() + print 'Error was: %s' % exc + sys.exit(1) + else: + secs = 0.25 + output = gen_sine(freq, secs) + print 'Wrote sample to %s' % output diff -r 0571deb177e9 -r ebc48b397fd5 pyntnclick/tools/rect_drawer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyntnclick/tools/rect_drawer.py Sat Feb 11 17:07:52 2012 +0200 @@ -0,0 +1,643 @@ +# Quickly hacked together helper for working out +# interactive regions in Suspended Sentence + +import sys +import os.path + +script_path = os.path.realpath(os.path.dirname(os.path.dirname(__file__))) +sys.path.append(script_path) + +from albow.root import RootWidget +from albow.utils import frame_rect +from albow.widget import Widget +from albow.controls import Button, Image +from albow.palette_view import PaletteView +from albow.file_dialogs import request_old_filename +from albow.resource import get_font +from pygame.locals import (K_LEFT, K_RIGHT, K_UP, K_DOWN, + K_a, K_t, K_d, K_i, K_r, K_o, K_b, K_z, + BLEND_RGBA_MIN, SRCALPHA) +import pygame + +import pyntnclick.constants +from pyntnclick import state +state.DEBUG_RECTS = True +from pyntnclick.widgets import BoomLabel + + +class RectDrawerConstants(pyntnclick.constants.GameConstants): + debug = True + menu_width = 200 + menu_button_height = 25 + zoom = 4 + zoom_step = 100 + +constants = RectDrawerConstants() + + +class AppPalette(PaletteView): + + sel_width = 5 + + colors = [ + 'red', 'maroon1', 'palevioletred1', 'moccasin', 'orange', + 'honeydew', 'yellow', 'gold', 'goldenrod', 'brown', + 'blue', 'purple', 'darkorchid4', 'thistle', 'skyblue1', + 'green', 'palegreen1', 'darkgreen', 'aquamarine', 'darkolivegreen', + ] + + def __init__(self, app_image): + self.image = app_image + super(AppPalette, self).__init__((35, 35), 4, 5, margin=2) + self.selection = 0 + self.image.rect_color = pygame.color.Color(self.colors[self.selection]) + + def num_items(self): + return len(self.colors) + + def draw_item(self, surface, item_no, rect): + d = -2 * self.sel_width + r = rect.inflate(d, d) + surface.fill(pygame.color.Color(self.colors[item_no]), r) + + def click_item(self, item_no, event): + self.selection = item_no + self.image.rect_color = pygame.color.Color(self.colors[item_no]) + + def item_is_selected(self, item_no): + return self.selection == item_no + + +class AppImage(Widget): + + rect_thick = 3 + draw_thick = 1 + + def __init__(self, state): + self.state = state + super(AppImage, self).__init__(pygame.rect.Rect(0, 0, + constants.screen[0], + constants.screen[1])) + self.mode = 'draw' + self.rects = [] + self.images = [] + self.start_pos = None + self.end_pos = None + self.rect_color = pygame.color.Color('white') + self.current_image = None + self.place_image_menu = None + self.close_button = BoomLabel('Close', font=get_font(20, 'Vera.ttf')) + self.close_button.fg_color = (0, 0, 0) + self.close_button.bg_color = (0, 0, 0) + self.draw_rects = True + self.draw_things = True + self.draw_thing_rects = True + self.draw_images = True + self.trans_images = False + self.draw_toolbar = True + self.old_mouse_pos = None + self.zoom_display = False + self.draw_anim = False + self.zoom_offset = (600, 600) + if self.state.current_detail: + w, h = self.state.current_detail.get_detail_size() + rect = pygame.rect.Rect(0, 0, w, h) + self.close_button.rect.midbottom = rect.midbottom + self.offset = (0, 0) + else: + self.offset = (-self.state.current_scene.OFFSET[0], + -self.state.current_scene.OFFSET[1]) + self.find_existing_intersects() + + def _get_scene(self): + if self.state.current_detail: + return self.state.current_detail + else: + return self.state.current_scene + + def find_existing_intersects(self): + """Parse the things in the scene for overlaps""" + scene = self._get_scene() + # Pylint hates this function + for thing in scene.things.itervalues(): + for interact_name in thing.interacts: + thing.set_interact(interact_name) + if hasattr(thing.rect, 'collidepoint'): + thing_rects = [thing.rect] + else: + thing_rects = thing.rect + for thing2 in scene.things.itervalues(): + if thing is thing2: + continue + for interact2_name in thing2.interacts: + thing2.set_interact(interact2_name) + if hasattr(thing2.rect, 'collidepoint'): + thing2_rects = [thing2.rect] + else: + thing2_rects = thing2.rect + for my_rect in thing_rects: + for other_rect in thing2_rects: + if my_rect.colliderect(other_rect): + print 'Existing Intersecting rects' + print (" Thing1 %s Interact %s" + % (thing.name, interact_name)) + print (" Thing2 %s Interact %s" + % (thing2.name, interact2_name)) + print " Rects", my_rect, other_rect + print + + def find_intersecting_rects(self, d): + """Find if any rect collections intersect""" + # I loath N^X brute search algorithm's, but whatever, hey + scene = self._get_scene() + for (num, col) in enumerate(d): + rect_list = d[col] + for thing in scene.things.itervalues(): + for interact_name in thing.interacts: + thing.set_interact(interact_name) + if hasattr(thing.rect, 'collidepoint'): + thing_rects = [thing.rect] + else: + thing_rects = thing.rect + for other_rect in thing_rects: + for my_rect in rect_list: + if my_rect.colliderect(other_rect): + print 'Intersecting rects' + print " Object %s" % num + print (" Thing %s Interact %s" + % (thing.name, interact_name)) + print " Rects", my_rect, other_rect + if thing.INITIAL: + thing.set_interact(thing.INITIAL) + print + for (num2, col2) in enumerate(d): + if num2 == num: + continue + other_list = d[col2] + for my_rect in rect_list: + for other_rect in other_list: + if my_rect.colliderect(other_rect): + print 'Intersecting rects', + print ' Object %s and %s' % (num, num2) + print " Rects", my_rect, other_rect + print + print + + def toggle_things(self): + self.draw_things = not self.draw_things + + def toggle_thing_rects(self): + self.draw_thing_rects = not self.draw_thing_rects + scene = self._get_scene() + for thing in scene.things.itervalues(): + if not self.draw_thing_rects: + if not hasattr(thing, 'old_colour'): + thing.old_colour = thing._interact_hilight_color + thing._interact_hilight_color = None + else: + thing._interact_hilight_color = thing.old_colour + + def toggle_images(self): + self.draw_images = not self.draw_images + + def toggle_trans_images(self): + self.trans_images = not self.trans_images + self.invalidate() + + def toggle_rects(self): + self.draw_rects = not self.draw_rects + + def toggle_toolbar(self): + self.draw_toolbar = not self.draw_toolbar + + def toggle_zoom(self): + self.zoom_display = not self.zoom_display + + def toggle_anim(self): + self.draw_anim = not self.draw_anim + + def draw_mode(self): + self.mode = 'draw' + + def del_mode(self): + self.mode = 'del' + self.start_pos = None + self.end_pos = None + + def draw_sub_image(self, image, surface, cropped_rect): + """Tweaked image drawing to avoid albow's centring the image in the + subsurface""" + surf = pygame.surface.Surface((cropped_rect.w, cropped_rect.h), + SRCALPHA).convert_alpha() + frame = surf.get_rect() + imsurf = image.get_image().convert_alpha() + r = imsurf.get_rect() + r.topleft = frame.topleft + if self.trans_images: + surf.fill(pygame.color.Color(255, 255, 255, 96)) + surf.blit(imsurf, r, None, BLEND_RGBA_MIN) + else: + surf.blit(imsurf, r, None) + surface.blit(surf, cropped_rect) + + def draw(self, surface): + if self.zoom_display: + base_surface = surface.copy() + self.do_unzoomed_draw(base_surface) + zoomed = pygame.transform.scale(base_surface, + (constants.zoom * constants.screen[0], + constants.zoom * constants.screen[1])) + area = pygame.rect.Rect(self.zoom_offset[0], self.zoom_offset[1], + self.zoom_offset[0] + constants.screen[0], + self.zoom_offset[1] + constants.screen[1]) + surface.blit(zoomed, (0, 0), area) + else: + self.do_unzoomed_draw(surface) + + def do_unzoomed_draw(self, surface): + if self.state.current_detail: + if self.draw_things: + self.state.current_detail.draw(surface, None) + else: + self.state.current_detail.draw_background(surface) + # We duplicate Albow's draw logic here, so we zoom the close + # button correctly + r = self.close_button.get_rect() + surf_rect = surface.get_rect() + sub_rect = surf_rect.clip(r) + try: + sub = surface.subsurface(sub_rect) + self.close_button.draw_all(sub) + except ValueError, e: + print 'Error, failed to draw close button', e + else: + if self.draw_things: + self.state.current_scene.draw(surface, None) + else: + self.state.current_scene.draw_background(surface) + if self.mode == 'draw' and self.start_pos and self.draw_rects: + rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], + self.end_pos[0] - self.start_pos[0], + self.end_pos[1] - self.start_pos[1]) + rect.normalize() + frame_rect(surface, self.rect_color, rect, self.draw_thick) + if self.draw_rects: + for (col, rect) in self.rects: + frame_rect(surface, col, rect, self.rect_thick) + if self.draw_images: + for image in self.images: + if image.rect.colliderect(surface.get_rect()): + cropped_rect = image.rect.clip(surface.get_rect()) + self.draw_sub_image(image, surface, cropped_rect) + else: + print 'image outside surface', image + if self.current_image and self.mode == 'image': + if self.current_image.rect.colliderect(surface.get_rect()): + cropped_rect = self.current_image.rect.clip( + surface.get_rect()) + self.draw_sub_image(self.current_image, surface, + cropped_rect) + if self.draw_toolbar: + tb_surf = surface.subsurface(0, constants.screen[1] + - constants.button_size, + constants.screen[0], + constants.button_size).convert_alpha() + tb_surf.fill(pygame.color.Color(127, 0, 0, 191)) + surface.blit(tb_surf, (0, constants.screen[1] + - constants.button_size)) + + def _make_dict(self): + d = {} + for col, rect in self.rects: + col = (col.r, col.g, col.b) + d.setdefault(col, []) + d[col].append(rect) + return d + + def print_objs(self): + d = self._make_dict() + self.find_intersecting_rects(d) + for (num, col) in enumerate(d): + print 'Rect %d : ' % num + for rect in d[col]: + r = rect.move(self.offset) + print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) + print + for i, image in enumerate(self.images): + print 'Image %d' % i + rect = image.rect + r = rect.move(self.offset) + print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) + print + print + + def image_load(self): + image_path = ('%s/Resources/images/%s' + % (script_path, self.state.current_scene.FOLDER)) + imagename = request_old_filename(directory=image_path) + try: + image_data = pygame.image.load(imagename) + self.current_image = Image(image_data) + self.place_image_menu.enabled = True + # ensure we're off screen to start + self.current_image.rect = image_data.get_rect() \ + .move(constants.screen[0] + constants.menu_width, + constants.screen[1]) + except pygame.error, e: + print 'Unable to load image %s' % e + + def image_mode(self): + self.mode = 'image' + self.start_pos = None + self.end_pos = None + # So we do the right thing for off screen images + self.old_mouse_pos = None + + def cycle_mode(self): + self.mode = 'cycle' + + def _conv_pos(self, mouse_pos): + if self.zoom_display: + pos = ((mouse_pos[0] + self.zoom_offset[0]) / constants.zoom, + (mouse_pos[1] + self.zoom_offset[1]) / constants.zoom) + else: + pos = mouse_pos + return pos + + def _check_limits(self, offset): + if offset[0] < 0: + offset[0] = 0 + if offset[1] < 0: + offset[1] = 0 + width, height = constants.screen + if offset[0] > constants.zoom * width - width: + offset[0] = constants.zoom * width - width + if offset[1] > constants.zoom * height - height: + offset[1] = constants.zoom * height - height + + def _make_zoom_offset(self, pos): + zoom_pos = (pos[0] * constants.zoom, pos[1] * constants.zoom) + offset = [zoom_pos[0] - constants.screen[0] / 2, + zoom_pos[1] - constants.screen[1] / 2] + self._check_limits(offset) + self.zoom_offset = tuple(offset) + + def _move_zoom(self, x, y): + offset = list(self.zoom_offset) + offset[0] += constants.zoom_step * x + offset[1] += constants.zoom_step * y + self._check_limits(offset) + self.zoom_offset = tuple(offset) + + def do_mouse_move(self, e): + pos = self._conv_pos(e.pos) + if not self.zoom_display: + # Construct zoom offset from mouse pos + self._make_zoom_offset(e.pos) + if self.mode == 'image' and self.current_image: + if self.old_mouse_pos: + delta = (pos[0] - self.old_mouse_pos[0], + pos[1] - self.old_mouse_pos[1]) + self.current_image.rect.center = ( + self.current_image.rect.center[0] + delta[0], + self.current_image.rect.center[1] + delta[1]) + else: + self.current_image.rect.center = pos + self.invalidate() + self.old_mouse_pos = pos + + def key_down(self, e): + if self.mode == 'image' and self.current_image: + # Move the image by 1 pixel + cur_pos = self.current_image.rect.center + if e.key == K_LEFT: + self.current_image.rect.center = (cur_pos[0] - 1, cur_pos[1]) + elif e.key == K_RIGHT: + self.current_image.rect.center = (cur_pos[0] + 1, cur_pos[1]) + elif e.key == K_UP: + self.current_image.rect.center = (cur_pos[0], cur_pos[1] - 1) + elif e.key == K_DOWN: + self.current_image.rect.center = (cur_pos[0], cur_pos[1] + 1) + elif self.zoom_display: + if e.key == K_LEFT: + self._move_zoom(-1, 0) + elif e.key == K_RIGHT: + self._move_zoom(1, 0) + elif e.key == K_UP: + self._move_zoom(0, -1) + elif e.key == K_DOWN: + self._move_zoom(0, 1) + + if e.key == K_o: + self.toggle_trans_images() + elif e.key == K_t: + self.toggle_things() + elif e.key == K_r: + self.toggle_thing_rects() + elif e.key == K_i: + self.toggle_images() + elif e.key == K_d: + self.toggle_rects() + elif e.key == K_b: + self.toggle_toolbar() + elif e.key == K_z: + self.toggle_zoom() + elif e.key == K_a: + self.toggle_anim() + + def mouse_down(self, e): + pos = self._conv_pos(e.pos) + if self.mode == 'del': + cand = None + # Images are drawn above rectangles, so search those first + for image in self.images: + if image.rect.collidepoint(pos): + cand = image + break + if cand: + self.images.remove(cand) + self.invalidate() + return + for (col, rect) in self.rects: + if rect.collidepoint(pos): + cand = (col, rect) + break + if cand: + self.rects.remove(cand) + self.invalidate() + elif self.mode == 'cycle': + scene = self._get_scene() + cand = None + for thing in scene.things.itervalues(): + if thing.contains(pos): + cand = thing + break + if cand: + # Find current interacts in this thing + cur_interact = cand.current_interact + j = cand.interacts.values().index(cur_interact) + if j + 1 < len(cand.interacts): + next_name = cand.interacts.keys()[j + 1] + else: + next_name = cand.interacts.keys()[0] + if cand.interacts[next_name] != cur_interact: + cand.set_interact(next_name) + elif self.mode == 'draw': + self.start_pos = pos + self.end_pos = pos + elif self.mode == 'image': + if self.current_image: + self.images.append(self.current_image) + self.current_image = None + self.old_mouse_pos = None + self.invalidate() + else: + cand = None + for image in self.images: + if image.rect.collidepoint(e.pos): + cand = image + break + if cand: + self.images.remove(cand) + self.current_image = cand + # We want to move relative to the current mouse pos, so + self.old_mouse_pos = pos + self.invalidate() + + def mouse_up(self, e): + if self.mode == 'draw': + rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], + self.end_pos[0] - self.start_pos[0], + self.end_pos[1] - self.start_pos[1]) + rect.normalize() + self.rects.append((self.rect_color, rect)) + self.start_pos = self.end_pos = None + + def mouse_drag(self, e): + if self.mode == 'draw': + self.end_pos = self._conv_pos(e.pos) + self.invalidate() + + def animate(self): + if self.draw_anim: + if self.state.animate(): + self.invalidate() + + +class ModeLabel(BoomLabel): + + def __init__(self, app_image): + self.app_image = app_image + super(ModeLabel, self).__init__('Mode : ', 200, + font=get_font(15, 'VeraBd.ttf'), + fg_color=pygame.color.Color(128, 0, 255)) + self.rect.move_ip(805, 0) + + def draw_all(self, surface): + self.set_text('Mode : %s' % self.app_image.mode) + super(ModeLabel, self).draw_all(surface) + + +def make_button(text, action, ypos): + button = Button(text, action=action, font=get_font(15, 'VeraBd.ttf')) + button.align = 'l' + button.rect = pygame.rect.Rect(0, 0, constants.menu_width, + constants.menu_button_height) + button.rect.move_ip(805, ypos) + return button + + +class RectApp(RootWidget): + """Handle the app stuff for the rect drawer""" + + def __init__(self, display, get_initial_state, scene, detail): + super(RectApp, self).__init__(display) + pygame.key.set_repeat(200, 100) + state = get_initial_state() + state.set_current_scene(scene) + state.set_current_detail(detail) + state.do_check = None + + self.image = AppImage(state) + self.add(self.image) + mode_label = ModeLabel(self.image) + self.add(mode_label) + y = mode_label.get_rect().h + draw = make_button('Draw Rect', self.image.draw_mode, y) + self.add(draw) + y += draw.get_rect().h + load_image = make_button("Load image", self.image.image_load, y) + self.add(load_image) + y += load_image.get_rect().h + add_image = make_button("Place/Move images", self.image.image_mode, y) + add_image.enabled = False + self.add(add_image) + self.image.place_image_menu = add_image + y += add_image.get_rect().h + cycle = make_button("Cycle interacts", self.image.cycle_mode, y) + self.add(cycle) + y += cycle.get_rect().h + delete = make_button('Delete Objects', self.image.del_mode, y) + self.add(delete) + y += delete.get_rect().h + palette = AppPalette(self.image) + palette.rect.move_ip(810, y) + self.add(palette) + y += palette.get_rect().h + print_rects = make_button("Print objects", self.image.print_objs, y) + self.add(print_rects) + y += print_rects.get_rect().h + toggle_things = make_button("Show Things (t)", + self.image.toggle_things, y) + self.add(toggle_things) + y += toggle_things.get_rect().h + toggle_thing_rects = make_button("Show Thing Rects (r)", + self.image.toggle_thing_rects, y) + self.add(toggle_thing_rects) + y += toggle_thing_rects.get_rect().h + toggle_images = make_button("Show Images (i)", + self.image.toggle_images, y) + self.add(toggle_images) + y += toggle_images.get_rect().h + trans_images = make_button("Opaque Images (o)", + self.image.toggle_trans_images, y) + self.add(trans_images) + y += trans_images.get_rect().h + toggle_rects = make_button("Show Drawn Rects (d)", + self.image.toggle_rects, y) + self.add(toggle_rects) + y += toggle_rects.get_rect().h + toggle_toolbar = make_button("Show Toolbar (b)", + self.image.toggle_toolbar, y) + self.add(toggle_toolbar) + y += toggle_toolbar.get_rect().h + toggle_anim = make_button("Show Animations (a)", + self.image.toggle_anim, y) + self.add(toggle_anim) + y += toggle_anim.get_rect().h + toggle_zoom = make_button("Zoom (z)", self.image.toggle_zoom, y) + self.add(toggle_zoom) + y += toggle_zoom.get_rect().h + quit_but = make_button("Quit", self.quit, 570) + self.add(quit_but) + self.set_timer(constants.frame_rate) + + def key_down(self, event): + # Dispatch to image widget + self.image.key_down(event) + + def mouse_delta(self, event): + # We propogate mouse move from here to draw region, so images move + # off-screen + self.image.do_mouse_move(event) + + def begin_frame(self): + self.image.animate() + + +def make_rect_display(): + pygame.display.init() + pygame.font.init() + return pygame.display.set_mode((constants.screen[0] + + constants.menu_width, + constants.screen[1])) diff -r 0571deb177e9 -r ebc48b397fd5 pyntnclick/tools/utils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pyntnclick/tools/utils.py Sat Feb 11 17:07:52 2012 +0200 @@ -0,0 +1,12 @@ +# Misc utils I don't know where else to put + + +def list_scenes(get_initial_state): + """List the scenes in the state""" + state = get_initial_state() + print 'Available scenes are : ' + for scene in state.scenes: + print ' ', scene + print 'Available details are : ' + for detail in state.detail_views: + print ' ', detail diff -r 0571deb177e9 -r ebc48b397fd5 tools/gen_sound.py --- a/tools/gen_sound.py Sat Feb 11 17:04:59 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -# Generate 'perfect' sine wave sounds - -# Design notes: produces ~= (use requested) s raw CDDA audio - 44100 Hz -# 16 bit signed values -# Input is freq in Hz - 440 for A, etc. - must be an integer -# Output is written the file beep.pcm -# Convert to ogg with oggenc -r - -import sys -import math -import struct - -CDDA_RATE = 44100 -MAX = 105 * 256 # Max value for sine wave - - -def gen_sine(freq, secs): - filename = 'beep%s.pcm' % freq - # We need to generate freq cycles and sample that CDDA_RATE times - samples_per_cycle = CDDA_RATE / freq - data = [] - for x in range(samples_per_cycle): - rad = float(x) / samples_per_cycle * 2 * math.pi - y = MAX * math.sin(rad) - data.append(struct.pack(' []' - print ' where is the frequency in Hz (integer)' - print ' and [] is the time is seconds (float)' - -if __name__ == "__main__": - try: - freq = int(sys.argv[1]) - except Exception, exc: - usage() - print 'Error was: %s' % exc - sys.exit(1) - - if len(sys.argv) > 2: - try: - secs = float(sys.argv[2]) - except Exception, exc: - usage() - print 'Error was: %s' % exc - sys.exit(1) - else: - secs = 0.25 - output = gen_sine(freq, secs) - print 'Wrote sample to %s' % output diff -r 0571deb177e9 -r ebc48b397fd5 tools/rect_drawer.py --- a/tools/rect_drawer.py Sat Feb 11 17:04:59 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,672 +0,0 @@ -# Quickly hacked together helper for working out -# interactive regions in Suspended Sentence - -import sys -import os.path - -script_path = os.path.realpath(os.path.dirname(os.path.dirname(__file__))) -sys.path.append(script_path) - -from albow.root import RootWidget -from albow.utils import frame_rect -from albow.widget import Widget -from albow.controls import Button, Image -from albow.palette_view import PaletteView -from albow.file_dialogs import request_old_filename -from albow.resource import get_font -from pygame.locals import (K_LEFT, K_RIGHT, K_UP, K_DOWN, - K_a, K_t, K_d, K_i, K_r, K_o, K_b, K_z, - BLEND_RGBA_MIN, SRCALPHA) -import pygame - -import pyntnclick.constants -from pyntnclick import state -state.DEBUG_RECTS = True -from pyntnclick.widgets import BoomLabel - - -class RectDrawerConstants(pyntnclick.constants.GameConstants): - debug = True - menu_width = 200 - menu_button_height = 25 - zoom = 4 - zoom_step = 100 - -constants = RectDrawerConstants() - - -class AppPalette(PaletteView): - - sel_width = 5 - - colors = [ - 'red', 'maroon1', 'palevioletred1', 'moccasin', 'orange', - 'honeydew', 'yellow', 'gold', 'goldenrod', 'brown', - 'blue', 'purple', 'darkorchid4', 'thistle', 'skyblue1', - 'green', 'palegreen1', 'darkgreen', 'aquamarine', 'darkolivegreen', - ] - - def __init__(self, app_image): - self.image = app_image - super(AppPalette, self).__init__((35, 35), 4, 5, margin=2) - self.selection = 0 - self.image.rect_color = pygame.color.Color(self.colors[self.selection]) - - def num_items(self): - return len(self.colors) - - def draw_item(self, surface, item_no, rect): - d = -2 * self.sel_width - r = rect.inflate(d, d) - surface.fill(pygame.color.Color(self.colors[item_no]), r) - - def click_item(self, item_no, event): - self.selection = item_no - self.image.rect_color = pygame.color.Color(self.colors[item_no]) - - def item_is_selected(self, item_no): - return self.selection == item_no - - -class AppImage(Widget): - - rect_thick = 3 - draw_thick = 1 - - def __init__(self, state): - self.state = state - super(AppImage, self).__init__(pygame.rect.Rect(0, 0, - constants.screen[0], - constants.screen[1])) - self.mode = 'draw' - self.rects = [] - self.images = [] - self.start_pos = None - self.end_pos = None - self.rect_color = pygame.color.Color('white') - self.current_image = None - self.place_image_menu = None - self.close_button = BoomLabel('Close', font=get_font(20, 'Vera.ttf')) - self.close_button.fg_color = (0, 0, 0) - self.close_button.bg_color = (0, 0, 0) - self.draw_rects = True - self.draw_things = True - self.draw_thing_rects = True - self.draw_images = True - self.trans_images = False - self.draw_toolbar = True - self.old_mouse_pos = None - self.zoom_display = False - self.draw_anim = False - self.zoom_offset = (600, 600) - if self.state.current_detail: - w, h = self.state.current_detail.get_detail_size() - rect = pygame.rect.Rect(0, 0, w, h) - self.close_button.rect.midbottom = rect.midbottom - self.offset = (0, 0) - else: - self.offset = (-self.state.current_scene.OFFSET[0], - -self.state.current_scene.OFFSET[1]) - self.find_existing_intersects() - - def _get_scene(self): - if self.state.current_detail: - return self.state.current_detail - else: - return self.state.current_scene - - def find_existing_intersects(self): - """Parse the things in the scene for overlaps""" - scene = self._get_scene() - # Pylint hates this function - for thing in scene.things.itervalues(): - for interact_name in thing.interacts: - thing.set_interact(interact_name) - if hasattr(thing.rect, 'collidepoint'): - thing_rects = [thing.rect] - else: - thing_rects = thing.rect - for thing2 in scene.things.itervalues(): - if thing is thing2: - continue - for interact2_name in thing2.interacts: - thing2.set_interact(interact2_name) - if hasattr(thing2.rect, 'collidepoint'): - thing2_rects = [thing2.rect] - else: - thing2_rects = thing2.rect - for my_rect in thing_rects: - for other_rect in thing2_rects: - if my_rect.colliderect(other_rect): - print 'Existing Intersecting rects' - print (" Thing1 %s Interact %s" - % (thing.name, interact_name)) - print (" Thing2 %s Interact %s" - % (thing2.name, interact2_name)) - print " Rects", my_rect, other_rect - print - - def find_intersecting_rects(self, d): - """Find if any rect collections intersect""" - # I loath N^X brute search algorithm's, but whatever, hey - scene = self._get_scene() - for (num, col) in enumerate(d): - rect_list = d[col] - for thing in scene.things.itervalues(): - for interact_name in thing.interacts: - thing.set_interact(interact_name) - if hasattr(thing.rect, 'collidepoint'): - thing_rects = [thing.rect] - else: - thing_rects = thing.rect - for other_rect in thing_rects: - for my_rect in rect_list: - if my_rect.colliderect(other_rect): - print 'Intersecting rects' - print " Object %s" % num - print (" Thing %s Interact %s" - % (thing.name, interact_name)) - print " Rects", my_rect, other_rect - if thing.INITIAL: - thing.set_interact(thing.INITIAL) - print - for (num2, col2) in enumerate(d): - if num2 == num: - continue - other_list = d[col2] - for my_rect in rect_list: - for other_rect in other_list: - if my_rect.colliderect(other_rect): - print 'Intersecting rects', - print ' Object %s and %s' % (num, num2) - print " Rects", my_rect, other_rect - print - print - - def toggle_things(self): - self.draw_things = not self.draw_things - - def toggle_thing_rects(self): - self.draw_thing_rects = not self.draw_thing_rects - scene = self._get_scene() - for thing in scene.things.itervalues(): - if not self.draw_thing_rects: - if not hasattr(thing, 'old_colour'): - thing.old_colour = thing._interact_hilight_color - thing._interact_hilight_color = None - else: - thing._interact_hilight_color = thing.old_colour - - def toggle_images(self): - self.draw_images = not self.draw_images - - def toggle_trans_images(self): - self.trans_images = not self.trans_images - self.invalidate() - - def toggle_rects(self): - self.draw_rects = not self.draw_rects - - def toggle_toolbar(self): - self.draw_toolbar = not self.draw_toolbar - - def toggle_zoom(self): - self.zoom_display = not self.zoom_display - - def toggle_anim(self): - self.draw_anim = not self.draw_anim - - def draw_mode(self): - self.mode = 'draw' - - def del_mode(self): - self.mode = 'del' - self.start_pos = None - self.end_pos = None - - def draw_sub_image(self, image, surface, cropped_rect): - """Tweaked image drawing to avoid albow's centring the image in the - subsurface""" - surf = pygame.surface.Surface((cropped_rect.w, cropped_rect.h), - SRCALPHA).convert_alpha() - frame = surf.get_rect() - imsurf = image.get_image().convert_alpha() - r = imsurf.get_rect() - r.topleft = frame.topleft - if self.trans_images: - surf.fill(pygame.color.Color(255, 255, 255, 96)) - surf.blit(imsurf, r, None, BLEND_RGBA_MIN) - else: - surf.blit(imsurf, r, None) - surface.blit(surf, cropped_rect) - - def draw(self, surface): - if self.zoom_display: - base_surface = surface.copy() - self.do_unzoomed_draw(base_surface) - zoomed = pygame.transform.scale(base_surface, - (constants.zoom * constants.screen[0], - constants.zoom * constants.screen[1])) - area = pygame.rect.Rect(self.zoom_offset[0], self.zoom_offset[1], - self.zoom_offset[0] + constants.screen[0], - self.zoom_offset[1] + constants.screen[1]) - surface.blit(zoomed, (0, 0), area) - else: - self.do_unzoomed_draw(surface) - - def do_unzoomed_draw(self, surface): - if self.state.current_detail: - if self.draw_things: - self.state.current_detail.draw(surface, None) - else: - self.state.current_detail.draw_background(surface) - # We duplicate Albow's draw logic here, so we zoom the close - # button correctly - r = self.close_button.get_rect() - surf_rect = surface.get_rect() - sub_rect = surf_rect.clip(r) - try: - sub = surface.subsurface(sub_rect) - self.close_button.draw_all(sub) - except ValueError, e: - print 'Error, failed to draw close button', e - else: - if self.draw_things: - self.state.current_scene.draw(surface, None) - else: - self.state.current_scene.draw_background(surface) - if self.mode == 'draw' and self.start_pos and self.draw_rects: - rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], - self.end_pos[0] - self.start_pos[0], - self.end_pos[1] - self.start_pos[1]) - rect.normalize() - frame_rect(surface, self.rect_color, rect, self.draw_thick) - if self.draw_rects: - for (col, rect) in self.rects: - frame_rect(surface, col, rect, self.rect_thick) - if self.draw_images: - for image in self.images: - if image.rect.colliderect(surface.get_rect()): - cropped_rect = image.rect.clip(surface.get_rect()) - self.draw_sub_image(image, surface, cropped_rect) - else: - print 'image outside surface', image - if self.current_image and self.mode == 'image': - if self.current_image.rect.colliderect(surface.get_rect()): - cropped_rect = self.current_image.rect.clip( - surface.get_rect()) - self.draw_sub_image(self.current_image, surface, - cropped_rect) - if self.draw_toolbar: - tb_surf = surface.subsurface(0, constants.screen[1] - - constants.button_size, - constants.screen[0], - constants.button_size).convert_alpha() - tb_surf.fill(pygame.color.Color(127, 0, 0, 191)) - surface.blit(tb_surf, (0, constants.screen[1] - - constants.button_size)) - - def _make_dict(self): - d = {} - for col, rect in self.rects: - col = (col.r, col.g, col.b) - d.setdefault(col, []) - d[col].append(rect) - return d - - def print_objs(self): - d = self._make_dict() - self.find_intersecting_rects(d) - for (num, col) in enumerate(d): - print 'Rect %d : ' % num - for rect in d[col]: - r = rect.move(self.offset) - print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) - print - for i, image in enumerate(self.images): - print 'Image %d' % i - rect = image.rect - r = rect.move(self.offset) - print ' (%d, %d, %d, %d),' % (r.x, r.y, r.w, r.h) - print - print - - def image_load(self): - image_path = ('%s/Resources/images/%s' - % (script_path, self.state.current_scene.FOLDER)) - imagename = request_old_filename(directory=image_path) - try: - image_data = pygame.image.load(imagename) - self.current_image = Image(image_data) - self.place_image_menu.enabled = True - # ensure we're off screen to start - self.current_image.rect = image_data.get_rect() \ - .move(constants.screen[0] + constants.menu_width, - constants.screen[1]) - except pygame.error, e: - print 'Unable to load image %s' % e - - def image_mode(self): - self.mode = 'image' - self.start_pos = None - self.end_pos = None - # So we do the right thing for off screen images - self.old_mouse_pos = None - - def cycle_mode(self): - self.mode = 'cycle' - - def _conv_pos(self, mouse_pos): - if self.zoom_display: - pos = ((mouse_pos[0] + self.zoom_offset[0]) / constants.zoom, - (mouse_pos[1] + self.zoom_offset[1]) / constants.zoom) - else: - pos = mouse_pos - return pos - - def _check_limits(self, offset): - if offset[0] < 0: - offset[0] = 0 - if offset[1] < 0: - offset[1] = 0 - width, height = constants.screen - if offset[0] > constants.zoom * width - width: - offset[0] = constants.zoom * width - width - if offset[1] > constants.zoom * height - height: - offset[1] = constants.zoom * height - height - - def _make_zoom_offset(self, pos): - zoom_pos = (pos[0] * constants.zoom, pos[1] * constants.zoom) - offset = [zoom_pos[0] - constants.screen[0] / 2, - zoom_pos[1] - constants.screen[1] / 2] - self._check_limits(offset) - self.zoom_offset = tuple(offset) - - def _move_zoom(self, x, y): - offset = list(self.zoom_offset) - offset[0] += constants.zoom_step * x - offset[1] += constants.zoom_step * y - self._check_limits(offset) - self.zoom_offset = tuple(offset) - - def do_mouse_move(self, e): - pos = self._conv_pos(e.pos) - if not self.zoom_display: - # Construct zoom offset from mouse pos - self._make_zoom_offset(e.pos) - if self.mode == 'image' and self.current_image: - if self.old_mouse_pos: - delta = (pos[0] - self.old_mouse_pos[0], - pos[1] - self.old_mouse_pos[1]) - self.current_image.rect.center = ( - self.current_image.rect.center[0] + delta[0], - self.current_image.rect.center[1] + delta[1]) - else: - self.current_image.rect.center = pos - self.invalidate() - self.old_mouse_pos = pos - - def key_down(self, e): - if self.mode == 'image' and self.current_image: - # Move the image by 1 pixel - cur_pos = self.current_image.rect.center - if e.key == K_LEFT: - self.current_image.rect.center = (cur_pos[0] - 1, cur_pos[1]) - elif e.key == K_RIGHT: - self.current_image.rect.center = (cur_pos[0] + 1, cur_pos[1]) - elif e.key == K_UP: - self.current_image.rect.center = (cur_pos[0], cur_pos[1] - 1) - elif e.key == K_DOWN: - self.current_image.rect.center = (cur_pos[0], cur_pos[1] + 1) - elif self.zoom_display: - if e.key == K_LEFT: - self._move_zoom(-1, 0) - elif e.key == K_RIGHT: - self._move_zoom(1, 0) - elif e.key == K_UP: - self._move_zoom(0, -1) - elif e.key == K_DOWN: - self._move_zoom(0, 1) - - if e.key == K_o: - self.toggle_trans_images() - elif e.key == K_t: - self.toggle_things() - elif e.key == K_r: - self.toggle_thing_rects() - elif e.key == K_i: - self.toggle_images() - elif e.key == K_d: - self.toggle_rects() - elif e.key == K_b: - self.toggle_toolbar() - elif e.key == K_z: - self.toggle_zoom() - elif e.key == K_a: - self.toggle_anim() - - def mouse_down(self, e): - pos = self._conv_pos(e.pos) - if self.mode == 'del': - cand = None - # Images are drawn above rectangles, so search those first - for image in self.images: - if image.rect.collidepoint(pos): - cand = image - break - if cand: - self.images.remove(cand) - self.invalidate() - return - for (col, rect) in self.rects: - if rect.collidepoint(pos): - cand = (col, rect) - break - if cand: - self.rects.remove(cand) - self.invalidate() - elif self.mode == 'cycle': - scene = self._get_scene() - cand = None - for thing in scene.things.itervalues(): - if thing.contains(pos): - cand = thing - break - if cand: - # Find current interacts in this thing - cur_interact = cand.current_interact - j = cand.interacts.values().index(cur_interact) - if j + 1 < len(cand.interacts): - next_name = cand.interacts.keys()[j + 1] - else: - next_name = cand.interacts.keys()[0] - if cand.interacts[next_name] != cur_interact: - cand.set_interact(next_name) - elif self.mode == 'draw': - self.start_pos = pos - self.end_pos = pos - elif self.mode == 'image': - if self.current_image: - self.images.append(self.current_image) - self.current_image = None - self.old_mouse_pos = None - self.invalidate() - else: - cand = None - for image in self.images: - if image.rect.collidepoint(e.pos): - cand = image - break - if cand: - self.images.remove(cand) - self.current_image = cand - # We want to move relative to the current mouse pos, so - self.old_mouse_pos = pos - self.invalidate() - - def mouse_up(self, e): - if self.mode == 'draw': - rect = pygame.rect.Rect(self.start_pos[0], self.start_pos[1], - self.end_pos[0] - self.start_pos[0], - self.end_pos[1] - self.start_pos[1]) - rect.normalize() - self.rects.append((self.rect_color, rect)) - self.start_pos = self.end_pos = None - - def mouse_drag(self, e): - if self.mode == 'draw': - self.end_pos = self._conv_pos(e.pos) - self.invalidate() - - def animate(self): - if self.draw_anim: - if self.state.animate(): - self.invalidate() - - -class ModeLabel(BoomLabel): - - def __init__(self, app_image): - self.app_image = app_image - super(ModeLabel, self).__init__('Mode : ', 200, - font=get_font(15, 'VeraBd.ttf'), - fg_color=pygame.color.Color(128, 0, 255)) - self.rect.move_ip(805, 0) - - def draw_all(self, surface): - self.set_text('Mode : %s' % self.app_image.mode) - super(ModeLabel, self).draw_all(surface) - - -def make_button(text, action, ypos): - button = Button(text, action=action, font=get_font(15, 'VeraBd.ttf')) - button.align = 'l' - button.rect = pygame.rect.Rect(0, 0, constants.menu_width, - constants.menu_button_height) - button.rect.move_ip(805, ypos) - return button - - -class RectApp(RootWidget): - """Handle the app stuff for the rect drawer""" - - def __init__(self, display): - super(RectApp, self).__init__(display) - self.image = AppImage(state) - self.add(self.image) - mode_label = ModeLabel(self.image) - self.add(mode_label) - y = mode_label.get_rect().h - draw = make_button('Draw Rect', self.image.draw_mode, y) - self.add(draw) - y += draw.get_rect().h - load_image = make_button("Load image", self.image.image_load, y) - self.add(load_image) - y += load_image.get_rect().h - add_image = make_button("Place/Move images", self.image.image_mode, y) - add_image.enabled = False - self.add(add_image) - self.image.place_image_menu = add_image - y += add_image.get_rect().h - cycle = make_button("Cycle interacts", self.image.cycle_mode, y) - self.add(cycle) - y += cycle.get_rect().h - delete = make_button('Delete Objects', self.image.del_mode, y) - self.add(delete) - y += delete.get_rect().h - palette = AppPalette(self.image) - palette.rect.move_ip(810, y) - self.add(palette) - y += palette.get_rect().h - print_rects = make_button("Print objects", self.image.print_objs, y) - self.add(print_rects) - y += print_rects.get_rect().h - toggle_things = make_button("Show Things (t)", - self.image.toggle_things, y) - self.add(toggle_things) - y += toggle_things.get_rect().h - toggle_thing_rects = make_button("Show Thing Rects (r)", - self.image.toggle_thing_rects, y) - self.add(toggle_thing_rects) - y += toggle_thing_rects.get_rect().h - toggle_images = make_button("Show Images (i)", - self.image.toggle_images, y) - self.add(toggle_images) - y += toggle_images.get_rect().h - trans_images = make_button("Opaque Images (o)", - self.image.toggle_trans_images, y) - self.add(trans_images) - y += trans_images.get_rect().h - toggle_rects = make_button("Show Drawn Rects (d)", - self.image.toggle_rects, y) - self.add(toggle_rects) - y += toggle_rects.get_rect().h - toggle_toolbar = make_button("Show Toolbar (b)", - self.image.toggle_toolbar, y) - self.add(toggle_toolbar) - y += toggle_toolbar.get_rect().h - toggle_anim = make_button("Show Animations (a)", - self.image.toggle_anim, y) - self.add(toggle_anim) - y += toggle_anim.get_rect().h - toggle_zoom = make_button("Zoom (z)", self.image.toggle_zoom, y) - self.add(toggle_zoom) - y += toggle_zoom.get_rect().h - quit_but = make_button("Quit", self.quit, 570) - self.add(quit_but) - self.set_timer(constants.frame_rate) - - def key_down(self, event): - # Dispatch to image widget - self.image.key_down(event) - - def mouse_delta(self, event): - # We propogate mouse move from here to draw region, so images move - # off-screen - self.image.do_mouse_move(event) - - def begin_frame(self): - self.image.animate() - - -def list_scenes(state): - """List the scenes in the state""" - print 'Available scenes are : ' - for scene in state.scenes: - print ' ', scene - print 'Available details are : ' - for detail in state.detail_views: - print ' ', detail - -if __name__ == "__main__": - pygame.display.init() - pygame.font.init() - display = pygame.display.set_mode((constants.screen[0] - + constants.menu_width, - constants.screen[1])) - state = state.initial_state() - if len(sys.argv) < 2: - print 'Please provide a scene name or scene and detail names' - list_scenes(state) - sys.exit(0) - # enable key repeating - pygame.key.set_repeat(200, 100) - if len(sys.argv) < 3: - try: - state.set_current_scene(sys.argv[1]) - state.do_check = None - except KeyError: - print 'Invalid scene name' - list_scenes(state) - sys.exit(1) - else: - try: - state.set_current_scene(sys.argv[1]) - state.set_current_detail(sys.argv[2]) - state.do_check = None - except KeyError: - print 'Invalid scene or detail name' - list_scenes(state) - sys.exit(1) - app = RectApp(display) - app.run()