Use dedicated loader window to perform loading.

This paves the way to use OpenGL core profile in the future while still using legacy to draw the simple loader.
This commit is contained in:
Quantum 2018-08-24 15:20:24 -04:00
parent 88bf6d1dff
commit aa225c70fa
6 changed files with 139 additions and 127 deletions

View file

@ -1,9 +1,9 @@
from math import * from math import *
from random import random, gauss, choice from random import random, gauss, choice
from pyglet.gl import *
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves import range from six.moves import range
from pyglet.gl import *
TWOPI = pi * 2 TWOPI = pi * 2
@ -11,6 +11,18 @@ __all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'disk', 'spher
'flare', 'glSection', 'glMatrix', 'glRestore', 'progress_bar'] 'flare', 'glSection', 'glMatrix', 'glRestore', 'progress_bar']
class glContext(object):
def __init__(self, context):
self.new_context = context
def __enter__(self):
self.old_context = get_current_context()
self.new_context.set_current()
def __exit__(self, exc_type, exc_val, exc_tb):
self.old_context.set_current()
class glSection(object): class glSection(object):
def __init__(self, type): def __init__(self, type):
self.type = type self.type = type

76
punyverse/loader.py Normal file
View file

@ -0,0 +1,76 @@
import time
import pyglet
from pyglet.gl import *
from six.moves import zip_longest
from punyverse.glgeom import glContext, progress_bar
from punyverse.world import World
class LoaderWindow(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super(LoaderWindow, self).__init__(*args, **kwargs)
self.loading_phase = pyglet.text.Label(
font_name='Consolas', font_size=20, x=10, y=self.height - 50,
color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True, text='Punyverse is starting...'
)
self.loading_label = pyglet.text.Label(
font_name='Consolas', font_size=16, x=10, y=self.height - 120,
color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True
)
self.info_label = pyglet.text.Label(
font_name='Consolas', font_size=13, x=10, y=self.height - 220,
color=(255, 255, 255, 255), width=self.width - 20,
multiline=True
)
self.progress = 0
self._main_context = None
def set_main_context(self, context):
self._main_context = context
info = [' %-22s %s' % (key + ':', value)
for key, value in context.config.get_gl_attributes()]
info = ['%-30s %-30s' % group for group in
zip_longest(info[::2], info[1::2], fillvalue='')]
with glContext(context):
self.info_label.text = '\n'.join([
'Graphics Vendor: ' + gl_info.get_vendor(),
'Graphics Version: ' + gl_info.get_version(),
'Graphics Renderer: ' + gl_info.get_renderer(),
]) + '\n\n' + 'OpenGL configuration:\n' + '\n'.join(info)
def _load_callback(self, phase, message, progress):
print(message)
with glContext(self.context):
self.loading_phase.text = phase
self.loading_label.text = message
self.progress = progress
self.on_draw()
self.flip()
self.dispatch_events()
def load(self):
start = time.clock()
with glContext(self._main_context):
world = World('world.json', self._load_callback)
print('Loaded in %s seconds.' % (time.clock() - start))
return world
def on_draw(self):
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
self.loading_phase.draw()
self.loading_label.draw()
progress_bar(10, self.height - 140, self.width - 20, 50, self.progress)
self.info_label.draw()
def main_is_initializing(self):
self._load_callback('Loading main window...', '', 0)

View file

@ -2,7 +2,8 @@ import argparse
import pyglet import pyglet
from punyverse import game from punyverse.loader import LoaderWindow
from punyverse.ui import Punyverse
INITIAL_WIN_HEIGHT = 540 INITIAL_WIN_HEIGHT = 540
INITIAL_WIN_WIDTH = 700 INITIAL_WIN_WIDTH = 700
@ -24,10 +25,12 @@ def main():
args = parser.parse_args() args = parser.parse_args()
pyglet.options['shadow_window'] = False pyglet.options['shadow_window'] = False
loader = LoaderWindow(width=INITIAL_WIN_WIDTH, height=INITIAL_WIN_HEIGHT)
template = pyglet.gl.Config(depth_size=args.depth, double_buffer=True, template = pyglet.gl.Config(depth_size=args.depth, double_buffer=True,
sample_buffers=args.multisample > 1, sample_buffers=args.multisample > 1,
samples=args.multisample) samples=args.multisample,
major_version=3)
platform = pyglet.window.get_platform() platform = pyglet.window.get_platform()
display = platform.get_default_display() display = platform.get_default_display()
@ -42,9 +45,17 @@ def main():
for key in config._attribute_names: for key in config._attribute_names:
print(' %-22s %s' % (key + ':', getattr(config, key))) print(' %-22s %s' % (key + ':', getattr(config, key)))
game.Applet(width=INITIAL_WIN_WIDTH, height=INITIAL_WIN_HEIGHT, punyverse = Punyverse(width=INITIAL_WIN_WIDTH, height=INITIAL_WIN_HEIGHT,
caption=WIN_TITLE, resizable=True, vsync=args.vsync, caption=WIN_TITLE, resizable=True, vsync=args.vsync,
config=config) config=config, visible=False)
loader.set_main_context(punyverse.context)
world = loader.load()
punyverse.context.set_current()
punyverse.initialize(world)
loader.close()
punyverse.set_visible(True)
pyglet.app.run() pyglet.app.run()

View file

@ -17,6 +17,7 @@ except ImportError:
import warnings import warnings
warnings.warn('Compile _glgeom.c, or double the start up time.') warnings.warn('Compile _glgeom.c, or double the start up time.')
def bgr_to_rgb(source, width, height, alpha=False): def bgr_to_rgb(source, width, height, alpha=False):
length = len(source) length = len(source)
depth = length // (width * height) depth = length // (width * height)
@ -47,25 +48,9 @@ __all__ = ['load_texture', 'load_clouds', 'load_image', 'get_best_texture']
id = 0 id = 0
cache = {} cache = {}
max_texture = None
power_of_two = None
bgra = False
def is_power2(num):
def init(): return num != 0 and ((num & (num - 1)) == 0)
global max_texture, power_of_two, bgra
if max_texture is None:
buf = c_int()
glGetIntegerv(GL_MAX_TEXTURE_SIZE, byref(buf))
max_texture = buf.value
bgra = gl_info.have_extension('GL_EXT_bgra')
if power_of_two is None:
power_of_two = gl_info.have_version(2) or gl_info.have_extension('GL_ARB_texture_non_power_of_two')
is_power2 = lambda num: num != 0 and ((num & (num - 1)) == 0)
def image_info(data): def image_info(data):
@ -126,12 +111,19 @@ def image_info(data):
return content_type, width, height return content_type, width, height
def max_texture_size():
buf = c_int()
glGetIntegerv(GL_MAX_TEXTURE_SIZE, byref(buf))
return buf.value
def check_size(width, height): def check_size(width, height):
init() max_texture = max_texture_size()
if width > max_texture or height > max_texture: if width > max_texture or height > max_texture:
print('too large') print('too large')
raise ValueError('Texture too large') raise ValueError('Texture too large')
elif not power_of_two: elif not gl_info.have_version(2) and not gl_info.have_extension('GL_ARB_texture_non_power_of_two'):
if not is_power2(width) or not is_power2(height): if not is_power2(width) or not is_power2(height):
print('not power of two') print('not power of two')
raise ValueError('Texture not power of two') raise ValueError('Texture not power of two')
@ -165,7 +157,7 @@ def load_image(file, path):
# Flip from BGR to RGB # Flip from BGR to RGB
if raw.format in ('BGR', 'BGRA'): if raw.format in ('BGR', 'BGRA'):
if bgra: if gl_info.have_extension('GL_EXT_bgra'):
mode = GL_BGRA if 'A' in raw.format else GL_BGR mode = GL_BGRA if 'A' in raw.format else GL_BGR
texture = raw.data texture = raw.data
else: else:

View file

@ -3,29 +3,19 @@ import os
import time import time
from math import hypot from math import hypot
from operator import attrgetter from operator import attrgetter
from time import clock
import pyglet
import six import six
from pyglet.gl import *
from pyglet.window import key, mouse
from punyverse import texture
from punyverse.glgeom import * from punyverse.glgeom import *
from punyverse.world import World
try: try:
from punyverse._model import model_list, load_model from punyverse._model import model_list, load_model
except ImportError: except ImportError:
from punyverse.model import model_list, load_model from punyverse.model import model_list, load_model
try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
from pyglet.gl import *
from pyglet.window import key, mouse
import pyglet
MOUSE_SENSITIVITY = 0.3 # Mouse sensitivity, 0..1, none...hyperspeed MOUSE_SENSITIVITY = 0.3 # Mouse sensitivity, 0..1, none...hyperspeed
MAX_DELTA = 5 MAX_DELTA = 5
@ -40,55 +30,11 @@ def entity_distance(x0, y0, z0):
return distance return distance
class Applet(pyglet.window.Window): class Punyverse(pyglet.window.Window):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Applet, self).__init__(*args, **kwargs) super(Punyverse, self).__init__(*args, **kwargs)
texture.init()
if hasattr(self.config, '_attribute_names'):
info = [' %-22s %s' % (key + ':', value)
for key, value in self.config.get_gl_attributes()]
info = ['%-30s %-30s' % group for group in
zip_longest(info[::2], info[1::2], fillvalue='')]
info = 'OpenGL configuration:\n' + '\n'.join(info)
else:
info = 'Unknown OpenGL configuration'
info = '\n'.join([
'Graphics Vendor: ' + gl_info.get_vendor(),
'Graphics Version: ' + gl_info.get_version(),
'Graphics Renderer: ' + gl_info.get_renderer(),
]) + '\n\n' + info
self.loaded = False
self._loading_phase = pyglet.text.Label(
font_name='Consolas', font_size=20, x=10, y=self.height - 50,
color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True, text='Punyverse is starting...'
)
self._loading_label = pyglet.text.Label(
font_name='Consolas', font_size=16, x=10, y=self.height - 120,
color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True
)
self._info_label = pyglet.text.Label(
font_name='Consolas', font_size=13, x=10, y=self.height - 220,
color=(255, 255, 255, 255), width=self.width - 20,
multiline=True, text=info
)
pyglet.clock.schedule_once(self.load, 0)
def _load_callback(self, phase, message, progress):
print(message)
self.draw_loading(phase, message, progress)
self.flip()
self.dispatch_events()
def load(self, *args, **kwargs):
start = clock()
self.fps = 0 self.fps = 0
self.world = World('world.json', self._load_callback)
self._load_callback('Initializing game...', '', 0)
self.info = True self.info = True
self.debug = False self.debug = False
self.orbit = True self.orbit = True
@ -109,6 +55,19 @@ class Applet(pyglet.window.Window):
630720000, 1576800000, 3153600000, # 20, 50, 100 years 630720000, 1576800000, 3153600000, # 20, 50, 100 years
] ]
self.key_handler = {}
self.mouse_press_handler = {}
self.label = pyglet.text.Label('', font_name='Consolas', font_size=12, x=10, y=self.height - 20,
color=(255,) * 4, multiline=True, width=600)
self.exclusive = False
self.modifiers = 0
self.world = None
def initialize(self, world):
self.world = world
def speed_incrementer(object, increment): def speed_incrementer(object, increment):
def incrementer(): def incrementer():
object.speed += increment object.speed += increment
@ -163,11 +122,6 @@ class Applet(pyglet.window.Window):
mouse.RIGHT: attribute_toggler(self, 'moving'), mouse.RIGHT: attribute_toggler(self, 'moving'),
} }
self.label = pyglet.text.Label('', font_name='Consolas', font_size=12, x=10, y=self.height - 20,
color=(255,) * 4, multiline=True, width=600)
self.exclusive = False
glClearColor(0, 0, 0, 1) glClearColor(0, 0, 0, 1)
glClearDepth(1.0) glClearDepth(1.0)
@ -193,8 +147,6 @@ class Applet(pyglet.window.Window):
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('Loaded in %s seconds.' % (clock() - start))
self.loaded = True
pyglet.clock.schedule(self.update) pyglet.clock.schedule(self.update)
self.on_resize(self.width, self.height) # On resize handler does nothing unless it's loaded self.on_resize(self.width, self.height) # On resize handler does nothing unless it's loaded
@ -225,13 +177,11 @@ class Applet(pyglet.window.Window):
image.save(os.path.expanduser('~/punyverse.png')) image.save(os.path.expanduser('~/punyverse.png'))
def set_exclusive_mouse(self, exclusive): def set_exclusive_mouse(self, exclusive):
super(Applet, self).set_exclusive_mouse(exclusive) super(Punyverse, self).set_exclusive_mouse(exclusive)
self.exclusive = exclusive self.exclusive = exclusive
def on_mouse_press(self, x, y, button, modifiers): def on_mouse_press(self, x, y, button, modifiers):
self.modifiers = modifiers self.modifiers = modifiers
if not self.loaded:
return
if not self.exclusive: if not self.exclusive:
self.set_exclusive_mouse(True) self.set_exclusive_mouse(True)
@ -240,9 +190,6 @@ 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.world.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY) self.world.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY)
@ -250,8 +197,7 @@ class Applet(pyglet.window.Window):
self.modifiers = modifiers self.modifiers = modifiers
if symbol == key.Q: if symbol == key.Q:
self.screenshot() self.screenshot()
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]()
@ -261,18 +207,12 @@ class Applet(pyglet.window.Window):
self.world.cam.roll_right = True self.world.cam.roll_right = True
def on_key_release(self, symbol, modifiers): def on_key_release(self, symbol, modifiers):
if not self.loaded:
return
if symbol == key.A: if symbol == key.A:
self.world.cam.roll_left = False self.world.cam.roll_left = False
elif symbol == key.S: elif symbol == key.S:
self.world.cam.roll_right = False self.world.cam.roll_right = False
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)
@ -283,9 +223,6 @@ 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.world.cam.speed += scroll_y * 50 + scroll_x * 500 self.world.cam.speed += scroll_y * 50 + scroll_x * 500
def get_time_per_second(self): def get_time_per_second(self):
@ -302,23 +239,7 @@ class Applet(pyglet.window.Window):
def update(self, dt): def update(self, dt):
self.world.update(dt, move=self.exclusive and self.moving, tick=self.running) self.world.update(dt, move=self.exclusive and self.moving, tick=self.running)
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 - 140, self.width - 20, 50, progress)
self._info_label.draw()
def on_draw(self): def on_draw(self):
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()

View file

@ -57,7 +57,7 @@ class World(object):
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_size(), 'KM': 1.0 / self._length}
self.tick_length = root.get('tick', 4320) # How many second is a tick? self.tick_length = root.get('tick', 4320) # How many second is a tick?