update pyglet
fix crash
This commit is contained in:
parent
dc8ee0b4a5
commit
8c96116afb
9
DR.py
9
DR.py
@ -38,14 +38,17 @@ if __name__ == '__main__':
|
|||||||
print(sys.path)
|
print(sys.path)
|
||||||
print(hi)
|
print(hi)
|
||||||
|
|
||||||
DEBUGGING = False
|
DEBUGGING = True
|
||||||
from Difficult_Rocket.api.Exp import *
|
from Difficult_Rocket.api.Exp import *
|
||||||
from Difficult_Rocket.crash import crash
|
from Difficult_Rocket.crash import crash
|
||||||
try:
|
try:
|
||||||
from Difficult_Rocket import main
|
from Difficult_Rocket import main
|
||||||
|
|
||||||
game = main.Game()
|
game = main.Game()
|
||||||
from libs.pyglet.gl import glClearColor
|
|
||||||
glClearColor(0, 0, 0, 0)
|
# from libs.pyglet.gl import glClearColor
|
||||||
|
# glClearColor(0, 0, 0, 0)
|
||||||
|
|
||||||
cprofile = False
|
cprofile = False
|
||||||
if cprofile:
|
if cprofile:
|
||||||
cProfile.run('game.start()', sort='calls')
|
cProfile.run('game.start()', sort='calls')
|
||||||
|
@ -173,7 +173,7 @@ class ClientWindow(Window):
|
|||||||
|
|
||||||
def start_game(self) -> None:
|
def start_game(self) -> None:
|
||||||
self.run_input = True
|
self.run_input = True
|
||||||
self.read_input()
|
# self.read_input()
|
||||||
pyglet.app.run()
|
pyglet.app.run()
|
||||||
|
|
||||||
@new_thread('window read_input', daemon=True)
|
@new_thread('window read_input', daemon=True)
|
||||||
@ -193,11 +193,11 @@ class ClientWindow(Window):
|
|||||||
|
|
||||||
@new_thread('window save_info')
|
@new_thread('window save_info')
|
||||||
def save_info(self):
|
def save_info(self):
|
||||||
print('save_info start')
|
self.logger.info('save_info start')
|
||||||
config_file = tools.load_file('./config/config.toml')
|
config_file = tools.load_file('./configs/main.toml')
|
||||||
config_file['window']['width'] = self.width
|
config_file['window']['width'] = self.width
|
||||||
config_file['window']['height'] = self.height
|
config_file['window']['height'] = self.height
|
||||||
toml.dump(config_file, open('./config/config.toml', 'w'))
|
toml.dump(config_file, open('./configs/main.toml', 'w'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
draws and some event
|
draws and some event
|
||||||
@ -211,9 +211,10 @@ class ClientWindow(Window):
|
|||||||
def FPS_update(self, tick: Decimal):
|
def FPS_update(self, tick: Decimal):
|
||||||
now_FPS = pyglet.clock.get_fps()
|
now_FPS = pyglet.clock.get_fps()
|
||||||
self.fps_log.update_tick(tick)
|
self.fps_log.update_tick(tick)
|
||||||
self.fps_label.text = f'FPS: {self.fps_log.fps: >5.1f}({self.fps_log.middle_fps: >5.1f})[{now_FPS}] \n{self.fps_log.max_fps: >7.1f} {self.fps_log.min_fps:>5.1f}'
|
self.fps_label.text = f'FPS: {self.fps_log.fps: >5.1f}({self.fps_log.middle_fps: >5.1f})[{now_FPS}] {self.fps_log.max_fps: >7.1f} {self.fps_log.min_fps:>5.1f}'
|
||||||
|
|
||||||
def on_draw(self, *dt):
|
def on_draw(self, *dt):
|
||||||
|
# self.logger.debug('on_draw call dt: {}'.format(dt))
|
||||||
self.clear()
|
self.clear()
|
||||||
self.draw_batch()
|
self.draw_batch()
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ class Game:
|
|||||||
# @new_thread('main')
|
# @new_thread('main')
|
||||||
def _start(self):
|
def _start(self):
|
||||||
self.server.run()
|
self.server.run()
|
||||||
threaded = True
|
threaded = False
|
||||||
if threaded:
|
if threaded:
|
||||||
try:
|
try:
|
||||||
game_process = multiprocessing.Process(target=self.client.start(), name='pyglet app')
|
game_process = multiprocessing.Process(target=self.client.start(), name='pyglet app')
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
fps = 60
|
fps = 60
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
language = "zh-CN"
|
language = "zh-CN"
|
||||||
date_fmt = '%Y-%m-%d %H-%M-%S'
|
date_fmt = "%Y-%m-%d %H-%M-%S"
|
||||||
write_py_v = "3.8.10"
|
write_py_v = "3.8.10"
|
||||||
fonts_folder = 'libs/fonts'
|
fonts_folder = "libs/fonts"
|
||||||
|
|
||||||
[window]
|
[window]
|
||||||
style = "None"
|
style = "None"
|
||||||
@ -18,4 +18,3 @@ full_screen = false
|
|||||||
[window.default]
|
[window.default]
|
||||||
width = 1024
|
width = 1024
|
||||||
height = 768
|
height = 768
|
||||||
|
|
||||||
|
@ -452,3 +452,6 @@ class Font:
|
|||||||
glyphs = glyph_buffer
|
glyphs = glyph_buffer
|
||||||
|
|
||||||
return glyphs
|
return glyphs
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.__class__.__name__}('{self.name}')"
|
||||||
|
@ -170,7 +170,7 @@ from pyglet.graphics.vertexbuffer import BufferObject
|
|||||||
_debug_graphics_batch = pyglet.options['debug_graphics_batch']
|
_debug_graphics_batch = pyglet.options['debug_graphics_batch']
|
||||||
|
|
||||||
|
|
||||||
def draw(size, mode, **kwargs):
|
def draw(size, mode, **data):
|
||||||
"""Draw a primitive immediately.
|
"""Draw a primitive immediately.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
@ -194,7 +194,7 @@ def draw(size, mode, **kwargs):
|
|||||||
program.use()
|
program.use()
|
||||||
|
|
||||||
buffers = []
|
buffers = []
|
||||||
for name, (fmt, array) in kwargs.items():
|
for name, (fmt, array) in data.items():
|
||||||
location = program.attributes[name]['location']
|
location = program.attributes[name]['location']
|
||||||
count = program.attributes[name]['count']
|
count = program.attributes[name]['count']
|
||||||
gl_type = vertexdomain._gl_types[fmt[0]]
|
gl_type = vertexdomain._gl_types[fmt[0]]
|
||||||
@ -340,6 +340,8 @@ class Batch:
|
|||||||
self._draw_list = []
|
self._draw_list = []
|
||||||
self._draw_list_dirty = False
|
self._draw_list_dirty = False
|
||||||
|
|
||||||
|
self._context = pyglet.gl.current_context
|
||||||
|
|
||||||
def invalidate(self):
|
def invalidate(self):
|
||||||
"""Force the batch to update the draw list.
|
"""Force the batch to update the draw list.
|
||||||
|
|
||||||
@ -554,7 +556,7 @@ class Group:
|
|||||||
"""Group of common OpenGL state.
|
"""Group of common OpenGL state.
|
||||||
|
|
||||||
Before a VertexList is rendered, its Group's OpenGL state is set.
|
Before a VertexList is rendered, its Group's OpenGL state is set.
|
||||||
This can including binding textures, or setting any other parameters.
|
This includes binding textures, shaders, or setting any other parameters.
|
||||||
"""
|
"""
|
||||||
def __init__(self, order=0, parent=None):
|
def __init__(self, order=0, parent=None):
|
||||||
"""Create a Group.
|
"""Create a Group.
|
||||||
@ -565,6 +567,8 @@ class Group:
|
|||||||
`parent` : `~pyglet.graphics.Group`
|
`parent` : `~pyglet.graphics.Group`
|
||||||
Group to contain this Group; its state will be set before this
|
Group to contain this Group; its state will be set before this
|
||||||
Group's state.
|
Group's state.
|
||||||
|
|
||||||
|
:Ivariables:
|
||||||
`visible` : bool
|
`visible` : bool
|
||||||
Determines whether this Group is visible in any of the Batches
|
Determines whether this Group is visible in any of the Batches
|
||||||
it is assigned to. If False, objects in this Group will not
|
it is assigned to. If False, objects in this Group will not
|
||||||
|
@ -28,65 +28,63 @@ _uniform_getters = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_uniform_setters = {
|
_uniform_setters = {
|
||||||
# uniform type: (gl_type, setter, length, count)
|
# uniform: gl_type, legacy_setter, setter, length, count
|
||||||
GL_BOOL: (GLint, glUniform1iv, 1, 1),
|
GL_BOOL: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
GL_BOOL_VEC2: (GLint, glUniform1iv, 2, 1),
|
GL_BOOL_VEC2: (GLint, glUniform1iv, glProgramUniform1iv, 2, 1),
|
||||||
GL_BOOL_VEC3: (GLint, glUniform1iv, 3, 1),
|
GL_BOOL_VEC3: (GLint, glUniform1iv, glProgramUniform1iv, 3, 1),
|
||||||
GL_BOOL_VEC4: (GLint, glUniform1iv, 4, 1),
|
GL_BOOL_VEC4: (GLint, glUniform1iv, glProgramUniform1iv, 4, 1),
|
||||||
|
|
||||||
GL_INT: (GLint, glUniform1iv, 1, 1),
|
GL_INT: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
GL_INT_VEC2: (GLint, glUniform2iv, 2, 1),
|
GL_INT_VEC2: (GLint, glUniform2iv, glProgramUniform2iv, 2, 1),
|
||||||
GL_INT_VEC3: (GLint, glUniform3iv, 3, 1),
|
GL_INT_VEC3: (GLint, glUniform3iv, glProgramUniform3iv, 3, 1),
|
||||||
GL_INT_VEC4: (GLint, glUniform4iv, 4, 1),
|
GL_INT_VEC4: (GLint, glUniform4iv, glProgramUniform4iv, 4, 1),
|
||||||
|
|
||||||
GL_FLOAT: (GLfloat, glUniform1fv, 1, 1),
|
GL_FLOAT: (GLfloat, glUniform1fv, glProgramUniform1fv, 1, 1),
|
||||||
GL_FLOAT_VEC2: (GLfloat, glUniform2fv, 2, 1),
|
GL_FLOAT_VEC2: (GLfloat, glUniform2fv, glProgramUniform2fv, 2, 1),
|
||||||
GL_FLOAT_VEC3: (GLfloat, glUniform3fv, 3, 1),
|
GL_FLOAT_VEC3: (GLfloat, glUniform3fv, glProgramUniform3fv, 3, 1),
|
||||||
GL_FLOAT_VEC4: (GLfloat, glUniform4fv, 4, 1),
|
GL_FLOAT_VEC4: (GLfloat, glUniform4fv, glProgramUniform4fv, 4, 1),
|
||||||
|
|
||||||
GL_SAMPLER_1D: (GLint, glUniform1iv, 1, 1),
|
GL_SAMPLER_1D: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
GL_SAMPLER_2D: (GLint, glUniform1iv, 1, 1),
|
GL_SAMPLER_2D: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
GL_SAMPLER_2D_ARRAY: (GLint, glUniform1iv, 1, 1),
|
GL_SAMPLER_2D_ARRAY: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
|
|
||||||
GL_SAMPLER_3D: (GLint, glUniform1iv, 1, 1),
|
GL_SAMPLER_3D: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||||
|
|
||||||
GL_FLOAT_MAT2: (GLfloat, glUniformMatrix2fv, 4, 1),
|
GL_FLOAT_MAT2: (GLfloat, glUniformMatrix2fv, glProgramUniformMatrix2fv, 4, 1),
|
||||||
GL_FLOAT_MAT3: (GLfloat, glUniformMatrix3fv, 6, 1),
|
GL_FLOAT_MAT3: (GLfloat, glUniformMatrix3fv, glProgramUniformMatrix3fv, 6, 1),
|
||||||
GL_FLOAT_MAT4: (GLfloat, glUniformMatrix4fv, 16, 1),
|
GL_FLOAT_MAT4: (GLfloat, glUniformMatrix4fv, glProgramUniformMatrix4fv, 16, 1),
|
||||||
|
|
||||||
# TODO: test/implement these:
|
# TODO: test/implement these:
|
||||||
# GL_FLOAT_MAT2x3: glUniformMatrix2x3fv,
|
# GL_FLOAT_MAT2x3: glUniformMatrix2x3fv, glProgramUniformMatrix2x3fv,
|
||||||
# GL_FLOAT_MAT2x4: glUniformMatrix2x4fv,
|
# GL_FLOAT_MAT2x4: glUniformMatrix2x4fv, glProgramUniformMatrix2x4fv,
|
||||||
#
|
# GL_FLOAT_MAT3x2: glUniformMatrix3x2fv, glProgramUniformMatrix3x2fv,
|
||||||
# GL_FLOAT_MAT3x2: glUniformMatrix3x2fv,
|
# GL_FLOAT_MAT3x4: glUniformMatrix3x4fv, glProgramUniformMatrix3x4fv,
|
||||||
# GL_FLOAT_MAT3x4: glUniformMatrix3x4fv,
|
# GL_FLOAT_MAT4x2: glUniformMatrix4x2fv, glProgramUniformMatrix4x2fv,
|
||||||
#
|
# GL_FLOAT_MAT4x3: glUniformMatrix4x3fv, glProgramUniformMatrix4x3fv,
|
||||||
# GL_FLOAT_MAT4x2: glUniformMatrix4x2fv,
|
|
||||||
# GL_FLOAT_MAT4x3: glUniformMatrix4x3fv,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_attribute_types = {
|
_attribute_types = {
|
||||||
GL_BOOL: (1, '?'),
|
GL_BOOL: (1, '?'),
|
||||||
GL_BOOL_VEC2: (2, '?'),
|
GL_BOOL_VEC2: (2, '?'),
|
||||||
GL_BOOL_VEC3: (3, '?'),
|
GL_BOOL_VEC3: (3, '?'),
|
||||||
GL_BOOL_VEC4: (4, '?'),
|
GL_BOOL_VEC4: (4, '?'),
|
||||||
|
|
||||||
GL_INT: (1, 'i'),
|
GL_INT: (1, 'i'),
|
||||||
GL_INT_VEC2: (2, 'i'),
|
GL_INT_VEC2: (2, 'i'),
|
||||||
GL_INT_VEC3: (3, 'i'),
|
GL_INT_VEC3: (3, 'i'),
|
||||||
GL_INT_VEC4: (4, 'i'),
|
GL_INT_VEC4: (4, 'i'),
|
||||||
|
|
||||||
GL_UNSIGNED_INT: (1, 'I'),
|
GL_UNSIGNED_INT: (1, 'I'),
|
||||||
GL_UNSIGNED_INT_VEC2: (2, 'I'),
|
GL_UNSIGNED_INT_VEC2: (2, 'I'),
|
||||||
GL_UNSIGNED_INT_VEC3: (3, 'I'),
|
GL_UNSIGNED_INT_VEC3: (3, 'I'),
|
||||||
GL_UNSIGNED_INT_VEC4: (4, 'I'),
|
GL_UNSIGNED_INT_VEC4: (4, 'I'),
|
||||||
|
|
||||||
GL_FLOAT: (1, 'f'),
|
GL_FLOAT: (1, 'f'),
|
||||||
GL_FLOAT_VEC2: (2, 'f'),
|
GL_FLOAT_VEC2: (2, 'f'),
|
||||||
GL_FLOAT_VEC3: (3, 'f'),
|
GL_FLOAT_VEC3: (3, 'f'),
|
||||||
GL_FLOAT_VEC4: (4, 'f'),
|
GL_FLOAT_VEC4: (4, 'f'),
|
||||||
|
|
||||||
GL_DOUBLE: (1, 'd'),
|
GL_DOUBLE: (1, 'd'),
|
||||||
GL_DOUBLE_VEC2: (2, 'd'),
|
GL_DOUBLE_VEC2: (2, 'd'),
|
||||||
GL_DOUBLE_VEC3: (3, 'd'),
|
GL_DOUBLE_VEC3: (3, 'd'),
|
||||||
GL_DOUBLE_VEC4: (4, 'd'),
|
GL_DOUBLE_VEC4: (4, 'd'),
|
||||||
@ -96,11 +94,16 @@ _attribute_types = {
|
|||||||
class _Uniform:
|
class _Uniform:
|
||||||
__slots__ = 'program', 'name', 'type', 'location', 'length', 'count', 'get', 'set'
|
__slots__ = 'program', 'name', 'type', 'location', 'length', 'count', 'get', 'set'
|
||||||
|
|
||||||
def __init__(self, program, name, uniform_type, gl_type, location, length, count, gl_setter, gl_getter):
|
def __init__(self, program, name, uniform_type, location, dsa):
|
||||||
self.program = program
|
self.program = program
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = uniform_type
|
self.type = uniform_type
|
||||||
self.location = location
|
self.location = location
|
||||||
|
|
||||||
|
gl_type, gl_setter_legacy, gl_setter_dsa, length, count = _uniform_setters[uniform_type]
|
||||||
|
gl_setter = gl_setter_dsa if dsa else gl_setter_legacy
|
||||||
|
gl_getter = _uniform_getters[gl_type]
|
||||||
|
|
||||||
self.length = length
|
self.length = length
|
||||||
self.count = count
|
self.count = count
|
||||||
|
|
||||||
@ -112,45 +115,66 @@ class _Uniform:
|
|||||||
ptr = cast(c_array, POINTER(gl_type))
|
ptr = cast(c_array, POINTER(gl_type))
|
||||||
|
|
||||||
self.get = self._create_getter_func(program, location, gl_getter, c_array, length)
|
self.get = self._create_getter_func(program, location, gl_getter, c_array, length)
|
||||||
self.set = self._create_setter_func(location, gl_setter, c_array, length, count, ptr, is_matrix)
|
self.set = self._create_setter_func(program, location, gl_setter, c_array, length, count, ptr, is_matrix, dsa)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_getter_func(program_id, location, gl_getter, c_array, length):
|
def _create_getter_func(program, location, gl_getter, c_array, length):
|
||||||
"""Factory function for creating simplified Uniform getters"""
|
"""Factory function for creating simplified Uniform getters"""
|
||||||
|
|
||||||
if length == 1:
|
if length == 1:
|
||||||
def getter_func():
|
def getter_func():
|
||||||
gl_getter(program_id, location, c_array)
|
gl_getter(program, location, c_array)
|
||||||
return c_array[0]
|
return c_array[0]
|
||||||
else:
|
else:
|
||||||
def getter_func():
|
def getter_func():
|
||||||
gl_getter(program_id, location, c_array)
|
gl_getter(program, location, c_array)
|
||||||
return c_array[:]
|
return c_array[:]
|
||||||
|
|
||||||
return getter_func
|
return getter_func
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_setter_func(location, gl_setter, c_array, length, count, ptr, is_matrix):
|
def _create_setter_func(program, location, gl_setter, c_array, length, count, ptr, is_matrix, dsa):
|
||||||
"""Factory function for creating simplified Uniform setters"""
|
"""Factory function for creating simplified Uniform setters"""
|
||||||
|
if dsa: # Bindless updates:
|
||||||
|
|
||||||
if is_matrix:
|
if is_matrix:
|
||||||
def setter_func(value):
|
def setter_func(value):
|
||||||
c_array[:] = value
|
c_array[:] = value
|
||||||
gl_setter(location, count, GL_FALSE, ptr)
|
gl_setter(program, location, count, GL_FALSE, ptr)
|
||||||
|
elif length == 1 and count == 1:
|
||||||
|
def setter_func(value):
|
||||||
|
c_array[0] = value
|
||||||
|
gl_setter(program, location, count, ptr)
|
||||||
|
elif length > 1 and count == 1:
|
||||||
|
def setter_func(values):
|
||||||
|
c_array[:] = values
|
||||||
|
gl_setter(program, location, count, ptr)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("Uniform type not yet supported.")
|
||||||
|
|
||||||
elif length == 1 and count == 1:
|
return setter_func
|
||||||
def setter_func(value):
|
|
||||||
c_array[0] = value
|
|
||||||
gl_setter(location, count, ptr)
|
|
||||||
elif length > 1 and count == 1:
|
|
||||||
def setter_func(values):
|
|
||||||
c_array[:] = values
|
|
||||||
gl_setter(location, count, ptr)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("Uniform type not yet supported.")
|
|
||||||
|
|
||||||
return setter_func
|
if is_matrix:
|
||||||
|
def setter_func(value):
|
||||||
|
glUseProgram(program)
|
||||||
|
c_array[:] = value
|
||||||
|
gl_setter(location, count, GL_FALSE, ptr)
|
||||||
|
elif length == 1 and count == 1:
|
||||||
|
def setter_func(value):
|
||||||
|
glUseProgram(program)
|
||||||
|
c_array[0] = value
|
||||||
|
gl_setter(location, count, ptr)
|
||||||
|
elif length > 1 and count == 1:
|
||||||
|
def setter_func(values):
|
||||||
|
glUseProgram(program)
|
||||||
|
c_array[:] = values
|
||||||
|
gl_setter(location, count, ptr)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("Uniform type not yet supported.")
|
||||||
|
|
||||||
|
return setter_func
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Uniform('{self.name}', location={self.location}, length={self.length}, count={self.count})"
|
return f"Uniform('{self.name}', location={self.location}, length={self.length}, count={self.count})"
|
||||||
@ -167,9 +191,9 @@ class Shader:
|
|||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
`source_string` : str
|
`source_string` : str
|
||||||
A string containing the Shader code.
|
A string containing the Shader source code.
|
||||||
`shader_type` : str
|
`shader_type` : str
|
||||||
The Shader type, such as "vertex" or "fragment".
|
The Shader type, such as "vertex", "fragment", "geometry", etc.
|
||||||
"""
|
"""
|
||||||
self._id = None
|
self._id = None
|
||||||
|
|
||||||
@ -228,7 +252,7 @@ class Shader:
|
|||||||
class ShaderProgram:
|
class ShaderProgram:
|
||||||
"""OpenGL Shader Program"""
|
"""OpenGL Shader Program"""
|
||||||
|
|
||||||
__slots__ = '_id', '_context', '_active', '_attributes', '_uniforms', '_uniform_blocks', '__weakref__'
|
__slots__ = '_id', '_context', '_attributes', '_uniforms', '_uniform_blocks', '__weakref__', '_dsa'
|
||||||
|
|
||||||
def __init__(self, *shaders):
|
def __init__(self, *shaders):
|
||||||
"""Create an OpenGL ShaderProgram, from multiple Shaders.
|
"""Create an OpenGL ShaderProgram, from multiple Shaders.
|
||||||
@ -242,15 +266,13 @@ class ShaderProgram:
|
|||||||
assert shaders, "At least one Shader object is required."
|
assert shaders, "At least one Shader object is required."
|
||||||
self._id = self._link_program(shaders)
|
self._id = self._link_program(shaders)
|
||||||
self._context = pyglet.gl.current_context
|
self._context = pyglet.gl.current_context
|
||||||
self._active = False
|
|
||||||
|
|
||||||
self._attributes = {}
|
# Query if Direct State Access is available:
|
||||||
self._uniforms = {}
|
self._dsa = gl_info.have_version(4, 1) or gl_info.have_extension("GL_ARB_separate_shader_objects")
|
||||||
self._uniform_blocks = {}
|
|
||||||
|
|
||||||
self._introspect_attributes()
|
self._attributes = self._introspect_attributes()
|
||||||
self._introspect_uniforms()
|
self._uniforms = self._introspect_uniforms()
|
||||||
self._introspect_uniform_blocks()
|
self._uniform_blocks = self._introspect_uniform_blocks()
|
||||||
|
|
||||||
if _debug_gl_shaders:
|
if _debug_gl_shaders:
|
||||||
print(self._get_program_log())
|
print(self._get_program_log())
|
||||||
@ -259,10 +281,6 @@ class ShaderProgram:
|
|||||||
def id(self):
|
def id(self):
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@property
|
|
||||||
def is_active(self):
|
|
||||||
return self._active
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def attributes(self):
|
def attributes(self):
|
||||||
return self._attributes
|
return self._attributes
|
||||||
@ -275,10 +293,6 @@ class ShaderProgram:
|
|||||||
def uniform_blocks(self):
|
def uniform_blocks(self):
|
||||||
return self._uniform_blocks
|
return self._uniform_blocks
|
||||||
|
|
||||||
@property
|
|
||||||
def formats(self):
|
|
||||||
return tuple(f"{atr.name}{atr.count}{atr.format}" for atr in self._attributes.values())
|
|
||||||
|
|
||||||
def _get_program_log(self):
|
def _get_program_log(self):
|
||||||
result = c_int(0)
|
result = c_int(0)
|
||||||
glGetProgramiv(self._id, GL_INFO_LOG_LENGTH, byref(result))
|
glGetProgramiv(self._id, GL_INFO_LOG_LENGTH, byref(result))
|
||||||
@ -302,11 +316,9 @@ class ShaderProgram:
|
|||||||
|
|
||||||
def use(self):
|
def use(self):
|
||||||
glUseProgram(self._id)
|
glUseProgram(self._id)
|
||||||
self._active = True
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
glUseProgram(0)
|
glUseProgram(0)
|
||||||
self._active = False
|
|
||||||
|
|
||||||
__enter__ = use
|
__enter__ = use
|
||||||
bind = use
|
bind = use
|
||||||
@ -314,7 +326,6 @@ class ShaderProgram:
|
|||||||
|
|
||||||
def __exit__(self, *_):
|
def __exit__(self, *_):
|
||||||
glUseProgram(0)
|
glUseProgram(0)
|
||||||
self._active = False
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
try:
|
try:
|
||||||
@ -325,13 +336,12 @@ class ShaderProgram:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
if not self._active:
|
|
||||||
raise Exception("Shader Program is not active.")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uniform = self._uniforms[key]
|
uniform = self._uniforms[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise Exception("Uniform with the name `{0}` was not found.".format(key))
|
raise Exception(f"A Uniform with the name `{key}` was not found.\n"
|
||||||
|
f"The spelling may be incorrect, or if not in use it "
|
||||||
|
f"may have been optimized out by the OpenGL driver.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uniform.set(value)
|
uniform.set(value)
|
||||||
@ -363,68 +373,62 @@ class ShaderProgram:
|
|||||||
loc = glGetAttribLocation(program, create_string_buffer(a_name.encode('utf-8')))
|
loc = glGetAttribLocation(program, create_string_buffer(a_name.encode('utf-8')))
|
||||||
count, fmt = _attribute_types[a_type]
|
count, fmt = _attribute_types[a_type]
|
||||||
attributes[a_name] = dict(type=a_type, size=a_size, location=loc, count=count, format=fmt)
|
attributes[a_name] = dict(type=a_type, size=a_size, location=loc, count=count, format=fmt)
|
||||||
self._attributes = attributes
|
|
||||||
|
|
||||||
if _debug_gl_shaders:
|
if _debug_gl_shaders:
|
||||||
for attribute in attributes.values():
|
for attribute in attributes.values():
|
||||||
print(f"Found attribute: {attribute}")
|
print(f"Found attribute: {attribute}")
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
|
||||||
def _introspect_uniforms(self):
|
def _introspect_uniforms(self):
|
||||||
prg_id = self._id
|
program = self._id
|
||||||
|
uniforms = {}
|
||||||
for index in range(self._get_number(GL_ACTIVE_UNIFORMS)):
|
for index in range(self._get_number(GL_ACTIVE_UNIFORMS)):
|
||||||
u_name, u_type, u_size = self._query_uniform(index)
|
u_name, u_type, u_size = self._query_uniform(index)
|
||||||
loc = glGetUniformLocation(prg_id, create_string_buffer(u_name.encode('utf-8')))
|
loc = glGetUniformLocation(program, create_string_buffer(u_name.encode('utf-8')))
|
||||||
|
|
||||||
if loc == -1: # Skip uniforms that may be inside a Uniform Block
|
if loc == -1: # Skip uniforms that may be inside a Uniform Block
|
||||||
continue
|
continue
|
||||||
|
uniforms[u_name] = _Uniform(program, u_name, u_type, loc, self._dsa)
|
||||||
|
|
||||||
try:
|
if _debug_gl_shaders:
|
||||||
gl_type, gl_setter, length, count = _uniform_setters[u_type]
|
for uniform in self._uniforms.values():
|
||||||
gl_getter = _uniform_getters[gl_type]
|
print(f"Found uniform: {uniform}")
|
||||||
|
|
||||||
if _debug_gl_shaders:
|
return uniforms
|
||||||
print("Found uniform: {0}, type: {1}, size: {2}, location: {3}, length: {4},"
|
|
||||||
" count: {5}".format(u_name, u_type, u_size, loc, length, count))
|
|
||||||
|
|
||||||
except KeyError:
|
|
||||||
raise GLException("Unsupported Uniform type {0}".format(u_type))
|
|
||||||
|
|
||||||
self._uniforms[u_name] = _Uniform(prg_id, u_name, u_type, gl_type, loc, length, count, gl_setter, gl_getter)
|
|
||||||
|
|
||||||
def _introspect_uniform_blocks(self):
|
def _introspect_uniform_blocks(self):
|
||||||
p_id = self._id
|
program = self._id
|
||||||
|
|
||||||
uniform_blocks = {}
|
uniform_blocks = {}
|
||||||
|
|
||||||
for index in range(self._get_number(GL_ACTIVE_UNIFORM_BLOCKS)):
|
for index in range(self._get_number(GL_ACTIVE_UNIFORM_BLOCKS)):
|
||||||
name = self._get_uniform_block_name(index)
|
name = self._get_uniform_block_name(index)
|
||||||
|
|
||||||
uniform_blocks[name] = {}
|
|
||||||
|
|
||||||
num_active = GLint()
|
num_active = GLint()
|
||||||
block_data_size = GLint()
|
block_data_size = GLint()
|
||||||
|
|
||||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_DATA_SIZE, block_data_size)
|
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, block_data_size)
|
||||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, num_active)
|
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, num_active)
|
||||||
|
|
||||||
indices = (GLuint * num_active.value)()
|
indices = (GLuint * num_active.value)()
|
||||||
indices_ptr = cast(addressof(indices), POINTER(GLint))
|
indices_ptr = cast(addressof(indices), POINTER(GLint))
|
||||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices_ptr)
|
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices_ptr)
|
||||||
|
|
||||||
|
uniforms = {}
|
||||||
|
|
||||||
for i in range(num_active.value):
|
for i in range(num_active.value):
|
||||||
uniform_name, u_type, u_size = self._query_uniform(indices[i])
|
uniform_name, u_type, u_size = self._query_uniform(indices[i])
|
||||||
|
|
||||||
# Separate uniform name from block name (Only if instance name is provided on the Uniform Block)
|
# Separate uniform name from block name (Only if instance name is provided on the Uniform Block)
|
||||||
try:
|
try:
|
||||||
_, uniform_name = uniform_name.split(".")
|
_, uniform_name = uniform_name.split(".")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
gl_type, _, length, _ = _uniform_setters[u_type]
|
|
||||||
|
|
||||||
uniform_blocks[name][i] = (uniform_name, gl_type, length)
|
|
||||||
|
|
||||||
self._uniform_blocks[name] = UniformBlock(self, name, index, block_data_size.value, uniform_blocks[name])
|
gl_type, _, _, length, _ = _uniform_setters[u_type]
|
||||||
|
uniforms[i] = (uniform_name, gl_type, length)
|
||||||
|
|
||||||
|
uniform_blocks[name] = UniformBlock(self, name, index, block_data_size.value, uniforms)
|
||||||
|
|
||||||
|
return uniform_blocks
|
||||||
|
|
||||||
def _get_uniform_block_name(self, index):
|
def _get_uniform_block_name(self, index):
|
||||||
buf_size = 128
|
buf_size = 128
|
||||||
@ -484,10 +488,10 @@ class ShaderProgram:
|
|||||||
try:
|
try:
|
||||||
if isinstance(fmt, tuple):
|
if isinstance(fmt, tuple):
|
||||||
fmt, array = fmt
|
fmt, array = fmt
|
||||||
initial_arrays.append((attributes[name]['location'], array))
|
initial_arrays.append((name, array))
|
||||||
attributes[name] = {**attributes[name], **{'format': fmt}}
|
attributes[name] = {**attributes[name], **{'format': fmt}}
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ShaderException(f"\nThe attribute `{name}` doesn't exist. Valid names: \n{attributes.keys()}")
|
raise ShaderException(f"\nThe attribute `{name}` doesn't exist. Valid names: \n{list(attributes)}")
|
||||||
|
|
||||||
batch = batch or pyglet.graphics.get_default_batch()
|
batch = batch or pyglet.graphics.get_default_batch()
|
||||||
domain = batch.get_domain(False, mode, group, self._id, attributes)
|
domain = batch.get_domain(False, mode, group, self._id, attributes)
|
||||||
@ -495,8 +499,8 @@ class ShaderProgram:
|
|||||||
# Create vertex list and initialize
|
# Create vertex list and initialize
|
||||||
vlist = domain.create(count)
|
vlist = domain.create(count)
|
||||||
|
|
||||||
for index, array in initial_arrays:
|
for name, array in initial_arrays:
|
||||||
vlist.set_attribute_data(index, array)
|
vlist.set_attribute_data(name, array)
|
||||||
|
|
||||||
return vlist
|
return vlist
|
||||||
|
|
||||||
@ -528,7 +532,7 @@ class ShaderProgram:
|
|||||||
try:
|
try:
|
||||||
if isinstance(fmt, tuple):
|
if isinstance(fmt, tuple):
|
||||||
fmt, array = fmt
|
fmt, array = fmt
|
||||||
initial_arrays.append((attributes[name]['location'], array))
|
initial_arrays.append((name, array))
|
||||||
attributes[name] = {**attributes[name], **{'format': fmt}}
|
attributes[name] = {**attributes[name], **{'format': fmt}}
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ShaderException(f"\nThe attribute `{name}` doesn't exist. Valid names: \n{list(attributes)}")
|
raise ShaderException(f"\nThe attribute `{name}` doesn't exist. Valid names: \n{list(attributes)}")
|
||||||
@ -541,8 +545,8 @@ class ShaderProgram:
|
|||||||
start = vlist.start
|
start = vlist.start
|
||||||
vlist.indices = [i + start for i in indices]
|
vlist.indices = [i + start for i in indices]
|
||||||
|
|
||||||
for index, array in initial_arrays:
|
for name, array in initial_arrays:
|
||||||
vlist.set_attribute_data(index, array)
|
vlist.set_attribute_data(name, array)
|
||||||
|
|
||||||
return vlist
|
return vlist
|
||||||
|
|
||||||
@ -578,7 +582,6 @@ class UniformBufferObject:
|
|||||||
self.view = self._introspect_uniforms()
|
self.view = self._introspect_uniforms()
|
||||||
self._view_ptr = pointer(self.view)
|
self._view_ptr = pointer(self.view)
|
||||||
self.index = index
|
self.index = index
|
||||||
# glUniformBlockBinding(self.block.program.id, self.block.index, self.index)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
@ -329,8 +329,8 @@ class VertexList:
|
|||||||
for version in self._cache_versions:
|
for version in self._cache_versions:
|
||||||
self._cache_versions[version] = None
|
self._cache_versions[version] = None
|
||||||
|
|
||||||
def set_attribute_data(self, i, data):
|
def set_attribute_data(self, name, data):
|
||||||
attribute = self.domain.attributes[i]
|
attribute = self.domain.attribute_names[name]
|
||||||
attribute.set_region(attribute.buffer, self.start, self.count, data)
|
attribute.set_region(attribute.buffer, self.start, self.count, data)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
|
@ -81,15 +81,15 @@ class _Relation:
|
|||||||
def _map_pair(raw_relation):
|
def _map_pair(raw_relation):
|
||||||
inverted = False
|
inverted = False
|
||||||
relation_string = raw_relation.split(":")[1]
|
relation_string = raw_relation.split(":")[1]
|
||||||
if relation_string.startswith("+"):
|
if "+" in relation_string:
|
||||||
relation_string = relation_string[1:]
|
relation_string = relation_string.strip('+')
|
||||||
inverted = False
|
inverted = False
|
||||||
elif relation_string.startswith("-"):
|
elif "-" in relation_string:
|
||||||
relation_string = relation_string[1:]
|
relation_string = relation_string.strip('-')
|
||||||
inverted = True
|
inverted = True
|
||||||
if "~" in relation_string:
|
if "~" in relation_string:
|
||||||
# TODO: handle this
|
relation_string = relation_string.strip('~')
|
||||||
return None
|
inverted = True
|
||||||
if relation_string.startswith("b"): # Button
|
if relation_string.startswith("b"): # Button
|
||||||
return _Relation("button", int(relation_string[1:]), inverted)
|
return _Relation("button", int(relation_string[1:]), inverted)
|
||||||
elif relation_string.startswith("a"): # Axis
|
elif relation_string.startswith("a"): # Axis
|
||||||
@ -189,7 +189,6 @@ def add_mappings_from_file(filename) -> None:
|
|||||||
`filename` : str
|
`filename` : str
|
||||||
A file path.
|
A file path.
|
||||||
"""
|
"""
|
||||||
assert os.path.exists(filename), f"Invalid path: {filename}"
|
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
add_mappings_from_string(f.read())
|
add_mappings_from_string(f.read())
|
||||||
|
|
||||||
|
@ -34,11 +34,15 @@
|
|||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import errno
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import struct
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
|
from ctypes import c_uint16 as _u16
|
||||||
|
from ctypes import c_int16 as _s16
|
||||||
|
from ctypes import c_uint32 as _u32
|
||||||
|
from ctypes import c_int32 as _s32
|
||||||
|
from ctypes import c_int64 as _s64
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
|
|
||||||
from pyglet.app.xlib import XlibSelectDevice
|
from pyglet.app.xlib import XlibSelectDevice
|
||||||
@ -47,18 +51,11 @@ from .base import DeviceOpenException
|
|||||||
from .evdev_constants import *
|
from .evdev_constants import *
|
||||||
from .controller import get_mapping
|
from .controller import get_mapping
|
||||||
|
|
||||||
c = pyglet.lib.load_library('c')
|
|
||||||
|
|
||||||
_IOC_NRBITS = 8
|
_IOC_NRBITS = 8
|
||||||
_IOC_TYPEBITS = 8
|
_IOC_TYPEBITS = 8
|
||||||
_IOC_SIZEBITS = 14
|
_IOC_SIZEBITS = 14
|
||||||
_IOC_DIRBITS = 2
|
_IOC_DIRBITS = 2
|
||||||
|
|
||||||
_IOC_NRMASK = ((1 << _IOC_NRBITS) - 1)
|
|
||||||
_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
|
|
||||||
_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
|
|
||||||
_IOC_DIRMASK = ((1 << _IOC_DIRBITS) - 1)
|
|
||||||
|
|
||||||
_IOC_NRSHIFT = 0
|
_IOC_NRSHIFT = 0
|
||||||
_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
|
_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
|
||||||
_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
|
_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
|
||||||
@ -81,9 +78,7 @@ def _IOR(type, nr, struct):
|
|||||||
|
|
||||||
def f(fileno):
|
def f(fileno):
|
||||||
buffer = struct()
|
buffer = struct()
|
||||||
if c.ioctl(fileno, request, ctypes.byref(buffer)) < 0:
|
fcntl.ioctl(fileno, request, buffer)
|
||||||
err = ctypes.c_int.in_dll(c, 'errno').value
|
|
||||||
raise OSError(err, errno.errorcode[err])
|
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
return f
|
return f
|
||||||
@ -92,9 +87,7 @@ def _IOR(type, nr, struct):
|
|||||||
def _IOR_len(type, nr):
|
def _IOR_len(type, nr):
|
||||||
def f(fileno, buffer):
|
def f(fileno, buffer):
|
||||||
request = _IOC(_IOC_READ, ord(type), nr, ctypes.sizeof(buffer))
|
request = _IOC(_IOC_READ, ord(type), nr, ctypes.sizeof(buffer))
|
||||||
if c.ioctl(fileno, request, ctypes.byref(buffer)) < 0:
|
fcntl.ioctl(fileno, request, buffer)
|
||||||
err = ctypes.c_int.in_dll(c, 'errno').value
|
|
||||||
raise OSError(err, errno.errorcode[err])
|
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
return f
|
return f
|
||||||
@ -103,56 +96,154 @@ def _IOR_len(type, nr):
|
|||||||
def _IOR_str(type, nr):
|
def _IOR_str(type, nr):
|
||||||
g = _IOR_len(type, nr)
|
g = _IOR_len(type, nr)
|
||||||
|
|
||||||
def f(fileno, len=256):
|
def f(fileno, length=256):
|
||||||
return g(fileno, ctypes.create_string_buffer(len)).value
|
return g(fileno, ctypes.create_string_buffer(length)).value
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
time_t = ctypes.c_long
|
def _IOW(type, nr):
|
||||||
suseconds_t = ctypes.c_long
|
|
||||||
|
def f(fileno, buffer):
|
||||||
|
request = _IOC(_IOC_WRITE, ord(type), nr, ctypes.sizeof(buffer))
|
||||||
|
fcntl.ioctl(fileno, request, buffer)
|
||||||
|
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
class timeval(ctypes.Structure):
|
# Structures from /linux/blob/master/include/uapi/linux/input.h
|
||||||
|
|
||||||
|
class Timeval(ctypes.Structure):
|
||||||
_fields_ = (
|
_fields_ = (
|
||||||
('tv_sec', time_t),
|
('tv_sec', _s64),
|
||||||
('tv_usec', suseconds_t)
|
('tv_usec', _s64)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class input_event(ctypes.Structure):
|
class InputEvent(ctypes.Structure):
|
||||||
_fields_ = (
|
_fields_ = (
|
||||||
('time', timeval),
|
('time', Timeval),
|
||||||
('type', ctypes.c_uint16),
|
('type', _u16),
|
||||||
('code', ctypes.c_uint16),
|
('code', _u16),
|
||||||
('value', ctypes.c_int32)
|
('value', _s32)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class input_id(ctypes.Structure):
|
class InputID(ctypes.Structure):
|
||||||
_fields_ = (
|
_fields_ = (
|
||||||
('bustype', ctypes.c_uint16),
|
('bustype', _u16),
|
||||||
('vendor', ctypes.c_uint16),
|
('vendor', _u16),
|
||||||
('product', ctypes.c_uint16),
|
('product', _u16),
|
||||||
('version', ctypes.c_uint16),
|
('version', _u16),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class input_absinfo(ctypes.Structure):
|
class InputABSInfo(ctypes.Structure):
|
||||||
_fields_ = (
|
_fields_ = (
|
||||||
('value', ctypes.c_int32),
|
('value', _s32),
|
||||||
('minimum', ctypes.c_int32),
|
('minimum', _s32),
|
||||||
('maximum', ctypes.c_int32),
|
('maximum', _s32),
|
||||||
('fuzz', ctypes.c_int32),
|
('fuzz', _s32),
|
||||||
('flat', ctypes.c_int32),
|
('flat', _s32),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FFReplay(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('length', _u16),
|
||||||
|
('delay', _u16)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FFTrigger(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('button', _u16),
|
||||||
|
('interval', _u16)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FFEnvelope(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('attack_length', _u16),
|
||||||
|
('attack_level', _u16),
|
||||||
|
('fade_length', _u16),
|
||||||
|
('fade_level', _u16),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FFConstantEffect(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('level', _s16),
|
||||||
|
('ff_envelope', FFEnvelope),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FFRampEffect(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('start_level', _s16),
|
||||||
|
('end_level', _s16),
|
||||||
|
('ff_envelope', FFEnvelope),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FFConditionEffect(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('right_saturation', _u16),
|
||||||
|
('left_saturation', _u16),
|
||||||
|
('right_coeff', _s16),
|
||||||
|
('left_coeff', _s16),
|
||||||
|
('deadband', _u16),
|
||||||
|
('center', _s16),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FFPeriodicEffect(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('waveform', _u16),
|
||||||
|
('period', _u16),
|
||||||
|
('magnitude', _s16),
|
||||||
|
('offset', _s16),
|
||||||
|
('phase', _u16),
|
||||||
|
('envelope', FFEnvelope),
|
||||||
|
('custom_len', _u32),
|
||||||
|
('custom_data', ctypes.POINTER(_s16)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FFRumbleEffect(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('strong_magnitude', _u16),
|
||||||
|
('weak_magnitude', _u16)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FFEffectType(ctypes.Union):
|
||||||
|
_fields_ = (
|
||||||
|
('ff_constant_effect', FFConstantEffect),
|
||||||
|
('ff_ramp_effect', FFRampEffect),
|
||||||
|
('ff_periodic_effect', FFPeriodicEffect),
|
||||||
|
('ff_condition_effect', FFConditionEffect * 2),
|
||||||
|
('ff_rumble_effect', FFRumbleEffect),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FFEvent(ctypes.Structure):
|
||||||
|
_fields_ = (
|
||||||
|
('type', _u16),
|
||||||
|
('id', _s16),
|
||||||
|
('direction', _u16),
|
||||||
|
('ff_trigger', FFTrigger),
|
||||||
|
('ff_replay', FFReplay),
|
||||||
|
('u', FFEffectType)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
EVIOCGVERSION = _IOR('E', 0x01, ctypes.c_int)
|
EVIOCGVERSION = _IOR('E', 0x01, ctypes.c_int)
|
||||||
EVIOCGID = _IOR('E', 0x02, input_id)
|
EVIOCGID = _IOR('E', 0x02, InputID)
|
||||||
EVIOCGNAME = _IOR_str('E', 0x06)
|
EVIOCGNAME = _IOR_str('E', 0x06)
|
||||||
EVIOCGPHYS = _IOR_str('E', 0x07)
|
EVIOCGPHYS = _IOR_str('E', 0x07)
|
||||||
EVIOCGUNIQ = _IOR_str('E', 0x08)
|
EVIOCGUNIQ = _IOR_str('E', 0x08)
|
||||||
|
EVIOCSFF = _IOW('E', 0x80)
|
||||||
|
|
||||||
|
|
||||||
def EVIOCGBIT(fileno, ev, buffer):
|
def EVIOCGBIT(fileno, ev, buffer):
|
||||||
@ -160,14 +251,14 @@ def EVIOCGBIT(fileno, ev, buffer):
|
|||||||
|
|
||||||
|
|
||||||
def EVIOCGABS(fileno, abs):
|
def EVIOCGABS(fileno, abs):
|
||||||
buffer = input_absinfo()
|
buffer = InputABSInfo()
|
||||||
return _IOR_len('E', 0x40 + abs)(fileno, buffer)
|
return _IOR_len('E', 0x40 + abs)(fileno, buffer)
|
||||||
|
|
||||||
|
|
||||||
def get_set_bits(bytes):
|
def get_set_bits(bytestring):
|
||||||
bits = set()
|
bits = set()
|
||||||
j = 0
|
j = 0
|
||||||
for byte in bytes:
|
for byte in bytestring:
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
if byte & 1:
|
if byte & 1:
|
||||||
bits.add(j + i)
|
bits.add(j + i)
|
||||||
@ -208,7 +299,6 @@ def _create_control(fileno, event_type, event_code):
|
|||||||
maximum = absinfo.maximum
|
maximum = absinfo.maximum
|
||||||
control = AbsoluteAxis(name, minimum, maximum, raw_name)
|
control = AbsoluteAxis(name, minimum, maximum, raw_name)
|
||||||
control.value = value
|
control.value = value
|
||||||
|
|
||||||
if name == 'hat_y':
|
if name == 'hat_y':
|
||||||
control.inverted = True
|
control.inverted = True
|
||||||
elif event_type == EV_REL:
|
elif event_type == EV_REL:
|
||||||
@ -235,6 +325,7 @@ event_types = {
|
|||||||
EV_MSC: MSC_MAX,
|
EV_MSC: MSC_MAX,
|
||||||
EV_LED: LED_MAX,
|
EV_LED: LED_MAX,
|
||||||
EV_SND: SND_MAX,
|
EV_SND: SND_MAX,
|
||||||
|
EV_FF: FF_MAX,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -273,6 +364,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
|
|
||||||
self.controls = []
|
self.controls = []
|
||||||
self.control_map = {}
|
self.control_map = {}
|
||||||
|
self.ff_types = []
|
||||||
|
|
||||||
event_types_bits = (ctypes.c_byte * 4)()
|
event_types_bits = (ctypes.c_byte * 4)()
|
||||||
EVIOCGBIT(fileno, 0, event_types_bits)
|
EVIOCGBIT(fileno, 0, event_types_bits)
|
||||||
@ -283,11 +375,14 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
nbytes = max_code // 8 + 1
|
nbytes = max_code // 8 + 1
|
||||||
event_codes_bits = (ctypes.c_byte * nbytes)()
|
event_codes_bits = (ctypes.c_byte * nbytes)()
|
||||||
EVIOCGBIT(fileno, event_type, event_codes_bits)
|
EVIOCGBIT(fileno, event_type, event_codes_bits)
|
||||||
for event_code in get_set_bits(event_codes_bits):
|
if event_type == EV_FF:
|
||||||
control = _create_control(fileno, event_type, event_code)
|
self.ff_types.extend(get_set_bits(event_codes_bits))
|
||||||
if control:
|
else:
|
||||||
self.control_map[(event_type, event_code)] = control
|
for event_code in get_set_bits(event_codes_bits):
|
||||||
self.controls.append(control)
|
control = _create_control(fileno, event_type, event_code)
|
||||||
|
if control:
|
||||||
|
self.control_map[(event_type, event_code)] = control
|
||||||
|
self.controls.append(control)
|
||||||
|
|
||||||
os.close(fileno)
|
os.close(fileno)
|
||||||
|
|
||||||
@ -308,7 +403,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
hex_product, shifted_product, hex_version, shifted_version)
|
hex_product, shifted_product, hex_version, shifted_version)
|
||||||
|
|
||||||
def open(self, window=None, exclusive=False):
|
def open(self, window=None, exclusive=False):
|
||||||
super(EvdevDevice, self).open(window, exclusive)
|
super().open(window, exclusive)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._fileno = os.open(self._filename, os.O_RDWR | os.O_NONBLOCK)
|
self._fileno = os.open(self._filename, os.O_RDWR | os.O_NONBLOCK)
|
||||||
@ -318,7 +413,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
pyglet.app.platform_event_loop.select_devices.add(self)
|
pyglet.app.platform_event_loop.select_devices.add(self)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
super(EvdevDevice, self).close()
|
super().close()
|
||||||
|
|
||||||
if not self._fileno:
|
if not self._fileno:
|
||||||
return
|
return
|
||||||
@ -332,33 +427,8 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
|
|
||||||
# Force Feedback methods
|
# Force Feedback methods
|
||||||
|
|
||||||
def supports_ff(self):
|
def ff_upload_effect(self, structure):
|
||||||
try:
|
os.write(self._fileno, structure)
|
||||||
self._fileno = os.open(self._filename, os.O_RDWR | os.O_NONBLOCK)
|
|
||||||
self.ff_create_effect(0, 0, 0)
|
|
||||||
os.close(self._fileno)
|
|
||||||
return True
|
|
||||||
except OSError:
|
|
||||||
os.close(self._fileno)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def ff_create_effect(self, weak, strong, duration, effect=-1):
|
|
||||||
weak = int(max(min(1, weak), 0) * 0xFFFF) # Clamp range from 0-1, convert to 16bit
|
|
||||||
strong = int(max(min(1, strong), 0) * 0xFFFF) # Clamp range from 0-1, convert to 16bit
|
|
||||||
duration = int(duration * 1000)
|
|
||||||
effect = bytearray(struct.pack('HhHHHHHxHH', FF_RUMBLE, effect, 0, 0, 0, duration, 0, strong, weak))
|
|
||||||
view = memoryview(effect).cast('h')
|
|
||||||
|
|
||||||
fcntl.ioctl(self._fileno, 0x40304580, view, True)
|
|
||||||
return view[1] # effect ID
|
|
||||||
|
|
||||||
def ff_play(self, effect):
|
|
||||||
ev_play = struct.pack('LLHHi', 0, 0, EV_FF, effect, 1)
|
|
||||||
os.write(self._fileno, ev_play)
|
|
||||||
|
|
||||||
def ff_stop(self, effect):
|
|
||||||
ev_stop = struct.pack('LLHHi', 0, 0, EV_FF, effect, 0)
|
|
||||||
os.write(self._fileno, ev_stop)
|
|
||||||
|
|
||||||
# XlibSelectDevice interface
|
# XlibSelectDevice interface
|
||||||
|
|
||||||
@ -372,12 +442,14 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
if not self._fileno:
|
if not self._fileno:
|
||||||
return
|
return
|
||||||
|
|
||||||
events = (input_event * 64)()
|
try:
|
||||||
bytes_read = c.read(self._fileno, events, ctypes.sizeof(events))
|
events = (InputEvent * 64)()
|
||||||
if bytes_read < 0:
|
bytes_read = os.readv(self._fileno, events)
|
||||||
|
except OSError:
|
||||||
|
self.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
n_events = bytes_read // ctypes.sizeof(input_event)
|
n_events = bytes_read // ctypes.sizeof(InputEvent)
|
||||||
for event in events[:n_events]:
|
for event in events[:n_events]:
|
||||||
try:
|
try:
|
||||||
control = self.control_map[(event.type, event.code)]
|
control = self.control_map[(event.type, event.code)]
|
||||||
@ -386,32 +458,54 @@ class EvdevDevice(XlibSelectDevice, Device):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class EvdevController(Controller):
|
class FFController(Controller):
|
||||||
|
"""Controller that supports force-feedback"""
|
||||||
_rumble_weak = -1
|
_fileno = None
|
||||||
_rumble_strong = -1
|
_weak_effect = None
|
||||||
|
_play_weak_event = None
|
||||||
|
_stop_weak_event = None
|
||||||
|
_strong_effect = None
|
||||||
|
_play_strong_event = None
|
||||||
|
_stop_strong_event = None
|
||||||
|
|
||||||
def open(self, window=None, exclusive=False):
|
def open(self, window=None, exclusive=False):
|
||||||
super().open(window, exclusive)
|
super().open(window, exclusive)
|
||||||
# Create Force Feedback effects when the device is opened:
|
self._fileno = self.device.fileno()
|
||||||
self._rumble_weak = self.device.ff_create_effect(0, 0, 0)
|
# Create Force Feedback effects & events when opened:
|
||||||
self._rumble_strong = self.device.ff_create_effect(0, 0, 0)
|
# https://www.kernel.org/doc/html/latest/input/ff.html
|
||||||
|
self._weak_effect = self._create_effect()
|
||||||
|
self._play_weak_event = InputEvent(Timeval(), EV_FF, self._weak_effect.id, 1)
|
||||||
|
self._stop_weak_event = InputEvent(Timeval(), EV_FF, self._weak_effect.id, 0)
|
||||||
|
self._strong_effect = self._create_effect()
|
||||||
|
self._play_strong_event = InputEvent(Timeval(), EV_FF, self._strong_effect.id, 1)
|
||||||
|
self._stop_strong_event = InputEvent(Timeval(), EV_FF, self._strong_effect.id, 0)
|
||||||
|
|
||||||
|
def _create_effect(self):
|
||||||
|
event = FFEvent(FF_RUMBLE, -1)
|
||||||
|
EVIOCSFF(self._fileno, event)
|
||||||
|
return event
|
||||||
|
|
||||||
def rumble_play_weak(self, strength=1.0, duration=0.5):
|
def rumble_play_weak(self, strength=1.0, duration=0.5):
|
||||||
effect = self.device.ff_create_effect(strength, 0, duration, self._rumble_weak)
|
effect = self._weak_effect
|
||||||
self.device.ff_play(effect)
|
effect.u.ff_rumble_effect.weak_magnitude = int(max(min(1.0, strength), 0) * 0xFFFF)
|
||||||
|
effect.ff_replay.length = int(duration * 1000)
|
||||||
|
EVIOCSFF(self._fileno, effect)
|
||||||
|
self.device.ff_upload_effect(self._play_weak_event)
|
||||||
|
|
||||||
def rumble_play_strong(self, strength=1.0, duration=0.5):
|
def rumble_play_strong(self, strength=1.0, duration=0.5):
|
||||||
effect = self.device.ff_create_effect(0, strength, duration, self._rumble_strong)
|
effect = self._strong_effect
|
||||||
self.device.ff_play(effect)
|
effect.u.ff_rumble_effect.strong_magnitude = int(max(min(1.0, strength), 0) * 0xFFFF)
|
||||||
|
effect.ff_replay.length = int(duration * 1000)
|
||||||
|
EVIOCSFF(self._fileno, effect)
|
||||||
|
self.device.ff_upload_effect(self._play_strong_event)
|
||||||
|
|
||||||
def rumble_stop_weak(self):
|
def rumble_stop_weak(self):
|
||||||
"""Stop playing rumble effects on the weak motor."""
|
"""Stop playing rumble effects on the weak motor."""
|
||||||
self.device.ff_stop(self._rumble_weak)
|
self.device.ff_upload_effect(self._stop_weak_event)
|
||||||
|
|
||||||
def rumble_stop_strong(self):
|
def rumble_stop_strong(self):
|
||||||
"""Stop playing rumble effects on the strong motor."""
|
"""Stop playing rumble effects on the strong motor."""
|
||||||
self.device.ff_stop(self._rumble_strong)
|
self.device.ff_upload_effect(self._stop_strong_event)
|
||||||
|
|
||||||
|
|
||||||
def get_devices(display=None):
|
def get_devices(display=None):
|
||||||
@ -470,8 +564,8 @@ def _create_controller(device):
|
|||||||
if have_button is False or mapping is None:
|
if have_button is False or mapping is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if device.supports_ff():
|
if FF_RUMBLE in device.ff_types:
|
||||||
return EvdevController(device, mapping)
|
return FFController(device, mapping)
|
||||||
else:
|
else:
|
||||||
return Controller(device, mapping)
|
return Controller(device, mapping)
|
||||||
|
|
||||||
|
@ -36,14 +36,19 @@
|
|||||||
"""Matrix and Vector math.
|
"""Matrix and Vector math.
|
||||||
|
|
||||||
This module provides Vector and Matrix objects, include Vec2, Vec3, Vec4,
|
This module provides Vector and Matrix objects, include Vec2, Vec3, Vec4,
|
||||||
Mat3 and Mat4. Most common operations are supported, and many helper
|
Mat3, and Mat4. Most common operations are supported, and many helper
|
||||||
methods are included for rotating, scaling, and transforming.
|
methods are included for rotating, scaling, and transforming. The
|
||||||
The :py:class:`~pyglet.matrix.Mat4` includes class methods
|
:py:class:`~pyglet.matrix.Mat4` includes class methods for creating
|
||||||
for creating orthographic and perspective projection matrixes.
|
orthographic and perspective projection matrixes.
|
||||||
|
|
||||||
|
:note: For performance, these objects' subclass the `tuple` type. They
|
||||||
|
are therefore immutable - all operations return a new object; the
|
||||||
|
object is not updated in-place.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import math as _math
|
import math as _math
|
||||||
import warnings as _warnings
|
import warnings as _warnings
|
||||||
|
|
||||||
from operator import mul as _mul
|
from operator import mul as _mul
|
||||||
|
|
||||||
|
|
||||||
@ -52,7 +57,7 @@ def clamp(num, min_val, max_val):
|
|||||||
|
|
||||||
|
|
||||||
class Vec2(tuple):
|
class Vec2(tuple):
|
||||||
"""A two dimensional vector represented as an X Y coordinate pair.
|
"""A two-dimensional vector represented as an X Y coordinate pair.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`x` : int or float :
|
`x` : int or float :
|
||||||
@ -60,7 +65,8 @@ class Vec2(tuple):
|
|||||||
`y` : int or float :
|
`y` : int or float :
|
||||||
The Y coordinate of the vector.
|
The Y coordinate of the vector.
|
||||||
|
|
||||||
Vectors must be created with either 0 or 2 values. If no arguments are provided a vector with the coordinates 0, 0 is created.
|
Vectors must be created with either 0 or 2 values. If no
|
||||||
|
arguments are provided a vector with the coordinates 0, 0 is created.
|
||||||
|
|
||||||
Vectors are stored as a tuple and therefore immutable and cannot be modified directly
|
Vectors are stored as a tuple and therefore immutable and cannot be modified directly
|
||||||
"""
|
"""
|
||||||
@ -148,7 +154,8 @@ class Vec2(tuple):
|
|||||||
return self.__add__(other)
|
return self.__add__(other)
|
||||||
|
|
||||||
def from_magnitude(self, magnitude):
|
def from_magnitude(self, magnitude):
|
||||||
"""Create a new Vector of the given magnitude by normalizing, then scaling the vector. The heading remains unchanged.
|
"""Create a new Vector of the given magnitude by normalizing,
|
||||||
|
then scaling the vector. The heading remains unchanged.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`magnitude` : int or float :
|
`magnitude` : int or float :
|
||||||
@ -172,18 +179,18 @@ class Vec2(tuple):
|
|||||||
mag = self.__abs__()
|
mag = self.__abs__()
|
||||||
return Vec2(mag * _math.cos(heading), mag * _math.sin(heading))
|
return Vec2(mag * _math.cos(heading), mag * _math.sin(heading))
|
||||||
|
|
||||||
def limit(self, max):
|
def limit(self, maximum):
|
||||||
"""Limit the magnitude of the vector to the value used for the max parameter.
|
"""Limit the magnitude of the vector to the value used for the max parameter.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`max` : int or float :
|
`maximum` : int or float :
|
||||||
The maximum magnitude for the vector.
|
The maximum magnitude for the vector.
|
||||||
|
|
||||||
:returns: Either self or a new vector with the maximum magnitude.
|
:returns: Either self or a new vector with the maximum magnitude.
|
||||||
:rtype: Vec2
|
:rtype: Vec2
|
||||||
"""
|
"""
|
||||||
if self[0] ** 2 + self[1] ** 2 > max * max:
|
if self[0] ** 2 + self[1] ** 2 > maximum * maximum:
|
||||||
return self.from_magnitude(max)
|
return self.from_magnitude(maximum)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def lerp(self, other, alpha):
|
def lerp(self, other, alpha):
|
||||||
@ -291,7 +298,7 @@ class Vec2(tuple):
|
|||||||
|
|
||||||
|
|
||||||
class Vec3(tuple):
|
class Vec3(tuple):
|
||||||
"""A three dimensional vector represented as a X Y Z coordinates.
|
"""A three-dimensional vector represented as X Y Z coordinates.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`x` : int or float :
|
`x` : int or float :
|
||||||
@ -301,7 +308,8 @@ class Vec3(tuple):
|
|||||||
`z` : int or float :
|
`z` : int or float :
|
||||||
The Z coordinate of the vector.
|
The Z coordinate of the vector.
|
||||||
|
|
||||||
3D Vectors must be created with either 0 or 3 values. If no arguments are provided a vector with the coordinates 0, 0, 0 is created.
|
3D Vectors must be created with either 0 or 3 values. If no arguments
|
||||||
|
are provided, a vector with the coordinates 0, 0, 0 is created.
|
||||||
|
|
||||||
Vectors are stored as a tuple and therefore immutable and cannot be modified directly
|
Vectors are stored as a tuple and therefore immutable and cannot be modified directly
|
||||||
"""
|
"""
|
||||||
@ -374,7 +382,8 @@ class Vec3(tuple):
|
|||||||
return self.__add__(other)
|
return self.__add__(other)
|
||||||
|
|
||||||
def from_magnitude(self, magnitude):
|
def from_magnitude(self, magnitude):
|
||||||
"""Create a new Vector of the given magnitude by normalizing, then scaling the vector. The rotation remains unchanged.
|
"""Create a new Vector of the given magnitude by normalizing,
|
||||||
|
then scaling the vector. The rotation remains unchanged.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`magnitude` : int or float :
|
`magnitude` : int or float :
|
||||||
@ -385,17 +394,17 @@ class Vec3(tuple):
|
|||||||
"""
|
"""
|
||||||
return self.normalize().scale(magnitude)
|
return self.normalize().scale(magnitude)
|
||||||
|
|
||||||
def limit(self, max):
|
def limit(self, maximum):
|
||||||
"""Limit the magnitude of the vector to the value used for the max parameter.
|
"""Limit the magnitude of the vector to the value used for the max parameter.
|
||||||
|
|
||||||
:parameters:
|
:parameters:
|
||||||
`max` : int or float :
|
`maximum` : int or float :
|
||||||
The maximum magnitude for the vector.
|
The maximum magnitude for the vector.
|
||||||
|
|
||||||
:returns: Either self or a new vector with the maximum magnitude.
|
:returns: Either self or a new vector with the maximum magnitude.
|
||||||
:rtype: Vec3
|
:rtype: Vec3
|
||||||
"""
|
"""
|
||||||
if self[0] ** 2 + self[1] ** 2 + self[2] **2 > max * max * max:
|
if self[0] ** 2 + self[1] ** 2 + self[2] ** 2 > maximum * maximum * maximum:
|
||||||
return self.from_magnitude(max)
|
return self.from_magnitude(max)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -829,7 +838,7 @@ class Mat4(tuple):
|
|||||||
return Mat4(temp)
|
return Mat4(temp)
|
||||||
|
|
||||||
def translate(self, vector: Vec3) -> 'Mat4':
|
def translate(self, vector: Vec3) -> 'Mat4':
|
||||||
"""Get a translate Matrix along x, y, and z axis."""
|
"""Get a translation Matrix along x, y, and z axis."""
|
||||||
return Mat4(self) @ Mat4((1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, *vector, 1))
|
return Mat4(self) @ Mat4((1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, *vector, 1))
|
||||||
|
|
||||||
def rotate(self, angle: float, vector: Vec3) -> 'Mat4':
|
def rotate(self, angle: float, vector: Vec3) -> 'Mat4':
|
||||||
|
@ -219,7 +219,7 @@ class SynthesisSource(Source):
|
|||||||
def _generate_data(self, num_bytes):
|
def _generate_data(self, num_bytes):
|
||||||
"""Generate `num_bytes` bytes of data.
|
"""Generate `num_bytes` bytes of data.
|
||||||
|
|
||||||
Return data as ctypes array or string.
|
Return data as ctypes array or bytes.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('abstract')
|
raise NotImplementedError('abstract')
|
||||||
|
|
||||||
@ -451,6 +451,8 @@ class Encoder(SynthesisSource):
|
|||||||
def __init__(self, duration, generator, **kwargs):
|
def __init__(self, duration, generator, **kwargs):
|
||||||
super().__init__(duration, **kwargs)
|
super().__init__(duration, **kwargs)
|
||||||
self._generator = generator
|
self._generator = generator
|
||||||
|
self._total = int(duration * self.audio_format.sample_rate)
|
||||||
|
self._consumed = 0
|
||||||
|
|
||||||
def _generate_data(self, num_bytes):
|
def _generate_data(self, num_bytes):
|
||||||
envelope = self._envelope_generator
|
envelope = self._envelope_generator
|
||||||
|
@ -81,7 +81,7 @@ instance when loading the Model::
|
|||||||
|
|
||||||
.. versionadded:: 1.4
|
.. versionadded:: 1.4
|
||||||
"""
|
"""
|
||||||
from math import radians
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
@ -190,8 +190,7 @@ class Model:
|
|||||||
self.vertex_lists = vertex_lists
|
self.vertex_lists = vertex_lists
|
||||||
self.groups = groups
|
self.groups = groups
|
||||||
self._batch = batch
|
self._batch = batch
|
||||||
self._rotation = Vec3()
|
self._modelview_matrix = Mat4()
|
||||||
self._translation = Vec3()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def batch(self):
|
def batch(self):
|
||||||
@ -220,24 +219,14 @@ class Model:
|
|||||||
self._batch = batch
|
self._batch = batch
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rotation(self):
|
def matrix(self):
|
||||||
return self._rotation
|
return self._modelview_matrix
|
||||||
|
|
||||||
@rotation.setter
|
@matrix.setter
|
||||||
def rotation(self, values):
|
def matrix(self, matrix):
|
||||||
self._rotation = values
|
self._modelview_matrix = matrix
|
||||||
for group in self.groups:
|
for group in self.groups:
|
||||||
group.rotation = values
|
group.matrix = matrix
|
||||||
|
|
||||||
@property
|
|
||||||
def translation(self):
|
|
||||||
return self._translation
|
|
||||||
|
|
||||||
@translation.setter
|
|
||||||
def translation(self, values):
|
|
||||||
self._translation = values
|
|
||||||
for group in self.groups:
|
|
||||||
group.translation = values
|
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
"""Draw the model.
|
"""Draw the model.
|
||||||
@ -274,28 +263,11 @@ class Material:
|
|||||||
class BaseMaterialGroup(graphics.ShaderGroup):
|
class BaseMaterialGroup(graphics.ShaderGroup):
|
||||||
default_vert_src = None
|
default_vert_src = None
|
||||||
default_frag_src = None
|
default_frag_src = None
|
||||||
|
matrix = Mat4()
|
||||||
|
|
||||||
def __init__(self, material, program, order=0, parent=None):
|
def __init__(self, material, program, order=0, parent=None):
|
||||||
super().__init__(program, order, parent)
|
super().__init__(program, order, parent)
|
||||||
|
|
||||||
self.material = material
|
self.material = material
|
||||||
self.rotation = Vec3()
|
|
||||||
self.translation = Vec3()
|
|
||||||
|
|
||||||
def set_modelview_matrix(self):
|
|
||||||
# NOTE: Matrix operations can be optimized later with transform feedback
|
|
||||||
view = Mat4()
|
|
||||||
view = view.rotate(radians(self.rotation[2]), Vec3(0, 0, 1))
|
|
||||||
view = view.rotate(radians(self.rotation[1]), Vec3(0, 1, 0))
|
|
||||||
view = view.rotate(radians(self.rotation[0]), Vec3(1, 0, 0))
|
|
||||||
view = view.translate(self.translation)
|
|
||||||
|
|
||||||
# TODO: separate the projection block, and remove this hack
|
|
||||||
block = self.program.uniform_blocks['WindowBlock']
|
|
||||||
ubo = block.create_ubo(0)
|
|
||||||
with ubo as window_block:
|
|
||||||
window_block.projection[:] = pyglet.math.Mat4.perspective_projection(0, 720, 0, 480, z_near=0.1, z_far=255)
|
|
||||||
window_block.view[:] = view
|
|
||||||
|
|
||||||
|
|
||||||
class TexturedMaterialGroup(BaseMaterialGroup):
|
class TexturedMaterialGroup(BaseMaterialGroup):
|
||||||
@ -316,12 +288,13 @@ class TexturedMaterialGroup(BaseMaterialGroup):
|
|||||||
mat4 view;
|
mat4 view;
|
||||||
} window;
|
} window;
|
||||||
|
|
||||||
|
uniform mat4 model;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 pos = window.view * vec4(vertices, 1.0);
|
vec4 pos = window.view * model * vec4(vertices, 1.0);
|
||||||
gl_Position = window.projection * pos;
|
gl_Position = window.projection * pos;
|
||||||
mat3 normal_matrix = transpose(inverse(mat3(window.view)));
|
mat3 normal_matrix = transpose(inverse(mat3(model)));
|
||||||
|
|
||||||
vertex_position = pos.xyz;
|
vertex_position = pos.xyz;
|
||||||
vertex_colors = colors;
|
vertex_colors = colors;
|
||||||
@ -345,15 +318,15 @@ class TexturedMaterialGroup(BaseMaterialGroup):
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, material, texture):
|
def __init__(self, material, program, texture, order=0, parent=None):
|
||||||
super().__init__(material, get_default_textured_shader())
|
super().__init__(material, program, order, parent)
|
||||||
self.texture = texture
|
self.texture = texture
|
||||||
|
|
||||||
def set_state(self):
|
def set_state(self):
|
||||||
gl.glActiveTexture(gl.GL_TEXTURE0)
|
gl.glActiveTexture(gl.GL_TEXTURE0)
|
||||||
gl.glBindTexture(self.texture.target, self.texture.id)
|
gl.glBindTexture(self.texture.target, self.texture.id)
|
||||||
self.program.use()
|
self.program.use()
|
||||||
self.set_modelview_matrix()
|
self.program['model'] = self.matrix
|
||||||
|
|
||||||
def unset_state(self):
|
def unset_state(self):
|
||||||
gl.glBindTexture(self.texture.target, 0)
|
gl.glBindTexture(self.texture.target, 0)
|
||||||
@ -387,11 +360,13 @@ class MaterialGroup(BaseMaterialGroup):
|
|||||||
mat4 view;
|
mat4 view;
|
||||||
} window;
|
} window;
|
||||||
|
|
||||||
|
uniform mat4 model;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 pos = window.view * vec4(vertices, 1.0);
|
vec4 pos = window.view * model * vec4(vertices, 1.0);
|
||||||
gl_Position = window.projection * pos;
|
gl_Position = window.projection * pos;
|
||||||
mat3 normal_matrix = transpose(inverse(mat3(window.view)));
|
mat3 normal_matrix = transpose(inverse(mat3(model)));
|
||||||
|
|
||||||
vertex_position = pos.xyz;
|
vertex_position = pos.xyz;
|
||||||
vertex_colors = colors;
|
vertex_colors = colors;
|
||||||
@ -411,12 +386,9 @@ class MaterialGroup(BaseMaterialGroup):
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, material):
|
|
||||||
super().__init__(material, get_default_shader())
|
|
||||||
|
|
||||||
def set_state(self):
|
def set_state(self):
|
||||||
self.program.use()
|
self.program.use()
|
||||||
self.set_modelview_matrix()
|
self.program['model'] = self.matrix
|
||||||
|
|
||||||
|
|
||||||
add_default_model_codecs()
|
add_default_model_codecs()
|
||||||
|
@ -245,17 +245,17 @@ class OBJModelDecoder(ModelDecoder):
|
|||||||
material = mesh.material
|
material = mesh.material
|
||||||
count = len(mesh.vertices) // 3
|
count = len(mesh.vertices) // 3
|
||||||
if material.texture_name:
|
if material.texture_name:
|
||||||
texture = pyglet.resource.texture(material.texture_name)
|
|
||||||
group = TexturedMaterialGroup(material, texture)
|
|
||||||
program = pyglet.model.get_default_textured_shader()
|
program = pyglet.model.get_default_textured_shader()
|
||||||
|
texture = pyglet.resource.texture(material.texture_name)
|
||||||
|
group = TexturedMaterialGroup(material, program, texture)
|
||||||
vertex_lists.append(program.vertex_list(count, GL_TRIANGLES, batch, group,
|
vertex_lists.append(program.vertex_list(count, GL_TRIANGLES, batch, group,
|
||||||
vertices=('f', mesh.vertices),
|
vertices=('f', mesh.vertices),
|
||||||
normals=('f', mesh.normals),
|
normals=('f', mesh.normals),
|
||||||
tex_coords=('f', mesh.tex_coords),
|
tex_coords=('f', mesh.tex_coords),
|
||||||
colors=('f', material.diffuse * count)))
|
colors=('f', material.diffuse * count)))
|
||||||
else:
|
else:
|
||||||
group = MaterialGroup(material)
|
|
||||||
program = pyglet.model.get_default_shader()
|
program = pyglet.model.get_default_shader()
|
||||||
|
group = MaterialGroup(material, program)
|
||||||
vertex_lists.append(program.vertex_list(count, GL_TRIANGLES, batch, group,
|
vertex_lists.append(program.vertex_list(count, GL_TRIANGLES, batch, group,
|
||||||
vertices=('f', mesh.vertices),
|
vertices=('f', mesh.vertices),
|
||||||
normals=('f', mesh.normals),
|
normals=('f', mesh.normals),
|
||||||
|
Loading…
Reference in New Issue
Block a user