pyglet update
This commit is contained in:
parent
392722cd37
commit
5667dacda6
@ -79,14 +79,14 @@ def pyglet_load_fonts_folder(folder) -> None:
|
||||
class ClientWindow(Window):
|
||||
|
||||
def __init__(self, net_mode='local', *args, **kwargs):
|
||||
"""
|
||||
|
||||
@param net_mode:
|
||||
@param args:
|
||||
@param kwargs:
|
||||
"""
|
||||
start_time = time.time_ns()
|
||||
super().__init__(*args, **kwargs)
|
||||
"""
|
||||
:param dev_list: 共享内存
|
||||
:param dev_dic: 共享内存
|
||||
:param logger: logger
|
||||
:param net_mode: 网络模式 # local / ip
|
||||
"""
|
||||
# logging
|
||||
self.logger = logging.getLogger('client')
|
||||
# value
|
||||
|
@ -7,19 +7,43 @@
|
||||
#include <Python.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
int *print_PyUcs4(PyObject *pyObject){
|
||||
if(PyUnicode_READY(pyObject) == -1){
|
||||
PyErr_SetString(PyExc_UnicodeDecodeError, "failed");
|
||||
return NULL;
|
||||
}
|
||||
#if defined(__linux__)
|
||||
const char *out_char = PyUnicode_AsUTF8(pyObject);
|
||||
printf("%s\n", out_char);
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
Py_UCS4 *ucs4 = PyUnicode_4BYTE_DATA(pyObject);
|
||||
printf("%ws\n", ucs4); // win
|
||||
#endif
|
||||
return (int *) 1;
|
||||
};
|
||||
|
||||
static PyObject *pycprint_print(PyObject *self, PyObject *args){
|
||||
const char *text;
|
||||
if(!PyArg_ParseTuple(args, "s", &text)){ // 解析 text
|
||||
if(!print_PyUcs4(PyTuple_GetItem(args, 0))){
|
||||
return NULL;
|
||||
};
|
||||
printf("%s", text);
|
||||
Py_RETURN_NONE;
|
||||
};
|
||||
|
||||
Py_UCS4 *get_ucs4from_unicode(PyObject *unicode){
|
||||
|
||||
const char *get_char_from_PyUnicode(PyObject *unicodeObject){
|
||||
if(!PyUnicode_READY(unicodeObject)){
|
||||
return NULL;
|
||||
};
|
||||
const char *char_obj = PyUnicode_AsUTF8(unicodeObject);
|
||||
if(char_obj == NULL){
|
||||
return NULL;
|
||||
} else {
|
||||
return char_obj;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static PyObject *pycpint_printf(PyObject *self, PyObject *args, PyObject *kwargs){
|
||||
printf("args == NULL: %d\n", args == NULL);
|
||||
printf("kwargs == NULL: %d\n", kwargs == NULL);
|
||||
@ -34,14 +58,13 @@ static PyObject *pycpint_printf(PyObject *self, PyObject *args, PyObject *kwargs
|
||||
for (Py_ssize_t i = 0; i < text_len; i++){ // for 遍历
|
||||
cache_obj = PyTuple_GetItem(args, i); // 获取一个字符串
|
||||
if (cache_obj == NULL){ return NULL; }; // 出毛病了就报错
|
||||
if (PyUnicode_Check(cache_obj) == 1) { // 他不是个字符串(实际上如果有pyi文件就不需要这个检查)
|
||||
|
||||
if (PyUnicode_Check(cache_obj) == 1) {
|
||||
print_PyUcs4(cache_obj);
|
||||
} else if (PyList_Check(cache_obj) == 1) {
|
||||
|
||||
};
|
||||
};
|
||||
printf("text_len = %lld\n", (Py_size)text_len);
|
||||
|
||||
};
|
||||
if(kwargs != NULL){ // 传入了 end 或者 sep
|
||||
Py_ssize_t kwargs_len = PyDict_Size(kwargs);
|
||||
@ -49,13 +72,8 @@ static PyObject *pycpint_printf(PyObject *self, PyObject *args, PyObject *kwargs
|
||||
if(PyDict_Contains(kwargs, PyUnicode_FromString("end"))){ // 如果包含 end 的参数
|
||||
PyObject *end_unicode; // 整个缓存
|
||||
end_unicode = PyDict_GetItemString(kwargs, "end"); // 先获取出来 Pyobj
|
||||
if(!PyUnicode_READY(end_unicode)){ return NULL; }; // 确认这个字符串对象可以用宏
|
||||
|
||||
Py_ssize_t end_unicode_len = PyUnicode_GetLength(end_unicode); // 缓存一手长度
|
||||
Py_UCS4 *new_end = malloc(sizeof(char) * end_unicode_len); // 提前分配好不定长度的字符串内存
|
||||
for (Py_ssize_t i = 0; i < end_unicode_len; i++){
|
||||
new_end[i] = PyUnicode_ReadChar(end_unicode, i); // 每一位对应读取
|
||||
};
|
||||
end = PyUnicode_AsUTF8(end_unicode);
|
||||
};
|
||||
};
|
||||
printf("%s", end);
|
||||
|
@ -3,11 +3,22 @@
|
||||
# Copyright © 2021-2022 by shenjackyuanjie 3695888@qq.com
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
import timeit
|
||||
import time
|
||||
from build import pycprint
|
||||
|
||||
pycprint.print("a啊a\n")
|
||||
|
||||
time.sleep(1)
|
||||
cpyprint = timeit.timeit('pycprint.print("啊啊")', number=100000, globals=globals())
|
||||
pyprint = timeit.timeit('print("啊啊")', number=100000, globals=globals())
|
||||
|
||||
print(cpyprint, pyprint, pyprint - cpyprint)
|
||||
time.sleep(10)
|
||||
|
||||
pycprint.print("a啊 a\n")
|
||||
pycprint.print("a啊采购好难过 a\n")
|
||||
print()
|
||||
#
|
||||
pycprint.printf("a啊a\n", "aaa", "aaa", end='')
|
||||
|
||||
print()
|
||||
|
@ -29,13 +29,15 @@ class Threads(threading.Thread):
|
||||
|
||||
class ThreadLock:
|
||||
|
||||
def __init__(self, the_lock: Lock) -> None:
|
||||
def __init__(self, the_lock: Lock, time_out: Union[float, int] = 1/60) -> None:
|
||||
self.lock = the_lock
|
||||
self.time_out = time_out
|
||||
|
||||
def __enter__(self, timeout: Union[float, int] = 1/60):
|
||||
self.lock.acquire(timeout=timeout)
|
||||
def __enter__(self):
|
||||
self.lock.acquire(timeout=self.time_out)
|
||||
if not self.lock.locked():
|
||||
raise LockTimeOutError
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if (exc_type is None) and (exc_val is None) and (exc_tb is None):
|
||||
|
@ -3,14 +3,26 @@
|
||||
@contact 3695888@qq.com
|
||||
"""
|
||||
import atexit
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from typing import Optional, Union
|
||||
from time import strftime
|
||||
from typing import Optional, Union, List, Iterable
|
||||
from logging import NOTSET, DEBUG, INFO, WARNING, ERROR, FATAL
|
||||
|
||||
from Difficult_Rocket.utils.thread import ThreadLock
|
||||
|
||||
# 如果想要直接使用 logger 来 logging
|
||||
# 直接调用 logger.debug() 即可
|
||||
# 默认配置会有
|
||||
# ----------
|
||||
# 配置方式一
|
||||
# 直接使用 logger.Logger()
|
||||
# 将会创建一个空 logger
|
||||
# 可以自行通过
|
||||
# 配置方式二
|
||||
#
|
||||
#
|
||||
|
||||
color_reset_suffix = "\033[0m"
|
||||
|
||||
"""
|
||||
@ -28,7 +40,6 @@ NOTSET = 0
|
||||
DETAIL = 5
|
||||
|
||||
|
||||
|
||||
class LogFileCache:
|
||||
"""日志文件缓存"""
|
||||
|
||||
@ -43,23 +54,21 @@ class LogFileCache:
|
||||
self._logfile_name = file_name # log 文件名称
|
||||
self.flush_time = flush_time # 缓存刷新时长
|
||||
self.cache_entries_num = log_cache_lens_max
|
||||
# 写入缓存数
|
||||
self.cache_count = 0
|
||||
# 日志缓存表
|
||||
self.logs_cache = []
|
||||
self._log_cache = []
|
||||
# 同步锁
|
||||
self.thread_lock = threading.Lock()
|
||||
self.with_thread_lock = ThreadLock(self.thread_lock)
|
||||
self.threaded_write = threading.Timer(1, self._log_file_time_write)
|
||||
self.cache_lock = threading.Lock() # 主锁
|
||||
self.write_lock = threading.Lock() # 写入锁
|
||||
self.with_thread_lock = ThreadLock(self.cache_lock, time_out=1 / 60) # 直接用于 with 的主锁
|
||||
self.threaded_write = threading.Timer(1, self._log_file_time_write) # 基于 timer 的多线程
|
||||
|
||||
def end_thread(self):
|
||||
def end_thread(self) -> None:
|
||||
"""结束日志写入进程,顺手把目前的缓存写入"""
|
||||
self.thread_lock.acquire(blocking=True)
|
||||
self.cache_lock.acquire(blocking=True)
|
||||
self.threaded_write.cancel()
|
||||
if self.cache_count:
|
||||
self._log_file_time_write()
|
||||
self._log_file_time_write()
|
||||
|
||||
def start_thread(self):
|
||||
def start_thread(self) -> None:
|
||||
self.threaded_write.start()
|
||||
atexit.register(self.end_thread)
|
||||
|
||||
@ -72,17 +81,34 @@ class LogFileCache:
|
||||
with self.with_thread_lock:
|
||||
self._logfile_name = value
|
||||
|
||||
@property
|
||||
def log_caches(self) -> list:
|
||||
return self._log_cache
|
||||
|
||||
@log_caches.setter
|
||||
def log_caches(self, value: Union[str, Iterable[str]]):
|
||||
if type(value) == str:
|
||||
with self.with_thread_lock:
|
||||
self._log_cache.append(value)
|
||||
return
|
||||
elif isinstance(value, Iterable):
|
||||
with self.with_thread_lock:
|
||||
list(map(self._log_cache.append, value))
|
||||
...
|
||||
|
||||
def _log_file_time_write(self) -> None:
|
||||
"""使用 threading.Timer 调用的定时写入日志文件的函数"""
|
||||
with self.with_thread_lock:
|
||||
if self.cache_count == 0:
|
||||
return None
|
||||
if self.log_caches:
|
||||
with self.with_thread_lock:
|
||||
if self.log_caches:
|
||||
...
|
||||
|
||||
...
|
||||
|
||||
def write_logs(self, string: str, wait_for_cache: bool = True) -> None:
|
||||
if wait_for_cache:
|
||||
with open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
|
||||
log_file.writelines(self.logs_cache)
|
||||
with self.with_thread_lock and open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
|
||||
log_file.writelines(self._log_cache)
|
||||
log_file.write(string)
|
||||
...
|
||||
else:
|
||||
@ -92,82 +118,118 @@ class LogFileCache:
|
||||
class Logger:
|
||||
"""shenjack logger"""
|
||||
|
||||
def __init__(self, config: dict = None, **kwargs) -> None:
|
||||
"""请注意,如果需要获取一个"""
|
||||
def __init__(self, **kwargs) -> None:
|
||||
"""
|
||||
配置模式: 使用 kwargs 配置
|
||||
@param config: 字典格式的配置
|
||||
@param kwargs: key word 格式的配置
|
||||
"""
|
||||
self.name = 'root'
|
||||
if config is None:
|
||||
if name := kwargs.pop('name', default=False):
|
||||
self.level = DEBUG
|
||||
self.colors = None
|
||||
if kwargs is not None: # 使用 kwargs 尝试配置
|
||||
if name := kwargs.pop('name', False): # 顺手把获取到的配置填入临时变量 如果成功获取再填入 self
|
||||
self.name = name
|
||||
if level := kwargs.pop('level', False):
|
||||
self.level = level
|
||||
else:
|
||||
|
||||
...
|
||||
|
||||
def make_log(self, level: int,
|
||||
*values: object,
|
||||
self.file_cache = LogFileCache()
|
||||
self.warn = self.warning
|
||||
self.fine = self.detail
|
||||
|
||||
def make_log(self, *values: object,
|
||||
level: int,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
if level < self.level:
|
||||
return None
|
||||
print(level, values, sep, end, flush, sep='|')
|
||||
write_text = sep.join(*values)
|
||||
print(write_text)
|
||||
...
|
||||
|
||||
def detail(self, *values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=DETAIL, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=DETAIL, sep=sep, end=end, flush=flush)
|
||||
|
||||
def debug(self,
|
||||
*values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=DEBUG, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=DEBUG, sep=sep, end=end, flush=flush)
|
||||
|
||||
def info(self,
|
||||
*values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=INFO, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=INFO, sep=sep, end=end, flush=flush)
|
||||
|
||||
def warning(self,
|
||||
*values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=WARNING, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=WARNING, sep=sep, end=end, flush=flush)
|
||||
|
||||
def error(self,
|
||||
*values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=ERROR, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=ERROR, sep=sep, end=end, flush=flush)
|
||||
|
||||
def fatal(self,
|
||||
*values: object,
|
||||
sep: Optional[str] = ' ',
|
||||
end: Optional[str] = '\n',
|
||||
flush: Optional[bool] = False) -> None:
|
||||
self.make_log(level=FATAL, *values, sep=sep, end=end, flush=flush)
|
||||
self.make_log(*values, level=FATAL, sep=sep, end=end, flush=flush)
|
||||
|
||||
|
||||
logger_configs = {
|
||||
'root': {
|
||||
'level': DEBUG,
|
||||
'color': {
|
||||
DEBUG: '\033[0m'
|
||||
'Logger': {
|
||||
'root': {
|
||||
'level': DETAIL,
|
||||
'color': {
|
||||
DEBUG: '\033[0m'
|
||||
},
|
||||
'file': 'main_log_file',
|
||||
},
|
||||
'file': {
|
||||
},
|
||||
'Color': {
|
||||
'detail'
|
||||
},
|
||||
'File': {
|
||||
'main_log_file': {
|
||||
'mode': 'a',
|
||||
'encoding': 'utf-8'
|
||||
'encoding': 'utf-8',
|
||||
'level': DEBUG,
|
||||
'file_name': '{main_time}_logs.md'
|
||||
},
|
||||
},
|
||||
'Formatter': {
|
||||
'main_time': {'strftime': '%Y-%m-%d %H-%M-%S'},
|
||||
'version': 'game.version',
|
||||
'level': 'level',
|
||||
'encoding': 'utf-8',
|
||||
...: ...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def add_dict_config_to_global(some_dict: dict, name: str) -> dict:
|
||||
def add_dict_config_to_global(some_dict: Union[dict, list, str], name: str) -> dict:
|
||||
"""
|
||||
|
||||
提前声明,这个函数很有可能搞坏 config
|
||||
请使用 add_kwargs_to_global 来修改配置
|
||||
如果你不知道你在改什么,请**务必不要**用这个函数来修改配置
|
||||
@param some_dict: 一个你丢进来的 logger 设置
|
||||
@param name: 这个 logger 设置的名称
|
||||
@return: 修改过的 logger 配置
|
||||
@ -184,3 +246,19 @@ def add_kwargs_to_global(**kwargs) -> dict:
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
def get_logger(name: str = 'name') -> Logger:
|
||||
"""
|
||||
此函数用于从 global_config 中取出对应的配置建立一个相应的 logger
|
||||
@param name: logger的名称
|
||||
@return: 创建好的 logger
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 在这里可以使用 add_kwargs_to_global
|
||||
some_logger = Logger(name='aaa')
|
||||
some_logger.level = DETAIL
|
||||
some_logger.warn('aaaa', 'aaaa')
|
||||
...
|
||||
|
@ -44,7 +44,7 @@ import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
#: The release version
|
||||
version = '2.0.dev18'
|
||||
version = '2.0.dev20'
|
||||
__version__ = version
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
@ -149,6 +149,7 @@ options = {
|
||||
'debug_trace_depth': 1,
|
||||
'debug_trace_flush': True,
|
||||
'debug_win32': False,
|
||||
'debug_input': False,
|
||||
'debug_x11': False,
|
||||
'shadow_window': True,
|
||||
'vsync': None,
|
||||
@ -178,6 +179,7 @@ _option_types = {
|
||||
'debug_trace_depth': int,
|
||||
'debug_trace_flush': bool,
|
||||
'debug_win32': bool,
|
||||
'debug_input': bool,
|
||||
'debug_x11': bool,
|
||||
'shadow_window': bool,
|
||||
'vsync': bool,
|
||||
|
@ -245,7 +245,7 @@ class EventLoop(event.EventDispatcher):
|
||||
self.clock.call_scheduled_functions(dt)
|
||||
|
||||
# Update timout
|
||||
return self.clock.get_sleep_time(False)
|
||||
return self.clock.get_sleep_time(True)
|
||||
|
||||
@property
|
||||
def has_exit(self):
|
||||
|
@ -38,19 +38,19 @@
|
||||
Measuring time
|
||||
==============
|
||||
|
||||
The `tick` and `get_fps` functions can be used in conjunction to fulfil most
|
||||
The `tick` and `get_frequency` functions can be used in conjunction to fulfil most
|
||||
games' basic requirements::
|
||||
|
||||
from pyglet import clock
|
||||
while True:
|
||||
dt = clock.tick()
|
||||
# ... update and render ...
|
||||
print(f"FPS is {clock.get_fps()}")
|
||||
print(f"FPS is {clock.get_frequency()}")
|
||||
|
||||
The ``dt`` value returned gives the number of seconds (as a float) since the
|
||||
last "tick".
|
||||
|
||||
The `get_fps` function averages the framerate over a sliding window of
|
||||
The `get_frequency` function averages the framerate over a sliding window of
|
||||
approximately 1 second. (You can calculate the instantaneous framerate by
|
||||
taking the reciprocal of ``dt``).
|
||||
|
||||
@ -176,7 +176,7 @@ class Clock:
|
||||
self.next_ts = self.time()
|
||||
self.last_ts = None
|
||||
|
||||
# Used by self.get_fps to show update frequency
|
||||
# Used by self.get_frequency to show update frequency
|
||||
self.times = _deque()
|
||||
self.cumulative_time = 0
|
||||
self.window_size = 60
|
||||
|
@ -114,22 +114,34 @@ def load(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None
|
||||
if dpi is None:
|
||||
dpi = 96
|
||||
|
||||
# Find first matching name
|
||||
if type(name) in (tuple, list):
|
||||
for n in name:
|
||||
if _font_class.have_font(n):
|
||||
name = n
|
||||
break
|
||||
else:
|
||||
name = None
|
||||
|
||||
# Locate or create font cache
|
||||
shared_object_space = gl.current_context.object_space
|
||||
if not hasattr(shared_object_space, 'pyglet_font_font_cache'):
|
||||
shared_object_space.pyglet_font_font_cache = weakref.WeakValueDictionary()
|
||||
shared_object_space.pyglet_font_font_hold = []
|
||||
shared_object_space.pyglet_font_font_name_match = {} # Match a tuple to specific name to reduce lookups.
|
||||
|
||||
font_cache = shared_object_space.pyglet_font_font_cache
|
||||
font_hold = shared_object_space.pyglet_font_font_hold
|
||||
font_name_match = shared_object_space.pyglet_font_font_name_match
|
||||
|
||||
name_type = type(name)
|
||||
if name_type in (tuple, list):
|
||||
if name_type == list:
|
||||
name = tuple(name)
|
||||
|
||||
if name in font_name_match:
|
||||
name = font_name_match[name]
|
||||
else:
|
||||
# Find first matching name, cache it.
|
||||
found_name = None
|
||||
for n in name:
|
||||
if _font_class.have_font(n):
|
||||
found_name = n
|
||||
break
|
||||
|
||||
font_name_match[name] = found_name
|
||||
name = found_name
|
||||
|
||||
# Look for font name in font cache
|
||||
descriptor = (name, size, bold, italic, stretch, dpi)
|
||||
|
@ -44,8 +44,7 @@ __all__ = ['link_GL', 'link_WGL']
|
||||
|
||||
_debug_trace = pyglet.options['debug_trace']
|
||||
|
||||
# gl_lib = ctypes.windll.opengl32
|
||||
gl_lib = pyglet.lib.load_library('opengl32')
|
||||
gl_lib = ctypes.windll.opengl32
|
||||
wgl_lib = gl_lib
|
||||
|
||||
if _debug_trace:
|
||||
|
@ -202,7 +202,7 @@ def draw(size, mode, **data):
|
||||
attribute = vertexattribute.VertexAttribute(name, location, count, gl_type, normalize)
|
||||
assert size == len(array) // attribute.count, 'Data for %s is incorrect length' % fmt
|
||||
|
||||
buffer = BufferObject(size * attribute.stride, GL_ARRAY_BUFFER)
|
||||
buffer = BufferObject(size * attribute.stride)
|
||||
attribute.set_region(buffer, 0, size, array)
|
||||
attribute.enable()
|
||||
attribute.set_pointer(buffer.ptr)
|
||||
@ -252,7 +252,7 @@ def draw_indexed(size, mode, indices, **data):
|
||||
attribute = vertexattribute.VertexAttribute(name, location, count, gl_type, normalize)
|
||||
assert size == len(array) // attribute.count, 'Data for %s is incorrect length' % fmt
|
||||
|
||||
buffer = BufferObject(size * attribute.stride, GL_ARRAY_BUFFER)
|
||||
buffer = BufferObject(size * attribute.stride)
|
||||
attribute.set_region(buffer, 0, size, array)
|
||||
attribute.enable()
|
||||
attribute.set_pointer(buffer.ptr)
|
||||
@ -271,8 +271,9 @@ def draw_indexed(size, mode, indices, **data):
|
||||
# With GL 3.3 vertex arrays indices needs to be in a buffer
|
||||
# bound to the ELEMENT_ARRAY slot
|
||||
index_array = (index_c_type * len(indices))(*indices)
|
||||
index_buffer = BufferObject(ctypes.sizeof(index_array), GL_ELEMENT_ARRAY_BUFFER)
|
||||
index_buffer = BufferObject(ctypes.sizeof(index_array))
|
||||
index_buffer.set_data(index_array)
|
||||
index_buffer.bind_to_index_buffer()
|
||||
|
||||
glDrawElements(mode, len(indices), index_type, 0)
|
||||
glFlush()
|
||||
@ -385,7 +386,7 @@ class Batch:
|
||||
|
||||
def get_domain(self, indexed, mode, group, program, attributes):
|
||||
if group is None:
|
||||
group = get_default_group()
|
||||
group = ShaderGroup(program=program)
|
||||
|
||||
# Batch group
|
||||
if group not in self.group_map:
|
||||
|
@ -484,17 +484,17 @@ class ShaderProgram:
|
||||
num_active = GLint()
|
||||
block_data_size = GLint()
|
||||
|
||||
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, block_data_size)
|
||||
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, num_active)
|
||||
|
||||
glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, block_data_size)
|
||||
|
||||
indices = (GLuint * num_active.value)()
|
||||
indices_ptr = cast(addressof(indices), POINTER(GLint))
|
||||
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])
|
||||
for block_uniform_index in indices:
|
||||
uniform_name, u_type, u_size = self._query_uniform(block_uniform_index)
|
||||
|
||||
# Separate uniform name from block name (Only if instance name is provided on the Uniform Block)
|
||||
try:
|
||||
@ -503,9 +503,12 @@ class ShaderProgram:
|
||||
pass
|
||||
|
||||
gl_type, _, _, length, _ = _uniform_setters[u_type]
|
||||
uniforms[i] = (uniform_name, gl_type, length)
|
||||
uniforms[block_uniform_index] = (uniform_name, gl_type, length)
|
||||
|
||||
uniform_blocks[name] = UniformBlock(self, name, index, block_data_size.value, uniforms)
|
||||
# This might cause an error if index > GL_MAX_UNIFORM_BUFFER_BINDINGS, but surely no
|
||||
# one would be crazy enough to use more than 36 uniform blocks, right?
|
||||
glUniformBlockBinding(self.id, index, index)
|
||||
|
||||
if _debug_gl_shaders:
|
||||
for block in uniform_blocks.values():
|
||||
@ -638,7 +641,7 @@ class ShaderProgram:
|
||||
|
||||
|
||||
class UniformBlock:
|
||||
__slots__ = 'program', 'name', 'index', 'size', 'uniforms'
|
||||
__slots__ = 'program', 'name', 'index', 'size', 'uniforms', 'view_cls'
|
||||
|
||||
def __init__(self, program, name, index, size, uniforms):
|
||||
self.program = proxy(program)
|
||||
@ -646,23 +649,88 @@ class UniformBlock:
|
||||
self.index = index
|
||||
self.size = size
|
||||
self.uniforms = uniforms
|
||||
self.view_cls = None
|
||||
|
||||
def create_ubo(self, index=0):
|
||||
return UniformBufferObject(self, index)
|
||||
"""
|
||||
Create a new UniformBufferObject from this uniform block.
|
||||
|
||||
:Parameters:
|
||||
`index` : int
|
||||
The uniform buffer index the returned UBO will bind itself to.
|
||||
By default this is 0.
|
||||
|
||||
:rtype: :py:class:`~pyglet.graphics.shader.UniformBufferObject`
|
||||
"""
|
||||
if self.view_cls is None:
|
||||
self.view_cls = self._introspect_uniforms()
|
||||
return UniformBufferObject(self.view_cls, self.size, index)
|
||||
|
||||
def _introspect_uniforms(self):
|
||||
"""Introspect the block's structure and return a ctypes struct for
|
||||
manipulating the uniform block's members.
|
||||
"""
|
||||
p_id = self.program.id
|
||||
index = self.index
|
||||
|
||||
active_count = len(self.uniforms)
|
||||
|
||||
# Query the uniform index order and each uniform's offset:
|
||||
indices = (GLuint * active_count)()
|
||||
offsets = (GLint * active_count)()
|
||||
indices_ptr = cast(addressof(indices), POINTER(GLint))
|
||||
offsets_ptr = cast(addressof(offsets), POINTER(GLint))
|
||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices_ptr)
|
||||
glGetActiveUniformsiv(p_id, active_count, indices, GL_UNIFORM_OFFSET, offsets_ptr)
|
||||
|
||||
# Offsets may be returned in non-ascending order, sort them with the corresponding index:
|
||||
_oi = sorted(zip(offsets, indices), key=lambda x: x[0])
|
||||
offsets = [x[0] for x in _oi] + [self.size]
|
||||
indices = (GLuint * active_count)(*(x[1] for x in _oi))
|
||||
|
||||
# # Query other uniform information:
|
||||
# gl_types = (GLint * active_count)()
|
||||
# mat_stride = (GLint * active_count)()
|
||||
# gl_types_ptr = cast(addressof(gl_types), POINTER(GLint))
|
||||
# stride_ptr = cast(addressof(mat_stride), POINTER(GLint))
|
||||
# glGetActiveUniformsiv(p_id, active_count, indices, GL_UNIFORM_TYPE, gl_types_ptr)
|
||||
# glGetActiveUniformsiv(p_id, active_count, indices, GL_UNIFORM_MATRIX_STRIDE, stride_ptr)
|
||||
|
||||
view_fields = []
|
||||
for i in range(active_count):
|
||||
u_name, gl_type, length = self.uniforms[indices[i]]
|
||||
size = offsets[i+1] - offsets[i]
|
||||
c_type_size = sizeof(gl_type)
|
||||
actual_size = c_type_size * length
|
||||
padding = size - actual_size
|
||||
|
||||
# TODO: handle stride for multiple matrixes in the same UBO (crashes now)
|
||||
# m_stride = mat_stride[i]
|
||||
|
||||
arg = (u_name, gl_type * length) if length > 1 else (u_name, gl_type)
|
||||
view_fields.append(arg)
|
||||
|
||||
if padding > 0:
|
||||
padding_bytes = padding // c_type_size
|
||||
view_fields.append((f'_padding{i}', gl_type * padding_bytes))
|
||||
|
||||
# Custom ctypes Structure for Uniform access:
|
||||
class View(Structure):
|
||||
_fields_ = view_fields
|
||||
__repr__ = lambda self: str(dict(self._fields_))
|
||||
|
||||
return View
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}(name={self.name}, index={self.index})"
|
||||
|
||||
|
||||
class UniformBufferObject:
|
||||
__slots__ = 'block', 'buffer', 'view', '_view', '_view_ptr', 'index'
|
||||
__slots__ = 'buffer', 'view', '_view_ptr', 'index'
|
||||
|
||||
def __init__(self, block, index):
|
||||
assert type(block) == UniformBlock, "Must be a UniformBlock instance"
|
||||
self.block = block
|
||||
self.buffer = BufferObject(self.block.size, GL_UNIFORM_BUFFER)
|
||||
self.buffer.bind()
|
||||
self.view = self._introspect_uniforms()
|
||||
def __init__(self, view_class, buffer_size, index):
|
||||
self.buffer = BufferObject(buffer_size)
|
||||
self.view = view_class()
|
||||
self._view_ptr = pointer(self.view)
|
||||
self.index = index
|
||||
|
||||
@ -670,81 +738,24 @@ class UniformBufferObject:
|
||||
def id(self):
|
||||
return self.buffer.id
|
||||
|
||||
def _introspect_uniforms(self):
|
||||
p_id = self.block.program.id
|
||||
index = self.block.index
|
||||
|
||||
# Query the number of active Uniforms:
|
||||
num_active = GLint()
|
||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, num_active)
|
||||
|
||||
# Query the uniform index order and each uniform's offset:
|
||||
indices = (GLuint * num_active.value)()
|
||||
offsets = (GLint * num_active.value)()
|
||||
indices_ptr = cast(addressof(indices), POINTER(GLint))
|
||||
offsets_ptr = cast(addressof(offsets), POINTER(GLint))
|
||||
glGetActiveUniformBlockiv(p_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices_ptr)
|
||||
glGetActiveUniformsiv(p_id, num_active.value, indices, GL_UNIFORM_OFFSET, offsets_ptr)
|
||||
|
||||
# Offsets may be returned in non-ascending order, sort them with the corresponding index:
|
||||
_oi = sorted(zip(offsets, indices), key=lambda x: x[0])
|
||||
offsets = [x[0] for x in _oi] + [self.block.size]
|
||||
indices = (GLuint * num_active.value)(*(x[1] for x in _oi))
|
||||
|
||||
# Query other uniform information:
|
||||
gl_types = (GLint * num_active.value)()
|
||||
mat_stride = (GLint * num_active.value)()
|
||||
gl_types_ptr = cast(addressof(gl_types), POINTER(GLint))
|
||||
stride_ptr = cast(addressof(mat_stride), POINTER(GLint))
|
||||
glGetActiveUniformsiv(p_id, num_active.value, indices, GL_UNIFORM_TYPE, gl_types_ptr)
|
||||
glGetActiveUniformsiv(p_id, num_active.value, indices, GL_UNIFORM_MATRIX_STRIDE, stride_ptr)
|
||||
|
||||
args = []
|
||||
|
||||
for i in range(num_active.value):
|
||||
u_name, gl_type, length = self.block.uniforms[indices[i]]
|
||||
size = offsets[i+1] - offsets[i]
|
||||
c_type_size = sizeof(gl_type)
|
||||
actual_size = c_type_size * length
|
||||
padding = size - actual_size
|
||||
|
||||
# TODO: handle stride for multiple matrixes in the same UBO (crashes now)
|
||||
m_stride = mat_stride[i]
|
||||
|
||||
arg = (u_name, gl_type * length) if length > 1 else (u_name, gl_type)
|
||||
args.append(arg)
|
||||
|
||||
if padding > 0:
|
||||
padding_bytes = padding // c_type_size
|
||||
args.append((f'_padding{i}', gl_type * padding_bytes))
|
||||
|
||||
# Custom ctypes Structure for Uniform access:
|
||||
class View(Structure):
|
||||
_fields_ = args
|
||||
__repr__ = lambda self: str(dict(self._fields_))
|
||||
|
||||
return View()
|
||||
|
||||
def bind(self, index=None):
|
||||
glUniformBlockBinding(self.block.program.id, self.block.index, index or self.index)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, index or self.index, self.buffer.id)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.index if index is None else index, self.buffer.id)
|
||||
|
||||
def read(self):
|
||||
"""Read the byte contents of the buffer"""
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, self.buffer.id)
|
||||
ptr = glMapBufferRange(GL_UNIFORM_BUFFER, 0, self.buffer.size, GL_MAP_READ_BIT)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.buffer.id)
|
||||
ptr = glMapBufferRange(GL_ARRAY_BUFFER, 0, self.buffer.size, GL_MAP_READ_BIT)
|
||||
data = string_at(ptr, size=self.buffer.size)
|
||||
glUnmapBuffer(GL_UNIFORM_BUFFER)
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER)
|
||||
return data
|
||||
|
||||
def __enter__(self):
|
||||
# Return the view to the user in a `with` context:
|
||||
glUniformBlockBinding(self.block.program.id, self.block.index, self.index)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.index, self.buffer.id)
|
||||
return self.view
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.bind()
|
||||
self.buffer.set_data(self._view_ptr)
|
||||
|
||||
def __repr__(self):
|
||||
return "{0}(id={1})".format(self.block.name + 'Buffer', self.buffer.id)
|
||||
return "{0}(id={1})".format(self.__class__.__name__, self.buffer.id)
|
||||
|
@ -59,8 +59,6 @@ class AbstractBuffer:
|
||||
`ptr` : int
|
||||
Memory offset of the buffer, as used by the ``glVertexPointer``
|
||||
family of functions
|
||||
`target` : int
|
||||
OpenGL buffer target, for example ``GL_ARRAY_BUFFER``
|
||||
`usage` : int
|
||||
OpenGL buffer usage, for example ``GL_DYNAMIC_DRAW``
|
||||
|
||||
@ -69,8 +67,8 @@ class AbstractBuffer:
|
||||
ptr = 0
|
||||
size = 0
|
||||
|
||||
def bind(self):
|
||||
"""Bind this buffer to its OpenGL target."""
|
||||
def bind(self, target=GL_ARRAY_BUFFER):
|
||||
"""Bind this buffer to an OpenGL target."""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def unbind(self):
|
||||
@ -170,6 +168,9 @@ class BufferObject(AbstractBuffer):
|
||||
The data in the buffer is not replicated in any system memory (unless it
|
||||
is done so by the video driver). While this can improve memory usage and
|
||||
possibly performance, updates to the buffer are relatively slow.
|
||||
The target of the buffer is ``GL_ARRAY_BUFFER`` internally to avoid
|
||||
accidentally overriding other states when altering the buffer contents.
|
||||
The intended target can be set when binding the buffer.
|
||||
|
||||
This class does not implement :py:class:`AbstractMappable`, and so has no
|
||||
:py:meth:`~AbstractMappable.get_region` method. See
|
||||
@ -177,9 +178,8 @@ class BufferObject(AbstractBuffer):
|
||||
that does implement :py:meth:`~AbstractMappable.get_region`.
|
||||
"""
|
||||
|
||||
def __init__(self, size, target, usage=GL_DYNAMIC_DRAW):
|
||||
def __init__(self, size, usage=GL_DYNAMIC_DRAW):
|
||||
self.size = size
|
||||
self.target = target
|
||||
self.usage = usage
|
||||
self._context = pyglet.gl.current_context
|
||||
|
||||
@ -187,39 +187,43 @@ class BufferObject(AbstractBuffer):
|
||||
glGenBuffers(1, buffer_id)
|
||||
self.id = buffer_id.value
|
||||
|
||||
glBindBuffer(target, self.id)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
data = (GLubyte * self.size)()
|
||||
glBufferData(target, self.size, data, self.usage)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, data, self.usage)
|
||||
|
||||
def invalidate(self):
|
||||
glBufferData(self.target, self.size, None, self.usage)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, None, self.usage)
|
||||
|
||||
def bind(self):
|
||||
glBindBuffer(self.target, self.id)
|
||||
def bind(self, target=GL_ARRAY_BUFFER):
|
||||
glBindBuffer(target, self.id)
|
||||
|
||||
def unbind(self):
|
||||
glBindBuffer(self.target, 0)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
|
||||
def bind_to_index_buffer(self):
|
||||
"""Binds this buffer as an index buffer on the active vertex array."""
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.id)
|
||||
|
||||
def set_data(self, data):
|
||||
glBindBuffer(self.target, self.id)
|
||||
glBufferData(self.target, self.size, data, self.usage)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, data, self.usage)
|
||||
|
||||
def set_data_region(self, data, start, length):
|
||||
glBindBuffer(self.target, self.id)
|
||||
glBufferSubData(self.target, start, length, data)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
glBufferSubData(GL_ARRAY_BUFFER, start, length, data)
|
||||
|
||||
def map(self):
|
||||
glBindBuffer(self.target, self.id)
|
||||
ptr = ctypes.cast(glMapBuffer(self.target, GL_WRITE_ONLY), ctypes.POINTER(ctypes.c_byte * self.size)).contents
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
ptr = ctypes.cast(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY), ctypes.POINTER(ctypes.c_byte * self.size)).contents
|
||||
return ptr
|
||||
|
||||
def map_range(self, start, size, ptr_type):
|
||||
glBindBuffer(self.target, self.id)
|
||||
ptr = ctypes.cast(glMapBufferRange(self.target, start, size, GL_MAP_WRITE_BIT), ptr_type).contents
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
ptr = ctypes.cast(glMapBufferRange(GL_ARRAY_BUFFER, start, size, GL_MAP_WRITE_BIT), ptr_type).contents
|
||||
return ptr
|
||||
|
||||
def unmap(self):
|
||||
glUnmapBuffer(self.target)
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
@ -240,13 +244,13 @@ class BufferObject(AbstractBuffer):
|
||||
# Map, create a copy, then reinitialize.
|
||||
temp = (ctypes.c_byte * size)()
|
||||
|
||||
glBindBuffer(self.target, self.id)
|
||||
data = glMapBufferRange(self.target, 0, self.size, GL_MAP_READ_BIT)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
data = glMapBufferRange(GL_ARRAY_BUFFER, 0, self.size, GL_MAP_READ_BIT)
|
||||
ctypes.memmove(temp, data, min(size, self.size))
|
||||
glUnmapBuffer(self.target)
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER)
|
||||
|
||||
self.size = size
|
||||
glBufferData(self.target, self.size, temp, self.usage)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, temp, self.usage)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}(id={self.id}, size={self.size})"
|
||||
@ -263,8 +267,8 @@ class MappableBufferObject(BufferObject, AbstractMappable):
|
||||
|
||||
Updates to data via :py:meth:`map` are committed immediately.
|
||||
"""
|
||||
def __init__(self, size, target, usage=GL_DYNAMIC_DRAW):
|
||||
super(MappableBufferObject, self).__init__(size, target, usage)
|
||||
def __init__(self, size, usage=GL_DYNAMIC_DRAW):
|
||||
super(MappableBufferObject, self).__init__(size, usage)
|
||||
self.data = (ctypes.c_byte * size)()
|
||||
self.data_ptr = ctypes.addressof(self.data)
|
||||
self._dirty_min = sys.maxsize
|
||||
@ -276,9 +280,9 @@ class MappableBufferObject(BufferObject, AbstractMappable):
|
||||
size = self._dirty_max - self._dirty_min
|
||||
if size > 0:
|
||||
if size == self.size:
|
||||
glBufferData(self.target, self.size, self.data, self.usage)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, self.data, self.usage)
|
||||
else:
|
||||
glBufferSubData(self.target, self._dirty_min, size, self.data_ptr + self._dirty_min)
|
||||
glBufferSubData(GL_ARRAY_BUFFER, self._dirty_min, size, self.data_ptr + self._dirty_min)
|
||||
self._dirty_min = sys.maxsize
|
||||
self._dirty_max = 0
|
||||
|
||||
@ -313,8 +317,8 @@ class MappableBufferObject(BufferObject, AbstractMappable):
|
||||
|
||||
self.size = size
|
||||
|
||||
glBindBuffer(self.target, self.id)
|
||||
glBufferData(self.target, self.size, self.data, self.usage)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.id)
|
||||
glBufferData(GL_ARRAY_BUFFER, self.size, self.data, self.usage)
|
||||
|
||||
self._dirty_min = sys.maxsize
|
||||
self._dirty_max = 0
|
||||
|
@ -127,7 +127,7 @@ class VertexDomain:
|
||||
attribute = vertexattribute.VertexAttribute(name, location, count, gl_type, normalize)
|
||||
self.attributes.append(attribute)
|
||||
# Create buffer:
|
||||
attribute.buffer = MappableBufferObject(attribute.stride * self.allocator.capacity, GL_ARRAY_BUFFER)
|
||||
attribute.buffer = MappableBufferObject(attribute.stride * self.allocator.capacity)
|
||||
attribute.buffer.element_size = attribute.stride
|
||||
attribute.buffer.attributes = (attribute,)
|
||||
self.buffer_attributes.append((attribute.buffer, (attribute,)))
|
||||
@ -370,8 +370,7 @@ class IndexedVertexDomain(VertexDomain):
|
||||
self.index_gl_type = index_gl_type
|
||||
self.index_c_type = vertexattribute._c_types[index_gl_type]
|
||||
self.index_element_size = ctypes.sizeof(self.index_c_type)
|
||||
self.index_buffer = BufferObject(
|
||||
self.index_allocator.capacity * self.index_element_size, GL_ELEMENT_ARRAY_BUFFER)
|
||||
self.index_buffer = BufferObject(self.index_allocator.capacity * self.index_element_size)
|
||||
|
||||
def safe_index_alloc(self, count):
|
||||
"""Allocate indices, resizing the buffers if necessary."""
|
||||
@ -454,7 +453,7 @@ class IndexedVertexDomain(VertexDomain):
|
||||
for attribute in attributes:
|
||||
attribute.enable()
|
||||
attribute.set_pointer(attribute.buffer.ptr)
|
||||
self.index_buffer.bind()
|
||||
self.index_buffer.bind_to_index_buffer()
|
||||
|
||||
starts, sizes = self.index_allocator.get_allocated_regions()
|
||||
primcount = len(starts)
|
||||
@ -494,7 +493,7 @@ class IndexedVertexDomain(VertexDomain):
|
||||
for attribute in attributes:
|
||||
attribute.enable()
|
||||
attribute.set_pointer(attribute.buffer.ptr)
|
||||
self.index_buffer.bind()
|
||||
self.index_buffer.bind_to_index_buffer()
|
||||
|
||||
glDrawElements(mode, vertex_list.index_count, self.index_gl_type,
|
||||
self.index_buffer.ptr +
|
||||
|
@ -418,7 +418,7 @@ class TextEntry(WidgetBase):
|
||||
The color of the outline box in RGBA format.
|
||||
`text_color` : (int, int, int, int)
|
||||
The color of the text in RGBA format.
|
||||
`text_color` : (int, int, int)
|
||||
`caret_color` : (int, int, int)
|
||||
The color of the caret in RGB format.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the text entry widget to.
|
||||
|
@ -600,7 +600,7 @@ class Controller(EventDispatcher):
|
||||
`dpleft` : bool
|
||||
`dpright` : bool
|
||||
|
||||
.. versionadded:: 1.2
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
|
||||
self.device = device
|
||||
@ -1079,7 +1079,7 @@ class TabletCanvas(EventDispatcher):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_motion(self, cursor, x, y, pressure, tilt_x, tilt_y):
|
||||
def on_motion(self, cursor, x, y, pressure, tilt_x, tilt_y, buttons):
|
||||
"""The cursor moved on the tablet surface.
|
||||
|
||||
If `pressure` is 0, then the cursor is actually hovering above the
|
||||
@ -1099,6 +1099,9 @@ class TabletCanvas(EventDispatcher):
|
||||
Currently undefined.
|
||||
`tilt_y` : float
|
||||
Currently undefined.
|
||||
`buttons` : int
|
||||
Button state may be provided if the platform supports it.
|
||||
Supported on: Windows
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
@ -2,7 +2,7 @@ from pyglet import compat_platform
|
||||
|
||||
|
||||
# This file is automatically generated by 'pyglet/tools/gen_controller_db.py'
|
||||
# Generated on: Thu Mar 3 16:25:08 2022
|
||||
# Generated on: Thu Jul 7 09:31:08 2022
|
||||
|
||||
if compat_platform.startswith("linux"):
|
||||
mapping_list = [
|
||||
@ -216,6 +216,10 @@ if compat_platform.startswith("linux"):
|
||||
"03000000c62400003a54000001010000,PowerA XBox One Controller,a:b0,b:b1,back:b6,dpdown:h0.7,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,",
|
||||
"03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@ -252,8 +256,11 @@ if compat_platform.startswith("linux"):
|
||||
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
|
||||
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
|
||||
"03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
|
||||
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
@ -266,6 +273,7 @@ if compat_platform.startswith("linux"):
|
||||
"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
|
||||
"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
|
||||
"030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
|
||||
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
|
||||
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",
|
||||
@ -405,6 +413,7 @@ elif compat_platform.startswith("darwin"):
|
||||
"030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
|
||||
"03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
|
||||
"03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
@ -602,6 +611,7 @@ elif compat_platform.startswith("win"):
|
||||
"030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000380700006382000000000000,MLG Gamepad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
@ -676,8 +686,9 @@ elif compat_platform.startswith("win"):
|
||||
"03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
|
||||
"03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,",
|
||||
"03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,",
|
||||
"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
|
@ -388,6 +388,7 @@ class EvdevDevice(XlibSelectDevice, Device):
|
||||
self.control_map[(event_type, event_code)] = control
|
||||
self.controls.append(control)
|
||||
|
||||
self.controls.sort(key=lambda c: c._event_code)
|
||||
os.close(fileno)
|
||||
|
||||
super().__init__(display, name)
|
||||
@ -553,7 +554,8 @@ class EvdevControllerManager(ControllerManager, XlibSelectDevice):
|
||||
self._controllers[name] = controller
|
||||
|
||||
if controller:
|
||||
self.dispatch_event('on_connect', controller)
|
||||
# Dispatch event in main thread:
|
||||
pyglet.app.platform_event_loop.post_event(self, 'on_connect', controller)
|
||||
|
||||
def _make_device(self, name, count=1):
|
||||
path = os.path.join('/dev/input', name)
|
||||
|
@ -34,12 +34,14 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
import ctypes
|
||||
|
||||
from collections import defaultdict
|
||||
import pyglet
|
||||
from pyglet.input.base import DeviceOpenException
|
||||
from pyglet.input.base import Tablet, TabletCanvas
|
||||
|
||||
from pyglet.libs.win32 import libwintab as wintab
|
||||
from pyglet.util import debug_print
|
||||
|
||||
_debug = debug_print('debug_input')
|
||||
|
||||
lib = wintab.lib
|
||||
|
||||
@ -116,12 +118,19 @@ class WintabTablet(Tablet):
|
||||
|
||||
|
||||
class WintabTabletCanvas(TabletCanvas):
|
||||
override_keys = False
|
||||
|
||||
def __init__(self, device, window, msg_base=wintab.WT_DEFBASE):
|
||||
super(WintabTabletCanvas, self).__init__(window)
|
||||
|
||||
self.device = device
|
||||
self.msg_base = msg_base
|
||||
|
||||
# Get the extension masks available. Only need to do this once.
|
||||
global _extension_masks
|
||||
if not _extension_masks:
|
||||
_extension_masks = get_extension_masks()
|
||||
|
||||
# Just use system context, for similarity w/ os x and xinput.
|
||||
# WTI_DEFCONTEXT detaches mouse from tablet, which is nice, but not
|
||||
# possible on os x afiak.
|
||||
@ -132,11 +141,11 @@ class WintabTabletCanvas(TabletCanvas):
|
||||
|
||||
# If you change this, change definition of PACKET also.
|
||||
context_info.lcPktData = (
|
||||
wintab.PK_CHANGED | wintab.PK_CURSOR | wintab.PK_BUTTONS |
|
||||
wintab.PK_X | wintab.PK_Y | wintab.PK_Z |
|
||||
wintab.PK_NORMAL_PRESSURE | wintab.PK_TANGENT_PRESSURE |
|
||||
wintab.PK_ORIENTATION)
|
||||
context_info.lcPktMode = 0 # All absolute
|
||||
wintab.PK_CHANGED | wintab.PK_CURSOR | wintab.PK_BUTTONS |
|
||||
wintab.PK_X | wintab.PK_Y | wintab.PK_Z |
|
||||
wintab.PK_NORMAL_PRESSURE | wintab.PK_TANGENT_PRESSURE |
|
||||
wintab.PK_ORIENTATION) | _extension_masks
|
||||
context_info.lcPktMode = 0 # All absolute (PACKETMODE)
|
||||
|
||||
self._context = lib.WTOpenW(window._hwnd, ctypes.byref(context_info), True)
|
||||
if not self._context:
|
||||
@ -145,10 +154,66 @@ class WintabTabletCanvas(TabletCanvas):
|
||||
window._event_handlers[msg_base + wintab.WT_PACKET] = self._event_wt_packet
|
||||
window._event_handlers[msg_base + wintab.WT_PROXIMITY] = self._event_wt_proximity
|
||||
|
||||
if _extension_masks:
|
||||
window._event_handlers[msg_base + wintab.WT_PACKETEXT] = self._event_wt_packetext
|
||||
|
||||
self._current_cursor = None
|
||||
self._pressure_scale = device.pressure_axis.get_scale()
|
||||
self._pressure_bias = device.pressure_axis.get_bias()
|
||||
|
||||
self.express_keys = defaultdict(lambda: defaultdict(bool)) # [control_id][location_id]
|
||||
self.express_key_ct = 0
|
||||
self.touchrings = [] # Not currently implemented.
|
||||
self.touchstrips = [] # Not currently implemented.
|
||||
|
||||
# Override test
|
||||
for tablet_id in range(get_tablet_count()):
|
||||
control_count = self.extension_get(wintab.WTX_EXPKEYS2, tablet_id, 0, 0,
|
||||
wintab.TABLET_PROPERTY_CONTROLCOUNT)
|
||||
self.express_key_ct = control_count
|
||||
assert _debug(f"Controls Found: {control_count}")
|
||||
if self.override_keys is True:
|
||||
for control_id in range(control_count):
|
||||
function_count = self.extension_get(wintab.WTX_EXPKEYS2, tablet_id, control_id, 0,
|
||||
wintab.TABLET_PROPERTY_FUNCCOUNT)
|
||||
for function_id in range(function_count):
|
||||
self.extension_set(wintab.WTX_EXPKEYS2, tablet_id, control_id, function_id,
|
||||
wintab.TABLET_PROPERTY_OVERRIDE, wintab.BOOL(True))
|
||||
|
||||
def extension_get(self, extension, tablet_id, control_id, function_id, property_id, value_type=wintab.UINT):
|
||||
prop = wintab.EXTPROPERTY()
|
||||
|
||||
prop.version = 0
|
||||
prop.tabletIndex = tablet_id
|
||||
prop.controlIndex = control_id
|
||||
prop.functionIndex = function_id
|
||||
prop.propertyID = property_id
|
||||
prop.reserved = 0
|
||||
prop.dataSize = ctypes.sizeof(value_type)
|
||||
|
||||
success = lib.WTExtGet(self._context, extension, ctypes.byref(prop))
|
||||
if success:
|
||||
return ctypes.cast(prop.data, ctypes.POINTER(value_type)).contents.value
|
||||
|
||||
return 0
|
||||
|
||||
def extension_set(self, extension, tablet_id, control_id, function_id, property_id, value):
|
||||
prop = wintab.EXTPROPERTY()
|
||||
prop.version = 0
|
||||
prop.tabletIndex = tablet_id
|
||||
prop.controlIndex = control_id
|
||||
prop.functionIndex = function_id
|
||||
prop.propertyID = property_id
|
||||
prop.reserved = 0
|
||||
prop.dataSize = ctypes.sizeof(value)
|
||||
prop.data[0] = value.value
|
||||
|
||||
success = lib.WTExtSet(self._context, extension, ctypes.byref(prop))
|
||||
if success:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
lib.WTClose(self._context)
|
||||
self._context = None
|
||||
@ -156,6 +221,9 @@ class WintabTabletCanvas(TabletCanvas):
|
||||
del self.window._event_handlers[self.msg_base + wintab.WT_PACKET]
|
||||
del self.window._event_handlers[self.msg_base + wintab.WT_PROXIMITY]
|
||||
|
||||
if _extension_masks:
|
||||
del self.window._event_handlers[self.msg_base + wintab.WT_PACKETEXT]
|
||||
|
||||
def _set_current_cursor(self, cursor_type):
|
||||
if self._current_cursor:
|
||||
self.dispatch_event('on_leave', self._current_cursor)
|
||||
@ -186,7 +254,25 @@ class WintabTabletCanvas(TabletCanvas):
|
||||
if self._current_cursor is None:
|
||||
self._set_current_cursor(packet.pkCursor)
|
||||
|
||||
self.dispatch_event('on_motion', self._current_cursor, x, y, pressure, 0., 0.)
|
||||
self.dispatch_event('on_motion', self._current_cursor, x, y, pressure, 0., 0., packet.pkButtons)
|
||||
|
||||
@pyglet.window.win32.Win32EventHandler(0)
|
||||
def _event_wt_packetext(self, msg, wParam, lParam):
|
||||
packet = wintab.PACKETEXT()
|
||||
if lib.WTPacket(lParam, wParam, ctypes.byref(packet)) == 0:
|
||||
return
|
||||
|
||||
# Proper context exists in the packet, not the lParam.
|
||||
if packet.pkBase.nContext == self._context:
|
||||
if packet.pkExpKeys.nControl < self.express_key_ct:
|
||||
current_state = self.express_keys[packet.pkExpKeys.nControl][packet.pkExpKeys.nLocation]
|
||||
new_state = bool(packet.pkExpKeys.nState)
|
||||
if current_state != new_state:
|
||||
event_type = "on_express_key_press" if new_state else "on_express_key_release"
|
||||
|
||||
self.express_keys[packet.pkExpKeys.nControl][packet.pkExpKeys.nLocation] = new_state
|
||||
|
||||
self.dispatch_event(event_type, packet.pkExpKeys.nControl, packet.pkExpKeys.nLocation)
|
||||
|
||||
@pyglet.window.win32.Win32EventHandler(0)
|
||||
def _event_wt_proximity(self, msg, wParam, lParam):
|
||||
@ -205,6 +291,40 @@ class WintabTabletCanvas(TabletCanvas):
|
||||
# can actually grab a cursor id.
|
||||
self._current_cursor = None
|
||||
|
||||
def on_express_key_press(self, control_id: int, location_id: int):
|
||||
"""An event called when an ExpressKey is pressed down.
|
||||
|
||||
:Parameters:
|
||||
`control_id` : int
|
||||
Zero-based index number given to the assigned key by the driver.
|
||||
The same control_id may exist in multiple locations, which the location_id is used to differentiate.
|
||||
`location_id: int
|
||||
Zero-based index indicating side of tablet where control id was found.
|
||||
Some tablets may have clusters of ExpressKey's on various areas of the tablet.
|
||||
(0 = left, 1 = right, 2 = top, 3 = bottom, 4 = transducer).
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_express_key_release(self, control_id: int, location_id: int):
|
||||
"""An event called when an ExpressKey is released.
|
||||
|
||||
:Parameters:
|
||||
`control_id` : int
|
||||
Zero-based index number given to the assigned key by the driver.
|
||||
The same control_id may exist in multiple locations, which the location_id is used to differentiate.
|
||||
`location_id: int
|
||||
Zero-based index indicating side of tablet where control id was found.
|
||||
Some tablets may have clusters of ExpressKey's on various areas of the tablet.
|
||||
(0 = left, 1 = right, 2 = top, 3 = bottom, 4 = transducer).
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
|
||||
WintabTabletCanvas.register_event_type('on_express_key_press')
|
||||
WintabTabletCanvas.register_event_type('on_express_key_release')
|
||||
|
||||
|
||||
class WintabTabletCursor:
|
||||
def __init__(self, device, index):
|
||||
@ -244,11 +364,73 @@ def get_implementation_version():
|
||||
return impl_version
|
||||
|
||||
|
||||
def get_tablets(display=None):
|
||||
# Require spec version 1.1 or greater
|
||||
if get_spec_version() < 0x101:
|
||||
return []
|
||||
def extension_index(ext):
|
||||
"""Check if a particular extension exists within the driver."""
|
||||
exists = True
|
||||
i = 0
|
||||
index = 0xFFFFFFFF
|
||||
|
||||
while exists:
|
||||
tag = wintab.UINT()
|
||||
exists = lib.WTInfoW(wintab.WTI_EXTENSIONS + i, wintab.EXT_TAG, ctypes.byref(tag))
|
||||
if tag.value == ext:
|
||||
index = i
|
||||
break
|
||||
|
||||
i += 1
|
||||
|
||||
if index != 0xFFFFFFFF:
|
||||
return index
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def get_extension_masks():
|
||||
"""Determine which extension support is available by getting the masks."""
|
||||
masks = 0
|
||||
tr_idx = extension_index(wintab.WTX_TOUCHRING)
|
||||
if tr_idx is not None:
|
||||
assert _debug("Touchring support found")
|
||||
masks |= wtinfo_uint(wintab.WTI_EXTENSIONS + tr_idx, wintab.EXT_MASK)
|
||||
else:
|
||||
assert _debug("Touchring extension not found.")
|
||||
|
||||
ts_idx = extension_index(wintab.WTX_TOUCHSTRIP)
|
||||
if ts_idx is not None:
|
||||
assert _debug("Touchstrip support found.")
|
||||
masks |= wtinfo_uint(wintab.WTI_EXTENSIONS + ts_idx, wintab.EXT_MASK)
|
||||
else:
|
||||
assert _debug("Touchstrip extension not found.")
|
||||
|
||||
expkeys_idx = extension_index(wintab.WTX_EXPKEYS2)
|
||||
if expkeys_idx is not None:
|
||||
assert _debug("ExpressKey support found.")
|
||||
masks |= wtinfo_uint(wintab.WTI_EXTENSIONS + expkeys_idx, wintab.EXT_MASK)
|
||||
else:
|
||||
assert _debug("ExpressKey extension not found.")
|
||||
|
||||
return masks
|
||||
|
||||
|
||||
def get_tablet_count():
|
||||
"""Return just the number of current devices."""
|
||||
spec_version = get_spec_version()
|
||||
assert _debug(f"Wintab Version: {spec_version}")
|
||||
if spec_version < 0x101:
|
||||
return 0
|
||||
|
||||
n_devices = wtinfo_uint(wintab.WTI_INTERFACE, wintab.IFC_NDEVICES)
|
||||
return n_devices
|
||||
|
||||
|
||||
_extension_masks = None
|
||||
|
||||
|
||||
def get_tablets(display=None):
|
||||
# Require spec version 1.1 or greater
|
||||
n_devices = get_tablet_count()
|
||||
if not n_devices:
|
||||
return []
|
||||
|
||||
devices = [WintabTablet(i) for i in range(n_devices)]
|
||||
return devices
|
||||
|
@ -93,7 +93,7 @@ class XInputTabletCanvas(DeviceResponder, TabletCanvas):
|
||||
x = e.x
|
||||
y = self.window.height - e.y
|
||||
pressure = e.axis_data[2] / float(cursor.max_pressure)
|
||||
self.dispatch_event('on_motion', cursor, x, y, pressure, 0.0, 0.0)
|
||||
self.dispatch_event('on_motion', cursor, x, y, pressure, 0.0, 0.0, 0.0)
|
||||
|
||||
def _proximity_in(self, e):
|
||||
cursor = self._cursor_map.get(e.deviceid)
|
||||
|
@ -12,10 +12,14 @@ from pyglet.libs.win32.constants import CLSCTX_INPROC_SERVER
|
||||
from pyglet.input.base import Device, Controller, Button, AbsoluteAxis, ControllerManager
|
||||
|
||||
|
||||
lib = pyglet.lib.load_library('xinput1_4')
|
||||
# TODO Add: xinput1_3 and xinput9_1_0 support
|
||||
|
||||
library_name = lib._name
|
||||
for library_name in ['xinput1_4', 'xinput9_1_0', 'xinput1_3']:
|
||||
try:
|
||||
lib = ctypes.windll.LoadLibrary(library_name)
|
||||
break
|
||||
except OSError:
|
||||
continue
|
||||
else:
|
||||
raise OSError('Could not import XInput')
|
||||
|
||||
|
||||
XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE = 7849
|
||||
@ -159,35 +163,38 @@ class XINPUT_CAPABILITIES_EX(Structure):
|
||||
]
|
||||
|
||||
|
||||
XInputGetState = lib.XInputGetState
|
||||
XInputGetState.restype = DWORD
|
||||
XInputGetState.argtypes = [DWORD, POINTER(XINPUT_STATE)]
|
||||
|
||||
XInputGetStateEx = lib[100]
|
||||
XInputGetStateEx.restype = DWORD
|
||||
XInputGetStateEx.argtypes = [DWORD, POINTER(XINPUT_STATE)]
|
||||
|
||||
XInputSetState = lib.XInputSetState
|
||||
XInputSetState.argtypes = [DWORD, POINTER(XINPUT_VIBRATION)]
|
||||
XInputSetState.restype = DWORD
|
||||
|
||||
XInputGetCapabilities = lib.XInputGetCapabilities
|
||||
XInputGetCapabilities.restype = DWORD
|
||||
XInputGetCapabilities.argtypes = [DWORD, DWORD, POINTER(XINPUT_CAPABILITIES)]
|
||||
|
||||
# Hidden function
|
||||
XInputGetCapabilitiesEx = lib[108]
|
||||
XInputGetCapabilitiesEx.restype = DWORD
|
||||
XInputGetCapabilitiesEx.argtypes = [DWORD, DWORD, DWORD, POINTER(XINPUT_CAPABILITIES_EX)]
|
||||
|
||||
# Only available for 1.4+
|
||||
if library_name == "xinput1_4":
|
||||
XInputGetBatteryInformation = lib.XInputGetBatteryInformation
|
||||
XInputGetBatteryInformation.argtypes = [DWORD, BYTE, POINTER(XINPUT_BATTERY_INFORMATION)]
|
||||
XInputGetBatteryInformation.restype = DWORD
|
||||
|
||||
XInputGetState = lib[100]
|
||||
XInputGetState.restype = DWORD
|
||||
XInputGetState.argtypes = [DWORD, POINTER(XINPUT_STATE)]
|
||||
|
||||
# Hidden function
|
||||
XInputGetCapabilities = lib[108]
|
||||
XInputGetCapabilities.restype = DWORD
|
||||
XInputGetCapabilities.argtypes = [DWORD, DWORD, DWORD, POINTER(XINPUT_CAPABILITIES_EX)]
|
||||
|
||||
else:
|
||||
XInputGetBatteryInformation = None
|
||||
|
||||
XInputGetState = lib.XInputGetState
|
||||
XInputGetState.restype = DWORD
|
||||
XInputGetState.argtypes = [DWORD, POINTER(XINPUT_STATE)]
|
||||
|
||||
XInputGetCapabilities = lib.XInputGetCapabilities
|
||||
XInputGetCapabilities.restype = DWORD
|
||||
XInputGetCapabilities.argtypes = [DWORD, DWORD, POINTER(XINPUT_CAPABILITIES)]
|
||||
|
||||
|
||||
XInputSetState = lib.XInputSetState
|
||||
XInputSetState.argtypes = [DWORD, POINTER(XINPUT_VIBRATION)]
|
||||
XInputSetState.restype = DWORD
|
||||
|
||||
|
||||
# wbemcli #################################################
|
||||
|
||||
BSTR = LPCWSTR
|
||||
@ -337,7 +344,7 @@ def get_xinput_guids():
|
||||
if sdl_guid not in guids_found:
|
||||
guids_found.append(sdl_guid)
|
||||
|
||||
oleaut32.VariantClear(var)
|
||||
oleaut32.VariantClear(byref(var))
|
||||
return guids_found
|
||||
|
||||
|
||||
@ -420,7 +427,7 @@ class XInputDeviceManager(EventDispatcher):
|
||||
|
||||
for i in range(XUSER_MAX_COUNT):
|
||||
device = self.all_devices[i]
|
||||
if XInputGetStateEx(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
|
||||
if XInputGetState(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
|
||||
continue
|
||||
device.connected = True
|
||||
self._connected_devices.add(i)
|
||||
@ -436,6 +443,7 @@ class XInputDeviceManager(EventDispatcher):
|
||||
with self._dev_lock:
|
||||
return [dev for dev in self.all_devices if dev.connected]
|
||||
|
||||
# Threaded method:
|
||||
def _get_state(self):
|
||||
xuser_max_count = set(range(XUSER_MAX_COUNT)) # {0, 1, 2, 3}
|
||||
polling_rate = self._polling_rate
|
||||
@ -451,13 +459,14 @@ class XInputDeviceManager(EventDispatcher):
|
||||
# Only check if not currently connected:
|
||||
for i in xuser_max_count - self._connected_devices:
|
||||
device = self.all_devices[i]
|
||||
if XInputGetStateEx(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
|
||||
if XInputGetState(i, byref(device.xinput_state)) == ERROR_DEVICE_NOT_CONNECTED:
|
||||
continue
|
||||
|
||||
# Found a new connection:
|
||||
device.connected = True
|
||||
self._connected_devices.add(i)
|
||||
self.dispatch_event('on_connect', device)
|
||||
# Dispatch event in main thread:
|
||||
pyglet.app.platform_event_loop.post_event(self, 'on_connect', device)
|
||||
|
||||
elapsed = 0.0
|
||||
|
||||
@ -465,14 +474,15 @@ class XInputDeviceManager(EventDispatcher):
|
||||
# opened devices. Skip unopened devices to save CPU:
|
||||
for i in self._connected_devices.copy():
|
||||
device = self.all_devices[i]
|
||||
result = XInputGetStateEx(i, byref(device.xinput_state))
|
||||
result = XInputGetState(i, byref(device.xinput_state))
|
||||
|
||||
if result == ERROR_DEVICE_NOT_CONNECTED:
|
||||
# Newly disconnected device:
|
||||
if device.connected:
|
||||
device.connected = False
|
||||
self._connected_devices.remove(i)
|
||||
self.dispatch_event('on_disconnect', device)
|
||||
# Dispatch event in main thread:
|
||||
pyglet.app.platform_event_loop.post_event(self, 'on_disconnect', device)
|
||||
continue
|
||||
|
||||
elif result == ERROR_SUCCESS and device.is_open:
|
||||
|
@ -1,38 +1,16 @@
|
||||
'''Wrapper for /usr/include/EGL/egl
|
||||
"""Wrapper for /usr/include/EGL/egl
|
||||
|
||||
Generated with:
|
||||
wrap.py -o lib_egl.py /usr/include/EGL/egl.h
|
||||
|
||||
Do not modify this file.
|
||||
'''
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id$'
|
||||
|
||||
import ctypes
|
||||
"""
|
||||
from ctypes import *
|
||||
|
||||
import pyglet.lib
|
||||
|
||||
_lib = pyglet.lib.load_library('EGL')
|
||||
|
||||
_int_types = (c_int16, c_int32)
|
||||
if hasattr(ctypes, 'c_int64'):
|
||||
# Some builds of ctypes apparently do not have c_int64
|
||||
# defined; it's a pretty good bet that these builds do not
|
||||
# have 64-bit pointers.
|
||||
_int_types += (ctypes.c_int64,)
|
||||
for t in _int_types:
|
||||
if sizeof(t) == sizeof(c_size_t):
|
||||
c_ptrdiff_t = t
|
||||
|
||||
class c_void(Structure):
|
||||
# c_void_p is a buggy return type, converting to int, so
|
||||
# POINTER(None) == c_void_p is actually written as
|
||||
# POINTER(c_void), so it can be treated as a real pointer.
|
||||
_fields_ = [('dummy', c_int)]
|
||||
|
||||
|
||||
|
||||
__egl_h_ = 1 # /usr/include/EGL/egl.h:2
|
||||
EGL_EGL_PROTOTYPES = 1 # /usr/include/EGL/egl.h:42
|
||||
@ -117,12 +95,6 @@ PFNEGLGETCONFIGATTRIBPROC = CFUNCTYPE(EGLBoolean, EGLDisplay, EGLConfig, EGLint,
|
||||
PFNEGLGETCONFIGSPROC = CFUNCTYPE(EGLBoolean, EGLDisplay, POINTER(EGLConfig), EGLint, POINTER(EGLint)) # /usr/include/EGL/egl.h:134
|
||||
PFNEGLGETCURRENTDISPLAYPROC = CFUNCTYPE(EGLDisplay) # /usr/include/EGL/egl.h:135
|
||||
PFNEGLGETCURRENTSURFACEPROC = CFUNCTYPE(EGLSurface, EGLint) # /usr/include/EGL/egl.h:136
|
||||
class struct__XDisplay(Structure):
|
||||
__slots__ = [
|
||||
]
|
||||
struct__XDisplay._fields_ = [
|
||||
('_opaque_struct', c_int)
|
||||
]
|
||||
|
||||
class struct__XDisplay(Structure):
|
||||
__slots__ = [
|
||||
@ -502,7 +474,7 @@ eglWaitSync.restype = EGLBoolean
|
||||
eglWaitSync.argtypes = [EGLDisplay, EGLSync, EGLint]
|
||||
|
||||
|
||||
__all__ = ['__egl_h_', 'EGL_EGL_PROTOTYPES', 'EGL_VERSION_1_0', 'EGLBoolean',
|
||||
__all__ = ['__egl_h_', 'EGL_EGL_PROTOTYPES', 'EGL_VERSION_1_0', 'EGLBoolean', 'EGLint',
|
||||
'EGLDisplay', 'EGLConfig', 'EGLSurface', 'EGLContext',
|
||||
'__eglMustCastToProperFunctionPointerType', 'EGL_ALPHA_SIZE',
|
||||
'EGL_BAD_ACCESS', 'EGL_BAD_ALLOC', 'EGL_BAD_ATTRIBUTE', 'EGL_BAD_CONFIG',
|
||||
|
@ -2,9 +2,16 @@ from ctypes import *
|
||||
from pyglet.libs.egl import egl
|
||||
from pyglet.libs.egl.lib import link_EGL as _link_function
|
||||
|
||||
|
||||
EGL_PLATFORM_GBM_MESA = 12759
|
||||
EGL_PLATFORM_DEVICE_EXT = 12607
|
||||
EGLDeviceEXT = POINTER(None)
|
||||
|
||||
eglGetPlatformDisplayEXT = _link_function('eglGetPlatformDisplayEXT', egl.EGLDisplay, [egl.EGLenum, POINTER(None), POINTER(egl.EGLint)], None)
|
||||
eglCreatePlatformWindowSurfaceEXT = _link_function('eglCreatePlatformWindowSurfaceEXT', egl.EGLSurface, [egl.EGLDisplay, egl.EGLConfig, POINTER(None), POINTER(egl.EGLAttrib)], None)
|
||||
eglQueryDevicesEXT = _link_function('eglQueryDevicesEXT', egl.EGLBoolean, [egl.EGLint, POINTER(EGLDeviceEXT), POINTER(egl.EGLint)], None)
|
||||
|
||||
__all__ = ['EGL_PLATFORM_DEVICE_EXT', 'EGLDeviceEXT', 'eglGetPlatformDisplayEXT', 'eglQueryDevicesEXT']
|
||||
|
||||
__all__ = ['EGL_PLATFORM_DEVICE_EXT', 'EGL_PLATFORM_GBM_MESA',
|
||||
'EGLDeviceEXT', 'eglGetPlatformDisplayEXT', 'eglCreatePlatformWindowSurfaceEXT',
|
||||
'eglQueryDevicesEXT']
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
import atexit
|
||||
import struct
|
||||
import warnings
|
||||
|
||||
import pyglet
|
||||
from . import com
|
||||
|
@ -34,17 +34,13 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
import ctypes
|
||||
from ctypes.wintypes import HANDLE, BYTE, HWND, BOOL, UINT, LONG, WORD, DWORD, WCHAR, LPVOID
|
||||
|
||||
lib = ctypes.windll.wintab32
|
||||
|
||||
LONG = ctypes.c_long
|
||||
BOOL = ctypes.c_int
|
||||
UINT = ctypes.c_uint
|
||||
WORD = ctypes.c_uint16
|
||||
DWORD = ctypes.c_uint32
|
||||
WCHAR = ctypes.c_wchar
|
||||
FIX32 = DWORD
|
||||
WTPKT = DWORD
|
||||
HCTX = HANDLE # CONTEXT HANDLE
|
||||
|
||||
LCNAMELEN = 40
|
||||
|
||||
@ -119,6 +115,56 @@ class LOGCONTEXT(ctypes.Structure):
|
||||
)
|
||||
|
||||
|
||||
class TILT(ctypes.Structure): # 1.1
|
||||
_fields_ = (
|
||||
('tiltX', ctypes.c_int),
|
||||
('tiltY', ctypes.c_int),
|
||||
)
|
||||
|
||||
|
||||
class EXTENSIONBASE(ctypes.Structure): # 1.4
|
||||
_fields_ = (
|
||||
('nContext', HCTX), # Specifies the Wintab context to which these properties apply.
|
||||
('nStatus', UINT), # Status of setting/getting properties.
|
||||
('nTime', DWORD), # Timestamp applied to property transaction.
|
||||
('nSerialNumber', UINT), # Reserved - not use
|
||||
)
|
||||
|
||||
|
||||
class EXPKEYSDATA(ctypes.Structure): # 1.4
|
||||
_fields_ = (
|
||||
('nTablet', BYTE), # Tablet index where control is found.
|
||||
('nControl', BYTE), # Zero-based control index.
|
||||
('nLocation', BYTE), # Zero-based index indicating side of tablet where control found (0 = left, 1 = right).
|
||||
('nReserved', BYTE), # Reserved - not used
|
||||
('nState', DWORD) # Indicates Express Key button press (1 = pressed, 0 = released)
|
||||
)
|
||||
|
||||
|
||||
class SLIDERDATA(ctypes.Structure): # 1.4
|
||||
_fields_ = (
|
||||
('nTablet', BYTE), # Tablet index where control is found.
|
||||
('nControl', BYTE), # Zero-based control index.
|
||||
('nMode', BYTE), # Zero-based current active mode of control. Mode selected by control's toggle button.
|
||||
('nReserved', BYTE), # Reserved - not used
|
||||
('nPosition', DWORD) # An integer representing the position of the user's finger on the control.
|
||||
# When there is no finger on the control, this value is negative.
|
||||
)
|
||||
|
||||
|
||||
class EXTPROPERTY(ctypes.Structure): # 1.4
|
||||
_fields_ = (
|
||||
('version', BYTE), # Structure version, 0 for now
|
||||
('tabletIndex', BYTE), # 0-based index for tablet
|
||||
('controlIndex', BYTE), # 0-based index for control
|
||||
('functionIndex', BYTE), # 0-based index for control's sub-function
|
||||
('propertyID', WORD), # property ID
|
||||
('reserved', WORD), # DWORD-alignment filler
|
||||
('dataSize', DWORD), # number of bytes in data[] buffer
|
||||
('data', BYTE * 1), # raw data
|
||||
)
|
||||
|
||||
|
||||
# Custom packet format with fields
|
||||
# PK_CHANGED
|
||||
# PK_CURSOR
|
||||
@ -143,6 +189,15 @@ class PACKET(ctypes.Structure):
|
||||
)
|
||||
|
||||
|
||||
class PACKETEXT(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('pkBase', EXTENSIONBASE), # Extension control properties common to all control types.
|
||||
('pkExpKeys', EXPKEYSDATA), # Extension data for one Express Key.
|
||||
('pkTouchStrip', SLIDERDATA), # Extension data for one Touch Strip.
|
||||
('pkTouchRing', SLIDERDATA) # Extension data for one Touch Ring.
|
||||
)
|
||||
|
||||
|
||||
PK_CONTEXT = 0x0001 # reporting context
|
||||
PK_STATUS = 0x0002 # status bits
|
||||
PK_TIME = 0x0004 # time stamp
|
||||
@ -174,6 +229,7 @@ WT_CTXOVERLAP = 4
|
||||
WT_PROXIMITY = 5
|
||||
WT_INFOCHANGE = 6
|
||||
WT_CSRCHANGE = 7
|
||||
WT_PACKETEXT = 8
|
||||
|
||||
# system button assignment values
|
||||
SBN_NONE = 0x00
|
||||
@ -370,4 +426,47 @@ WTX_FKEYS = 1 # Function keys
|
||||
WTX_TILT = 2 # Raw Cartesian tilt; 1.1
|
||||
WTX_CSRMASK = 3 # select input by cursor type; 1.1
|
||||
WTX_XBTNMASK = 4 # Extended button mask; 1.1
|
||||
WTX_EXPKEYS = 5 # ExpressKeys; 1.3
|
||||
WTX_EXPKEYS = 5 # ExpressKeys; 1.3 - DEPRECATED USE 2
|
||||
WTX_TOUCHSTRIP = 6 # TouchStrips; 1.4
|
||||
WTX_TOUCHRING = 7 # TouchRings; 1.4
|
||||
WTX_EXPKEYS2 = 8 # ExpressKeys; 1.4
|
||||
|
||||
TABLET_PROPERTY_CONTROLCOUNT = 0 # UINT32: number of physical controls on tablet
|
||||
TABLET_PROPERTY_FUNCCOUNT = 1 # UINT32: number of functions of control
|
||||
TABLET_PROPERTY_AVAILABLE = 2 # BOOL: control/mode is available for override
|
||||
TABLET_PROPERTY_MIN = 3 # UINT32: minimum value
|
||||
TABLET_PROPERTY_MAX = 4 # UINT32: maximum value
|
||||
TABLET_PROPERTY_OVERRIDE = 5 # BOOL: control is overridden
|
||||
TABLET_PROPERTY_OVERRIDE_NAME = 6 # UTF-8: Displayable name when control is overridden
|
||||
TABLET_PROPERTY_OVERRIDE_ICON = 7 # Image: Icon to show when control is overridden
|
||||
TABLET_PROPERTY_ICON_WIDTH = 8 # UINT32: Pixel width of icon display
|
||||
TABLET_PROPERTY_ICON_HEIGHT = 9 # UINT32: Pixel height of icon display
|
||||
TABLET_PROPERTY_ICON_FORMAT = 10 # UINT32: UINT32: Pixel format of icon display (see TABLET_ICON_FMT_*)
|
||||
TABLET_PROPERTY_LOCATION = 11 # UINT32: Physical location of control (see TABLET_LOC_*)
|
||||
|
||||
TABLET_LOC_LEFT = 0
|
||||
TABLET_LOC_RIGHT = 1
|
||||
TABLET_LOC_TOP = 2
|
||||
TABLET_LOC_BOTTOM = 3
|
||||
TABLET_LOC_TRANSDUCER = 4
|
||||
|
||||
lib.WTOpenW.restype = HCTX
|
||||
lib.WTOpenW.argtypes = [HWND, ctypes.POINTER(LOGCONTEXT), BOOL]
|
||||
|
||||
lib.WTClose.restype = BOOL
|
||||
lib.WTClose.argtypes = [HCTX]
|
||||
|
||||
lib.WTInfoW.restype = UINT
|
||||
lib.WTInfoW.argtypes = [UINT, UINT, LPVOID]
|
||||
|
||||
lib.WTPacket.restype = BOOL
|
||||
lib.WTPacket.argtypes = [HCTX, UINT, LPVOID]
|
||||
|
||||
lib.WTGetW.restype = BOOL
|
||||
lib.WTGetW.argtypes = [HCTX, BOOL]
|
||||
|
||||
lib.WTExtGet.restype = BOOL
|
||||
lib.WTExtGet.argtypes = [HCTX, UINT, LPVOID]
|
||||
|
||||
lib.WTExtSet.restype = BOOL
|
||||
lib.WTExtSet.argtypes = [HCTX, UINT, LPVOID]
|
||||
|
@ -113,9 +113,15 @@ class Vec2:
|
||||
else:
|
||||
return self.__add__(other)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x or self.y != other.y
|
||||
|
||||
@staticmethod
|
||||
def from_polar(mag, angle):
|
||||
"""Create a new vector from the given polar coodinates.
|
||||
"""Create a new vector from the given polar coordinates.
|
||||
|
||||
:parameters:
|
||||
`mag` : int or float :
|
||||
@ -361,6 +367,12 @@ class Vec3:
|
||||
else:
|
||||
return self.__add__(other)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y and self.z == other.z
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x or self.y != other.y or self.z != other.z
|
||||
|
||||
def from_magnitude(self, magnitude):
|
||||
"""Create a new Vector of the given magnitude by normalizing,
|
||||
then scaling the vector. The rotation remains unchanged.
|
||||
@ -560,6 +572,12 @@ class Vec4:
|
||||
else:
|
||||
return self.__add__(other)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y and self.z == other.z and self.w == other.w
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x or self.y != other.y or self.z != other.z or self.w != other.w
|
||||
|
||||
def lerp(self, other, alpha):
|
||||
return Vec4(self.x + (alpha * (other.x - self.x)),
|
||||
self.y + (alpha * (other.y - self.y)),
|
||||
@ -964,7 +982,7 @@ class Mat4(tuple):
|
||||
c2 = other[2::4]
|
||||
c3 = other[3::4]
|
||||
|
||||
# Multiply and sum rows * colums:
|
||||
# Multiply and sum rows * columns:
|
||||
return Mat4((sum(map(_mul, r0, c0)),
|
||||
sum(map(_mul, r0, c1)),
|
||||
sum(map(_mul, r0, c2)),
|
||||
|
@ -85,7 +85,7 @@ def load_material_library(filename):
|
||||
name = values[1]
|
||||
|
||||
elif name is None:
|
||||
raise ModelDecodeException('Expected "newmtl" in '.format(filename))
|
||||
raise ModelDecodeException(f'Expected "newmtl" in {filename}')
|
||||
|
||||
try:
|
||||
if values[0] == 'Kd':
|
||||
@ -97,7 +97,8 @@ def load_material_library(filename):
|
||||
elif values[0] == 'Ke':
|
||||
emission = list(map(float, values[1:]))
|
||||
elif values[0] == 'Ns':
|
||||
shininess = float(values[1])
|
||||
shininess = float(values[1]) # Blender exports 1~1000
|
||||
shininess = (shininess * 128) / 1000 # Normalize to 1~128 for OpenGL
|
||||
elif values[0] == 'd':
|
||||
opacity = float(values[1])
|
||||
elif values[0] == 'map_Kd':
|
||||
|
@ -381,7 +381,8 @@ class _ShapeBase:
|
||||
|
||||
class Arc(_ShapeBase):
|
||||
def __init__(self, x, y, radius, segments=None, angle=math.tau, start_angle=0,
|
||||
closed=False, color=(255, 255, 255), batch=None, group=None):
|
||||
closed=False, color=(255, 255, 255), opacity=255, batch=None,
|
||||
group=None):
|
||||
"""Create an Arc.
|
||||
|
||||
The Arc's anchor point (x, y) defaults to its center.
|
||||
@ -409,6 +410,9 @@ class Arc(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the circle, specified as a tuple of
|
||||
three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the arc is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the circle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -421,6 +425,7 @@ class Arc(_ShapeBase):
|
||||
self._num_verts = self._segments * 2 + (2 if closed else 0)
|
||||
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
self._angle = angle
|
||||
self._start_angle = start_angle
|
||||
self._closed = closed
|
||||
@ -489,7 +494,8 @@ class Arc(_ShapeBase):
|
||||
|
||||
|
||||
class Circle(_ShapeBase):
|
||||
def __init__(self, x, y, radius, segments=None, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, x, y, radius, segments=None, color=(255, 255, 255), opacity=255,
|
||||
batch=None, group=None):
|
||||
"""Create a circle.
|
||||
|
||||
The circle's anchor point (x, y) defaults to the center of the circle.
|
||||
@ -509,6 +515,9 @@ class Circle(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the circle, specified as a tuple of
|
||||
three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the circle is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the circle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -519,6 +528,7 @@ class Circle(_ShapeBase):
|
||||
self._radius = radius
|
||||
self._segments = segments or max(14, int(radius / 1.25))
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
@ -567,7 +577,8 @@ class Circle(_ShapeBase):
|
||||
|
||||
|
||||
class Ellipse(_ShapeBase):
|
||||
def __init__(self, x, y, a, b, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, x, y, a, b, color=(255, 255, 255), opacity=255,
|
||||
batch=None, group=None):
|
||||
"""Create an ellipse.
|
||||
|
||||
The ellipse's anchor point (x, y) defaults to the center of the ellipse.
|
||||
@ -584,6 +595,9 @@ class Ellipse(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the ellipse. specify as a tuple of
|
||||
three ints in the range of 0~255.
|
||||
`opacity` : int
|
||||
How opaque the ellipse is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the circle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -594,6 +608,7 @@ class Ellipse(_ShapeBase):
|
||||
self._a = a
|
||||
self._b = b
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
self._rotation = 0
|
||||
self._segments = int(max(a, b) / 1.25)
|
||||
self._num_verts = self._segments * 2
|
||||
@ -685,7 +700,7 @@ class Ellipse(_ShapeBase):
|
||||
|
||||
class Sector(_ShapeBase):
|
||||
def __init__(self, x, y, radius, segments=None, angle=math.tau, start_angle=0,
|
||||
color=(255, 255, 255), batch=None, group=None):
|
||||
color=(255, 255, 255), opacity=255, batch=None, group=None):
|
||||
"""Create a Sector of a circle.
|
||||
|
||||
The sector's anchor point (x, y) defaults to the center of the circle.
|
||||
@ -710,6 +725,9 @@ class Sector(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the sector, specified as a tuple of
|
||||
three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the sector is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the sector to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -721,6 +739,7 @@ class Sector(_ShapeBase):
|
||||
self._segments = segments or max(14, int(radius / 1.25))
|
||||
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
self._angle = angle
|
||||
self._start_angle = start_angle
|
||||
self._rotation = 0
|
||||
@ -815,7 +834,8 @@ class Sector(_ShapeBase):
|
||||
|
||||
|
||||
class Line(_ShapeBase):
|
||||
def __init__(self, x, y, x2, y2, width=1, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, x, y, x2, y2, width=1, color=(255, 255, 255), opacity=255,
|
||||
batch=None, group=None):
|
||||
"""Create a line.
|
||||
|
||||
The line's anchor point defaults to the center of the line's
|
||||
@ -835,6 +855,9 @@ class Line(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the line, specified as a tuple of
|
||||
three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the line is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the line to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -848,6 +871,7 @@ class Line(_ShapeBase):
|
||||
self._width = width
|
||||
self._rotation = math.degrees(math.atan2(y2 - y, x2 - x))
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
@ -933,7 +957,8 @@ class Line(_ShapeBase):
|
||||
|
||||
|
||||
class Rectangle(_ShapeBase):
|
||||
def __init__(self, x, y, width, height, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, x, y, width, height, color=(255, 255, 255), opacity=255,
|
||||
batch=None, group=None):
|
||||
"""Create a rectangle or square.
|
||||
|
||||
The rectangle's anchor point defaults to the (x, y) coordinates,
|
||||
@ -951,6 +976,9 @@ class Rectangle(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the rectangle, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the rectangle is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the rectangle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -962,6 +990,7 @@ class Rectangle(_ShapeBase):
|
||||
self._height = height
|
||||
self._rotation = 0
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
@ -1037,7 +1066,7 @@ class Rectangle(_ShapeBase):
|
||||
|
||||
class BorderedRectangle(_ShapeBase):
|
||||
def __init__(self, x, y, width, height, border=1, color=(255, 255, 255),
|
||||
border_color=(100, 100, 100), batch=None, group=None):
|
||||
border_color=(100, 100, 100), opacity=255, batch=None, group=None):
|
||||
"""Create a rectangle or square.
|
||||
|
||||
The rectangle's anchor point defaults to the (x, y) coordinates,
|
||||
@ -1060,6 +1089,10 @@ class BorderedRectangle(_ShapeBase):
|
||||
`border_color` : (int, int, int)
|
||||
The RGB color of the rectangle's border, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the rectangle is. The default of 255 is fully
|
||||
visible. 0 is transparent. This affects the entire shape,
|
||||
not only the fill color.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the rectangle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -1073,6 +1106,7 @@ class BorderedRectangle(_ShapeBase):
|
||||
self._border = border
|
||||
self._rgb = color
|
||||
self._brgb = border_color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
@ -1176,7 +1210,8 @@ class BorderedRectangle(_ShapeBase):
|
||||
|
||||
|
||||
class Triangle(_ShapeBase):
|
||||
def __init__(self, x, y, x2, y2, x3, y3, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, x, y, x2, y2, x3, y3, color=(255, 255, 255), opacity=255,
|
||||
batch=None, group=None):
|
||||
"""Create a triangle.
|
||||
|
||||
The triangle's anchor point defaults to the first vertex point.
|
||||
@ -1197,6 +1232,9 @@ class Triangle(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the triangle, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the triangle is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the triangle to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -1210,6 +1248,7 @@ class Triangle(_ShapeBase):
|
||||
self._y3 = y3
|
||||
self._rotation = 0
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
@ -1316,7 +1355,7 @@ class Triangle(_ShapeBase):
|
||||
|
||||
class Star(_ShapeBase):
|
||||
def __init__(self, x, y, outer_radius, inner_radius, num_spikes, rotation=0,
|
||||
color=(255, 255, 255), batch=None, group=None) -> None:
|
||||
color=(255, 255, 255), opacity=255, batch=None, group=None) -> None:
|
||||
"""Create a star.
|
||||
|
||||
The star's anchor point (x, y) defaults to the center of the star.
|
||||
@ -1339,6 +1378,9 @@ class Star(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the star, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the star is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the star to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -1350,6 +1392,7 @@ class Star(_ShapeBase):
|
||||
self._inner_radius = inner_radius
|
||||
self._num_spikes = num_spikes
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
self._rotation = rotation
|
||||
|
||||
program = get_default_shader()
|
||||
@ -1437,7 +1480,7 @@ class Star(_ShapeBase):
|
||||
|
||||
|
||||
class Polygon(_ShapeBase):
|
||||
def __init__(self, *coordinates, color=(255, 255, 255), batch=None, group=None):
|
||||
def __init__(self, *coordinates, color=(255, 255, 255), opacity=255, batch=None, group=None):
|
||||
"""Create a convex polygon.
|
||||
|
||||
The polygon's anchor point defaults to the first vertex point.
|
||||
@ -1448,6 +1491,9 @@ class Polygon(_ShapeBase):
|
||||
`color` : (int, int, int)
|
||||
The RGB color of the polygon, specified as
|
||||
a tuple of three ints in the range of 0-255.
|
||||
`opacity` : int
|
||||
How opaque the polygon is. The default of 255 is fully
|
||||
visible. 0 is transparent.
|
||||
`batch` : `~pyglet.graphics.Batch`
|
||||
Optional batch to add the polygon to.
|
||||
`group` : `~pyglet.graphics.Group`
|
||||
@ -1460,6 +1506,7 @@ class Polygon(_ShapeBase):
|
||||
self._rotation = 0
|
||||
|
||||
self._rgb = color
|
||||
self._opacity = opacity
|
||||
|
||||
program = get_default_shader()
|
||||
self._batch = batch or Batch()
|
||||
|
@ -73,9 +73,11 @@ creating scrollable layouts.
|
||||
.. versionadded:: 1.1
|
||||
"""
|
||||
|
||||
import os.path
|
||||
from os.path import dirname as _dirname
|
||||
from os.path import splitext as _splitext
|
||||
|
||||
import pyglet
|
||||
|
||||
from pyglet.text import layout, document, caret
|
||||
|
||||
|
||||
@ -130,7 +132,7 @@ def get_decoder(filename, mimetype=None):
|
||||
:rtype: `DocumentDecoder`
|
||||
"""
|
||||
if mimetype is None:
|
||||
_, ext = os.path.splitext(filename)
|
||||
_, ext = _splitext(filename)
|
||||
if ext.lower() in ('.htm', '.html', '.xhtml'):
|
||||
mimetype = 'text/html'
|
||||
else:
|
||||
@ -176,7 +178,7 @@ def load(filename, file=None, mimetype=None):
|
||||
if hasattr(file_contents, "decode"):
|
||||
file_contents = file_contents.decode()
|
||||
|
||||
location = pyglet.resource.FileLocation(os.path.dirname(filename))
|
||||
location = pyglet.resource.FileLocation(_dirname(filename))
|
||||
return decoder.decode(file_contents, location)
|
||||
|
||||
|
||||
@ -265,11 +267,7 @@ class DocumentLabel(layout.TextLayout):
|
||||
Optional graphics group to use.
|
||||
|
||||
"""
|
||||
super(DocumentLabel, self).__init__(document,
|
||||
width=width, height=height,
|
||||
multiline=multiline,
|
||||
dpi=dpi, batch=batch, group=group)
|
||||
|
||||
super().__init__(document, width, height, multiline, dpi, batch, group)
|
||||
self._x = x
|
||||
self._y = y
|
||||
self._anchor_x = anchor_x
|
||||
@ -347,8 +345,7 @@ class DocumentLabel(layout.TextLayout):
|
||||
|
||||
@font_size.setter
|
||||
def font_size(self, font_size):
|
||||
self.document.set_style(0, len(self.document.text),
|
||||
{'font_size': font_size})
|
||||
self.document.set_style(0, len(self.document.text), {'font_size': font_size})
|
||||
|
||||
@property
|
||||
def bold(self):
|
||||
@ -360,8 +357,7 @@ class DocumentLabel(layout.TextLayout):
|
||||
|
||||
@bold.setter
|
||||
def bold(self, bold):
|
||||
self.document.set_style(0, len(self.document.text),
|
||||
{'bold': bold})
|
||||
self.document.set_style(0, len(self.document.text), {'bold': bold})
|
||||
|
||||
@property
|
||||
def italic(self):
|
||||
@ -373,8 +369,7 @@ class DocumentLabel(layout.TextLayout):
|
||||
|
||||
@italic.setter
|
||||
def italic(self, italic):
|
||||
self.document.set_style(0, len(self.document.text),
|
||||
{'italic': italic})
|
||||
self.document.set_style(0, len(self.document.text), {'italic': italic})
|
||||
|
||||
def get_style(self, name):
|
||||
"""Get a document style value by name.
|
||||
@ -404,6 +399,9 @@ class DocumentLabel(layout.TextLayout):
|
||||
"""
|
||||
self.document.set_style(0, len(self.document.text), {name: value})
|
||||
|
||||
def __del__(self):
|
||||
self.delete()
|
||||
|
||||
|
||||
class Label(DocumentLabel):
|
||||
"""Plain text label.
|
||||
@ -463,10 +461,8 @@ class Label(DocumentLabel):
|
||||
Optional graphics group to use.
|
||||
|
||||
"""
|
||||
document = decode_text(text)
|
||||
super(Label, self).__init__(document, x, y, width, height,
|
||||
anchor_x, anchor_y,
|
||||
multiline, dpi, batch, group)
|
||||
doc = decode_text(text)
|
||||
super().__init__(doc, x, y, width, height, anchor_x, anchor_y, multiline, dpi, batch, group)
|
||||
|
||||
self.document.set_style(0, len(self.document.text), {
|
||||
'font_name': font_name,
|
||||
@ -525,10 +521,8 @@ class HTMLLabel(DocumentLabel):
|
||||
"""
|
||||
self._text = text
|
||||
self._location = location
|
||||
document = decode_html(text, location)
|
||||
super(HTMLLabel, self).__init__(document, x, y, width, height,
|
||||
anchor_x, anchor_y,
|
||||
multiline, dpi, batch, group)
|
||||
doc = decode_html(text, location)
|
||||
super().__init__(doc, x, y, width, height, anchor_x, anchor_y, multiline, dpi, batch, group)
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
@ -542,4 +536,3 @@ class HTMLLabel(DocumentLabel):
|
||||
def text(self, text):
|
||||
self._text = text
|
||||
self.document = decode_html(text, self._location)
|
||||
|
||||
|
@ -1851,7 +1851,7 @@ class FPSDisplay:
|
||||
#: :type: float
|
||||
update_period = 0.25
|
||||
|
||||
def __init__(self, window, color=(127, 127, 127, 127), samples=60):
|
||||
def __init__(self, window, color=(127, 127, 127, 127), samples=240):
|
||||
from time import time
|
||||
from statistics import mean
|
||||
from collections import deque
|
||||
@ -1879,19 +1879,7 @@ class FPSDisplay:
|
||||
|
||||
if self._elapsed >= self.update_period:
|
||||
self._elapsed = 0
|
||||
self._set_fps_text(1 / self._mean(self._delta_times))
|
||||
|
||||
def _set_fps_text(self, fps):
|
||||
"""Set the label text for the given FPS estimation.
|
||||
|
||||
Called by `update` every `update_period` seconds.
|
||||
|
||||
:Parameters:
|
||||
`fps` : float
|
||||
Estimated framerate of the window.
|
||||
|
||||
"""
|
||||
self.label.text = '%.2f' % fps
|
||||
self.label.text = f"{1 / self._mean(self._delta_times):.2f}"
|
||||
|
||||
def draw(self):
|
||||
"""Draw the label."""
|
||||
|
@ -269,18 +269,14 @@ class Win32Window(BaseWindow):
|
||||
GWL_EXSTYLE,
|
||||
self._ex_ws_style)
|
||||
|
||||
if self._fullscreen:
|
||||
hwnd_after = HWND_TOPMOST
|
||||
else:
|
||||
hwnd_after = HWND_NOTOPMOST
|
||||
|
||||
# Position and size window
|
||||
if self._fullscreen:
|
||||
hwnd_after = HWND_TOPMOST if self.style == "overlay" else HWND_NOTOPMOST
|
||||
_user32.SetWindowPos(self._hwnd, hwnd_after,
|
||||
self._screen.x, self._screen.y, width, height, SWP_FRAMECHANGED)
|
||||
elif False: # TODO location not in pyglet API
|
||||
x, y = self._client_to_window_pos(*factory.get_location())
|
||||
_user32.SetWindowPos(self._hwnd, hwnd_after,
|
||||
_user32.SetWindowPos(self._hwnd, HWND_NOTOPMOST,
|
||||
x, y, width, height, SWP_FRAMECHANGED)
|
||||
elif self.style == 'transparent' or self.style == "overlay":
|
||||
_user32.SetLayeredWindowAttributes(self._hwnd, 0, 254, LWA_ALPHA)
|
||||
@ -288,7 +284,7 @@ class Win32Window(BaseWindow):
|
||||
_user32.SetWindowPos(self._hwnd, HWND_TOPMOST, 0,
|
||||
0, width, height, SWP_NOMOVE | SWP_NOSIZE)
|
||||
else:
|
||||
_user32.SetWindowPos(self._hwnd, hwnd_after,
|
||||
_user32.SetWindowPos(self._hwnd, HWND_NOTOPMOST,
|
||||
0, 0, width, height, SWP_NOMOVE | SWP_FRAMECHANGED)
|
||||
|
||||
self._update_view_location(self._width, self._height)
|
||||
@ -429,7 +425,7 @@ class Win32Window(BaseWindow):
|
||||
|
||||
def set_visible(self, visible=True):
|
||||
if visible:
|
||||
insertAfter = HWND_TOPMOST if self._fullscreen else HWND_TOP
|
||||
insertAfter = HWND_TOP
|
||||
_user32.SetWindowPos(self._hwnd, insertAfter, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)
|
||||
self.dispatch_event('on_resize', self._width, self._height)
|
||||
|
Loading…
Reference in New Issue
Block a user