Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First commit

  • Loading branch information...
commit 7bbf61c295f5d38a405f05c25f6048b43f0ba8a8 0 parents
@Halfwake authored
Showing with 46,659 additions and 0 deletions.
  1. +100 −0 BigPackages.py
  2. +6 −0 README.txt
  3. BIN  avbin.dll
  4. +21 −0 button.py
  5. +67 −0 char.py
  6. +30 −0 config.py
  7. +96 −0 credit.py
  8. +226 −0 game.py
  9. +100 −0 main.py
  10. +46 −0 menu.py
  11. +24 −0 messenger.py
  12. +362 −0 pyglet/__init__.py
  13. BIN  pyglet/__init__.pyc
  14. +297 −0 pyglet/app/__init__.py
  15. BIN  pyglet/app/__init__.pyc
  16. +144 −0 pyglet/app/carbon.py
  17. BIN  pyglet/app/carbon.pyc
  18. +106 −0 pyglet/app/win32.py
  19. BIN  pyglet/app/win32.pyc
  20. +98 −0 pyglet/app/xlib.py
  21. BIN  pyglet/app/xlib.pyc
  22. +949 −0 pyglet/clock.py
  23. BIN  pyglet/clock.pyc
  24. +154 −0 pyglet/com.py
  25. BIN  pyglet/com.pyc
  26. +437 −0 pyglet/event.py
  27. BIN  pyglet/event.pyc
  28. +694 −0 pyglet/font/__init__.py
  29. BIN  pyglet/font/__init__.pyc
  30. +442 −0 pyglet/font/base.py
  31. BIN  pyglet/font/base.pyc
  32. +437 −0 pyglet/font/carbon.py
  33. BIN  pyglet/font/carbon.pyc
  34. +354 −0 pyglet/font/freetype.py
  35. BIN  pyglet/font/freetype.pyc
  36. +427 −0 pyglet/font/freetype_lib.py
  37. BIN  pyglet/font/freetype_lib.pyc
  38. +635 −0 pyglet/font/ttf.py
  39. BIN  pyglet/font/ttf.pyc
  40. +575 −0 pyglet/font/win32.py
  41. BIN  pyglet/font/win32.pyc
  42. +510 −0 pyglet/gl/__init__.py
  43. BIN  pyglet/gl/__init__.pyc
  44. +452 −0 pyglet/gl/agl.py
  45. BIN  pyglet/gl/agl.pyc
  46. +2,156 −0 pyglet/gl/gl.py
  47. BIN  pyglet/gl/gl.pyc
  48. +196 −0 pyglet/gl/gl_info.py
  49. BIN  pyglet/gl/gl_info.pyc
  50. +9,349 −0 pyglet/gl/glext_arb.py
  51. BIN  pyglet/gl/glext_arb.pyc
  52. +127 −0 pyglet/gl/glext_missing.py
  53. BIN  pyglet/gl/glext_missing.pyc
  54. +10,240 −0 pyglet/gl/glext_nv.py
  55. BIN  pyglet/gl/glext_nv.pyc
  56. +494 −0 pyglet/gl/glu.py
  57. BIN  pyglet/gl/glu.pyc
  58. +160 −0 pyglet/gl/glu_info.py
  59. BIN  pyglet/gl/glu_info.pyc
  60. +587 −0 pyglet/gl/glx.py
  61. BIN  pyglet/gl/glx.pyc
  62. +143 −0 pyglet/gl/glx_info.py
  63. BIN  pyglet/gl/glx_info.pyc
  64. +756 −0 pyglet/gl/glxext_arb.py
  65. BIN  pyglet/gl/glxext_arb.pyc
  66. +45 −0 pyglet/gl/glxext_mesa.py
  67. BIN  pyglet/gl/glxext_mesa.pyc
  68. +901 −0 pyglet/gl/glxext_nv.py
  69. BIN  pyglet/gl/glxext_nv.pyc
  70. +144 −0 pyglet/gl/lib.py
  71. BIN  pyglet/gl/lib.pyc
  72. +74 −0 pyglet/gl/lib_agl.py
  73. BIN  pyglet/gl/lib_agl.pyc
  74. +92 −0 pyglet/gl/lib_glx.py
  75. BIN  pyglet/gl/lib_glx.pyc
  76. +153 −0 pyglet/gl/lib_wgl.py
  77. BIN  pyglet/gl/lib_wgl.pyc
  78. +374 −0 pyglet/gl/wgl.py
  79. BIN  pyglet/gl/wgl.pyc
  80. +71 −0 pyglet/gl/wgl_info.py
  81. BIN  pyglet/gl/wgl_info.pyc
  82. +811 −0 pyglet/gl/wglext_arb.py
  83. BIN  pyglet/gl/wglext_arb.pyc
  84. +909 −0 pyglet/gl/wglext_nv.py
  85. BIN  pyglet/gl/wglext_nv.pyc
  86. +721 −0 pyglet/graphics/__init__.py
  87. BIN  pyglet/graphics/__init__.pyc
  88. +390 −0 pyglet/graphics/allocation.py
  89. BIN  pyglet/graphics/allocation.pyc
  90. +506 −0 pyglet/graphics/vertexattribute.py
  91. BIN  pyglet/graphics/vertexattribute.pyc
  92. +597 −0 pyglet/graphics/vertexbuffer.py
  93. BIN  pyglet/graphics/vertexbuffer.pyc
  94. +776 −0 pyglet/graphics/vertexdomain.py
  95. BIN  pyglet/graphics/vertexdomain.pyc
  96. +2,537 −0 pyglet/image/__init__.py
  97. BIN  pyglet/image/__init__.pyc
  98. +259 −0 pyglet/image/atlas.py
  99. BIN  pyglet/image/atlas.pyc
  100. +231 −0 pyglet/image/codecs/__init__.py
  101. BIN  pyglet/image/codecs/__init__.pyc
  102. +359 −0 pyglet/image/codecs/bmp.py
  103. BIN  pyglet/image/codecs/bmp.pyc
  104. +227 −0 pyglet/image/codecs/dds.py
  105. BIN  pyglet/image/codecs/dds.pyc
  106. +273 −0 pyglet/image/codecs/gdiplus.py
  107. BIN  pyglet/image/codecs/gdiplus.pyc
  108. +164 −0 pyglet/image/codecs/gdkpixbuf2.py
  109. BIN  pyglet/image/codecs/gdkpixbuf2.pyc
  110. +169 −0 pyglet/image/codecs/gif.py
  111. BIN  pyglet/image/codecs/gif.pyc
  112. +110 −0 pyglet/image/codecs/pil.py
  113. BIN  pyglet/image/codecs/pil.pyc
  114. +110 −0 pyglet/image/codecs/png.py
  115. BIN  pyglet/image/codecs/png.pyc
  116. +1,092 −0 pyglet/image/codecs/pypng.py
  117. BIN  pyglet/image/codecs/pypng.pyc
  118. +288 −0 pyglet/image/codecs/quicktime.py
  119. BIN  pyglet/image/codecs/quicktime.pyc
  120. +381 −0 pyglet/image/codecs/s3tc.py
  121. BIN  pyglet/image/codecs/s3tc.pyc
  122. +191 −0 pyglet/info.py
  123. BIN  pyglet/info.pyc
  124. +303 −0 pyglet/lib.py
  125. BIN  pyglet/lib.pyc
  126. +1,404 −0 pyglet/media/__init__.py
  127. BIN  pyglet/media/__init__.pyc
Sorry, we could not display the entire diff because it was too big.
100 BigPackages.py
@@ -0,0 +1,100 @@
+import pyglet
+import sys
+import os
+try: #This will install avbin if needed, and it works on windows and linux!
+ pyglet.resource.image("resources/art/background1.png")
+except:
+ if sys.platform.startswith("win"):
+ print "Error: avbin.dll not found."
+ quit()
+ elif sys.platform.startswith("linux"):
+ if sys.maxsize > 2 ** 32:
+ if os.system("avbin-linux-x86-64-7/install.sh") != 0:
+ print "You must install avbin manually by running the install.sh script in avbin-linux-x86-64-7."
+ quit()
+ else:
+ if os.system("avbin-linux-x86-32-7/install.sh") !=0:
+ print "You must install avbin manually by running the install.sh script in avbin-linux-x86-64-7."
+ quit()
+ elif sys.platform == "dawrwin":
+ #Note, osx doesn't work because the avbin devs don't care about it
+ #and left it in the dust. Just a small town OS living in a
+ #dangerious dog eat world. Lost it all at the gambling games.
+ #Working hard to fight the man. Didn't even really have a plan.
+ #But hey, man? You gotta work. Work. Work this out. Get ahead.
+ #You gotta work. Work. Work this out. Get ahead. Ah yeah!
+ raise "Error: This game is not supported on OSX."
+ os.system("avbin-darwin-universal-5/install.sh")
+import config
+import messenger
+import menu
+import game
+import credit
+import char
+import random
+
+
+MUSIC = {"JingleBellsA" : pyglet.media.load(r"resources\music\Jingle Bells.mp3"),
+ "JingleBellsB" : pyglet.media.load(r"resources\music\Jingle Bells 3.mp3"),
+ "OhChristmasTree" : pyglet.media.load(r"resources\music\Oh Xmas.mp3"),
+ "UpOnAHouseTop" : pyglet.media.load(r"resources\music\Up on a Housetop.mp3"),
+ "WeWishYou" : pyglet.media.load(r"resources\music\We Wish You.mp3"),
+ "Grinch1" : pyglet.media.load(r"resources\music\grinch.mp3"),
+ "Grinch2" : pyglet.media.load(r"resources\music\02-Grinch.mp3")}
+
+
+class Game(pyglet.window.Window):
+ def __init__(self, width, height):
+ messenger.Messenger.game = self
+ self.create_music_player()
+ self.fps_display = pyglet.clock.ClockDisplay()
+ pyglet.clock.set_fps_limit(90)
+ super(Game, self).__init__(width,
+ height,
+ vsync = False,
+ caption = "Big Packages")
+ self.mode_hash = {}
+ self.mode_hash["MenuScreen"] = menu.MenuScreen()
+ self.mode_hash["GameScreen"] = game.GameScreen()
+ self.mode_hash["CreditScreen"] = credit.CreditScreen()
+ self.mode_hash["CharScreen"] = char.CharScreen()
+ #TESTING PURPOSES
+ self.mode = self.mode_hash["MenuScreen"]
+ #self.mode = self.mode_hash["GameScreen"]
+ #TESTING PURPOSES
+ def create_music_player(self):
+ "Creates a music player and loads all the fun christmas music on it."
+ self.music_player = pyglet.media.Player()
+ #self.music_player.eos_action = "loop" #disabling looping
+ music_list = []
+ for key in MUSIC:
+ item = MUSIC[key]
+ music_list.append(item)
+ random.shuffle(music_list)
+ for song in music_list:
+ self.music_player.queue(song)
+ self.music_player.play()
+ pyglet.clock.schedule_interval(lambda dt : self.music_player.play(), 2.0)
+ def on_draw(self):
+ self.clear()
+ self.mode.on_draw()
+ #self.fps_display.draw() #FPS should not be displayed during normal gameplay
+ def on_key_press(self, symbol, modifiers):
+ self.mode.on_key_press(symbol, modifiers)
+ def on_key_release(self, symbol, modifiers):
+ self.mode.on_key_release(symbol, modifiers)
+ def on_mouse_motion(self, x, y, dx, dy):
+ self.mode.on_mouse_motion(x, y, dx, dy)
+ def on_mouse_press(self, x, y, button, modifiers):
+ self.mode.on_mouse_press(x, y, button, modifiers)
+ def on_mouse_release(self, x, y, button, modifiers):
+ self.mode.on_mouse_release(x, y, button, modifiers)
+ def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
+ self.mode.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
+ def on_close(self):
+ self.music_player.pause()
+ self.music_player = None
+ super(Game, self).on_close()
+if __name__ == "__main__":
+ root = Game(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)
+ pyglet.app.run()
6 README.txt
@@ -0,0 +1,6 @@
+Non-Grinch Music: Kevin MacLeod
+Grinch Music: http://www.dilandau.eu
+Sound Effects: Soundjay
+
+Mouse for menu navigation
+wasd to move
BIN  avbin.dll
Binary file not shown
21 button.py
@@ -0,0 +1,21 @@
+import pyglet
+import config
+
+IMAGES = {}
+
+class Button(pyglet.sprite.Sprite):
+ "A sprite that reacts when clicked."
+ def __init__(self, image, x, y, text = None):
+ super(Button, self).__init__(image)
+ #The following text part needs work.
+## if text:
+## self.text = pyglet.text.label(text)
+ self.x = x
+ self.y = y
+ self.command = lambda : None
+ def click(self, x, y):
+ if self.x < x < self.x + self.width:
+ if self.y < y < self.y + self.height:
+ self.command()
+
+
67 char.py
@@ -0,0 +1,67 @@
+import pyglet
+import screen
+import messenger
+import button
+import config
+import text
+
+SPRITE_SHEET_MERGED = pyglet.image.load(r"resources/art/sprite_sheet.png") #Non-divided sprite_sheet
+SPRITE_SHEET_DIVIDED = pyglet.image.ImageGrid(SPRITE_SHEET_MERGED, 8, 8) #Divided sprite_sheet
+
+IMAGES = {}
+IMAGES["background"] = pyglet.image.load(r"resources/art/background1.png")
+IMAGES["menu_button"] = pyglet.image.load(r"resources/art/menu_button.png")
+IMAGES["tiber"] = SPRITE_SHEET_DIVIDED[63]
+IMAGES["gwen"] = SPRITE_SHEET_DIVIDED[62]
+
+class CharScreen(screen.AbstractScreen):
+ def __init__(self):
+ messenger.Messenger.charScreen = self
+ self.background = IMAGES["background"]
+ self.font_size = 30
+ self.make_descriptions()
+ self.menu_button = button.Button(image = IMAGES["menu_button"],
+ x = 40,
+ y = 40)
+ self.menu_button.command = lambda : messenger.Messenger.change_mode("MenuScreen")
+ def on_draw(self):
+ self.background.blit(0,0)
+ self.menu_button.draw()
+ self.tiber.draw()
+ self.tiber_descript.draw()
+ self.gwen.draw()
+ self.gwen_descript.draw()
+ def on_mouse_press(self, x, y, button, modifiers):
+ self.menu_button.click(x, y)
+ def make_descriptions(self):
+ self.tiber = button.Button(image = IMAGES["tiber"],
+ x = 25,
+ y = 450)
+ self.tiber.scale = 4.0
+ self.tiber_descript = text.TextBox(x = 100,
+ y = 550,
+ font_name = config.FONT_TYPE,
+ font_size = self.font_size,
+ color = (0, 0, 0, 255),
+ text = """
+A greedy elf warrior, in spite
+of Tiberius's Christmas spirit
+he was doomed to a life of
+no presents. Now he returns
+for his rightful tribute.""")
+
+ self.gwen = button.Button(image = IMAGES["gwen"],
+ x = 25,
+ y = 175)
+ self.gwen.scale = 4.0
+ self.gwen_descript = text.TextBox(x = 100,
+ y = 300,
+ font_name = config.FONT_TYPE,
+ font_size = self.font_size,
+ color = (0, 0, 0, 255),
+ text = """
+Gwendayln was once
+a promissing young
+snowmancer until
+she turned rotten
+with greed.""")
30 config.py
@@ -0,0 +1,30 @@
+"A file for storing configuration text. It's easier than parsing a text file."
+FONT_TYPE = "Arial"
+
+SCREEN_WIDTH = 800
+SCREEN_HEIGHT = 600
+
+START_SCORE = 0
+START_LIVES = 3
+
+START_PRESENT_SIZE = 5.0
+PRESENT_SIZE_INCREMENT = 0.5
+MIN_PRESENT_SIZE = 0.3
+
+START_PRESENT_AMOUNT = 3
+PRESENT_AMOUNT_INCREMENT = 2
+
+START_PRESENT_WORTH = 5
+PRESENT_WORTH_INCREMENT = 10
+
+PLAYER_START = (100,100)
+
+PLAYER_START_SPEED = 10
+PLAYER_SPEED_INCREMENT = 20
+MAX_PLAYER_SPEED = 300
+
+START_TIME = 30
+START_TIME += 2 #For some reason it starts with two seconds off
+TIME_INCREMENT = 2
+
+PLAYER_STEPS = 100
96 credit.py
@@ -0,0 +1,96 @@
+import pyglet
+import screen
+import button
+import messenger
+import config
+import text
+
+IMAGES = {}
+IMAGES["background"] = pyglet.image.load(r"resources/art/background1.png")
+IMAGES["menu_button"] = pyglet.image.load(r"resources/art/menu_button.png")
+
+class CreditScreen(screen.AbstractScreen):
+ def __init__(self):
+ messenger.Messenger.creditScreen = self
+ self.font_size = 40
+ self.color = (0, 0, 0, 255)
+ self.background = IMAGES["background"]
+ self.make_buttons()
+ self.make_labels()
+ def on_draw(self):
+ self.background.blit(0, 0)
+ self.menu_button.draw()
+ self.score_label.draw()
+ self.score_comment.draw()
+ def make_score_comment(self):
+ score = messenger.Messenger.gameScreen.score
+ if score == 0:
+ _text = """
+This is the only easter egg
+in the game, you truly
+understand the Christmas spirit.
+THANKS FOR PLAYING!"""
+ elif score < 500:
+ _text = """
+Did you even try? At this rate
+you'll never get that white
+iPhone!"""
+ elif score < 2000:
+ _text = """
+A decent amount of kids won't
+be getting parents this year,
+you bastard."""
+ elif score < 5000:
+ _text = """
+You have a fair portion of
+toys, but even with so many
+childhood dreams ruined...
+You really have not made an
+impact on a global scale."""
+ elif messenger.Messenger.score < 6000:
+ _text = """
+You're colder than Jack Frost.
+Thanks for ruining Christmas,
+asshole."""
+ elif messenger.Messenger.score < 7000:
+ _text = """
+There. Are. No. Presents. Left."""
+ elif messenger.Messenger.score < 8000:
+ _text = """
+If you cheat you get put on
+the naughty list. You know
+that, right?"""
+ else:
+ _text = """
+Stop. Messing. With. The.
+Config. File. You. Asshat."""
+
+ self.score_comment = text.TextBox(font_name = config.FONT_TYPE,
+ font_size = self.font_size,
+ text = _text,
+ color = self.color,
+ x = 25,
+ y = config.SCREEN_HEIGHT - 50)
+ def on_mouse_press(self, x, y, button, modifiers):
+ self.menu_button.click(x, y)
+ def make_labels(self):
+ self.score_label = pyglet.text.Label(text = "Final Score: %d" % 0,
+ font_name = config.FONT_TYPE,
+ font_size = self.font_size,
+ x = config.SCREEN_WIDTH / 4,
+ y = config.SCREEN_HEIGHT / 2,
+ color = self.color)
+ self.score_label.x -= 175 #Hard coded offset
+ self.score_comment = text.TextBox(font_name = config.FONT_TYPE,
+ font_size = self.font_size,
+ text = "If this text appears the developer is retarded.",
+ color = self.color,
+ x = config.SCREEN_WIDTH / 4,
+ y = config.SCREEN_HEIGHT / 4 * 2)
+ def make_buttons(self):
+ self.menu_button = button.Button(image = IMAGES["menu_button"],
+ x = config.SCREEN_WIDTH / 4,
+ y = config.SCREEN_HEIGHT / 4)
+ self.menu_button.x -= self.menu_button.width / 2
+ self.menu_button.y -= self.menu_button.height / 2
+ self.menu_button.command = lambda : messenger.Messenger.change_mode("MenuScreen")
226 game.py
@@ -0,0 +1,226 @@
+import pyglet
+import config
+import messenger
+import random
+import screen
+from pyglet.gl import * #Neccesary to prevent linear scaling
+
+SPRITE_SHEET_MERGED = pyglet.image.load(r"resources/art/sprite_sheet.png") #Non-divided sprite_sheet
+SPRITE_SHEET_DIVIDED = pyglet.image.ImageGrid(SPRITE_SHEET_MERGED, 8, 8) #Divided sprite_sheet
+IMAGES = {} #A hash of all the images in the game with the appropriate names
+PLAYER_IMAGES = [SPRITE_SHEET_DIVIDED[63],
+ SPRITE_SHEET_DIVIDED[62]]
+PRESENT_IMAGES = [SPRITE_SHEET_DIVIDED[56],
+ SPRITE_SHEET_DIVIDED[57],
+ SPRITE_SHEET_DIVIDED[58]]
+
+SOUNDS = {}
+SOUNDS["beep"] = pyglet.media.load(r"resources/music/bell-ring-01.mp3", streaming = False)
+SOUNDS["end"] = pyglet.media.load(r"resources/music/bell-ringing-01.mp3", streaming = False)
+SOUNDS["crumple"] = pyglet.media.load(r"resources/music/paper-rustle-8.mp3", streaming = False)
+BACKGROUND_IMAGES = [pyglet.image.load(r"resources/art/background1.png"),
+ pyglet.image.load(r"resources/art/background2.png"),
+ pyglet.image.load(r"resources/art/background3.png"),
+ pyglet.image.load(r"resources/art/background4.png")]
+
+class GameScreen(screen.AbstractScreen):
+ "Screen describing the actual game part of the game."
+ def __init__(self):
+ messenger.Messenger.gameScreen = self
+ self.background = random.choice(BACKGROUND_IMAGES)
+ self.player = Player()
+ self.time_amount = config.START_TIME
+ self.time = self.time_amount
+ self.lives = config.START_LIVES
+ self.score = config.START_SCORE
+ self.keys = set() #A set containg currently held down keys
+ self.present_size = config.START_PRESENT_SIZE
+ self.present_amount = config.START_PRESENT_AMOUNT
+ self.present_worth = config.START_PRESENT_WORTH
+ self.presents = [] #total list of current presents
+ self.labels = {}
+ self.present_batch = pyglet.graphics.Batch()
+ self.create_labels()
+ self.spawn_presents()
+ self.lambdas = [] #keeps a list of functions to schedule and unschedule
+ def start_updates(self):
+ "Begins scheduling 'GameScreen' updates and saving them for unscheduling."
+ lambdas = [(lambda dt : self.collect_present(), 0.05),
+ (lambda dt : self.player.move(dt, self.keys), 0.05),
+ (lambda dt : self.back_to_screen(), 0.01),
+ (lambda dt : self.self_update_labels(), 0.05),
+ (lambda dt : self.update_time(), 1.0)]
+ for _lambda in lambdas:
+ self.lambdas.append(_lambda)
+ pyglet.clock.schedule_interval(_lambda[0], _lambda[1])
+ def end_updates(self):
+ "Unschedules all 'GameScreen' updates."
+ for _lambda in self.lambdas: pyglet.clock.unschedule(_lambda[0])
+ def update_time(self):
+ self.time -= 1
+ if self.time < 0:
+ SOUNDS["end"].play()
+ messenger.Messenger.change_mode("CreditScreen")
+ elif self.time < 10:
+ self.labels["timer"].color = (0, 0, 0, 255)
+ pyglet.clock.schedule_once(lambda dt: SOUNDS["beep"].play(), 0.01)
+ elif self.time < 5:
+ self.labels["timer"].color = (0, 0, 0, 255)
+ pyglet.clock.schedule_once(lambda dt: SOUNDS["beep"].play(), 0.01)
+ pyglet.clock.schedule_once(lambda dt: SOUNDS["beep"].play(), 0.5)
+ def self_update_labels(self):
+ self.labels["timer"].text = "%.2f" % self.time
+ self.labels["score"].text = "Score: %d" % self.score
+ def create_labels(self):
+ font_size = 60
+ self.labels["score"] = pyglet.text.Label(text = "Score: %d" % self.score,
+ font_name = config.FONT_TYPE,
+ font_size = font_size,
+ y = config.SCREEN_HEIGHT - font_size)
+ self.labels["timer"] = pyglet.text.Label(text = "%.2f" % self.time,
+ font_name = config.FONT_TYPE,
+ font_size = font_size,
+ y = config.SCREEN_HEIGHT - font_size * 2)
+ def back_to_screen(self):
+ if self.player.x + self.player.width > config.SCREEN_WIDTH:
+ self.player.x = config.SCREEN_WIDTH - self.player.width
+ if self.player.x < 0:
+ self.player.x = 0
+ if self.player.y + self.player.height > config.SCREEN_HEIGHT:
+ self.player.y = config.SCREEN_HEIGHT - self.player.height
+ if self.player.y < 0:
+ self.player.y = 0
+ def on_key_press(self, symbol, modifiers):
+ "Adds keys to set of currently held down keys."
+ self.keys.add(symbol)
+ def on_key_release(self, symbol, modifiers):
+ "Removes keys from set of currently held down keys."
+ if symbol in self.keys: self.keys.remove(symbol)
+ def on_draw(self):
+ self.background.blit(0,0)
+ self.present_batch.draw()
+ for key in self.labels:
+ item = self.labels[key]
+ item.draw()
+ self.player.draw()
+ def collect_present(self):
+ for present in self.presents[:]:
+ if self.player.collide(present):
+ SOUNDS["crumple"].play()
+ self.increment_score(self.present_worth)
+ self.presents.remove(present)
+ if not self.presents:
+ self.present_size_reduce()
+ self.present_amount_increase()
+ self.present_worth_increase()
+ self.spawn_presents()
+ def spawn_presents(self):
+ "Spawns presents in batches"
+ self.time_amount -= config.TIME_INCREMENT
+ self.time = self.time_amount
+ self.labels["timer"].color = (255, 255, 255, 255)
+ for i in range(self.present_amount):
+ self.presents.append(Present(self.present_batch,
+ self.present_size))
+ def present_size_reduce(self):
+ "A setter for the size of a present sprite."
+ if self.present_size - config.PRESENT_SIZE_INCREMENT < config.MIN_PRESENT_SIZE:
+ self.present_size = config.MIN_PRESENT_SIZE
+ else:
+ self.present_size -= config.PRESENT_SIZE_INCREMENT
+ def present_amount_increase(self):
+ "A setter for the amount of presents per present spawn."
+ self.present_amount += config.PRESENT_AMOUNT_INCREMENT
+ def present_worth_increase(self):
+ "A setter for pointer per present."
+ self.present_worth += config.PRESENT_WORTH_INCREMENT
+ def player_speed_boost(self):
+ if self.player.speed + config.PLAYER_SPEED_INCREMENT > config.MAX_PLAYER_SPEED:
+ self.player.speed = config.MAX_PLAYER_SPEED
+ else:
+ self.player.speed += config.PLAYER_SPEED_INCREMENT
+ def lose_life(self):
+ "Handles running out of lives properly, a life setter."
+ lives -= 1
+ if lives < 0:
+ messenger.change_state("credit_screen", score)
+ def increment_score(self, points):
+ "Handles score increments correctly, a score setter."
+ self.score += points
+
+class Collide(object):
+ "Class that adds collsion methods."
+ def collide(self, other):
+ "Checks if one objects collides with another."
+ if other.x < self.x + (self.width / 2) < other.x + other.width:
+ if other.y < self.y + (self.height / 2) < other.y + other.height:
+ return True
+ if self.x < other.x + (other.width / 2) < self.x + self.width:
+ if self.y < other.y + (other.height / 2) < self.y + self.height:
+ return True
+ return False
+
+class Interpolate(object):
+ "Adds methods for tweening."
+ def interpolate(self, number, steps, form):
+ "Allows for various forms of interpolation."
+ if form == "step":
+ return [number / steps for i in range(steps)]
+ elif form == "accelerate":
+ return [number / step for steps in range(1, steps + 1)]
+
+class Player(pyglet.sprite.Sprite, Collide, Interpolate):
+ "A player object, can be controlled with input."
+ def __init__(self):
+ super(Player, self).__init__(random.choice(PLAYER_IMAGES))
+ self.x, self.y = config.PLAYER_START
+ self.speed = config.PLAYER_START_SPEED
+ self.time = 0.5
+ self.scale = 2.0
+ self.steps = config.PLAYER_STEPS
+ def draw(self):
+ super(Player, self).draw()
+ glEnable(GL_TEXTURE_2D)
+ gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
+ def axis_move(self, dt, axis, amount):
+ if axis == "x":
+ distance = self.interpolate(amount + amount * dt, self.steps, "step")
+ time = self.interpolate(self.time, self.steps, "step")
+ both = zip(distance, time)
+ for distance, time in both:
+ pyglet.clock.schedule_once(lambda dt : self._axis_move("x", distance), time)
+ if axis == "y":
+ distance = self.interpolate(amount + amount * dt, self.steps, "step")
+ time = self.interpolate(self.time, self.steps, "step")
+ both = zip(distance, time)
+ for distance, time in both:
+ pyglet.clock.schedule_once(lambda dt : self._axis_move("y", distance), time)
+ def _axis_move(self, axis, pos):
+ if axis == "x": self.x += pos
+ elif axis == "y": self.y += pos
+ def move(self, dt, keys):
+ if pyglet.window.key.W in keys:
+ self.axis_move(dt, "y", self.speed)
+ if pyglet.window.key.S in keys:
+ self.axis_move(dt, "y", -1 * self.speed)
+ if pyglet.window.key.D in keys:
+ self.axis_move(dt, "x", self.speed)
+ if pyglet.window.key.A in keys:
+ self.axis_move(dt, "x", -1 * self.speed)
+
+class Present(pyglet.sprite.Sprite, Collide):
+ "A collectible present object."
+ def __init__(self, batch, scale):
+ super(Present, self).__init__(random.choice(PRESENT_IMAGES))
+ self.scale = scale
+ self.x = random.randint(0, config.SCREEN_WIDTH - self.width)
+ self.y = random.randint(0, config.SCREEN_HEIGHT - self.height)
+ self.batch = batch
+ def draw(self):
+ super(Player, self).draw()
+ glEnable(GL_TEXTURE_2D)
+ gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
+
+
+
+
100 main.py
@@ -0,0 +1,100 @@
+import pyglet
+import sys
+import os
+try: #This will install avbin if needed, and it works on windows and linux!
+ pyglet.resource.image(r"resources/art/background1.png")
+except:
+ if sys.platform.startswith("win"):
+ print "Error: avbin.dll not found."
+ quit()
+ elif sys.platform.startswith("linux"):
+ if sys.maxsize > 2 ** 32:
+ if os.system("avbin-linux-x86-64-7/install.sh") != 0:
+ print "You must install avbin manually by running the install.sh script in avbin-linux-x86-64-7."
+ quit()
+ else:
+ if os.system("avbin-linux-x86-32-7/install.sh") !=0:
+ print "You must install avbin manually by running the install.sh script in avbin-linux-x86-64-7."
+ quit()
+ elif sys.platform == "dawrwin":
+ #Note, osx doesn't work because the avbin devs don't care about it
+ #and left it in the dust. Just a small town OS living in a
+ #dangerious dog eat world. Lost it all at the gambling games.
+ #Working hard to fight the man. Didn't even really have a plan.
+ #But hey, man? You gotta work. Work. Work this out. Get ahead.
+ #You gotta work. Work. Work this out. Get ahead. Ah yeah!
+ raise "Error: This game is not supported on OSX."
+ os.system("avbin-darwin-universal-5/install.sh")
+import config
+import messenger
+import menu
+import game
+import credit
+import char
+import random
+
+
+MUSIC = {"JingleBellsA" : pyglet.media.load(r"resources\music\Jingle Bells.mp3"),
+ "JingleBellsB" : pyglet.media.load(r"resources\music\Jingle Bells 3.mp3"),
+ "OhChristmasTree" : pyglet.media.load(r"resources\music\Oh Xmas.mp3"),
+ "UpOnAHouseTop" : pyglet.media.load(r"resources\music\Up on a Housetop.mp3"),
+ "WeWishYou" : pyglet.media.load(r"resources\music\We Wish You.mp3"),
+ "Grinch1" : pyglet.media.load(r"resources\music\grinch.mp3"),
+ "Grinch2" : pyglet.media.load(r"resources\music\02-Grinch.mp3")}
+
+
+class Game(pyglet.window.Window):
+ def __init__(self, width, height):
+ messenger.Messenger.game = self
+ self.create_music_player()
+ self.fps_display = pyglet.clock.ClockDisplay()
+ pyglet.clock.set_fps_limit(90)
+ super(Game, self).__init__(width,
+ height,
+ vsync = False,
+ caption = "Big Packages")
+ self.mode_hash = {}
+ self.mode_hash["MenuScreen"] = menu.MenuScreen()
+ self.mode_hash["GameScreen"] = game.GameScreen()
+ self.mode_hash["CreditScreen"] = credit.CreditScreen()
+ self.mode_hash["CharScreen"] = char.CharScreen()
+ #TESTING PURPOSES
+ self.mode = self.mode_hash["MenuScreen"]
+ #self.mode = self.mode_hash["GameScreen"]
+ #TESTING PURPOSES
+ def create_music_player(self):
+ "Creates a music player and loads all the fun christmas music on it."
+ self.music_player = pyglet.media.Player()
+ #self.music_player.eos_action = "loop" #disabling looping
+ music_list = []
+ for key in MUSIC:
+ item = MUSIC[key]
+ music_list.append(item)
+ random.shuffle(music_list)
+ for song in music_list:
+ self.music_player.queue(song)
+ self.music_player.play()
+ pyglet.clock.schedule_interval(lambda dt : self.music_player.play(), 2.0)
+ def on_draw(self):
+ self.clear()
+ self.mode.on_draw()
+ #self.fps_display.draw() #FPS should not be displayed during normal gameplay
+ def on_key_press(self, symbol, modifiers):
+ self.mode.on_key_press(symbol, modifiers)
+ def on_key_release(self, symbol, modifiers):
+ self.mode.on_key_release(symbol, modifiers)
+ def on_mouse_motion(self, x, y, dx, dy):
+ self.mode.on_mouse_motion(x, y, dx, dy)
+ def on_mouse_press(self, x, y, button, modifiers):
+ self.mode.on_mouse_press(x, y, button, modifiers)
+ def on_mouse_release(self, x, y, button, modifiers):
+ self.mode.on_mouse_release(x, y, button, modifiers)
+ def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
+ self.mode.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
+ def on_close(self):
+ self.music_player.pause()
+ self.music_player = None
+ super(Game, self).on_close()
+if __name__ == "__main__":
+ root = Game(config.SCREEN_WIDTH, config.SCREEN_HEIGHT)
+ pyglet.app.run()
46 menu.py
@@ -0,0 +1,46 @@
+import pyglet
+import screen
+import button
+import config
+import messenger
+
+IMAGES = {}
+IMAGES["title_screen"] = pyglet.image.load(r"resources/art/title_screen.png")
+IMAGES["start_button"] = pyglet.image.load(r"resources/art/start_button.png")
+IMAGES["quit_button"] = pyglet.image.load(r"resources/art/quit_button.png")
+IMAGES["char_button"] = pyglet.image.load(r"resources/art/char_button.png")
+
+class MenuScreen(screen.AbstractScreen):
+ def __init__(self):
+ self.color = (0, 0, 0, 255)
+ self.make_buttons()
+ self.background = IMAGES["title_screen"]
+ def on_draw(self):
+ self.background.blit(0,0)
+ self.start_button.draw()
+ self.char_button.draw()
+ self.quit_button.draw()
+ def make_buttons(self):
+ self.start_button = button.Button(image = IMAGES["start_button"],
+ x = config.SCREEN_WIDTH / 2,
+ y = config.SCREEN_HEIGHT / 2)
+ self.start_button.x -= self.start_button.width / 2
+ self.start_button.y -= self.start_button.height / 2
+ self.start_button.command = lambda : messenger.Messenger.change_mode("GameScreen")
+
+ self.char_button = button.Button(image = IMAGES["char_button"],
+ x = config.SCREEN_WIDTH / 2,
+ y = config.SCREEN_HEIGHT / 2)
+ self.char_button.x -= self.char_button.width / 2
+ self.char_button.y -= self.char_button.height * 2
+ self.char_button.command = lambda : messenger.Messenger.change_mode("CharScreen")
+ self.quit_button = button.Button(image = IMAGES["quit_button"],
+ x = config.SCREEN_WIDTH / 2,
+ y = config.SCREEN_HEIGHT / 2)
+ self.quit_button.x -= self.quit_button.width / 2
+ self.quit_button.y -= self.quit_button.height * 3.5
+ self.quit_button.command = lambda : messenger.Messenger.quit()
+ def on_mouse_press(self, x, y, button, modifiers):
+ self.start_button.click(x, y)
+ self.char_button.click(x, y)
+ self.quit_button.click(x, y)
24 messenger.py
@@ -0,0 +1,24 @@
+import game
+
+class Messenger(object):
+ "Used to allow objects to communicate with each other."
+ game = None
+ gameScreen = None
+ menuScreen = None
+ creditScreen = None
+ score = None
+ @staticmethod
+ def change_mode(new_mode):
+ "Changes game mode, makes me wish we had symbols in Python."
+ if new_mode == "CreditScreen":
+ Messenger.creditScreen.score_label.text = "Final Score: %d" % Messenger.gameScreen.score
+ Messenger.creditScreen.make_score_comment()
+ if Messenger.game.mode == Messenger.game.mode_hash["GameScreen"]:
+ Messenger.game.mode.end_updates()
+ Messenger.game.mode_hash["GameScreen"] = game.GameScreen()
+ Messenger.game.mode = Messenger.game.mode_hash[new_mode]
+ if new_mode == "GameScreen":
+ Messenger.game.mode.start_updates()
+ @staticmethod
+ def quit():
+ Messenger.game.on_close()
362 pyglet/__init__.py
@@ -0,0 +1,362 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+
+'''pyglet is a cross-platform games and multimedia package.
+
+Detailed documentation is available at http://www.pyglet.org
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: __init__.py 2530 2009-10-18 01:39:18Z benjamin.coder.smith $'
+
+import os
+import sys
+
+_is_epydoc = hasattr(sys, 'is_epydoc') and sys.is_epydoc
+
+#: The release version of this pyglet installation.
+#:
+#: Valid only if pyglet was installed from a source or binary distribution
+#: (i.e. not in a checked-out copy from SVN).
+#:
+#: Use setuptools if you need to check for a specific release version, e.g.::
+#:
+#: >>> import pyglet
+#: >>> from pkg_resources import parse_version
+#: >>> parse_version(pyglet.version) >= parse_version('1.1')
+#: True
+#:
+version = '1.1.4'
+
+def _require_ctypes_version(version):
+ # Check ctypes version
+ import ctypes
+ req = [int(i) for i in version.split('.')]
+ have = [int(i) for i in ctypes.__version__.split('.')]
+ if not tuple(have) >= tuple(req):
+ raise ImportError('pyglet requires ctypes %s or later.' % version)
+_require_ctypes_version('1.0.0')
+
+_enable_optimisations = not __debug__
+if getattr(sys, 'frozen', None):
+ _enable_optimisations = True
+
+#: Global dict of pyglet options. To change an option from its default, you
+#: must import ``pyglet`` before any sub-packages. For example::
+#:
+#: import pyglet
+#: pyglet.options['debug_gl'] = False
+#:
+#: The default options can be overridden from the OS environment. The
+#: corresponding environment variable for each option key is prefaced by
+#: ``PYGLET_``. For example, in Bash you can set the ``debug_gl`` option with::
+#:
+#: PYGLET_DEBUG_GL=True; export PYGLET_DEBUG_GL
+#:
+#: For options requiring a tuple of values, separate each value with a comma.
+#:
+#: The non-development options are:
+#:
+#: audio
+#: A sequence of the names of audio modules to attempt to load, in
+#: order of preference. Valid driver names are:
+#:
+#: * directsound, the Windows DirectSound audio module (Windows only)
+#: * alsa, the ALSA audio module (Linux only)
+#: * openal, the OpenAL audio module
+#: * silent, no audio
+#: debug_lib
+#: If True, prints the path of each dynamic library loaded.
+#: debug_gl
+#: If True, all calls to OpenGL functions are checked afterwards for
+#: errors using ``glGetError``. This will severely impact performance,
+#: but provides useful exceptions at the point of failure. By default,
+#: this option is enabled if ``__debug__`` is (i.e., if Python was not run
+#: with the -O option). It is disabled by default when pyglet is "frozen"
+#: within a py2exe or py2app library archive.
+#: shadow_window
+#: By default, pyglet creates a hidden window with a GL context when
+#: pyglet.gl is imported. This allows resources to be loaded before
+#: the application window is created, and permits GL objects to be
+#: shared between windows even after they've been closed. You can
+#: disable the creation of the shadow window by setting this option to
+#: False. Recommended for advanced devlopers only.
+#:
+#: **Since:** pyglet 1.1
+#: vsync
+#: If set, the `pyglet.window.Window.vsync` property is ignored, and
+#: this option overrides it (to either force vsync on or off). If unset,
+#: or set to None, the `pyglet.window.Window.vsync` property behaves
+#: as documented.
+#: xsync
+#: If set (the default), pyglet will attempt to synchronise the drawing of
+#: double-buffered windows to the border updates of the X11 window
+#: manager. This improves the appearance of the window during resize
+#: operations. This option only affects double-buffered windows on
+#: X11 servers supporting the Xsync extension with a window manager
+#: that implements the _NET_WM_SYNC_REQUEST protocol.
+#:
+#: **Since:** pyglet 1.1
+#:
+options = {
+ 'audio': ('directsound', 'openal', 'alsa', 'silent'),
+ 'font': ('gdiplus', 'win32'), # ignored outside win32; win32 is deprecated
+ 'debug_font': False,
+ 'debug_gl': not _enable_optimisations,
+ 'debug_gl_trace': False,
+ 'debug_gl_trace_args': False,
+ 'debug_graphics_batch': False,
+ 'debug_lib': False,
+ 'debug_media': False,
+ 'debug_texture': False,
+ 'debug_trace': False,
+ 'debug_trace_args': False,
+ 'debug_trace_depth': 1,
+ 'debug_trace_flush': True,
+ 'debug_win32': False,
+ 'debug_x11': False,
+ 'graphics_vbo': True,
+ 'shadow_window': True,
+ 'vsync': None,
+ 'xsync': True,
+}
+
+_option_types = {
+ 'audio': tuple,
+ 'font': tuple,
+ 'debug_font': bool,
+ 'debug_gl': bool,
+ 'debug_gl_trace': bool,
+ 'debug_gl_trace_args': bool,
+ 'debug_graphics_batch': bool,
+ 'debug_lib': bool,
+ 'debug_media': bool,
+ 'debug_texture': bool,
+ 'debug_trace': bool,
+ 'debug_trace_args': bool,
+ 'debug_trace_depth': int,
+ 'debug_trace_flush': bool,
+ 'debug_win32': bool,
+ 'debug_x11': bool,
+ 'graphics_vbo': bool,
+ 'shadow_window': bool,
+ 'vsync': bool,
+ 'xsync': bool,
+}
+
+def _read_environment():
+ '''Read defaults for options from environment'''
+ for key in options:
+ env = 'PYGLET_%s' % key.upper()
+ try:
+ value = os.environ[env]
+ if _option_types[key] is tuple:
+ options[key] = value.split(',')
+ elif _option_types[key] is bool:
+ options[key] = value in ('true', 'TRUE', 'True', '1')
+ elif _option_types[key] is int:
+ options[key] = int(value)
+ except KeyError:
+ pass
+_read_environment()
+
+if sys.platform == 'cygwin':
+ # This hack pretends that the posix-like ctypes provides windows
+ # functionality. COM does not work with this hack, so there is no
+ # DirectSound support.
+ import ctypes
+ ctypes.windll = ctypes.cdll
+ ctypes.oledll = ctypes.cdll
+ ctypes.WINFUNCTYPE = ctypes.CFUNCTYPE
+ ctypes.HRESULT = ctypes.c_long
+
+# Call tracing
+# ------------
+
+_trace_filename_abbreviations = {}
+
+def _trace_repr(value, size=40):
+ value = repr(value)
+ if len(value) > size:
+ value = value[:size//2-2] + '...' + value[-size//2-1:]
+ return value
+
+def _trace_frame(frame, indent):
+ from pyglet import lib
+ if frame.f_code is lib._TraceFunction.__call__.func_code:
+ is_ctypes = True
+ func = frame.f_locals['self']._func
+ name = func.__name__
+ location = '[ctypes]'
+ else:
+ is_ctypes = False
+ code = frame.f_code
+ name = code.co_name
+ path = code.co_filename
+ line = code.co_firstlineno
+
+ try:
+ filename = _trace_filename_abbreviations[path]
+ except KeyError:
+ # Trim path down
+ dir = ''
+ path, filename = os.path.split(path)
+ while len(dir + filename) < 30:
+ filename = os.path.join(dir, filename)
+ path, dir = os.path.split(path)
+ if not dir:
+ filename = os.path.join('', filename)
+ break
+ else:
+ filename = os.path.join('...', filename)
+ _trace_filename_abbreviations[path] = filename
+
+ location = '(%s:%d)' % (filename, line)
+
+ if indent:
+ name = 'Called from %s' % name
+ print '%s%s %s' % (indent, name, location)
+
+ if _trace_args:
+ if is_ctypes:
+ args = [_trace_repr(arg) for arg in frame.f_locals['args']]
+ print ' %sargs=(%s)' % (indent, ', '.join(args))
+ else:
+ for argname in code.co_varnames[:code.co_argcount]:
+ try:
+ argvalue = _trace_repr(frame.f_locals[argname])
+ print ' %s%s=%s' % (indent, argname, argvalue)
+ except:
+ pass
+
+ if _trace_flush:
+ sys.stdout.flush()
+
+def _trace_func(frame, event, arg):
+ if event == 'call':
+ indent = ''
+ for i in range(_trace_depth):
+ _trace_frame(frame, indent)
+ indent += ' '
+ frame = frame.f_back
+ if not frame:
+ break
+
+ elif event == 'exception':
+ (exception, value, traceback) = arg
+ print 'First chance exception raised:', repr(exception)
+
+def _install_trace():
+ sys.setprofile(_trace_func)
+
+_trace_args = options['debug_trace_args']
+_trace_depth = options['debug_trace_depth']
+_trace_flush = options['debug_trace_flush']
+if options['debug_trace']:
+ _install_trace()
+
+# Lazy loading
+# ------------
+
+class _ModuleProxy(object):
+ _module = None
+
+ def __init__(self, name):
+ self.__dict__['_module_name'] = name
+
+ def __getattr__(self, name):
+ try:
+ return getattr(self._module, name)
+ except AttributeError:
+ if self._module is not None:
+ raise
+
+ import_name = 'pyglet.%s' % self._module_name
+ __import__(import_name)
+ module = sys.modules[import_name]
+ object.__setattr__(self, '_module', module)
+ globals()[self._module_name] = module
+ return getattr(module, name)
+
+ def __setattr__(self, name, value):
+ try:
+ setattr(self._module, name, value)
+ except AttributeError:
+ if self._module is not None:
+ raise
+
+ import_name = 'pyglet.%s' % self._module_name
+ __import__(import_name)
+ module = sys.modules[import_name]
+ object.__setattr__(self, '_module', module)
+ globals()[self._module_name] = module
+ setattr(module, name, value)
+
+if not _is_epydoc:
+ app = _ModuleProxy('app')
+ clock = _ModuleProxy('clock')
+ com = _ModuleProxy('com')
+ event = _ModuleProxy('event')
+ font = _ModuleProxy('font')
+ gl = _ModuleProxy('gl')
+ graphics = _ModuleProxy('graphics')
+ image = _ModuleProxy('image')
+ lib = _ModuleProxy('lib')
+ media = _ModuleProxy('media')
+ resource = _ModuleProxy('resource')
+ sprite = _ModuleProxy('sprite')
+ text = _ModuleProxy('text')
+ window = _ModuleProxy('window')
+
+# Fool py2exe, py2app into including all top-level modules (doesn't understand
+# lazy loading)
+if False:
+ import app
+ import clock
+ import com
+ import event
+ import font
+ import gl
+ import graphics
+ import image
+ import lib
+ import media
+ import resource
+ import sprite
+ import text
+ import window
+
+# Hack around some epydoc bug that causes it to think pyglet.window is None.
+if _is_epydoc:
+ import window
BIN  pyglet/__init__.pyc
Binary file not shown
297 pyglet/app/__init__.py
@@ -0,0 +1,297 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+
+'''Application-wide functionality.
+
+Most applications need only call `run` after creating one or more windows
+to begin processing events. For example, a simple application consisting of
+one window is::
+
+ from pyglet import app
+ from pyglet import window
+
+ win = window.Window()
+ app.run()
+
+To handle events on the main event loop, instantiate it manually. The
+following example exits the application as soon as any window is closed (the
+default policy is to wait until all windows are closed)::
+
+ event_loop = app.EventLoop()
+
+ @event_loop.event
+ def on_window_close(window):
+ event_loop.exit()
+
+:since: pyglet 1.1
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: __init__.py 2140 2008-07-27 04:15:52Z Alex.Holkner $'
+
+import sys
+import weakref
+
+from pyglet import clock
+from pyglet import event
+
+_is_epydoc = hasattr(sys, 'is_epydoc') and sys.is_epydoc
+
+class WeakSet(object):
+ '''Set of objects, referenced weakly.
+
+ Adding an object to this set does not prevent it from being garbage
+ collected. Upon being garbage collected, the object is automatically
+ removed from the set.
+ '''
+ def __init__(self):
+ self._dict = weakref.WeakKeyDictionary()
+
+ def add(self, value):
+ self._dict[value] = True
+
+ def remove(self, value):
+ del self._dict[value]
+
+ def __iter__(self):
+ for key in self._dict.keys():
+ yield key
+
+ def __contains__(self, other):
+ return other in self._dict
+
+ def __len__(self):
+ return len(self._dict)
+
+#: Set of all open displays. Instances of `Display` are automatically added
+#: to this set upon construction. The set uses weak references, so displays
+#: are removed from the set when they are no longer referenced.
+#:
+#: :type: `WeakSet`
+displays = WeakSet()
+
+#: Set of all open windows (including invisible windows). Instances of
+#: `Window` are automatically added to this set upon construction. The set
+#: uses weak references, so windows are removed from the set when they are no
+#: longer referenced or are closed explicitly.
+#:
+#: :type: `WeakSet`
+windows = WeakSet()
+
+
+class BaseEventLoop(event.EventDispatcher):
+ '''The main run loop of the application.
+
+ Calling `run` begins the application event loop, which processes
+ operating system events, calls `pyglet.clock.tick` to call scheduled
+ functions and calls `pyglet.window.Window.on_draw` and
+ `pyglet.window.Window.flip` to update window contents.
+
+ Applications can subclass `EventLoop` and override certain methods
+ to integrate another framework's run loop, or to customise processing
+ in some other way. You should not in general override `run`, as
+ this method contains platform-specific code that ensures the application
+ remains responsive to the user while keeping CPU usage to a minimum.
+ '''
+
+ #: Flag indicating if the event loop will exit in the next iteration.
+ #: This is
+ has_exit = False
+
+ def run(self):
+ '''Begin processing events, scheduled functions and window updates.
+
+ This method returns when `has_exit` is set to True.
+
+ Developers are discouraged from overriding this method, as the
+ implementation is platform-specific.
+ '''
+ raise NotImplementedError('abstract')
+
+ def _setup(self):
+ global event_loop
+ event_loop = self
+
+ # Disable event queuing for dispatch_events
+ from pyglet.window import Window
+ Window._enable_event_queue = False
+
+ # Dispatch pending events
+ for window in windows:
+ window.switch_to()
+ window.dispatch_pending_events()
+
+ def _idle_chance(self):
+ '''If timeout has expired, manually force an idle loop.
+
+ Called by window that have blocked the event loop (e.g. during
+ resizing).
+ '''
+
+ def idle(self):
+ '''Called during each iteration of the event loop.
+
+ The method is called immediately after any window events (i.e., after
+ any user input). The method can return a duration after which
+ the idle method will be called again. The method may be called
+ earlier if the user creates more input events. The method
+ can return `None` to only wait for user events.
+
+ For example, return ``1.0`` to have the idle method called every
+ second, or immediately after any user events.
+
+ The default implementation dispatches the
+ `pyglet.window.Window.on_draw` event for all windows and uses
+ `pyglet.clock.tick` and `pyglet.clock.get_sleep_time` on the default
+ clock to determine the return value.
+
+ This method should be overridden by advanced users only. To have
+ code execute at regular intervals, use the
+ `pyglet.clock.schedule` methods.
+
+ :rtype: float
+ :return: The number of seconds before the idle method should
+ be called again, or `None` to block for user input.
+ '''
+ dt = clock.tick(True)
+
+ # Redraw all windows
+ for window in windows:
+ if window.invalid:
+ window.switch_to()
+ window.dispatch_event('on_draw')
+ window.flip()
+
+ # Update timout
+ return clock.get_sleep_time(True)
+
+ def exit(self):
+ '''Safely exit the event loop at the end of the current iteration.
+
+ This method is convenience for setting `has_exit` to ``True``.
+ '''
+ self.has_exit = True
+
+ def on_window_close(self, window):
+ '''Default window close handler.'''
+ if not windows:
+ self.exit()
+
+ if _is_epydoc:
+ def on_window_close(window):
+ '''A window was closed.
+
+ This event is dispatched when a window is closed. It is not
+ dispatched if the window's close button was pressed but the
+ window did not close.
+
+ The default handler calls `exit` if no more windows are open. You
+ can override this handler to base your application exit on some
+ other policy.
+
+ :event:
+ '''
+
+ def on_enter():
+ '''The event loop is about to begin.
+
+ This is dispatched when the event loop is prepared to enter
+ the main run loop, and represents the last chance for an
+ application to initialise itself.
+
+ :event:
+ '''
+
+ def on_exit():
+ '''The event loop is about to exit.
+
+ After dispatching this event, the `run` method returns (the
+ application may not actually exit if you have more code
+ following the `run` invocation).
+
+ :event:
+ '''
+
+BaseEventLoop.register_event_type('on_window_close')
+BaseEventLoop.register_event_type('on_enter')
+BaseEventLoop.register_event_type('on_exit')
+
+#: The global event loop. Set to the correct instance when an `EventLoop` is
+#: started.
+#:
+#: :type: `EventLoop`
+event_loop = None
+
+def run():
+ '''Begin processing events, scheduled functions and window updates.
+
+ This is a convenience function, equivalent to::
+
+ EventLoop().run()
+
+ '''
+ EventLoop().run()
+
+def exit():
+ '''Exit the application event loop.
+
+ Causes the application event loop to finish, if an event loop is currently
+ running. The application may not necessarily exit (for example, there may
+ be additional code following the `run` invocation).
+
+ This is a convenience function, equivalent to::
+
+ event_loop.exit()
+
+ '''
+ if event_loop:
+ event_loop.exit()
+
+if _is_epydoc:
+ EventLoop = BaseEventLoop
+ EventLoop.__name__ = 'EventLoop'
+ del BaseEventLoop
+else:
+ # Permit cyclic import.
+ import pyglet
+ pyglet.app = sys.modules[__name__]
+
+ if sys.platform == 'darwin':
+ from pyglet.app.carbon import CarbonEventLoop as EventLoop
+ elif sys.platform in ('win32', 'cygwin'):
+ from pyglet.app.win32 import Win32EventLoop as EventLoop
+ else:
+ from pyglet.app.xlib import XlibEventLoop as EventLoop
+
+
BIN  pyglet/app/__init__.pyc
Binary file not shown
144 pyglet/app/carbon.py
@@ -0,0 +1,144 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+
+'''
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: $'
+
+import ctypes
+
+from pyglet.app import windows, BaseEventLoop
+from pyglet.window.carbon import carbon, types, constants, _oscheck
+
+EventLoopTimerProc = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
+kEventDurationForever = ctypes.c_double(constants.kEventDurationForever)
+
+class CarbonEventLoop(BaseEventLoop):
+ def run(self):
+ self._setup()
+
+ e = ctypes.c_void_p()
+ event_dispatcher = carbon.GetEventDispatcherTarget()
+ self._event_loop = event_loop = carbon.GetMainEventLoop()
+ event_queue = carbon.GetMainEventQueue()
+ self._timer = timer = ctypes.c_void_p()
+ idle_event_proc = EventLoopTimerProc(self._timer_proc)
+ carbon.InstallEventLoopTimer(event_loop,
+ ctypes.c_double(0.1), #?
+ kEventDurationForever,
+ idle_event_proc,
+ None,
+ ctypes.byref(timer))
+
+ self._force_idle = False
+ self._allow_polling = True
+
+ self.dispatch_event('on_enter')
+
+ while not self.has_exit:
+ if self._force_idle:
+ duration = 0
+ else:
+ duration = kEventDurationForever
+ if carbon.ReceiveNextEvent(0, None, duration,
+ True, ctypes.byref(e)) == 0:
+ carbon.SendEventToEventTarget(e, event_dispatcher)
+ carbon.ReleaseEvent(e)
+
+ # Manual idle event
+ if carbon.GetNumEventsInQueue(event_queue) == 0 or self._force_idle:
+ self._force_idle = False
+ self._timer_proc(timer, None, False)
+
+ carbon.RemoveEventLoopTimer(self._timer)
+ self.dispatch_event('on_exit')
+
+ def _stop_polling(self):
+ carbon.SetEventLoopTimerNextFireTime(self._timer, ctypes.c_double(0.0))
+
+ def _enter_blocking(self):
+ carbon.SetEventLoopTimerNextFireTime(self._timer, ctypes.c_double(0.0))
+ self._allow_polling = False
+
+ def _exit_blocking(self):
+ self._allow_polling = True
+
+ def _timer_proc(self, timer, data, in_events=True):
+ allow_polling = True
+
+ for window in windows:
+ # Check for live resizing
+ if window._resizing is not None:
+ allow_polling = False
+ old_width, old_height = window._resizing
+ rect = types.Rect()
+ carbon.GetWindowBounds(window._window,
+ constants.kWindowContentRgn,
+ ctypes.byref(rect))
+ width = rect.right - rect.left
+ height = rect.bottom - rect.top
+ if width != old_width or height != old_height:
+ window._resizing = width, height
+ window.switch_to()
+ window.dispatch_event('on_resize', width, height)
+
+ # Check for live dragging
+ if window._dragging:
+ allow_polling = False
+
+ # Check for deferred recreate
+ if window._recreate_deferred:
+ if in_events:
+ # Break out of ReceiveNextEvent so it can be processed
+ # in next iteration.
+ carbon.QuitEventLoop(self._event_loop)
+ self._force_idle = True
+ else:
+ # Do it now.
+ window._recreate_immediate()
+
+ sleep_time = self.idle()
+
+ if sleep_time is None:
+ sleep_time = constants.kEventDurationForever
+ elif sleep_time < 0.01 and allow_polling and self._allow_polling:
+ # Switch event loop to polling.
+ if in_events:
+ carbon.QuitEventLoop(self._event_loop)
+ self._force_idle = True
+ sleep_time = constants.kEventDurationForever
+ carbon.SetEventLoopTimerNextFireTime(timer, ctypes.c_double(sleep_time))
+
BIN  pyglet/app/carbon.pyc
Binary file not shown
106 pyglet/app/win32.py
@@ -0,0 +1,106 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+# $Id:$
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: $'
+
+import ctypes
+import time
+
+from pyglet.app import windows, BaseEventLoop
+from pyglet.window.win32 import _user32, types, constants
+
+class Win32EventLoop(BaseEventLoop):
+ def run(self):
+ self._setup()
+
+ self._timer_proc = types.TIMERPROC(self._timer_func)
+ self._timer = timer = _user32.SetTimer(0, 0, 0, self._timer_proc)
+ self._polling = False
+ self._allow_polling = True
+ msg = types.MSG()
+
+ self.dispatch_event('on_enter')
+
+ while not self.has_exit:
+ if self._polling:
+ while _user32.PeekMessageW(ctypes.byref(msg),
+ 0, 0, 0, constants.PM_REMOVE):
+ _user32.TranslateMessage(ctypes.byref(msg))
+ _user32.DispatchMessageW(ctypes.byref(msg))
+ self._timer_func(0, 0, timer, 0)
+ else:
+ _user32.GetMessageW(ctypes.byref(msg), 0, 0, 0)
+ _user32.TranslateMessage(ctypes.byref(msg))
+ _user32.DispatchMessageW(ctypes.byref(msg))
+
+ # Manual idle event
+ msg_types = \
+ _user32.GetQueueStatus(constants.QS_ALLINPUT) & 0xffff0000
+ if (msg.message != constants.WM_TIMER and
+ not msg_types & ~(constants.QS_TIMER<<16)):
+ self._timer_func(0, 0, timer, 0)
+
+ self.dispatch_event('on_exit')
+
+ def _idle_chance(self):
+ if (self._next_idle_time is not None and
+ self._next_idle_time <= time.time()):
+ self._timer_func(0, 0, self._timer, 0)
+
+ def _timer_func(self, hwnd, msg, timer, t):
+ sleep_time = self.idle()
+
+ if sleep_time is None:
+ # Block indefinitely
+ millis = constants.USER_TIMER_MAXIMUM
+ self._next_idle_time = None
+ self._polling = False
+ _user32.SetTimer(0, timer, millis, self._timer_proc)
+ elif sleep_time < 0.01 and self._allow_polling:
+ # Degenerate to polling
+ millis = constants.USER_TIMER_MAXIMUM
+ self._next_idle_time = 0.
+ if not self._polling:
+ self._polling = True
+ _user32.SetTimer(0, timer, millis, self._timer_proc)
+ else:
+ # Block until timer
+ # XXX hack to avoid oversleep; needs to be api
+ sleep_time = max(sleep_time - 0.01, 0)
+ millis = int(sleep_time * 1000)
+ self._next_idle_time = time.time() + sleep_time
+ self._polling = False
+ _user32.SetTimer(0, timer, millis, self._timer_proc)
BIN  pyglet/app/win32.pyc
Binary file not shown
98 pyglet/app/xlib.py
@@ -0,0 +1,98 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+
+'''
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: xlib.py 2496 2009-08-19 01:17:30Z benjamin.coder.smith $'
+
+import select
+
+from pyglet.app import displays, windows, BaseEventLoop
+from pyglet.window.xlib import xlib
+
+class XlibEventLoop(BaseEventLoop):
+ def run(self):
+ self._setup()
+
+ e = xlib.XEvent()
+ t = 0
+ sleep_time = 0.
+
+ self.dispatch_event('on_enter')
+
+ while not self.has_exit:
+ # Check for already pending events
+ for display in displays:
+ if xlib.XPending(display._display):
+ pending_displays = (display,)
+ break
+ else:
+ # None found; select on all file descriptors or timeout
+ iwtd = self.get_select_files()
+ pending_displays, _, _ = select.select(iwtd, (), (), sleep_time)
+
+ # Dispatch platform events
+ for display in pending_displays:
+ while xlib.XPending(display._display):
+ xlib.XNextEvent(display._display, e)
+
+ # Key events are filtered by the xlib window event
+ # handler so they get a shot at the prefiltered event.
+ if e.xany.type not in (xlib.KeyPress, xlib.KeyRelease):
+ if xlib.XFilterEvent(e, e.xany.window):
+ continue
+ try:
+ window = display._window_map[e.xany.window]
+ except KeyError:
+ continue
+
+ window.dispatch_platform_event(e)
+
+ # Dispatch resize events
+ for window in windows:
+ if window._needs_resize:
+ window.switch_to()
+ window.dispatch_event('on_resize',
+ window._width, window._height)
+ window.dispatch_event('on_expose')
+ window._needs_resize = False
+
+ sleep_time = self.idle()
+
+ self.dispatch_event('on_exit')
+
+ def get_select_files(self):
+ return list(displays)
BIN  pyglet/app/xlib.pyc
Binary file not shown
949 pyglet/clock.py
@@ -0,0 +1,949 @@
+# ----------------------------------------------------------------------------
+# pyglet
+# Copyright (c) 2006-2008 Alex Holkner
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of pyglet nor the names of its
+# contributors may be used to endorse or promote products
+# derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ----------------------------------------------------------------------------
+
+'''Precise framerate calculation, scheduling and framerate limiting.
+
+Measuring time
+==============
+
+The `tick` and `get_fps` functions can be used in conjunction to fulfil most
+games' basic requirements::
+
+ from pyglet import clock
+ while True:
+ dt = clock.tick()
+ # ... update and render ...
+ print 'FPS is %f' % clock.get_fps()
+
+The ``dt`` value returned gives the number of seconds (as a float) since the
+last "tick".
+
+The `get_fps` function averages the framerate over a sliding window of
+approximately 1 second. (You can calculate the instantaneous framerate by
+taking the reciprocal of ``dt``).
+
+Always remember to `tick` the clock!
+
+Limiting frame-rate
+===================
+
+The framerate can be limited::
+
+ clock.set_fps_limit(60)
+
+This causes `clock` to sleep during each `tick` in an attempt to keep the
+number of ticks (frames) per second below 60.
+
+The implementation uses platform-dependent high-resolution sleep functions
+to achieve better accuracy with busy-waiting than would be possible using
+just the `time` module.
+
+Scheduling
+==========
+
+You can schedule a function to be called every time the clock is ticked::
+
+ def callback(dt):
+ print '%f seconds since last callback' % dt
+
+ clock.schedule(callback)
+
+The `schedule_interval` method causes a function to be called every "n"
+seconds::
+
+ clock.schedule_interval(callback, .5) # called twice a second
+
+The `schedule_once` method causes a function to be called once "n" seconds
+in the future::
+
+ clock.schedule_once(callback, 5) # called in 5 seconds
+
+All of the `schedule` methods will pass on any additional args or keyword args
+you specify to the callback function::
+
+ def animate(dt, velocity, sprite):
+ sprite.position += dt * velocity
+
+ clock.schedule(animate, velocity=5.0, sprite=alien)
+
+You can cancel a function scheduled with any of these methods using
+`unschedule`::
+
+ clock.unschedule(animate)
+
+Displaying FPS
+==============
+
+The ClockDisplay class provides a simple FPS counter. You should create
+an instance of ClockDisplay once during the application's start up::
+
+ fps_display = clock.ClockDisplay()
+
+Call draw on the ClockDisplay object for each frame::
+
+ fps_display.draw()
+
+There are several options to change the font, color and text displayed
+within the __init__ method.
+
+Using multiple clocks
+=====================
+
+The clock functions are all relayed to an instance of `Clock` which is
+initialised with the module. You can get this instance to use directly::
+
+ clk = clock.get_default()
+
+You can also replace the default clock with your own:
+
+ myclk = clock.Clock()
+ clock.set_default(myclk)
+
+Each clock maintains its own set of scheduled functions and FPS
+limiting/measurement. Each clock must be "ticked" separately.
+
+Multiple and derived clocks potentially allow you to separate "game-time" and
+"wall-time", or to synchronise your clock to an audio or video stream instead
+of the system clock.
+'''
+
+__docformat__ = 'restructuredtext'
+__version__ = '$Id: clock.py 2541 2009-12-31 04:31:11Z benjamin.coder.smith@gmail.com $'
+
+import time
+import sys
+import ctypes
+
+import pyglet.lib
+
+if sys.platform in ('win32', 'cygwin'):
+ # Win32 Sleep function is only 10-millisecond resolution, so instead
+ # use a waitable timer object, which has up to 100-nanosecond resolution
+ # (hardware and implementation dependent, of course).
+ _kernel32 = ctypes.windll.kernel32
+ class _ClockBase(object):
+ def __init__(self):
+ self._timer = _kernel32.CreateWaitableTimerA(ctypes.c_void_p(),
+ True, ctypes.c_void_p())
+
+ def sleep(self, microseconds):
+ delay = ctypes.c_longlong(int(-microseconds * 10))
+ _kernel32.SetWaitableTimer(self._timer, ctypes.byref(delay),
+ 0, ctypes.c_void_p(), ctypes.c_void_p(), False)
+ _kernel32.WaitForSingleObject(self._timer, 0xffffffff)
+ _default_time_function = time.clock
+
+else:
+ _c = pyglet.lib.load_library('c', darwin='/usr/lib/libc.dylib')
+ _c.usleep.argtypes = [ctypes.c_ulong]
+
+ class _ClockBase(object):
+ def sleep(self, microseconds):
+ _c.usleep(int(microseconds))
+ _default_time_function = time.time
+
+class _ScheduledItem(object):
+ __slots__ = ['func', 'args', 'kwargs']
+ def __init__(self, func, args, kwargs):
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+
+class _ScheduledIntervalItem(object):
+ __slots__ = ['func', 'interval', 'last_ts', 'next_ts',
+ 'args', 'kwargs']
+ def __init__(self, func, interval, last_ts, next_ts, args, kwargs):
+ self.func = func
+ self.interval = interval
+ self.last_ts = last_ts
+ self.next_ts = next_ts
+ self.args = args
+ self.kwargs = kwargs
+
+def _dummy_schedule_func(*args, **kwargs):
+ '''Dummy function that does nothing, placed onto zombie scheduled items
+ to ensure they have no side effect if already queued inside tick() method.
+ '''
+ pass
+
+class Clock(_ClockBase):
+ '''Class for calculating and limiting framerate, and for calling scheduled
+ functions.
+ '''
+
+ #: The minimum amount of time in seconds this clock will attempt to sleep
+ #: for when framerate limiting. Higher values will increase the
+ #: accuracy of the limiting but also increase CPU usage while
+ #: busy-waiting. Lower values mean the process sleeps more often, but is
+ #: prone to over-sleep and run at a potentially lower or uneven framerate
+ #: than desired.
+ MIN_SLEEP = 0.005
+
+ #: The amount of time in seconds this clock subtracts from sleep values
+ #: to compensate for lazy operating systems.
+ SLEEP_UNDERSHOOT = MIN_SLEEP - 0.001
+
+ # List of functions to call every tick.
+ _schedule_items = None
+
+ # List of schedule interval items kept in sort order.
+ _schedule_interval_items = None
+
+ # If True, a sleep(0) is inserted on every tick.
+ _force_sleep = False
+
+ def __init__(self, fps_limit=None, time_function=_default_time_function):
+ '''Initialise a Clock, with optional framerate limit and custom
+ time function.
+
+ :Parameters:
+ `fps_limit` : float
+ If not None, the maximum allowable framerate. Defaults
+ to None. Deprecated in pyglet 1.1.
+ `time_function` : function
+ Function to return the elapsed time of the application,
+ in seconds. Defaults to time.time, but can be replaced
+ to allow for easy time dilation effects or game pausing.
+
+ '''
+
+ super(Clock, self).__init__()
+ self.time = time_function
+ self.next_ts = self.time()
+ self.last_ts = None
+ self.times = []
+
+ self.set_fps_limit(fps_limit)
+ self.cumulative_time = 0
+
+ self._schedule_items = []
+ self._schedule_interval_items = []
+
+ def tick(self, poll=False):
+ '''Signify that one frame has passed.
+
+ This will call any scheduled functions that have elapsed.
+
+ :Parameters:
+ `poll` : bool
+ If True, the function will call any scheduled functions
+ but will not sleep or busy-wait for any reason. Recommended
+ for advanced applications managing their own sleep timers
+ only.
+
+ Since pyglet 1.1.
+
+ :rtype: float
+ :return: The number of seconds since the last "tick", or 0 if this was
+ the first frame.
+ '''
+ if poll:
+ if self.period_limit:
+ self.next_ts = self.next_ts + self.period_limit
+ else:
+ if self.period_limit:
+ self._limit()
+
+ if self._force_sleep:
+ self.sleep(0)
+
+ ts = self.time()
+ if self.last_ts is None:
+ delta_t = 0
+ else:
+ delta_t = ts - self.last_ts
+ self.times.insert(0, delta_t)
+ if len(self.times) > self.window_size:
+ self.cumulative_time -= self.times.pop()
+ self.cumulative_time += delta_t
+ self.last_ts = ts
+
+ # Call functions scheduled for every frame
+ # Dupe list just in case one of the items unchedules itself
+ for item in list(self._schedule_items):
+ item.func(delta_t, *item.args, **item.kwargs)
+
+ # Call all scheduled interval functions and reschedule for future.
+ need_resort = False
+ # Dupe list just in case one of the items unchedules itself
+ for item in list(self._schedule_interval_items):
+ if item.next_ts > ts:
+ break
+ item.func(ts - item.last_ts, *item.args, **item.kwargs)
+ if item.interval:
+ # Try to keep timing regular, even if overslept this time;
+ # but don't schedule in the past (which could lead to
+ # infinitely-worsing error).
+ item.next_ts = item.last_ts + item.interval
+ item.last_ts = ts
+ if item.next_ts <= ts:
+ if ts - item.next_ts < 0.05:
+ # Only missed by a little bit, keep the same schedule
+ item.next_ts = ts + item.interval
+ else:
+ # Missed by heaps, do a soft reschedule to avoid
+ # lumping everything together.
+ item.next_ts = self._get_soft_next_ts(ts, item.interval)
+ # Fake last_ts to avoid repeatedly over-scheduling in
+ # future. Unfortunately means the next reported dt is
+ # incorrect (looks like interval but actually isn't).
+ item.last_ts = item.next_ts - item.interval
+ need_resort = True
+ else:
+ item.next_ts = None
+
+ # Remove finished one-shots.
+ self._schedule_interval_items = \
+ [item for item in self._schedule_interval_items \
+ if item.next_ts is not None]
+
+ if need_resort:
+ # TODO bubble up changed items might be faster
+ self._schedule_interval_items.sort(key=lambda a: a.next_ts)
+
+ return delta_t
+
+ def _limit(self):
+ '''Sleep until the next frame is due. Called automatically by
+ `tick` if a framerate limit has been set.
+
+ This method uses several heuristics to determine whether to
+ sleep or busy-wait (or both).
+ '''
+ ts = self.time()
+ # Sleep to just before the desired time
+ sleeptime = self.get_sleep_time(False)
+ while sleeptime - self.SLEEP_UNDERSHOOT > self.MIN_SLEEP:
+ self.sleep(1000000 * (sleeptime - self.SLEEP_UNDERSHOOT))
+ sleeptime = self.get_sleep_time(False)
+
+ # Busy-loop CPU to get closest to the mark
+ sleeptime = self.next_ts - self.time()
+ while sleeptime > 0:
+ sleeptime = self.next_ts - self.time()
+
+ if sleeptime < -2 * self.period_limit:
+ # Missed the time by a long shot, let's reset the clock
+ # print >> sys.stderr, 'Step %f' % -sleeptime
+ self.next_ts = ts + 2 * self.period_limit
+ else:
+ # Otherwise keep the clock steady
+ self.next_ts = self.next_ts + self.period_limit
+
+ def get_sleep_time(self, sleep_idle):
+ '''Get the time until the next item is scheduled.
+
+ This method considers all scheduled items and the current
+ ``fps_limit``, if any.
+
+ Applications can choose to continue receiving updates at the
+ maximum framerate during idle time (when no functions are scheduled),
+ or they can sleep through their idle time and allow the CPU to
+ switch to other processes or run in low-power mode.
+
+ If `sleep_idle` is ``True`` the latter behaviour is selected, and
+ ``None`` will be returned if there are no scheduled items.
+
+ Otherwise, if `sleep_idle` is ``False``, a sleep time allowing
+ the maximum possible framerate (considering ``fps_limit``) will
+ be returned; or an earlier time if a scheduled function is ready.
+
+ :Parameters:
+ `sleep_idle` : bool
+ If True, the application intends to sleep through its idle
+ time; otherwise it will continue ticking at the maximum
+ frame rate allowed.
+
+ :rtype: float
+ :return: Time until the next scheduled event in seconds, or ``None``
+ if there is no event scheduled.
+
+ :since: pyglet 1.1
+ '''
+ if self._schedule_items or not sleep_idle:
+ if not self.period_limit:
+ return 0.
+ else:
+ wake_time = self.next_ts
+ if self._schedule_interval_items:
+ wake_time = min(wake_time,
+ self._schedule_interval_items[0].next_ts)
+ return max(wake_time - self.time(), 0.)
+
+ if self._schedule_interval_items:
+ return max(self._schedule_interval_items[0].next_ts - self.time(),
+ 0)
+
+ return None
+
+ def set_fps_limit(self, fps_limit):
+ '''Set the framerate limit.
+
+ The framerate limit applies only when a function is scheduled
+ for every frame. That is, the framerate limit can be exceeded by
+ scheduling a function for a very small period of time.
+
+ :Parameters:
+ `fps_limit` : float
+ Maximum frames per second allowed, or None to disable
+ limiting.
+
+ :deprecated: Use `pyglet.app.run` and `schedule_interval` instead.
+ '''
+ if not fps_limit:
+ self.period_limit = None
+ else:
+ self.period_limit = 1. / fps_limit
+ self.window_size = fps_limit or 60
+
+ def get_fps_limit(self):
+ '''Get the framerate limit.
+