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
from punyverse.camera import Camera
from punyverse.world import load_world
from punyverse.world import World
from punyverse.glgeom import *
from punyverse.entity import Asteroid
from punyverse import texture
@ -42,10 +42,33 @@ class Applet(pyglet.window.Window):
super(Applet, self).__init__(*args, **kwargs)
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()
self.fps = 0
self.world = load_world('world.json')
print 'Initializing game...'
self.world = World('world.json', callback)
phase = 'Initializing game...'
print phase
callback(phase, '', 0)
self.speed = INITIAL_SPEED
self.keys = set()
self.info = True
@ -70,7 +93,6 @@ class Applet(pyglet.window.Window):
self.__time_per_second_cache = None
self.__time_per_second_value = None
self.__time_accumulate = 0
pyglet.clock.schedule(self.update)
def speed_incrementer(object, increment):
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_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_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))
print 'Loading asteroids...'
self.asteroid_ids = [model_list(load_model(r'asteroids/01.obj'), 5, 5, 5, (0, 0, 0)),
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)),
]
phase = 'Loading asteroids...'
print phase
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.x, c.y, c.z = self.world.start
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:
entity.update()
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):
super(Applet, self).set_exclusive_mouse(exclusive)
@ -196,6 +227,9 @@ class Applet(pyglet.window.Window):
direction=(dx, dy, dz)))
def on_mouse_press(self, x, y, button, modifiers):
if not self.loaded:
return
if not self.exclusive:
self.set_exclusive_mouse(True)
else:
@ -203,10 +237,16 @@ class Applet(pyglet.window.Window):
self.mouse_press_handler[button]()
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
self.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY)
def on_key_press(self, symbol, modifiers):
if not self.loaded:
return
if self.exclusive: # Only handle keyboard input if mouse is grabbed
if symbol in self.key_handler:
self.key_handler[symbol]()
@ -214,10 +254,16 @@ class Applet(pyglet.window.Window):
self.keys.add(symbol)
def on_key_release(self, symbol, modifiers):
if not self.loaded:
return
if symbol in self.keys:
self.keys.remove(symbol)
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
self.label.y = height - 20
glViewport(0, 0, width, height)
@ -228,6 +274,9 @@ class Applet(pyglet.window.Window):
glMatrixMode(GL_MODELVIEW)
def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
if not self.loaded:
return
self.speed += scroll_y * 50 + scroll_x * 500
def get_time_per_second(self):
@ -267,9 +316,25 @@ class Applet(pyglet.window.Window):
else:
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):
if not self.loaded:
return self.draw_loading()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
c = self.cam
x, y, z = c.x, c.y, c.z

View file

@ -5,7 +5,18 @@ from random import random, gauss, choice
TWOPI = pi * 2
__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):
@ -289,4 +300,37 @@ except ImportError:
glVertex3f(x1 * r, y1 * r, z)
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.callback = callback
self._phase = 'Parsing configuration...'
self._parse(file)
del self.callback # So it can't be used after loading finishes
def _eval(self, value):
return eval(str(value), {'__builtins__': None}, self.context)
return eval(str(value), {'__builtins__': None}, self._context)
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:
root = json.load(f, object_pairs_hook=OrderedDict)
self.au = root.get('au', 2000)
self.length = root.get('length', 4320)
self.context = {'AU': self.au, 'TEXTURE': texture.max_texture, 'KM': 1.0 / self.length}
self._au = root.get('au', 2000)
self._length = root.get('length', 4320)
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?
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:
info = root['start']
x = self._eval(info.get('x', 0))
@ -102,11 +114,21 @@ class World(object):
self.direction = (pitch, yaw, roll)
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._current_object += 1
for name, info in root['belts'].iteritems():
print 'Loading %s.' % name
if 'belts' in root:
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):
x = self._eval(info.get('x', 0))
@ -143,9 +165,9 @@ class World(object):
yaw = self._eval(info.get('yaw', 0))
roll = self._eval(info.get('roll', 0))
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)
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))
if 'texture' in info:
@ -183,7 +205,7 @@ class World(object):
speed = info.get('orbit_speed', 1)
type = Satellite
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),
argument=info.get('argument', 0))
@ -240,5 +262,9 @@ class World(object):
(pitch, yaw, roll), **params))
for satellite, info in info.get('satellites', {}).iteritems():
print 'Loading %s, satellite of %s.' % (satellite, name)
self._body(satellite, info, object)
message = 'Loading %s, satellite of %s.' % (satellite, name)
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