Converted info display to use shaders.

This commit is contained in:
Quantum 2018-08-28 18:30:43 -04:00
parent 4857b5487c
commit 9e65004128
11 changed files with 143 additions and 20 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -5,10 +5,10 @@ from pyglet.gl import *
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from six.moves import range from six.moves import range
from punyverse.glgeom import compile, glRestore, belt, Disk, OrbitVBO, Matrix4f, SimpleSphere, TangentSphere, Cube from punyverse.glgeom import *
from punyverse.model import load_model, WavefrontVBO from punyverse.model import load_model, WavefrontVBO
from punyverse.orbit import KeplerOrbit from punyverse.orbit import KeplerOrbit
from punyverse.texture import get_best_texture, load_clouds, get_cube_map, load_texture_1d from punyverse.texture import get_best_texture, load_alpha_mask, get_cube_map, load_texture_1d
from punyverse.utils import cached_property from punyverse.utils import cached_property
G = 6.67384e-11 # Gravitation Constant G = 6.67384e-11 # Gravitation Constant
@ -325,7 +325,7 @@ class SphericalBody(Body):
atm_texture = atmosphere_data.get('diffuse_texture', None) atm_texture = atmosphere_data.get('diffuse_texture', None)
cloud_texture = atmosphere_data.get('cloud_texture', None) cloud_texture = atmosphere_data.get('cloud_texture', None)
if cloud_texture is not None: if cloud_texture is not None:
self.cloud_transparency = get_best_texture(cloud_texture, loader=load_clouds) self.cloud_transparency = get_best_texture(cloud_texture, loader=load_alpha_mask)
self.cloud_radius = self.radius + 2 self.cloud_radius = self.radius + 2
self.clouds = self._get_sphere(division, tangent=False) self.clouds = self._get_sphere(division, tangent=False)

View file

@ -1,3 +1,5 @@
from __future__ import division
from array import array from array import array
from ctypes import c_int, c_float, byref, cast, POINTER, c_uint, c_short, c_ushort from ctypes import c_int, c_float, byref, cast, POINTER, c_uint, c_short, c_ushort
from math import * from math import *
@ -10,7 +12,8 @@ from six.moves import range
TWOPI = pi * 2 TWOPI = pi * 2
__all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'belt', __all__ = ['compile', 'ortho', 'frustrum', 'crosshair', 'circle', 'belt',
'glSection', 'glRestore', 'progress_bar'] 'glSection', 'glRestore', 'glContext', 'progress_bar',
'FontEngine', 'Matrix4f', 'Disk', 'OrbitVBO', 'SimpleSphere', 'TangentSphere', 'Cube']
class glContext(object): class glContext(object):
@ -320,6 +323,53 @@ class OrbitVBO(object):
self.close() self.close()
class FontEngine(object):
type = GL_SHORT
stride = 4 * 2
position_offset = 0
position_size = 2
tex_offset = position_size * 2
tex_size = 2
def __init__(self, max_length=256):
self.storage = array('h', max_length * 24 * [0])
vbo = GLuint()
glGenBuffers(1, byref(vbo))
self.vbo = vbo.value
self.vertex_count = None
def draw(self, string):
index = 0
row = 0
col = 0
for c in string:
if c == '\n':
row += 1
col = 0
continue
o = ord(c)
if 32 <= o < 128:
self.storage[24*index:24*index+24] = array('h', [
row, col, o - 32, 1,
row + 1, col, o - 32, 0,
row + 1, col + 1, o - 31, 0,
row, col, o - 32, 1,
row + 1, col + 1, o - 31, 0,
row, col + 1, o - 31, 1,
])
index += 1
col += 1
self.vertex_count = index * 6
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, self.storage.itemsize * len(self.storage),
array_to_ctypes(self.storage), GL_STREAM_DRAW)
def end(self):
glBindBuffer(GL_ARRAY_BUFFER, 0)
def belt(radius, cross, object, count): def belt(radius, cross, object, count):
for i in range(count): for i in range(count):
theta = TWOPI * random() theta = TWOPI * random()

View file

@ -1,5 +1,6 @@
from __future__ import print_function from __future__ import print_function
import os
import sys import sys
import time import time
@ -26,21 +27,29 @@ def get_context_info(context):
class LoaderWindow(pyglet.window.Window): class LoaderWindow(pyglet.window.Window):
MONOSPACE = ('Consolas', 'Droid Sans Mono', 'Courier', 'Courier New', 'Dejavu Sans Mono')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(LoaderWindow, self).__init__(*args, **kwargs) super(LoaderWindow, self).__init__(*args, **kwargs)
# work around pyglet bug: decoding font names as utf-8 instead of mbcs when using EnumFontsA.
stderr = sys.stderr
sys.stderr = open(os.devnull, 'w')
pyglet.font.have_font(self.MONOSPACE[0])
sys.stderr = stderr
self.loading_phase = pyglet.text.Label( self.loading_phase = pyglet.text.Label(
font_name='Consolas', font_size=20, x=10, y=self.height - 50, font_name=self.MONOSPACE, font_size=20, x=10, y=self.height - 50,
color=(255, 255, 255, 255), width=self.width - 20, align='center', color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True, text='Punyverse is starting...' multiline=True, text='Punyverse is starting...'
) )
self.loading_label = pyglet.text.Label( self.loading_label = pyglet.text.Label(
font_name='Consolas', font_size=16, x=10, y=self.height - 120, font_name=self.MONOSPACE, font_size=16, x=10, y=self.height - 120,
color=(255, 255, 255, 255), width=self.width - 20, align='center', color=(255, 255, 255, 255), width=self.width - 20, align='center',
multiline=True multiline=True
) )
self.info_label = pyglet.text.Label( self.info_label = pyglet.text.Label(
font_name='Consolas', font_size=13, x=10, y=self.height - 220, font_name=self.MONOSPACE, font_size=13, x=10, y=self.height - 220,
color=(255, 255, 255, 255), width=self.width - 20, color=(255, 255, 255, 255), width=self.width - 20,
multiline=True multiline=True
) )

View file

@ -103,6 +103,9 @@ class Program(object):
def uniform_bool(self, name, value): def uniform_bool(self, name, value):
glUniform1i(self.uniforms[name], bool(value)) glUniform1i(self.uniforms[name], bool(value))
def uniform_vec2(self, name, a, b):
glUniform2f(self.uniforms[name], a, b)
def uniform_vec3(self, name, a, b, c): def uniform_vec3(self, name, a, b, c):
glUniform3f(self.uniforms[name], a, b, c) glUniform3f(self.uniforms[name], a, b, c)

View file

@ -0,0 +1,12 @@
#version 130
in vec2 v_uv;
out vec4 o_fragColor;
uniform sampler2D u_alpha;
uniform vec3 u_color;
void main() {
o_fragColor = vec4(u_color, texture(u_alpha, v_uv).r);
}

View file

@ -0,0 +1,14 @@
#version 130
in vec2 a_rc;
in vec2 a_tex;
out vec2 v_uv;
uniform mat4 u_projMatrix;
uniform vec2 u_start;
void main() {
gl_Position = u_projMatrix * vec4(a_rc.y * 8 + u_start.x, a_rc.x * 16 + u_start.y, 0, 1);
v_uv = vec2(a_tex.x * 8 / 1024, a_tex.y);
}

View file

@ -42,7 +42,8 @@ except ImportError:
result[y1 * row:y1 * row + row] = source[y2 * row:y2 * row + row] result[y1 * row:y1 * row + row] = source[y2 * row:y2 * row + row]
return six.binary_type(result) return six.binary_type(result)
__all__ = ['load_texture', 'load_clouds', 'load_image', 'get_best_texture', 'max_texture_size', 'get_cube_map'] __all__ = ['load_texture', 'load_alpha_mask', 'load_image', 'get_best_texture', 'max_texture_size',
'get_cube_map', 'load_texture_1d']
id = 0 id = 0
cache = {} cache = {}
@ -259,11 +260,8 @@ def load_texture_1d(file, clamp=False):
return id return id
def load_clouds(file): def load_alpha_mask(file, clamp=False):
path, file = get_file_path(file) path, file = get_file_path(file)
if path in cache:
return cache[path]
path, width, height, depth, mode, texture = load_image(file, path) path, width, height, depth, mode, texture = load_image(file, path)
if depth != 1: if depth != 1:
@ -284,10 +282,13 @@ def load_clouds(file):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
if clamp:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
if gl_info.have_extension('GL_EXT_texture_filter_anisotropic'): if gl_info.have_extension('GL_EXT_texture_filter_anisotropic'):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glGetInteger(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glGetInteger(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT))
cache[path] = id
return id return id

View file

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
from __future__ import division
import os import os
import time import time
from math import hypot from math import hypot
@ -54,8 +55,6 @@ class Punyverse(pyglet.window.Window):
self.key_handler = {} self.key_handler = {}
self.mouse_press_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.exclusive = False
self.modifiers = 0 self.modifiers = 0
@ -127,6 +126,8 @@ class Punyverse(pyglet.window.Window):
glEnable(GL_DEPTH_TEST) glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH) glShadeModel(GL_SMOOTH)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glMatrixMode(GL_MODELVIEW) glMatrixMode(GL_MODELVIEW)
glEnable(GL_LIGHTING) glEnable(GL_LIGHTING)
@ -144,6 +145,8 @@ class Punyverse(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))
self.info_engine = FontEngine()
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
@ -213,9 +216,8 @@ class Punyverse(pyglet.window.Window):
if not width or not height: if not width or not height:
# Sometimes this happen for no reason? # Sometimes this happen for no reason?
return return
self.label.y = height - 20
glViewport(0, 0, width, height)
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION) glMatrixMode(GL_PROJECTION)
self.world.resize(width, height) self.world.resize(width, height)
glLoadMatrixf(self.world.projection_matrix()) glLoadMatrixf(self.world.projection_matrix())
@ -262,7 +264,13 @@ class Punyverse(pyglet.window.Window):
width, height = self.get_size() width, height = self.get_size()
if self.info: if self.info:
ortho(width, height) projection = Matrix4f([
2 / width, 0, 0, 0,
0, -2 / height, 0, 0,
0, 0, -1, 0,
-1, 1, 0, 1,
])
if self.info_precise: if self.info_precise:
info = ('%d FPS @ (x=%.2f, y=%.2f, z=%.2f) @ %s, %s/s\n' info = ('%d FPS @ (x=%.2f, y=%.2f, z=%.2f) @ %s, %s/s\n'
'Direction(pitch=%.2f, yaw=%.2f, roll=%.2f)\nTick: %d' % 'Direction(pitch=%.2f, yaw=%.2f, roll=%.2f)\nTick: %d' %
@ -271,8 +279,30 @@ class Punyverse(pyglet.window.Window):
else: else:
info = ('%d FPS @ (x=%.2f, y=%.2f, z=%.2f) @ %s, %s/s\n' % info = ('%d FPS @ (x=%.2f, y=%.2f, z=%.2f) @ %s, %s/s\n' %
(pyglet.clock.get_fps(), c.x, c.y, c.z, self.world.cam.speed, self.get_time_per_second())) (pyglet.clock.get_fps(), c.x, c.y, c.z, self.world.cam.speed, self.get_time_per_second()))
self.label.text = info
self.label.draw() glEnable(GL_BLEND)
shader = self.world.activate_shader('text')
shader.uniform_mat4('u_projMatrix', projection)
self.info_engine.draw(info)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, self.world.font_tex)
shader.uniform_texture('u_alpha', 0)
shader.uniform_vec3('u_color', 1, 1, 1)
shader.uniform_vec2('u_start', 10, 10)
shader.vertex_attribute('a_rc', self.info_engine.position_size, self.info_engine.type, GL_FALSE,
self.info_engine.stride, self.info_engine.position_offset)
shader.vertex_attribute('a_tex', self.info_engine.tex_size, self.info_engine.type, GL_FALSE,
self.info_engine.stride, self.info_engine.tex_offset)
glDrawArrays(GL_TRIANGLES, 0, self.info_engine.vertex_count)
self.info_engine.end()
self.world.activate_shader(None)
glDisable(GL_BLEND)
ortho(width, height)
with glRestore(GL_CURRENT_BIT | GL_LINE_BIT): with glRestore(GL_CURRENT_BIT | GL_LINE_BIT):
glLineWidth(2) glLineWidth(2)
cx, cy = width / 2, height / 2 cx, cy = width / 2, height / 2

View file

@ -312,6 +312,7 @@
"yaw": -97 "yaw": -97
}, },
"asteroids": ["asteroids/01.obj", "asteroids/02.obj", "asteroids/03.obj"], "asteroids": ["asteroids/01.obj", "asteroids/02.obj", "asteroids/03.obj"],
"font": "font.png",
"start": { "start": {
"z": "AU - 400", "z": "AU - 400",
"yaw": 180 "yaw": 180

View file

@ -24,6 +24,7 @@ class World(object):
'star': ('star.vertex.glsl', 'star.fragment.glsl'), 'star': ('star.vertex.glsl', 'star.fragment.glsl'),
'ring': ('ring.vertex.glsl', 'ring.fragment.glsl'), 'ring': ('ring.vertex.glsl', 'ring.fragment.glsl'),
'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'), 'atmosphere': ('atmosphere.vertex.glsl', 'atmosphere.fragment.glsl'),
'text': ('text.vertex.glsl', 'text.fragment.glsl'),
} }
def __init__(self, file, callback): def __init__(self, file, callback):
@ -133,6 +134,8 @@ class World(object):
self.callback('Loading asteroids...', 'Loading %s...' % file, i / len(asteroids)) self.callback('Loading asteroids...', 'Loading %s...' % file, i / len(asteroids))
self.asteroids.load(file) self.asteroids.load(file)
self.font_tex = load_alpha_mask(root['font'], clamp=True)
def _body(self, name, info, parent=None): def _body(self, name, info, parent=None):
if 'texture' in info: if 'texture' in info:
body = SphericalBody(name, self, info, parent) body = SphericalBody(name, self, info, parent)