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(hi)
|
||||
|
||||
DEBUGGING = False
|
||||
DEBUGGING = True
|
||||
from Difficult_Rocket.api.Exp import *
|
||||
from Difficult_Rocket.crash import crash
|
||||
try:
|
||||
from Difficult_Rocket import main
|
||||
|
||||
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
|
||||
if cprofile:
|
||||
cProfile.run('game.start()', sort='calls')
|
||||
|
@ -173,7 +173,7 @@ class ClientWindow(Window):
|
||||
|
||||
def start_game(self) -> None:
|
||||
self.run_input = True
|
||||
self.read_input()
|
||||
# self.read_input()
|
||||
pyglet.app.run()
|
||||
|
||||
@new_thread('window read_input', daemon=True)
|
||||
@ -193,11 +193,11 @@ class ClientWindow(Window):
|
||||
|
||||
@new_thread('window save_info')
|
||||
def save_info(self):
|
||||
print('save_info start')
|
||||
config_file = tools.load_file('./config/config.toml')
|
||||
self.logger.info('save_info start')
|
||||
config_file = tools.load_file('./configs/main.toml')
|
||||
config_file['window']['width'] = self.width
|
||||
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
|
||||
@ -211,9 +211,10 @@ class ClientWindow(Window):
|
||||
def FPS_update(self, tick: Decimal):
|
||||
now_FPS = pyglet.clock.get_fps()
|
||||
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):
|
||||
# self.logger.debug('on_draw call dt: {}'.format(dt))
|
||||
self.clear()
|
||||
self.draw_batch()
|
||||
|
||||
|
@ -70,7 +70,7 @@ class Game:
|
||||
# @new_thread('main')
|
||||
def _start(self):
|
||||
self.server.run()
|
||||
threaded = True
|
||||
threaded = False
|
||||
if threaded:
|
||||
try:
|
||||
game_process = multiprocessing.Process(target=self.client.start(), name='pyglet app')
|
||||
|
@ -2,9 +2,9 @@
|
||||
fps = 60
|
||||
version = "0.6.1"
|
||||
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"
|
||||
fonts_folder = 'libs/fonts'
|
||||
fonts_folder = "libs/fonts"
|
||||
|
||||
[window]
|
||||
style = "None"
|
||||
@ -18,4 +18,3 @@ full_screen = false
|
||||
[window.default]
|
||||
width = 1024
|
||||
height = 768
|
||||
|
||||
|
@ -452,3 +452,6 @@ class Font:
|
||||
glyphs = glyph_buffer
|
||||
|
||||
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']
|
||||
|
||||
|
||||
def draw(size, mode, **kwargs):
|
||||
def draw(size, mode, **data):
|
||||
"""Draw a primitive immediately.
|
||||
|
||||
:Parameters:
|
||||
@ -194,7 +194,7 @@ def draw(size, mode, **kwargs):
|
||||
program.use()
|
||||
|
||||
buffers = []
|
||||
for name, (fmt, array) in kwargs.items():
|
||||
for name, (fmt, array) in data.items():
|
||||
location = program.attributes[name]['location']
|
||||
count = program.attributes[name]['count']
|
||||
gl_type = vertexdomain._gl_types[fmt[0]]
|
||||
@ -340,6 +340,8 @@ class Batch:
|
||||
self._draw_list = []
|
||||
self._draw_list_dirty = False
|
||||
|
||||
self._context = pyglet.gl.current_context
|
||||
|
||||
def invalidate(self):
|
||||
"""Force the batch to update the draw list.
|
||||
|
||||
@ -554,7 +556,7 @@ class Group:
|
||||
"""Group of common OpenGL state.
|
||||
|
||||
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):
|
||||
"""Create a Group.
|
||||
@ -565,6 +567,8 @@ class Group:
|
||||
`parent` : `~pyglet.graphics.Group`
|
||||
Group to contain this Group; its state will be set before this
|
||||
Group's state.
|
||||
|
||||
:Ivariables:
|
||||
`visible` : bool
|
||||
Determines whether this Group is visible in any of the Batches
|
||||
it is assigned to. If False, objects in this Group will not
|
||||
|
@ -28,65 +28,63 @@ _uniform_getters = {
|
||||
}
|
||||
|
||||
_uniform_setters = {
|
||||
# uniform type: (gl_type, setter, length, count)
|
||||
GL_BOOL: (GLint, glUniform1iv, 1, 1),
|
||||
GL_BOOL_VEC2: (GLint, glUniform1iv, 2, 1),
|
||||
GL_BOOL_VEC3: (GLint, glUniform1iv, 3, 1),
|
||||
GL_BOOL_VEC4: (GLint, glUniform1iv, 4, 1),
|
||||
# uniform: gl_type, legacy_setter, setter, length, count
|
||||
GL_BOOL: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||
GL_BOOL_VEC2: (GLint, glUniform1iv, glProgramUniform1iv, 2, 1),
|
||||
GL_BOOL_VEC3: (GLint, glUniform1iv, glProgramUniform1iv, 3, 1),
|
||||
GL_BOOL_VEC4: (GLint, glUniform1iv, glProgramUniform1iv, 4, 1),
|
||||
|
||||
GL_INT: (GLint, glUniform1iv, 1, 1),
|
||||
GL_INT_VEC2: (GLint, glUniform2iv, 2, 1),
|
||||
GL_INT_VEC3: (GLint, glUniform3iv, 3, 1),
|
||||
GL_INT_VEC4: (GLint, glUniform4iv, 4, 1),
|
||||
GL_INT: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||
GL_INT_VEC2: (GLint, glUniform2iv, glProgramUniform2iv, 2, 1),
|
||||
GL_INT_VEC3: (GLint, glUniform3iv, glProgramUniform3iv, 3, 1),
|
||||
GL_INT_VEC4: (GLint, glUniform4iv, glProgramUniform4iv, 4, 1),
|
||||
|
||||
GL_FLOAT: (GLfloat, glUniform1fv, 1, 1),
|
||||
GL_FLOAT_VEC2: (GLfloat, glUniform2fv, 2, 1),
|
||||
GL_FLOAT_VEC3: (GLfloat, glUniform3fv, 3, 1),
|
||||
GL_FLOAT_VEC4: (GLfloat, glUniform4fv, 4, 1),
|
||||
GL_FLOAT: (GLfloat, glUniform1fv, glProgramUniform1fv, 1, 1),
|
||||
GL_FLOAT_VEC2: (GLfloat, glUniform2fv, glProgramUniform2fv, 2, 1),
|
||||
GL_FLOAT_VEC3: (GLfloat, glUniform3fv, glProgramUniform3fv, 3, 1),
|
||||
GL_FLOAT_VEC4: (GLfloat, glUniform4fv, glProgramUniform4fv, 4, 1),
|
||||
|
||||
GL_SAMPLER_1D: (GLint, glUniform1iv, 1, 1),
|
||||
GL_SAMPLER_2D: (GLint, glUniform1iv, 1, 1),
|
||||
GL_SAMPLER_2D_ARRAY: (GLint, glUniform1iv, 1, 1),
|
||||
GL_SAMPLER_1D: (GLint, glUniform1iv, glProgramUniform1iv, 1, 1),
|
||||
GL_SAMPLER_2D: (GLint, glUniform1iv, glProgramUniform1iv, 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_MAT3: (GLfloat, glUniformMatrix3fv, 6, 1),
|
||||
GL_FLOAT_MAT4: (GLfloat, glUniformMatrix4fv, 16, 1),
|
||||
GL_FLOAT_MAT2: (GLfloat, glUniformMatrix2fv, glProgramUniformMatrix2fv, 4, 1),
|
||||
GL_FLOAT_MAT3: (GLfloat, glUniformMatrix3fv, glProgramUniformMatrix3fv, 6, 1),
|
||||
GL_FLOAT_MAT4: (GLfloat, glUniformMatrix4fv, glProgramUniformMatrix4fv, 16, 1),
|
||||
|
||||
# TODO: test/implement these:
|
||||
# GL_FLOAT_MAT2x3: glUniformMatrix2x3fv,
|
||||
# GL_FLOAT_MAT2x4: glUniformMatrix2x4fv,
|
||||
#
|
||||
# GL_FLOAT_MAT3x2: glUniformMatrix3x2fv,
|
||||
# GL_FLOAT_MAT3x4: glUniformMatrix3x4fv,
|
||||
#
|
||||
# GL_FLOAT_MAT4x2: glUniformMatrix4x2fv,
|
||||
# GL_FLOAT_MAT4x3: glUniformMatrix4x3fv,
|
||||
# GL_FLOAT_MAT2x3: glUniformMatrix2x3fv, glProgramUniformMatrix2x3fv,
|
||||
# GL_FLOAT_MAT2x4: glUniformMatrix2x4fv, glProgramUniformMatrix2x4fv,
|
||||
# GL_FLOAT_MAT3x2: glUniformMatrix3x2fv, glProgramUniformMatrix3x2fv,
|
||||
# GL_FLOAT_MAT3x4: glUniformMatrix3x4fv, glProgramUniformMatrix3x4fv,
|
||||
# GL_FLOAT_MAT4x2: glUniformMatrix4x2fv, glProgramUniformMatrix4x2fv,
|
||||
# GL_FLOAT_MAT4x3: glUniformMatrix4x3fv, glProgramUniformMatrix4x3fv,
|
||||
}
|
||||
|
||||
_attribute_types = {
|
||||
GL_BOOL: (1, '?'),
|
||||
GL_BOOL: (1, '?'),
|
||||
GL_BOOL_VEC2: (2, '?'),
|
||||
GL_BOOL_VEC3: (3, '?'),
|
||||
GL_BOOL_VEC4: (4, '?'),
|
||||
|
||||
GL_INT: (1, 'i'),
|
||||
GL_INT: (1, 'i'),
|
||||
GL_INT_VEC2: (2, 'i'),
|
||||
GL_INT_VEC3: (3, '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_VEC3: (3, 'I'),
|
||||
GL_UNSIGNED_INT_VEC4: (4, 'I'),
|
||||
|
||||
GL_FLOAT: (1, 'f'),
|
||||
GL_FLOAT: (1, 'f'),
|
||||
GL_FLOAT_VEC2: (2, 'f'),
|
||||
GL_FLOAT_VEC3: (3, 'f'),
|
||||
GL_FLOAT_VEC4: (4, 'f'),
|
||||
|
||||
GL_DOUBLE: (1, 'd'),
|
||||
GL_DOUBLE: (1, 'd'),
|
||||
GL_DOUBLE_VEC2: (2, 'd'),
|
||||
GL_DOUBLE_VEC3: (3, 'd'),
|
||||
GL_DOUBLE_VEC4: (4, 'd'),
|
||||
@ -96,11 +94,16 @@ _attribute_types = {
|
||||
class _Uniform:
|
||||
__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.name = name
|
||||
self.type = uniform_type
|
||||
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.count = count
|
||||
|
||||
@ -112,45 +115,66 @@ class _Uniform:
|
||||
ptr = cast(c_array, POINTER(gl_type))
|
||||
|
||||
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
|
||||
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"""
|
||||
|
||||
if length == 1:
|
||||
def getter_func():
|
||||
gl_getter(program_id, location, c_array)
|
||||
gl_getter(program, location, c_array)
|
||||
return c_array[0]
|
||||
else:
|
||||
def getter_func():
|
||||
gl_getter(program_id, location, c_array)
|
||||
gl_getter(program, location, c_array)
|
||||
return c_array[:]
|
||||
|
||||
return getter_func
|
||||
|
||||
@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"""
|
||||
if dsa: # Bindless updates:
|
||||
|
||||
if is_matrix:
|
||||
def setter_func(value):
|
||||
c_array[:] = value
|
||||
gl_setter(location, count, GL_FALSE, ptr)
|
||||
if is_matrix:
|
||||
def setter_func(value):
|
||||
c_array[:] = value
|
||||
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:
|
||||
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)
|
||||
return setter_func
|
||||
|
||||
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):
|
||||
return f"Uniform('{self.name}', location={self.location}, length={self.length}, count={self.count})"
|
||||
@ -167,9 +191,9 @@ class Shader:
|
||||
|
||||
:Parameters:
|
||||
`source_string` : str
|
||||
A string containing the Shader code.
|
||||
A string containing the Shader source code.
|
||||
`shader_type` : str
|
||||
The Shader type, such as "vertex" or "fragment".
|
||||
The Shader type, such as "vertex", "fragment", "geometry", etc.
|
||||
"""
|
||||
self._id = None
|
||||
|
||||
@ -228,7 +252,7 @@ class Shader:
|
||||
class ShaderProgram:
|
||||
"""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):
|
||||
"""Create an OpenGL ShaderProgram, from multiple Shaders.
|
||||
@ -242,15 +266,13 @@ class ShaderProgram:
|
||||
assert shaders, "At least one Shader object is required."
|
||||
self._id = self._link_program(shaders)
|
||||
self._context = pyglet.gl.current_context
|
||||
self._active = False
|
||||
|
||||
self._attributes = {}
|
||||
self._uniforms = {}
|
||||
self._uniform_blocks = {}
|
||||
# Query if Direct State Access is available:
|
||||
self._dsa = gl_info.have_version(4, 1) or gl_info.have_extension("GL_ARB_separate_shader_objects")
|
||||
|
||||
self._introspect_attributes()
|
||||
self._introspect_uniforms()
|
||||
self._introspect_uniform_blocks()
|
||||
self._attributes = self._introspect_attributes()
|
||||
self._uniforms = self._introspect_uniforms()
|
||||
self._uniform_blocks = self._introspect_uniform_blocks()
|
||||
|
||||
if _debug_gl_shaders:
|
||||
print(self._get_program_log())
|
||||
@ -259,10 +281,6 @@ class ShaderProgram:
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
return self._active
|
||||
|
||||
@property
|
||||
def attributes(self):
|
||||
return self._attributes
|
||||
@ -275,10 +293,6 @@ class ShaderProgram:
|
||||
def uniform_blocks(self):
|
||||
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):
|
||||
result = c_int(0)
|
||||
glGetProgramiv(self._id, GL_INFO_LOG_LENGTH, byref(result))
|
||||
@ -302,11 +316,9 @@ class ShaderProgram:
|
||||
|
||||
def use(self):
|
||||
glUseProgram(self._id)
|
||||
self._active = True
|
||||
|
||||
def stop(self):
|
||||
glUseProgram(0)
|
||||
self._active = False
|
||||
|
||||
__enter__ = use
|
||||
bind = use
|
||||
@ -314,7 +326,6 @@ class ShaderProgram:
|
||||
|
||||
def __exit__(self, *_):
|
||||
glUseProgram(0)
|
||||
self._active = False
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
@ -325,13 +336,12 @@ class ShaderProgram:
|
||||
pass
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if not self._active:
|
||||
raise Exception("Shader Program is not active.")
|
||||
|
||||
try:
|
||||
uniform = self._uniforms[key]
|
||||
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:
|
||||
uniform.set(value)
|
||||
@ -363,53 +373,46 @@ class ShaderProgram:
|
||||
loc = glGetAttribLocation(program, create_string_buffer(a_name.encode('utf-8')))
|
||||
count, fmt = _attribute_types[a_type]
|
||||
attributes[a_name] = dict(type=a_type, size=a_size, location=loc, count=count, format=fmt)
|
||||
self._attributes = attributes
|
||||
|
||||
if _debug_gl_shaders:
|
||||
for attribute in attributes.values():
|
||||
print(f"Found attribute: {attribute}")
|
||||
|
||||
return attributes
|
||||
|
||||
def _introspect_uniforms(self):
|
||||
prg_id = self._id
|
||||
program = self._id
|
||||
uniforms = {}
|
||||
for index in range(self._get_number(GL_ACTIVE_UNIFORMS)):
|
||||
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
|
||||
continue
|
||||
uniforms[u_name] = _Uniform(program, u_name, u_type, loc, self._dsa)
|
||||
|
||||
try:
|
||||
gl_type, gl_setter, length, count = _uniform_setters[u_type]
|
||||
gl_getter = _uniform_getters[gl_type]
|
||||
if _debug_gl_shaders:
|
||||
for uniform in self._uniforms.values():
|
||||
print(f"Found uniform: {uniform}")
|
||||
|
||||
if _debug_gl_shaders:
|
||||
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)
|
||||
return uniforms
|
||||
|
||||
def _introspect_uniform_blocks(self):
|
||||
p_id = self._id
|
||||
|
||||
program = self._id
|
||||
uniform_blocks = {}
|
||||
|
||||
for index in range(self._get_number(GL_ACTIVE_UNIFORM_BLOCKS)):
|
||||
name = self._get_uniform_block_name(index)
|
||||
|
||||
uniform_blocks[name] = {}
|
||||
|
||||
num_active = GLint()
|
||||
block_data_size = GLint()
|
||||
|
||||
glGetActiveUniformBlockiv(p_id, 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_DATA_SIZE, block_data_size)
|
||||
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, num_active)
|
||||
|
||||
indices = (GLuint * num_active.value)()
|
||||
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):
|
||||
uniform_name, u_type, u_size = self._query_uniform(indices[i])
|
||||
@ -420,11 +423,12 @@ class ShaderProgram:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
gl_type, _, length, _ = _uniform_setters[u_type]
|
||||
gl_type, _, _, length, _ = _uniform_setters[u_type]
|
||||
uniforms[i] = (uniform_name, gl_type, length)
|
||||
|
||||
uniform_blocks[name][i] = (uniform_name, gl_type, length)
|
||||
uniform_blocks[name] = UniformBlock(self, name, index, block_data_size.value, uniforms)
|
||||
|
||||
self._uniform_blocks[name] = UniformBlock(self, name, index, block_data_size.value, uniform_blocks[name])
|
||||
return uniform_blocks
|
||||
|
||||
def _get_uniform_block_name(self, index):
|
||||
buf_size = 128
|
||||
@ -484,10 +488,10 @@ class ShaderProgram:
|
||||
try:
|
||||
if isinstance(fmt, tuple):
|
||||
fmt, array = fmt
|
||||
initial_arrays.append((attributes[name]['location'], array))
|
||||
initial_arrays.append((name, array))
|
||||
attributes[name] = {**attributes[name], **{'format': fmt}}
|
||||
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()
|
||||
domain = batch.get_domain(False, mode, group, self._id, attributes)
|
||||
@ -495,8 +499,8 @@ class ShaderProgram:
|
||||
# Create vertex list and initialize
|
||||
vlist = domain.create(count)
|
||||
|
||||
for index, array in initial_arrays:
|
||||
vlist.set_attribute_data(index, array)
|
||||
for name, array in initial_arrays:
|
||||
vlist.set_attribute_data(name, array)
|
||||
|
||||
return vlist
|
||||
|
||||
@ -528,7 +532,7 @@ class ShaderProgram:
|
||||
try:
|
||||
if isinstance(fmt, tuple):
|
||||
fmt, array = fmt
|
||||
initial_arrays.append((attributes[name]['location'], array))
|
||||
initial_arrays.append((name, array))
|
||||
attributes[name] = {**attributes[name], **{'format': fmt}}
|
||||
except KeyError:
|
||||
raise ShaderException(f"\nThe attribute `{name}` doesn't exist. Valid names: \n{list(attributes)}")
|
||||
@ -541,8 +545,8 @@ class ShaderProgram:
|
||||
start = vlist.start
|
||||
vlist.indices = [i + start for i in indices]
|
||||
|
||||
for index, array in initial_arrays:
|
||||
vlist.set_attribute_data(index, array)
|
||||
for name, array in initial_arrays:
|
||||
vlist.set_attribute_data(name, array)
|
||||
|
||||
return vlist
|
||||
|
||||
@ -578,7 +582,6 @@ class UniformBufferObject:
|
||||
self.view = self._introspect_uniforms()
|
||||
self._view_ptr = pointer(self.view)
|
||||
self.index = index
|
||||
# glUniformBlockBinding(self.block.program.id, self.block.index, self.index)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
|
@ -329,8 +329,8 @@ class VertexList:
|
||||
for version in self._cache_versions:
|
||||
self._cache_versions[version] = None
|
||||
|
||||
def set_attribute_data(self, i, data):
|
||||
attribute = self.domain.attributes[i]
|
||||
def set_attribute_data(self, name, data):
|
||||
attribute = self.domain.attribute_names[name]
|
||||
attribute.set_region(attribute.buffer, self.start, self.count, data)
|
||||
|
||||
def __getattr__(self, name):
|
||||
|
@ -81,15 +81,15 @@ class _Relation:
|
||||
def _map_pair(raw_relation):
|
||||
inverted = False
|
||||
relation_string = raw_relation.split(":")[1]
|
||||
if relation_string.startswith("+"):
|
||||
relation_string = relation_string[1:]
|
||||
if "+" in relation_string:
|
||||
relation_string = relation_string.strip('+')
|
||||
inverted = False
|
||||
elif relation_string.startswith("-"):
|
||||
relation_string = relation_string[1:]
|
||||
elif "-" in relation_string:
|
||||
relation_string = relation_string.strip('-')
|
||||
inverted = True
|
||||
if "~" in relation_string:
|
||||
# TODO: handle this
|
||||
return None
|
||||
relation_string = relation_string.strip('~')
|
||||
inverted = True
|
||||
if relation_string.startswith("b"): # Button
|
||||
return _Relation("button", int(relation_string[1:]), inverted)
|
||||
elif relation_string.startswith("a"): # Axis
|
||||
@ -189,7 +189,6 @@ def add_mappings_from_file(filename) -> None:
|
||||
`filename` : str
|
||||
A file path.
|
||||
"""
|
||||
assert os.path.exists(filename), f"Invalid path: {filename}"
|
||||
with open(filename) as f:
|
||||
add_mappings_from_string(f.read())
|
||||
|
||||
|
@ -34,11 +34,15 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import errno
|
||||
import fcntl
|
||||
import struct
|
||||
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
|
||||
|
||||
from pyglet.app.xlib import XlibSelectDevice
|
||||
@ -47,18 +51,11 @@ from .base import DeviceOpenException
|
||||
from .evdev_constants import *
|
||||
from .controller import get_mapping
|
||||
|
||||
c = pyglet.lib.load_library('c')
|
||||
|
||||
_IOC_NRBITS = 8
|
||||
_IOC_TYPEBITS = 8
|
||||
_IOC_SIZEBITS = 14
|
||||
_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_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
|
||||
_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
|
||||
@ -81,9 +78,7 @@ def _IOR(type, nr, struct):
|
||||
|
||||
def f(fileno):
|
||||
buffer = struct()
|
||||
if c.ioctl(fileno, request, ctypes.byref(buffer)) < 0:
|
||||
err = ctypes.c_int.in_dll(c, 'errno').value
|
||||
raise OSError(err, errno.errorcode[err])
|
||||
fcntl.ioctl(fileno, request, buffer)
|
||||
return buffer
|
||||
|
||||
return f
|
||||
@ -92,9 +87,7 @@ def _IOR(type, nr, struct):
|
||||
def _IOR_len(type, nr):
|
||||
def f(fileno, buffer):
|
||||
request = _IOC(_IOC_READ, ord(type), nr, ctypes.sizeof(buffer))
|
||||
if c.ioctl(fileno, request, ctypes.byref(buffer)) < 0:
|
||||
err = ctypes.c_int.in_dll(c, 'errno').value
|
||||
raise OSError(err, errno.errorcode[err])
|
||||
fcntl.ioctl(fileno, request, buffer)
|
||||
return buffer
|
||||
|
||||
return f
|
||||
@ -103,56 +96,154 @@ def _IOR_len(type, nr):
|
||||
def _IOR_str(type, nr):
|
||||
g = _IOR_len(type, nr)
|
||||
|
||||
def f(fileno, len=256):
|
||||
return g(fileno, ctypes.create_string_buffer(len)).value
|
||||
def f(fileno, length=256):
|
||||
return g(fileno, ctypes.create_string_buffer(length)).value
|
||||
|
||||
return f
|
||||
|
||||
|
||||
time_t = ctypes.c_long
|
||||
suseconds_t = ctypes.c_long
|
||||
def _IOW(type, nr):
|
||||
|
||||
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_ = (
|
||||
('tv_sec', time_t),
|
||||
('tv_usec', suseconds_t)
|
||||
('tv_sec', _s64),
|
||||
('tv_usec', _s64)
|
||||
)
|
||||
|
||||
|
||||
class input_event(ctypes.Structure):
|
||||
class InputEvent(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('time', timeval),
|
||||
('type', ctypes.c_uint16),
|
||||
('code', ctypes.c_uint16),
|
||||
('value', ctypes.c_int32)
|
||||
('time', Timeval),
|
||||
('type', _u16),
|
||||
('code', _u16),
|
||||
('value', _s32)
|
||||
)
|
||||
|
||||
|
||||
class input_id(ctypes.Structure):
|
||||
class InputID(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('bustype', ctypes.c_uint16),
|
||||
('vendor', ctypes.c_uint16),
|
||||
('product', ctypes.c_uint16),
|
||||
('version', ctypes.c_uint16),
|
||||
('bustype', _u16),
|
||||
('vendor', _u16),
|
||||
('product', _u16),
|
||||
('version', _u16),
|
||||
)
|
||||
|
||||
|
||||
class input_absinfo(ctypes.Structure):
|
||||
class InputABSInfo(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('value', ctypes.c_int32),
|
||||
('minimum', ctypes.c_int32),
|
||||
('maximum', ctypes.c_int32),
|
||||
('fuzz', ctypes.c_int32),
|
||||
('flat', ctypes.c_int32),
|
||||
('value', _s32),
|
||||
('minimum', _s32),
|
||||
('maximum', _s32),
|
||||
('fuzz', _s32),
|
||||
('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)
|
||||
EVIOCGID = _IOR('E', 0x02, input_id)
|
||||
EVIOCGID = _IOR('E', 0x02, InputID)
|
||||
EVIOCGNAME = _IOR_str('E', 0x06)
|
||||
EVIOCGPHYS = _IOR_str('E', 0x07)
|
||||
EVIOCGUNIQ = _IOR_str('E', 0x08)
|
||||
EVIOCSFF = _IOW('E', 0x80)
|
||||
|
||||
|
||||
def EVIOCGBIT(fileno, ev, buffer):
|
||||
@ -160,14 +251,14 @@ def EVIOCGBIT(fileno, ev, buffer):
|
||||
|
||||
|
||||
def EVIOCGABS(fileno, abs):
|
||||
buffer = input_absinfo()
|
||||
buffer = InputABSInfo()
|
||||
return _IOR_len('E', 0x40 + abs)(fileno, buffer)
|
||||
|
||||
|
||||
def get_set_bits(bytes):
|
||||
def get_set_bits(bytestring):
|
||||
bits = set()
|
||||
j = 0
|
||||
for byte in bytes:
|
||||
for byte in bytestring:
|
||||
for i in range(8):
|
||||
if byte & 1:
|
||||
bits.add(j + i)
|
||||
@ -208,7 +299,6 @@ def _create_control(fileno, event_type, event_code):
|
||||
maximum = absinfo.maximum
|
||||
control = AbsoluteAxis(name, minimum, maximum, raw_name)
|
||||
control.value = value
|
||||
|
||||
if name == 'hat_y':
|
||||
control.inverted = True
|
||||
elif event_type == EV_REL:
|
||||
@ -235,6 +325,7 @@ event_types = {
|
||||
EV_MSC: MSC_MAX,
|
||||
EV_LED: LED_MAX,
|
||||
EV_SND: SND_MAX,
|
||||
EV_FF: FF_MAX,
|
||||
}
|
||||
|
||||
|
||||
@ -273,6 +364,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
|
||||
self.controls = []
|
||||
self.control_map = {}
|
||||
self.ff_types = []
|
||||
|
||||
event_types_bits = (ctypes.c_byte * 4)()
|
||||
EVIOCGBIT(fileno, 0, event_types_bits)
|
||||
@ -283,11 +375,14 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
nbytes = max_code // 8 + 1
|
||||
event_codes_bits = (ctypes.c_byte * nbytes)()
|
||||
EVIOCGBIT(fileno, event_type, event_codes_bits)
|
||||
for event_code in get_set_bits(event_codes_bits):
|
||||
control = _create_control(fileno, event_type, event_code)
|
||||
if control:
|
||||
self.control_map[(event_type, event_code)] = control
|
||||
self.controls.append(control)
|
||||
if event_type == EV_FF:
|
||||
self.ff_types.extend(get_set_bits(event_codes_bits))
|
||||
else:
|
||||
for event_code in get_set_bits(event_codes_bits):
|
||||
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)
|
||||
|
||||
@ -308,7 +403,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
hex_product, shifted_product, hex_version, shifted_version)
|
||||
|
||||
def open(self, window=None, exclusive=False):
|
||||
super(EvdevDevice, self).open(window, exclusive)
|
||||
super().open(window, exclusive)
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
def close(self):
|
||||
super(EvdevDevice, self).close()
|
||||
super().close()
|
||||
|
||||
if not self._fileno:
|
||||
return
|
||||
@ -332,33 +427,8 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
|
||||
# Force Feedback methods
|
||||
|
||||
def supports_ff(self):
|
||||
try:
|
||||
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)
|
||||
def ff_upload_effect(self, structure):
|
||||
os.write(self._fileno, structure)
|
||||
|
||||
# XlibSelectDevice interface
|
||||
|
||||
@ -372,12 +442,14 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
if not self._fileno:
|
||||
return
|
||||
|
||||
events = (input_event * 64)()
|
||||
bytes_read = c.read(self._fileno, events, ctypes.sizeof(events))
|
||||
if bytes_read < 0:
|
||||
try:
|
||||
events = (InputEvent * 64)()
|
||||
bytes_read = os.readv(self._fileno, events)
|
||||
except OSError:
|
||||
self.close()
|
||||
return
|
||||
|
||||
n_events = bytes_read // ctypes.sizeof(input_event)
|
||||
n_events = bytes_read // ctypes.sizeof(InputEvent)
|
||||
for event in events[:n_events]:
|
||||
try:
|
||||
control = self.control_map[(event.type, event.code)]
|
||||
@ -386,32 +458,54 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
pass
|
||||
|
||||
|
||||
class EvdevController(Controller):
|
||||
|
||||
_rumble_weak = -1
|
||||
_rumble_strong = -1
|
||||
class FFController(Controller):
|
||||
"""Controller that supports force-feedback"""
|
||||
_fileno = None
|
||||
_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):
|
||||
super().open(window, exclusive)
|
||||
# Create Force Feedback effects when the device is opened:
|
||||
self._rumble_weak = self.device.ff_create_effect(0, 0, 0)
|
||||
self._rumble_strong = self.device.ff_create_effect(0, 0, 0)
|
||||
self._fileno = self.device.fileno()
|
||||
# Create Force Feedback effects & events when opened:
|
||||
# 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):
|
||||
effect = self.device.ff_create_effect(strength, 0, duration, self._rumble_weak)
|
||||
self.device.ff_play(effect)
|
||||
effect = self._weak_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):
|
||||
effect = self.device.ff_create_effect(0, strength, duration, self._rumble_strong)
|
||||
self.device.ff_play(effect)
|
||||
effect = self._strong_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):
|
||||
"""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):
|
||||
"""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):
|
||||
@ -470,8 +564,8 @@ def _create_controller(device):
|
||||
if have_button is False or mapping is None:
|
||||
return
|
||||
|
||||
if device.supports_ff():
|
||||
return EvdevController(device, mapping)
|
||||
if FF_RUMBLE in device.ff_types:
|
||||
return FFController(device, mapping)
|
||||
else:
|
||||
return Controller(device, mapping)
|
||||
|
||||
|
@ -36,14 +36,19 @@
|
||||
"""Matrix and Vector math.
|
||||
|
||||
This module provides Vector and Matrix objects, include Vec2, Vec3, Vec4,
|
||||
Mat3 and Mat4. Most common operations are supported, and many helper
|
||||
methods are included for rotating, scaling, and transforming.
|
||||
The :py:class:`~pyglet.matrix.Mat4` includes class methods
|
||||
for creating orthographic and perspective projection matrixes.
|
||||
Mat3, and Mat4. Most common operations are supported, and many helper
|
||||
methods are included for rotating, scaling, and transforming. The
|
||||
:py:class:`~pyglet.matrix.Mat4` includes class methods for creating
|
||||
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 warnings as _warnings
|
||||
|
||||
from operator import mul as _mul
|
||||
|
||||
|
||||
@ -52,7 +57,7 @@ def clamp(num, min_val, max_val):
|
||||
|
||||
|
||||
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:
|
||||
`x` : int or float :
|
||||
@ -60,7 +65,8 @@ class Vec2(tuple):
|
||||
`y` : int or float :
|
||||
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
|
||||
"""
|
||||
@ -148,7 +154,8 @@ class Vec2(tuple):
|
||||
return self.__add__(other)
|
||||
|
||||
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:
|
||||
`magnitude` : int or float :
|
||||
@ -172,18 +179,18 @@ class Vec2(tuple):
|
||||
mag = self.__abs__()
|
||||
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.
|
||||
|
||||
:parameters:
|
||||
`max` : int or float :
|
||||
`maximum` : int or float :
|
||||
The maximum magnitude for the vector.
|
||||
|
||||
:returns: Either self or a new vector with the maximum magnitude.
|
||||
:rtype: Vec2
|
||||
"""
|
||||
if self[0] ** 2 + self[1] ** 2 > max * max:
|
||||
return self.from_magnitude(max)
|
||||
if self[0] ** 2 + self[1] ** 2 > maximum * maximum:
|
||||
return self.from_magnitude(maximum)
|
||||
return self
|
||||
|
||||
def lerp(self, other, alpha):
|
||||
@ -291,7 +298,7 @@ class Vec2(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:
|
||||
`x` : int or float :
|
||||
@ -301,7 +308,8 @@ class Vec3(tuple):
|
||||
`z` : int or float :
|
||||
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
|
||||
"""
|
||||
@ -374,7 +382,8 @@ class Vec3(tuple):
|
||||
return self.__add__(other)
|
||||
|
||||
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:
|
||||
`magnitude` : int or float :
|
||||
@ -385,17 +394,17 @@ class Vec3(tuple):
|
||||
"""
|
||||
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.
|
||||
|
||||
:parameters:
|
||||
`max` : int or float :
|
||||
`maximum` : int or float :
|
||||
The maximum magnitude for the vector.
|
||||
|
||||
:returns: Either self or a new vector with the maximum magnitude.
|
||||
: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
|
||||
|
||||
@ -829,7 +838,7 @@ class Mat4(tuple):
|
||||
return Mat4(temp)
|
||||
|
||||
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))
|
||||
|
||||
def rotate(self, angle: float, vector: Vec3) -> 'Mat4':
|
||||
|
@ -219,7 +219,7 @@ class SynthesisSource(Source):
|
||||
def _generate_data(self, num_bytes):
|
||||
"""Generate `num_bytes` bytes of data.
|
||||
|
||||
Return data as ctypes array or string.
|
||||
Return data as ctypes array or bytes.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
@ -451,6 +451,8 @@ class Encoder(SynthesisSource):
|
||||
def __init__(self, duration, generator, **kwargs):
|
||||
super().__init__(duration, **kwargs)
|
||||
self._generator = generator
|
||||
self._total = int(duration * self.audio_format.sample_rate)
|
||||
self._consumed = 0
|
||||
|
||||
def _generate_data(self, num_bytes):
|
||||
envelope = self._envelope_generator
|
||||
|
@ -81,7 +81,7 @@ instance when loading the Model::
|
||||
|
||||
.. versionadded:: 1.4
|
||||
"""
|
||||
from math import radians
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
import pyglet
|
||||
@ -190,8 +190,7 @@ class Model:
|
||||
self.vertex_lists = vertex_lists
|
||||
self.groups = groups
|
||||
self._batch = batch
|
||||
self._rotation = Vec3()
|
||||
self._translation = Vec3()
|
||||
self._modelview_matrix = Mat4()
|
||||
|
||||
@property
|
||||
def batch(self):
|
||||
@ -220,24 +219,14 @@ class Model:
|
||||
self._batch = batch
|
||||
|
||||
@property
|
||||
def rotation(self):
|
||||
return self._rotation
|
||||
def matrix(self):
|
||||
return self._modelview_matrix
|
||||
|
||||
@rotation.setter
|
||||
def rotation(self, values):
|
||||
self._rotation = values
|
||||
@matrix.setter
|
||||
def matrix(self, matrix):
|
||||
self._modelview_matrix = matrix
|
||||
for group in self.groups:
|
||||
group.rotation = values
|
||||
|
||||
@property
|
||||
def translation(self):
|
||||
return self._translation
|
||||
|
||||
@translation.setter
|
||||
def translation(self, values):
|
||||
self._translation = values
|
||||
for group in self.groups:
|
||||
group.translation = values
|
||||
group.matrix = matrix
|
||||
|
||||
def draw(self):
|
||||
"""Draw the model.
|
||||
@ -274,28 +263,11 @@ class Material:
|
||||
class BaseMaterialGroup(graphics.ShaderGroup):
|
||||
default_vert_src = None
|
||||
default_frag_src = None
|
||||
matrix = Mat4()
|
||||
|
||||
def __init__(self, material, program, order=0, parent=None):
|
||||
super().__init__(program, order, parent)
|
||||
|
||||
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):
|
||||
@ -316,12 +288,13 @@ class TexturedMaterialGroup(BaseMaterialGroup):
|
||||
mat4 view;
|
||||
} window;
|
||||
|
||||
uniform mat4 model;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = window.view * vec4(vertices, 1.0);
|
||||
vec4 pos = window.view * model * vec4(vertices, 1.0);
|
||||
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_colors = colors;
|
||||
@ -345,15 +318,15 @@ class TexturedMaterialGroup(BaseMaterialGroup):
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, material, texture):
|
||||
super().__init__(material, get_default_textured_shader())
|
||||
def __init__(self, material, program, texture, order=0, parent=None):
|
||||
super().__init__(material, program, order, parent)
|
||||
self.texture = texture
|
||||
|
||||
def set_state(self):
|
||||
gl.glActiveTexture(gl.GL_TEXTURE0)
|
||||
gl.glBindTexture(self.texture.target, self.texture.id)
|
||||
self.program.use()
|
||||
self.set_modelview_matrix()
|
||||
self.program['model'] = self.matrix
|
||||
|
||||
def unset_state(self):
|
||||
gl.glBindTexture(self.texture.target, 0)
|
||||
@ -387,11 +360,13 @@ class MaterialGroup(BaseMaterialGroup):
|
||||
mat4 view;
|
||||
} window;
|
||||
|
||||
uniform mat4 model;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 pos = window.view * vec4(vertices, 1.0);
|
||||
vec4 pos = window.view * model * vec4(vertices, 1.0);
|
||||
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_colors = colors;
|
||||
@ -411,12 +386,9 @@ class MaterialGroup(BaseMaterialGroup):
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, material):
|
||||
super().__init__(material, get_default_shader())
|
||||
|
||||
def set_state(self):
|
||||
self.program.use()
|
||||
self.set_modelview_matrix()
|
||||
self.program['model'] = self.matrix
|
||||
|
||||
|
||||
add_default_model_codecs()
|
||||
|
@ -245,17 +245,17 @@ class OBJModelDecoder(ModelDecoder):
|
||||
material = mesh.material
|
||||
count = len(mesh.vertices) // 3
|
||||
if material.texture_name:
|
||||
texture = pyglet.resource.texture(material.texture_name)
|
||||
group = TexturedMaterialGroup(material, texture)
|
||||
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,
|
||||
vertices=('f', mesh.vertices),
|
||||
normals=('f', mesh.normals),
|
||||
tex_coords=('f', mesh.tex_coords),
|
||||
colors=('f', material.diffuse * count)))
|
||||
else:
|
||||
group = MaterialGroup(material)
|
||||
program = pyglet.model.get_default_shader()
|
||||
group = MaterialGroup(material, program)
|
||||
vertex_lists.append(program.vertex_list(count, GL_TRIANGLES, batch, group,
|
||||
vertices=('f', mesh.vertices),
|
||||
normals=('f', mesh.normals),
|
||||
|
Loading…
Reference in New Issue
Block a user