Added loading screen.

This commit is contained in:
Quantum 2013-12-13 18:01:52 -05:00
parent dc6d0c6c67
commit 55ee2ee3d2
3 changed files with 162 additions and 27 deletions

View file

@ -6,7 +6,7 @@ import time
import random import random
from punyverse.camera import Camera from punyverse.camera import Camera
from punyverse.world import load_world from punyverse.world import World
from punyverse.glgeom import * from punyverse.glgeom import *
from punyverse.entity import Asteroid from punyverse.entity import Asteroid
from punyverse import texture from punyverse import texture
@ -42,10 +42,33 @@ class Applet(pyglet.window.Window):
super(Applet, self).__init__(*args, **kwargs) super(Applet, self).__init__(*args, **kwargs)
texture.init() texture.init()
self.loaded = False
self.__load_started = False
self._loading_phase = pyglet.text.Label(font_name='Consolas', font_size=20, x=10, y=self.height - 100,
color=(255, 255, 255, 255), width=self.width - 20, halign='center',
multiline=True, text='Punyverse is starting...')
self._loading_label = pyglet.text.Label(font_name='Consolas', font_size=16, x=10, y=self.height - 200,
color=(255, 255, 255, 255), width=self.width - 20, halign='center',
multiline=True)
pyglet.clock.schedule_once(self.load, 0)
def load(self, *args, **kwargs):
if self.loaded or self.__load_started:
return
self.__load_started = True
def callback(phase, message, progress):
self.draw_loading(phase, message, progress)
self.flip()
self.dispatch_events()
start = clock() start = clock()
self.fps = 0 self.fps = 0
self.world = load_world('world.json') self.world = World('world.json', callback)
print 'Initializing game...' phase = 'Initializing game...'
print phase
callback(phase, '', 0)
self.speed = INITIAL_SPEED self.speed = INITIAL_SPEED
self.keys = set() self.keys = set()
self.info = True self.info = True
@ -70,7 +93,6 @@ class Applet(pyglet.window.Window):
self.__time_per_second_cache = None self.__time_per_second_cache = None
self.__time_per_second_value = None self.__time_per_second_value = None
self.__time_accumulate = 0 self.__time_accumulate = 0
pyglet.clock.schedule(self.update)
def speed_incrementer(object, increment): def speed_incrementer(object, increment):
def incrementer(): def incrementer():
@ -160,26 +182,35 @@ class Applet(pyglet.window.Window):
glLightfv(GL_LIGHT0, GL_POSITION, fv4(.5, .5, 1, 0)) glLightfv(GL_LIGHT0, GL_POSITION, fv4(.5, .5, 1, 0))
glLightfv(GL_LIGHT0, GL_SPECULAR, fv4(.5, .5, 1, 1)) glLightfv(GL_LIGHT0, GL_SPECULAR, fv4(.5, .5, 1, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4(1, 1, 1, 1)) glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4(1, 1, 1, 1))
glLightfv(GL_LIGHT1, GL_POSITION, fv4(1, 0, .5, 0)) glLightfv(GL_LIGHT1, GL_POSITION, fv4(1, 0, .5, 0))
glLightfv(GL_LIGHT1, GL_DIFFUSE, fv4(.5, .5, .5, 1)) glLightfv(GL_LIGHT1, GL_DIFFUSE, fv4(.5, .5, .5, 1))
glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1)) glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1))
print 'Loading asteroids...' phase = 'Loading asteroids...'
self.asteroid_ids = [model_list(load_model(r'asteroids/01.obj'), 5, 5, 5, (0, 0, 0)), print phase
model_list(load_model(r'asteroids/02.obj'), 5, 5, 5, (0, 0, 0)),
model_list(load_model(r'asteroids/03.obj'), 5, 5, 5, (0, 0, 0)), def load_asteroids(files):
] for id, file in enumerate(files):
callback(phase, 'Loading %s...' % file, float(id) / len(files))
yield model_list(load_model(file), 5, 5, 5, (0, 0, 0))
self.asteroid_ids = list(load_asteroids([r'asteroids/01.obj', r'asteroids/02.obj', r'asteroids/03.obj']))
c = self.cam c = self.cam
c.x, c.y, c.z = self.world.start c.x, c.y, c.z = self.world.start
c.pitch, c.yaw, c.roll = self.world.direction c.pitch, c.yaw, c.roll = self.world.direction
print 'Updating entities...' phase = 'Updating entities...'
print phase
callback(phase, '', 0)
for entity in self.world.tracker: for entity in self.world.tracker:
entity.update() entity.update()
print 'Loaded in %s seconds.' % (clock() - start) print 'Loaded in %s seconds.' % (clock() - start)
self.loaded = True
pyglet.clock.schedule(self.update)
self.on_resize(self.width, self.height) # On resize handler does nothing unless it's loaded
def set_exclusive_mouse(self, exclusive): def set_exclusive_mouse(self, exclusive):
super(Applet, self).set_exclusive_mouse(exclusive) super(Applet, self).set_exclusive_mouse(exclusive)
@ -196,6 +227,9 @@ class Applet(pyglet.window.Window):
direction=(dx, dy, dz))) direction=(dx, dy, dz)))
def on_mouse_press(self, x, y, button, modifiers): def on_mouse_press(self, x, y, button, modifiers):
if not self.loaded:
return
if not self.exclusive: if not self.exclusive:
self.set_exclusive_mouse(True) self.set_exclusive_mouse(True)
else: else:
@ -203,10 +237,16 @@ class Applet(pyglet.window.Window):
self.mouse_press_handler[button]() self.mouse_press_handler[button]()
def on_mouse_motion(self, x, y, dx, dy): def on_mouse_motion(self, x, y, dx, dy):
if not self.loaded:
return
if self.exclusive: # Only handle camera movement if mouse is grabbed if self.exclusive: # Only handle camera movement if mouse is grabbed
self.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY) self.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY)
def on_key_press(self, symbol, modifiers): def on_key_press(self, symbol, modifiers):
if not self.loaded:
return
if self.exclusive: # Only handle keyboard input if mouse is grabbed if self.exclusive: # Only handle keyboard input if mouse is grabbed
if symbol in self.key_handler: if symbol in self.key_handler:
self.key_handler[symbol]() self.key_handler[symbol]()
@ -214,10 +254,16 @@ class Applet(pyglet.window.Window):
self.keys.add(symbol) self.keys.add(symbol)
def on_key_release(self, symbol, modifiers): def on_key_release(self, symbol, modifiers):
if not self.loaded:
return
if symbol in self.keys: if symbol in self.keys:
self.keys.remove(symbol) self.keys.remove(symbol)
def on_resize(self, width, height): def on_resize(self, width, height):
if not self.loaded:
return super(Applet, self).on_resize(width, height)
height = max(height, 1) # Prevent / by 0 height = max(height, 1) # Prevent / by 0
self.label.y = height - 20 self.label.y = height - 20
glViewport(0, 0, width, height) glViewport(0, 0, width, height)
@ -228,6 +274,9 @@ class Applet(pyglet.window.Window):
glMatrixMode(GL_MODELVIEW) glMatrixMode(GL_MODELVIEW)
def on_mouse_scroll(self, x, y, scroll_x, scroll_y): def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
if not self.loaded:
return
self.speed += scroll_y * 50 + scroll_x * 500 self.speed += scroll_y * 50 + scroll_x * 500
def get_time_per_second(self): def get_time_per_second(self):
@ -267,9 +316,25 @@ class Applet(pyglet.window.Window):
else: else:
self.__time_accumulate += delta self.__time_accumulate += delta
def draw_loading(self, phase=None, message=None, progress=None):
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
if phase is not None:
self._loading_phase.text = phase
if message is not None:
self._loading_label.text = message
self._loading_phase.draw()
self._loading_label.draw()
if progress is not None:
progress_bar(10, self.height - 300, self.width - 20, 50, progress)
def on_draw(self, glMatrix=GLfloat * 16): def on_draw(self, glMatrix=GLfloat * 16):
if not self.loaded:
return self.draw_loading()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity() glLoadIdentity()
c = self.cam c = self.cam
x, y, z = c.x, c.y, c.z x, y, z = c.x, c.y, c.z

View file

@ -5,7 +5,18 @@ from random import random, gauss, choice
TWOPI = pi * 2 TWOPI = pi * 2
__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'sphere', 'colourball', 'torus', 'belt', __all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'sphere', 'colourball', 'torus', 'belt',
'flare', 'normal_sphere'] 'flare', 'normal_sphere', 'glSection', 'progress_bar']
class glSection(object):
def __init__(self, type):
self.type = type
def __enter__(self):
glBegin(self.type)
def __exit__(self, exc_type, exc_val, exc_tb):
glEnd()
def compile(pointer, *args, **kwargs): def compile(pointer, *args, **kwargs):
@ -289,4 +300,37 @@ except ImportError:
glVertex3f(x1 * r, y1 * r, z) glVertex3f(x1 * r, y1 * r, z)
glEnd() glEnd()
glPopAttrib() glPopAttrib()
def progress_bar(x, y, width, height, filled):
x1 = x
x2 = x + width
y1 = y
y2 = y - height
y3 = 0.65 * y1 + 0.35 * y2
y4 = 0.25 * y1 + 0.75 * y2
glColor3f(0.6, 0.6, 0.6)
with glSection(GL_LINE_LOOP):
glVertex2f(x1, y1)
glVertex2f(x1, y2)
glVertex2f(x2, y2)
glVertex2f(x2, y1)
x1 += 1
y1 -= 1
x2 = x + width * filled - 1
with glSection(GL_TRIANGLE_STRIP):
glColor3f(0.81, 1, 0.82)
glVertex2f(x1, y1)
glVertex2f(x2, y1)
glColor3f(0, 0.83, 0.16)
glVertex2f(x1, y3)
glVertex2f(x2, y3)
glVertex2f(x1, y4)
glVertex2f(x2, y4)
glColor3f(0.37, 0.92, 0.43)
glVertex2f(x1, y2)
glVertex2f(x2, y2)

View file

@ -73,23 +73,35 @@ class World(object):
self.tick = 0 self.tick = 0
self.callback = callback self.callback = callback
self._phase = 'Parsing configuration...'
self._parse(file) self._parse(file)
del self.callback # So it can't be used after loading finishes del self.callback # So it can't be used after loading finishes
def _eval(self, value): def _eval(self, value):
return eval(str(value), {'__builtins__': None}, self.context) return eval(str(value), {'__builtins__': None}, self._context)
def _parse(self, file): def _parse(self, file):
self.callback('Loading configuration file...', 0) self.callback(self._phase, 'Loading configuration file...', 0)
with open(os.path.join(os.path.dirname(__file__), file)) as f: with open(os.path.join(os.path.dirname(__file__), file)) as f:
root = json.load(f, object_pairs_hook=OrderedDict) root = json.load(f, object_pairs_hook=OrderedDict)
self.au = root.get('au', 2000) self._au = root.get('au', 2000)
self.length = root.get('length', 4320) self._length = root.get('length', 4320)
self.context = {'AU': self.au, 'TEXTURE': texture.max_texture, 'KM': 1.0 / self.length} self._context = {'AU': self._au, 'TEXTURE': texture.max_texture, 'KM': 1.0 / self._length}
tick = root.get('tick', 4320) # How many second is a tick? tick = root.get('tick', 4320) # How many second is a tick?
self.tick_length = tick self.tick_length = tick
# Need to know how many objects are being loaded
self._objects = 0
self._current_object = 0
def count_objects(bodies):
for body in bodies.itervalues():
self._objects += 1
count_objects(body.get('satellites', {}))
count_objects(root['bodies'])
print self._objects, 'objects to be loaded...'
if 'start' in root: if 'start' in root:
info = root['start'] info = root['start']
x = self._eval(info.get('x', 0)) x = self._eval(info.get('x', 0))
@ -102,11 +114,21 @@ class World(object):
self.direction = (pitch, yaw, roll) self.direction = (pitch, yaw, roll)
for planet, info in root['bodies'].iteritems(): for planet, info in root['bodies'].iteritems():
print 'Loading %s.' % planet message = 'Loading %s.' % planet
print message
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
message, float(self._current_object) / self._objects)
self._body(planet, info) self._body(planet, info)
self._current_object += 1
for name, info in root['belts'].iteritems(): if 'belts' in root:
print 'Loading %s.' % name self._phase = 'Loading belts...'
self._current_object = 0
for name, info in root['belts'].iteritems():
message = 'Loading %s.' % name
print message
self.callback(self._phase, message, float(self._current_object) / len(root['belts']))
self._belt(name, info)
def _belt(self, name, info): def _belt(self, name, info):
x = self._eval(info.get('x', 0)) x = self._eval(info.get('x', 0))
@ -143,9 +165,9 @@ class World(object):
yaw = self._eval(info.get('yaw', 0)) yaw = self._eval(info.get('yaw', 0))
roll = self._eval(info.get('roll', 0)) roll = self._eval(info.get('roll', 0))
rotation = self._eval(info.get('rotation', 86400)) rotation = self._eval(info.get('rotation', 86400))
radius = self._eval(info.get('radius', self.length)) / self.length radius = self._eval(info.get('radius', self._length)) / self._length
background = info.get('background', False) background = info.get('background', False)
orbit_distance = self._eval(info.get('orbit_distance', self.au)) orbit_distance = self._eval(info.get('orbit_distance', self._au))
division = info.get('division', max(min(int(radius / 8), 60), 10)) division = info.get('division', max(min(int(radius / 8), 60), 10))
if 'texture' in info: if 'texture' in info:
@ -183,7 +205,7 @@ class World(object):
speed = info.get('orbit_speed', 1) speed = info.get('orbit_speed', 1)
type = Satellite type = Satellite
params.update(parent=parent, orbit_speed=speed, params.update(parent=parent, orbit_speed=speed,
distance=distance / self.length, eccentricity=info.get('eccentricity', 0), distance=distance / self._length, eccentricity=info.get('eccentricity', 0),
inclination=info.get('inclination', 0), longitude=info.get('longitude', 0), inclination=info.get('inclination', 0), longitude=info.get('longitude', 0),
argument=info.get('argument', 0)) argument=info.get('argument', 0))
@ -240,5 +262,9 @@ class World(object):
(pitch, yaw, roll), **params)) (pitch, yaw, roll), **params))
for satellite, info in info.get('satellites', {}).iteritems(): for satellite, info in info.get('satellites', {}).iteritems():
print 'Loading %s, satellite of %s.' % (satellite, name) message = 'Loading %s, satellite of %s.' % (satellite, name)
self._body(satellite, info, object) print message
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
message, float(self._current_object) / self._objects)
self._body(satellite, info, object)
self._current_object += 1