update pyglet
This commit is contained in:
parent
c79a0dbbb4
commit
76d591f2d9
@ -44,11 +44,14 @@ import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
#: The release version
|
||||
version = '2.0.dev20'
|
||||
version = '2.0.dev22'
|
||||
__version__ = version
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
raise Exception('pyglet %s requires Python 3.6 or newer.' % version)
|
||||
MIN_PYTHON_VERSION = 3, 7
|
||||
MIN_PYTHON_VERSION_STR = '.'.join([str(v) for v in MIN_PYTHON_VERSION])
|
||||
|
||||
if sys.version_info < MIN_PYTHON_VERSION:
|
||||
raise Exception(f"pyglet {version} requires Python {MIN_PYTHON_VERSION_STR} or newer.")
|
||||
|
||||
if 'sphinx' in sys.modules:
|
||||
setattr(sys, 'is_pyglet_doc_run', True)
|
||||
|
@ -65,11 +65,13 @@ class Win32Screen(Screen):
|
||||
self._handle = handle
|
||||
|
||||
def get_matching_configs(self, template):
|
||||
canvas = Win32Canvas(self.display, 0, _user32.GetDC(0))
|
||||
hdc = _user32.GetDC(0)
|
||||
canvas = Win32Canvas(self.display, 0, hdc)
|
||||
configs = template.match(canvas)
|
||||
# XXX deprecate config's being screen-specific
|
||||
for config in configs:
|
||||
config.screen = self
|
||||
_user32.ReleaseDC(0, hdc)
|
||||
return configs
|
||||
|
||||
def get_device_name(self):
|
||||
|
@ -35,6 +35,7 @@ except OSError as err:
|
||||
|
||||
_debug_font = debug_print('debug_font')
|
||||
|
||||
|
||||
def DWRITE_MAKE_OPENTYPE_TAG(a, b, c, d):
|
||||
return ord(d) << 24 | ord(c) << 16 | ord(b) << 8 | ord(a)
|
||||
|
||||
@ -171,8 +172,6 @@ class D2D1_COLOR_F(Structure):
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
class DWRITE_TEXT_METRICS(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('left', FLOAT),
|
||||
@ -316,6 +315,7 @@ class DWRITE_GLYPH_RUN(ctypes.Structure):
|
||||
('bidiLevel', UINT32),
|
||||
)
|
||||
|
||||
|
||||
DWRITE_SCRIPT_SHAPES = UINT
|
||||
DWRITE_SCRIPT_SHAPES_DEFAULT = 0
|
||||
|
||||
@ -1061,6 +1061,21 @@ class LegacyCollectionLoader(com.COMObject):
|
||||
IID_IDWriteFactory = com.GUID(0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48)
|
||||
|
||||
|
||||
class IDWriteRenderingParams(com.pIUnknown):
|
||||
_methods_ = [
|
||||
('GetGamma',
|
||||
com.METHOD(FLOAT)),
|
||||
('GetEnhancedContrast',
|
||||
com.METHOD(FLOAT)),
|
||||
('GetClearTypeLevel',
|
||||
com.METHOD(FLOAT)),
|
||||
('GetPixelGeometry',
|
||||
com.METHOD(UINT)),
|
||||
('GetRenderingMode',
|
||||
com.METHOD(UINT)),
|
||||
]
|
||||
|
||||
|
||||
class IDWriteFactory(com.pIUnknown):
|
||||
_methods_ = [
|
||||
('GetSystemFontCollection',
|
||||
@ -1078,11 +1093,11 @@ class IDWriteFactory(com.pIUnknown):
|
||||
('CreateFontFace',
|
||||
com.STDMETHOD()),
|
||||
('CreateRenderingParams',
|
||||
com.STDMETHOD()),
|
||||
com.STDMETHOD(POINTER(IDWriteRenderingParams))),
|
||||
('CreateMonitorRenderingParams',
|
||||
com.STDMETHOD()),
|
||||
('CreateCustomRenderingParams',
|
||||
com.STDMETHOD()),
|
||||
com.STDMETHOD(FLOAT, FLOAT, FLOAT, UINT, UINT, POINTER(IDWriteRenderingParams))),
|
||||
('RegisterFontFileLoader',
|
||||
com.STDMETHOD(c_void_p)), # Ambigious as newer is a pIUnknown and legacy is IUnknown.
|
||||
('UnregisterFontFileLoader',
|
||||
@ -1116,7 +1131,7 @@ class IDWriteFactory1(IDWriteFactory, com.pIUnknown):
|
||||
_methods_ = [
|
||||
('GetEudcFontCollection',
|
||||
com.STDMETHOD()),
|
||||
('CreateCustomRenderingParams',
|
||||
('CreateCustomRenderingParams1',
|
||||
com.STDMETHOD()),
|
||||
]
|
||||
|
||||
@ -1139,7 +1154,7 @@ class IDWriteFactory2(IDWriteFactory1, com.pIUnknown):
|
||||
com.STDMETHOD()),
|
||||
('TranslateColorGlyphRun',
|
||||
com.STDMETHOD()),
|
||||
('CreateCustomRenderingParams',
|
||||
('CreateCustomRenderingParams2',
|
||||
com.STDMETHOD()),
|
||||
('CreateGlyphRunAnalysis',
|
||||
com.STDMETHOD()),
|
||||
@ -1191,7 +1206,7 @@ class IDWriteFactory3(IDWriteFactory2, com.pIUnknown):
|
||||
_methods_ = [
|
||||
('CreateGlyphRunAnalysis',
|
||||
com.STDMETHOD()),
|
||||
('CreateCustomRenderingParams',
|
||||
('CreateCustomRenderingParams3',
|
||||
com.STDMETHOD()),
|
||||
('CreateFontFaceReference',
|
||||
com.STDMETHOD()),
|
||||
@ -1207,7 +1222,7 @@ class IDWriteFactory3(IDWriteFactory2, com.pIUnknown):
|
||||
com.STDMETHOD()),
|
||||
('GetFontDownloadQueue',
|
||||
com.STDMETHOD()),
|
||||
#('GetSystemFontSet',
|
||||
# ('GetSystemFontSet',
|
||||
# com.STDMETHOD()),
|
||||
]
|
||||
|
||||
@ -1220,10 +1235,12 @@ class IDWriteColorGlyphRunEnumerator1(com.pIUnknown):
|
||||
com.STDMETHOD()),
|
||||
]
|
||||
|
||||
|
||||
class IDWriteFactory4(IDWriteFactory3, com.pIUnknown):
|
||||
_methods_ = [
|
||||
('TranslateColorGlyphRun4', # Renamed to prevent clash from previous factories.
|
||||
com.STDMETHOD(D2D_POINT_2F, DWRITE_GLYPH_RUN, c_void_p, DWRITE_GLYPH_IMAGE_FORMATS, DWRITE_MEASURING_MODE, c_void_p, UINT32, POINTER(IDWriteColorGlyphRunEnumerator1))),
|
||||
com.STDMETHOD(D2D_POINT_2F, DWRITE_GLYPH_RUN, c_void_p, DWRITE_GLYPH_IMAGE_FORMATS, DWRITE_MEASURING_MODE,
|
||||
c_void_p, UINT32, POINTER(IDWriteColorGlyphRunEnumerator1))),
|
||||
('ComputeGlyphOrigins_',
|
||||
com.STDMETHOD()),
|
||||
('ComputeGlyphOrigins',
|
||||
@ -1259,7 +1276,6 @@ class IDWriteFactory5(IDWriteFactory4, IDWriteFactory3, IDWriteFactory2, IDWrite
|
||||
]
|
||||
|
||||
|
||||
|
||||
DWriteCreateFactory = dwrite_lib.DWriteCreateFactory
|
||||
DWriteCreateFactory.restype = HRESULT
|
||||
DWriteCreateFactory.argtypes = [DWRITE_FACTORY_TYPE, com.REFIID, POINTER(com.pIUnknown)]
|
||||
@ -1424,7 +1440,7 @@ class ID2D1RenderTarget(ID2D1Resource, com.pIUnknown):
|
||||
('GetTransform',
|
||||
com.STDMETHOD()),
|
||||
('SetAntialiasMode',
|
||||
com.STDMETHOD()),
|
||||
com.METHOD(c_void, D2D1_TEXT_ANTIALIAS_MODE)),
|
||||
('GetAntialiasMode',
|
||||
com.STDMETHOD()),
|
||||
('SetTextAntialiasMode',
|
||||
@ -1432,7 +1448,7 @@ class ID2D1RenderTarget(ID2D1Resource, com.pIUnknown):
|
||||
('GetTextAntialiasMode',
|
||||
com.STDMETHOD()),
|
||||
('SetTextRenderingParams',
|
||||
com.STDMETHOD()),
|
||||
com.STDMETHOD(IDWriteRenderingParams)),
|
||||
('GetTextRenderingParams',
|
||||
com.STDMETHOD()),
|
||||
('SetTags',
|
||||
@ -1444,7 +1460,7 @@ class ID2D1RenderTarget(ID2D1Resource, com.pIUnknown):
|
||||
('PopLayer',
|
||||
com.STDMETHOD()),
|
||||
('Flush',
|
||||
com.STDMETHOD()),
|
||||
com.STDMETHOD(c_void_p, c_void_p)),
|
||||
('SaveDrawingState',
|
||||
com.STDMETHOD()),
|
||||
('RestoreDrawingState',
|
||||
@ -1535,6 +1551,7 @@ if not wic_decoder:
|
||||
class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
antialias_mode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT
|
||||
draw_options = D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT
|
||||
measuring_mode = DWRITE_MEASURING_MODE_NATURAL
|
||||
|
||||
def __init__(self, font):
|
||||
self._render_target = None
|
||||
@ -1679,7 +1696,6 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
font_face.GetDesignGlyphMetrics(indices, count, glyph_metrics, False)
|
||||
|
||||
metrics_out = []
|
||||
i = 0
|
||||
for metric in glyph_metrics:
|
||||
glyph_width = (metric.advanceWidth - metric.leftSideBearing - metric.rightSideBearing)
|
||||
|
||||
@ -1696,7 +1712,6 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
advance_width = metric.advanceWidth
|
||||
|
||||
metrics_out.append((glyph_width, glyph_height, lsb, advance_width, bsb))
|
||||
i += 1
|
||||
|
||||
return metrics_out
|
||||
|
||||
@ -1721,7 +1736,7 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
run,
|
||||
None,
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_ALL,
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
self.measuring_mode,
|
||||
None,
|
||||
0,
|
||||
enumerator)
|
||||
@ -1735,7 +1750,7 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
|
||||
def render_single_glyph(self, font_face, indice, advance, offset, metrics):
|
||||
"""Renders a single glyph using D2D DrawGlyphRun"""
|
||||
glyph_width, glyph_height, lsb, font_advance, bsb = metrics # We use a shaped advance instead of the fonts.
|
||||
glyph_width, glyph_height, glyph_lsb, glyph_advance, glyph_bsb = metrics # We use a shaped advance instead of the fonts.
|
||||
|
||||
# Slicing an array turns it into a python object. Maybe a better way to keep it a ctypes value?
|
||||
new_indice = (UINT16 * 1)(indice)
|
||||
@ -1748,19 +1763,24 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
new_advance, # advance,
|
||||
pointer(offset), # offset,
|
||||
False,
|
||||
False
|
||||
0
|
||||
)
|
||||
|
||||
# If it's colored, return to render it using layout.
|
||||
if self.draw_options & D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT and self.is_color_run(run):
|
||||
return None
|
||||
|
||||
render_width = int(math.ceil((glyph_width) * self.font.font_scale_ratio))
|
||||
render_offset_x = int(math.floor(abs(lsb * self.font.font_scale_ratio)))
|
||||
if lsb < 0:
|
||||
# Negative LSB: we shift the layout rect to the right
|
||||
# Otherwise we will cut the left part of the glyph
|
||||
render_offset_x = -(render_offset_x)
|
||||
# Use the glyph's advance as a width as bitmap width.
|
||||
# Some characters such as diacritics (̃) may have 0 advance width. In that case, just use glyph_width
|
||||
if glyph_advance:
|
||||
render_width = int(math.ceil(glyph_advance * self.font.font_scale_ratio))
|
||||
else:
|
||||
render_width = int(math.ceil(glyph_width * self.font.font_scale_ratio))
|
||||
|
||||
render_offset_x = 0
|
||||
if glyph_lsb < 0:
|
||||
# Negative LSB: we shift the offset, otherwise the glyph will be cut off.
|
||||
render_offset_x = glyph_lsb * self.font.font_scale_ratio
|
||||
|
||||
# Create new bitmap.
|
||||
# TODO: We can probably adjust bitmap/baseline to reduce the whitespace and save a lot of texture space.
|
||||
@ -1769,11 +1789,9 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
int(math.ceil(self.font.max_glyph_height)))
|
||||
|
||||
# Glyphs are drawn at the baseline, and with LSB, so we need to offset it based on top left position.
|
||||
# Offsets are actually based on pixels somehow???
|
||||
baseline_offset = D2D_POINT_2F(-render_offset_x - offset.advanceOffset,
|
||||
self.font.ascent + offset.ascenderOffset)
|
||||
|
||||
|
||||
self._render_target.BeginDraw()
|
||||
|
||||
self._render_target.Clear(transparent)
|
||||
@ -1781,17 +1799,17 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
self._render_target.DrawGlyphRun(baseline_offset,
|
||||
run,
|
||||
self._brush,
|
||||
DWRITE_MEASURING_MODE_NATURAL)
|
||||
self.measuring_mode)
|
||||
|
||||
self._render_target.EndDraw(None, None)
|
||||
image = wic_decoder.get_image(self._bitmap)
|
||||
|
||||
glyph = self.font.create_glyph(image)
|
||||
|
||||
glyph.set_bearings(self.font.descent, render_offset_x,
|
||||
advance * self.font.font_scale_ratio,
|
||||
offset.advanceOffset * self.font.font_scale_ratio,
|
||||
offset.ascenderOffset * self.font.font_scale_ratio)
|
||||
glyph.set_bearings(-self.font.descent, render_offset_x,
|
||||
advance,
|
||||
offset.advanceOffset,
|
||||
offset.ascenderOffset)
|
||||
|
||||
return glyph
|
||||
|
||||
@ -1829,7 +1847,17 @@ class DirectWriteGlyphRenderer(base.GlyphRenderer):
|
||||
image = wic_decoder.get_image(self._bitmap)
|
||||
|
||||
glyph = self.font.create_glyph(image)
|
||||
glyph.set_bearings(self.font.descent, 0, int(math.ceil(layout_metrics.width)))
|
||||
glyph.set_bearings(-self.font.descent, 0, int(math.ceil(layout_metrics.width)))
|
||||
return glyph
|
||||
|
||||
def create_zero_glyph(self):
|
||||
"""Zero glyph is a 1x1 image that has a -1 advance. This is to fill in for ligature substitutions since
|
||||
font system requires 1 glyph per character in a string."""
|
||||
self._create_bitmap(1, 1)
|
||||
image = wic_decoder.get_image(self._bitmap)
|
||||
|
||||
glyph = self.font.create_glyph(image)
|
||||
glyph.set_bearings(-self.font.descent, 0, -1)
|
||||
return glyph
|
||||
|
||||
def _create_bitmap(self, width, height):
|
||||
@ -1878,6 +1906,7 @@ class Win32DirectWriteFont(base.Font):
|
||||
|
||||
_glyph_renderer = None
|
||||
_empty_glyph = None
|
||||
_zero_glyph = None
|
||||
|
||||
glyph_renderer_class = DirectWriteGlyphRenderer
|
||||
texture_internalformat = pyglet.gl.GL_RGBA
|
||||
@ -1973,10 +2002,10 @@ class Win32DirectWriteFont(base.Font):
|
||||
|
||||
self.font_scale_ratio = (self._real_size / self._font_metrics.designUnitsPerEm)
|
||||
|
||||
self.ascent = self._font_metrics.ascent * self.font_scale_ratio
|
||||
self.descent = self._font_metrics.descent * self.font_scale_ratio
|
||||
|
||||
self.ascent = math.ceil(self._font_metrics.ascent * self.font_scale_ratio)
|
||||
self.descent = -round(self._font_metrics.descent * self.font_scale_ratio)
|
||||
self.max_glyph_height = (self._font_metrics.ascent + self._font_metrics.descent) * self.font_scale_ratio
|
||||
|
||||
self.line_gap = self._font_metrics.lineGap * self.font_scale_ratio
|
||||
|
||||
self._fallback = None
|
||||
@ -1986,7 +2015,6 @@ class Win32DirectWriteFont(base.Font):
|
||||
else:
|
||||
assert _debug_font("Windows 8.1+ is required for font fallback. Colored glyphs cannot be omitted.")
|
||||
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
@ -2015,21 +2043,19 @@ class Win32DirectWriteFont(base.Font):
|
||||
new_glyph.set_bearings(
|
||||
glyph.baseline,
|
||||
glyph.lsb,
|
||||
advance * self.font_scale_ratio,
|
||||
offset.advanceOffset * self.font_scale_ratio,
|
||||
offset.ascenderOffset * self.font_scale_ratio
|
||||
advance,
|
||||
offset.advanceOffset,
|
||||
offset.ascenderOffset
|
||||
)
|
||||
return new_glyph
|
||||
|
||||
def _render_layout_glyph(self, text_buffer, i, clusters, check_color=True):
|
||||
formatted_clusters = clusters[:]
|
||||
|
||||
# Some glyphs can be more than 1 char. We use the clusters to determine how many of an index exist.
|
||||
text_length = formatted_clusters.count(i)
|
||||
text_length = clusters.count(i)
|
||||
|
||||
# Amount of glyphs don't always match 1:1 with text as some can be substituted or omitted. Get
|
||||
# actual text buffer index.
|
||||
text_index = formatted_clusters.index(i)
|
||||
text_index = clusters.index(i)
|
||||
|
||||
# Get actual text based on the index and length.
|
||||
actual_text = text_buffer[text_index:text_index + text_length]
|
||||
@ -2125,25 +2151,48 @@ class Win32DirectWriteFont(base.Font):
|
||||
if not self._glyph_renderer:
|
||||
self._glyph_renderer = self.glyph_renderer_class(self)
|
||||
self._empty_glyph = self._glyph_renderer.render_using_layout(" ")
|
||||
self._zero_glyph = self._glyph_renderer.create_zero_glyph()
|
||||
|
||||
text_buffer, actual_count, indices, advances, offsets, clusters = self._glyph_renderer.get_string_info(text, self.font_face)
|
||||
text_buffer, actual_count, indices, advances, offsets, clusters = self._glyph_renderer.get_string_info(text,
|
||||
self.font_face)
|
||||
|
||||
metrics = self._glyph_renderer.get_glyph_metrics(self.font_face, indices, actual_count)
|
||||
|
||||
formatted_clusters = list(clusters)
|
||||
|
||||
# Convert to real sizes.
|
||||
for i in range(actual_count):
|
||||
advances[i] *= self.font_scale_ratio
|
||||
|
||||
for i in range(actual_count):
|
||||
offsets[i].advanceOffset *= self.font_scale_ratio
|
||||
offsets[i].ascenderOffset *= self.font_scale_ratio
|
||||
|
||||
glyphs = []
|
||||
|
||||
# Pyglet expects 1 glyph for every string. However, ligatures can combine 1 or more glyphs, leading
|
||||
# to issues with multilines producing wrong output.
|
||||
substitutions = {}
|
||||
for idx in clusters:
|
||||
ct = formatted_clusters.count(idx)
|
||||
if ct > 1:
|
||||
substitutions[idx] = ct-1
|
||||
|
||||
for i in range(actual_count):
|
||||
indice = indices[i]
|
||||
|
||||
if indice == 0:
|
||||
# If an indice is 0, it will return no glyph. In this case we attempt to render leveraging
|
||||
# the built in text layout from MS. Which depending on version can use fallback fonts and other tricks
|
||||
# to possibly get something of use.
|
||||
glyph = self._render_layout_glyph(text_buffer, i, clusters)
|
||||
glyph = self._render_layout_glyph(text_buffer, i, formatted_clusters)
|
||||
glyphs.append(glyph)
|
||||
else:
|
||||
advance_key = (indice, advances[i], offsets[i].advanceOffset, offsets[i].ascenderOffset)
|
||||
|
||||
# Glyphs can vary depending on shaping. We will cache it by indice, advance, and offset.
|
||||
# Possible to just cache without offset and set them each time. This may be faster?
|
||||
if indice in self.glyphs:
|
||||
advance_key = (indice, advances[i], offsets[i].advanceOffset, offsets[i].ascenderOffset)
|
||||
if advance_key in self._advance_cache:
|
||||
glyph = self._advance_cache[advance_key]
|
||||
else:
|
||||
@ -2153,14 +2202,18 @@ class Win32DirectWriteFont(base.Font):
|
||||
glyph = self._glyph_renderer.render_single_glyph(self.font_face, indice, advances[i], offsets[i],
|
||||
metrics[i])
|
||||
if glyph is None: # Will only return None if a color glyph is found. Use DW to render it directly.
|
||||
glyph = self._render_layout_glyph(text_buffer, i, clusters, check_color=False)
|
||||
glyph = self._render_layout_glyph(text_buffer, i, formatted_clusters, check_color=False)
|
||||
glyph.colored = True
|
||||
|
||||
self.glyphs[indice] = glyph
|
||||
self._advance_cache[(indice, advances[i], offsets[i].advanceOffset, offsets[i].ascenderOffset)] = glyph
|
||||
self._advance_cache[advance_key] = glyph
|
||||
|
||||
glyphs.append(glyph)
|
||||
|
||||
if i in substitutions:
|
||||
for _ in range(substitutions[i]):
|
||||
glyphs.append(self._zero_glyph)
|
||||
|
||||
return glyphs
|
||||
|
||||
def create_text_layout(self, text):
|
||||
|
@ -120,7 +120,18 @@ class FreeTypeGlyphRenderer(base.GlyphRenderer):
|
||||
'A',
|
||||
self._data,
|
||||
abs(self._pitch))
|
||||
|
||||
# HACK: Get text working in GLES until image data can be converted properly
|
||||
# GLES don't support coversion during pixel transfer so we have to
|
||||
# force specify the glyph format to be GL_ALPHA. This format is not
|
||||
# supported in 3.3+ core, but are present in ES because of pixel transfer
|
||||
# limitations.
|
||||
if pyglet.gl.current_context.get_info().get_opengl_api() == "gles":
|
||||
GL_ALPHA = 0x1906
|
||||
glyph = self.font.create_glyph(img, fmt=GL_ALPHA)
|
||||
else:
|
||||
glyph = self.font.create_glyph(img)
|
||||
|
||||
glyph.set_bearings(self._baseline, self._lsb, self._advance_x)
|
||||
if self._pitch > 0:
|
||||
t = list(glyph.tex_coords)
|
||||
|
@ -824,14 +824,14 @@ class Controller(EventDispatcher):
|
||||
|
||||
# Input Event types:
|
||||
|
||||
def on_stick_motion(self, controller, axis, xvalue, yvalue):
|
||||
def on_stick_motion(self, controller, stick, xvalue, yvalue):
|
||||
"""The value of a controller analogue stick changed.
|
||||
|
||||
:Parameters:
|
||||
`controller` : `Controller`
|
||||
The controller whose analogue stick changed.
|
||||
`axis` : string
|
||||
The name of the axis that changed.
|
||||
`stick` : string
|
||||
The name of the stick that changed.
|
||||
`xvalue` : float
|
||||
The current x axis value, normalized to [-1, 1].
|
||||
`yvalue` : float
|
||||
|
@ -55,12 +55,13 @@ To query which GameControllers are available, call :py:func:`get_controllers`.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
"""
|
||||
import os
|
||||
import os as _os
|
||||
import warnings as _warnings
|
||||
|
||||
from .controller_db import mapping_list
|
||||
|
||||
|
||||
_env_config = os.environ.get('SDL_GAMECONTROLLERCONFIG')
|
||||
_env_config = _os.environ.get('SDL_GAMECONTROLLERCONFIG')
|
||||
if _env_config:
|
||||
# insert at the front of the list
|
||||
mapping_list.insert(0, _env_config)
|
||||
@ -101,12 +102,11 @@ def _parse_mapping(mapping_string):
|
||||
if ':' not in item:
|
||||
continue
|
||||
|
||||
key, relation_string = item.split(':')
|
||||
key, relation_string, *etc = item.split(':')
|
||||
|
||||
if key not in valid_keys:
|
||||
continue
|
||||
|
||||
inverted = False
|
||||
# Look for specific flags to signify inverted axis:
|
||||
if "+" in relation_string:
|
||||
relation_string = relation_string.strip('+')
|
||||
@ -114,9 +114,11 @@ def _parse_mapping(mapping_string):
|
||||
elif "-" in relation_string:
|
||||
relation_string = relation_string.strip('-')
|
||||
inverted = True
|
||||
if "~" in relation_string:
|
||||
elif "~" in relation_string:
|
||||
relation_string = relation_string.strip('~')
|
||||
inverted = True
|
||||
else:
|
||||
inverted = False
|
||||
|
||||
# All relations will be one of (Button, Axis, or Hat).
|
||||
if relation_string.startswith("b"): # Button
|
||||
@ -141,7 +143,11 @@ def get_mapping(guid):
|
||||
"""
|
||||
for mapping in mapping_list:
|
||||
if mapping.startswith(guid):
|
||||
try:
|
||||
return _parse_mapping(mapping)
|
||||
except ValueError:
|
||||
_warnings.warn(f"Unable to parse Controller mapping: {mapping}")
|
||||
continue
|
||||
|
||||
|
||||
def add_mappings_from_file(filename) -> None:
|
||||
|
@ -2,7 +2,7 @@ from pyglet import compat_platform
|
||||
|
||||
|
||||
# This file is automatically generated by 'pyglet/tools/gen_controller_db.py'
|
||||
# Generated on: Thu Jul 7 09:31:08 2022
|
||||
# Generated on: Wed Aug 3 10:51:56 2022
|
||||
|
||||
if compat_platform.startswith("linux"):
|
||||
mapping_list = [
|
||||
@ -27,6 +27,10 @@ if compat_platform.startswith("linux"):
|
||||
"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000102800000900000000010000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@ -105,6 +109,8 @@ if compat_platform.startswith("linux"):
|
||||
"030000000d0f00005001000009040000,HORI Fighting Commander OCTA,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,",
|
||||
"030000000d0f00008400000011010000,HORI Fighting Commander,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,",
|
||||
"030000000d0f00008500000010010000,HORI Fighting Commander,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,",
|
||||
"030000000d0f00008800000011010000,HORI Fighting Stick mini 4 (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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008700000011010000,HORI Fighting Stick mini 4 (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,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f0000d800000072056800,HORI Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,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:b3,y:b0,",
|
||||
"030000000d0f00006e00000011010000,HORIPAD 4 (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,",
|
||||
@ -171,8 +177,26 @@ if compat_platform.startswith("linux"):
|
||||
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,",
|
||||
"050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b1,b:b0,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:b3,y:b2,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,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:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000620000001800000,Nintendo Switch Joy-Con (L),a:b15,b:b16,guide:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b17,y:b14,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000620000001800000,Nintendo Switch Joy-Con (L),a:b16,b:b15,guide:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000620000000000000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000620000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000720000001800000,Nintendo Switch Joy-Con (R),a:b2,b:b1,guide:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000720000001800000,Nintendo Switch Joy-Con (R),a:b1,b:b2,guide:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b2,b:b1,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:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000013a7000011010000,Nintendo Switch PowerA 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,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b2,b:b1,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:b3,y:b0,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus 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,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,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:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b1,b:b0,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:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||
"05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
|
||||
@ -338,6 +362,8 @@ elif compat_platform.startswith("darwin"):
|
||||
"03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000203800000900000000010000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000000020000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000102800000900000000000000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@ -375,6 +401,8 @@ elif compat_platform.startswith("darwin"):
|
||||
"03000000d11800000094000000010000,Google Stadia Controller,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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"030000000d0f00005f00000000000000,HORI Fighting Commander 4 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,",
|
||||
"030000000d0f00005e00000000000000,HORI Fighting Commander 4 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008800000000010000,HORI Fighting Stick mini 4 (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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008700000000010000,HORI Fighting Stick mini 4 (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:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00004d00000000000000,HORI Gem Pad 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,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f0000aa00000072050000,HORI Real Arcade Pro,a:b2,b:b1,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:b3,y:b0,",
|
||||
"030000000d0f00006e00000000010000,HORIPAD 4 (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,",
|
||||
@ -490,6 +518,8 @@ elif compat_platform.startswith("win"):
|
||||
"03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,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,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000000000000,8BitDo Pro 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,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,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@ -554,8 +584,6 @@ elif compat_platform.startswith("win"):
|
||||
"03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,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:b1,",
|
||||
"03000000852100000201000000000000,FF-GP1,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,",
|
||||
"030000000d0f00002700000000000000,FIGHTING STICK 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,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
|
||||
"78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,",
|
||||
"03000000151900004000000000000000,Flydigi Vader 2,a:b11,b:b10,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,leftstick:b1,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b0,righttrigger:b4,rightx:a3,righty:a4,start:b2,x:b9,y:b8,",
|
||||
"03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,",
|
||||
@ -582,6 +610,8 @@ elif compat_platform.startswith("win"):
|
||||
"03000000632500002605000000000000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,",
|
||||
"030000000d0f00008400000000000000,HORI Fighting Commander,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:a5,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008500000000000000,HORI Fighting Commander,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,",
|
||||
"030000000d0f00008800000000000000,HORI Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,",
|
||||
"030000000d0f00008700000000000000,HORI Fighting Stick mini 4 (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,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00006e00000000000000,HORIPAD 4 (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,",
|
||||
"030000000d0f00006600000000000000,HORIPAD 4 (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,",
|
||||
"030000000d0f0000ee00000000000000,HORIPAD mini4,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:a5,start:b9,x:b0,y:b3,",
|
||||
|
@ -46,13 +46,16 @@ for creating orthographic and perspective projection matrixes.
|
||||
the object is not updated in-place.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math as _math
|
||||
import warnings as _warnings
|
||||
|
||||
from collections.abc import Iterable, Iterator
|
||||
from operator import mul as _mul
|
||||
from typing import NoReturn, TypeVar, cast, overload, Tuple
|
||||
|
||||
|
||||
def clamp(num, min_val, max_val):
|
||||
def clamp(num: float, min_val: float, max_val: float) -> float:
|
||||
return max(min(num, max_val), min_val)
|
||||
|
||||
|
||||
@ -70,57 +73,65 @@ class Vec2:
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, x=0.0, y=0.0):
|
||||
def __init__(self, x: float = 0.0, y: float = 0.0) -> None:
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __iter__(self):
|
||||
def __iter__(self) -> Iterator[float]:
|
||||
yield self.x
|
||||
yield self.y
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
return 2
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: int) -> float:
|
||||
...
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: slice) -> tuple[float, ...]:
|
||||
...
|
||||
|
||||
def __getitem__(self, item):
|
||||
return (self.x, self.y)[item]
|
||||
|
||||
def __add__(self, other):
|
||||
def __add__(self, other: Vec2) -> Vec2:
|
||||
return Vec2(self.x + other.x, self.y + other.y)
|
||||
|
||||
def __sub__(self, other):
|
||||
def __sub__(self, other: Vec2) -> Vec2:
|
||||
return Vec2(self.x - other.x, self.y - other.y)
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other: Vec2) -> Vec2:
|
||||
return Vec2(self.x * other.x, self.y * other.y)
|
||||
|
||||
def __truediv__(self, other):
|
||||
def __truediv__(self, other: Vec2) -> Vec2:
|
||||
return Vec2(self.x / other.x, self.y / other.y)
|
||||
|
||||
def __abs__(self):
|
||||
def __abs__(self) -> float:
|
||||
return _math.sqrt(self.x ** 2 + self.y ** 2)
|
||||
|
||||
def __neg__(self):
|
||||
def __neg__(self) -> Vec2:
|
||||
return Vec2(-self.x, -self.y)
|
||||
|
||||
def __round__(self, ndigits=None):
|
||||
def __round__(self, ndigits: int | None = None) -> Vec2:
|
||||
return Vec2(*(round(v, ndigits) for v in self))
|
||||
|
||||
def __radd__(self, other):
|
||||
def __radd__(self, other: Vec2 | int) -> Vec2:
|
||||
"""Reverse add. Required for functionality with sum()
|
||||
"""
|
||||
if other == 0:
|
||||
return self
|
||||
else:
|
||||
return self.__add__(other)
|
||||
return self.__add__(cast(Vec2, other))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return isinstance(other, Vec2) and self.x == other.x and self.y == other.y
|
||||
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x or self.y != other.y
|
||||
def __ne__(self, other: object) -> bool:
|
||||
return not isinstance(other, Vec2) or self.x != other.x or self.y != other.y
|
||||
|
||||
@staticmethod
|
||||
def from_polar(mag, angle):
|
||||
def from_polar(mag: float, angle: float) -> Vec2:
|
||||
"""Create a new vector from the given polar coordinates.
|
||||
|
||||
:parameters:
|
||||
@ -134,7 +145,7 @@ class Vec2:
|
||||
"""
|
||||
return Vec2(mag * _math.cos(angle), mag * _math.sin(angle))
|
||||
|
||||
def from_magnitude(self, magnitude):
|
||||
def from_magnitude(self, magnitude: float) -> Vec2:
|
||||
"""Create a new Vector of the given magnitude by normalizing,
|
||||
then scaling the vector. The heading remains unchanged.
|
||||
|
||||
@ -147,7 +158,7 @@ class Vec2:
|
||||
"""
|
||||
return self.normalize().scale(magnitude)
|
||||
|
||||
def from_heading(self, heading):
|
||||
def from_heading(self, heading: float) -> Vec2:
|
||||
"""Create a new vector of the same magnitude with the given heading. I.e. Rotate the vector to the heading.
|
||||
|
||||
:parameters:
|
||||
@ -161,7 +172,7 @@ class Vec2:
|
||||
return Vec2(mag * _math.cos(heading), mag * _math.sin(heading))
|
||||
|
||||
@property
|
||||
def heading(self):
|
||||
def heading(self) -> float:
|
||||
"""The angle of the vector in radians.
|
||||
|
||||
:type: float
|
||||
@ -169,7 +180,7 @@ class Vec2:
|
||||
return _math.atan2(self.y, self.x)
|
||||
|
||||
@property
|
||||
def mag(self):
|
||||
def mag(self) -> float:
|
||||
"""The magnitude, or length of the vector. The distance between the coordinates and the origin.
|
||||
|
||||
Alias of abs(self).
|
||||
@ -178,7 +189,7 @@ class Vec2:
|
||||
"""
|
||||
return self.__abs__()
|
||||
|
||||
def limit(self, maximum):
|
||||
def limit(self, maximum: float) -> Vec2:
|
||||
"""Limit the magnitude of the vector to the value used for the max parameter.
|
||||
|
||||
:parameters:
|
||||
@ -192,12 +203,12 @@ class Vec2:
|
||||
return self.from_magnitude(maximum)
|
||||
return self
|
||||
|
||||
def lerp(self, other, alpha):
|
||||
"""Create a new vector lineraly interpolated between this vector and another vector.
|
||||
def lerp(self, other: Vec2, alpha: float) -> Vec2:
|
||||
"""Create a new Vec2 linearly interpolated between this vector and another Vec2.
|
||||
|
||||
:parameters:
|
||||
`other` : Vec2 :
|
||||
The vector to be linerly interpolated to.
|
||||
The vector to linearly interpolate with.
|
||||
`alpha` : float or int :
|
||||
The amount of interpolation.
|
||||
Some value between 0.0 (this vector) and 1.0 (other vector).
|
||||
@ -209,19 +220,19 @@ class Vec2:
|
||||
return Vec2(self.x + (alpha * (other.x - self.x)),
|
||||
self.y + (alpha * (other.y - self.y)))
|
||||
|
||||
def scale(self, value):
|
||||
def scale(self, value: float) -> Vec2:
|
||||
"""Multiply the vector by a scalar value.
|
||||
|
||||
:parameters:
|
||||
`value` : int or float :
|
||||
The ammount to be scaled by
|
||||
The value to scale the vector by.
|
||||
|
||||
:returns: A new vector scaled by the value.
|
||||
:rtype: Vec2
|
||||
"""
|
||||
return Vec2(self.x * value, self.y * value)
|
||||
|
||||
def rotate(self, angle):
|
||||
def rotate(self, angle: float) -> Vec2:
|
||||
"""Create a new Vector rotated by the angle. The magnitude remains unchanged.
|
||||
|
||||
:parameters:
|
||||
@ -233,9 +244,9 @@ class Vec2:
|
||||
"""
|
||||
mag = self.mag
|
||||
heading = self.heading
|
||||
return Vec2(mag * _math.cos(heading + angle), mag * _math.sin(heading+angle))
|
||||
return Vec2(mag * _math.cos(heading + angle), mag * _math.sin(heading + angle))
|
||||
|
||||
def distance(self, other):
|
||||
def distance(self, other: Vec2) -> float:
|
||||
"""Calculate the distance between this vector and another 2D vector.
|
||||
|
||||
:parameters:
|
||||
@ -247,7 +258,7 @@ class Vec2:
|
||||
"""
|
||||
return _math.sqrt(((other.x - self.x) ** 2) + ((other.y - self.y) ** 2))
|
||||
|
||||
def normalize(self):
|
||||
def normalize(self) -> Vec2:
|
||||
"""Normalize the vector to have a magnitude of 1. i.e. make it a unit vector.
|
||||
|
||||
:returns: A unit vector with the same heading.
|
||||
@ -258,7 +269,7 @@ class Vec2:
|
||||
return Vec2(self.x / d, self.y / d)
|
||||
return self
|
||||
|
||||
def clamp(self, min_val, max_val):
|
||||
def clamp(self, min_val: float, max_val: float) -> Vec2:
|
||||
"""Restrict the value of the X and Y components of the vector to be within the given values.
|
||||
|
||||
:parameters:
|
||||
@ -272,7 +283,7 @@ class Vec2:
|
||||
"""
|
||||
return Vec2(clamp(self.x, min_val, max_val), clamp(self.y, min_val, max_val))
|
||||
|
||||
def dot(self, other):
|
||||
def dot(self, other: Vec2) -> float:
|
||||
"""Calculate the dot product of this vector and another 2D vector.
|
||||
|
||||
:parameters:
|
||||
@ -284,15 +295,17 @@ class Vec2:
|
||||
"""
|
||||
return self.x * other.x + self.y * other.y
|
||||
|
||||
def __getattr__(self, attrs):
|
||||
def __getattr__(self, attrs: str) -> Vec2 | Vec3 | Vec4:
|
||||
try:
|
||||
# Allow swizzed getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}.get(len(attrs))
|
||||
# Allow swizzled getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}[len(attrs)]
|
||||
return vec_class(*(self['xy'.index(c)] for c in attrs))
|
||||
except Exception:
|
||||
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attrs}'")
|
||||
raise AttributeError(
|
||||
f"'{self.__class__.__name__}' object has no attribute '{attrs}'"
|
||||
) from None
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return f"Vec2({self.x}, {self.y})"
|
||||
|
||||
|
||||
@ -312,24 +325,32 @@ class Vec3:
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, x=0.0, y=0.0, z=0.0):
|
||||
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0) -> None:
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
def __iter__(self):
|
||||
def __iter__(self) -> Iterator[float]:
|
||||
yield self.x
|
||||
yield self.y
|
||||
yield self.z
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: int) -> float:
|
||||
...
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: slice) -> tuple[float, ...]:
|
||||
...
|
||||
|
||||
def __getitem__(self, item):
|
||||
return (self.x, self.y, self.z)[item]
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
return 3
|
||||
|
||||
@property
|
||||
def mag(self):
|
||||
def mag(self) -> float:
|
||||
"""The magnitude, or length of the vector. The distance between the coordinates and the origin.
|
||||
|
||||
Alias of abs(self).
|
||||
@ -338,42 +359,42 @@ class Vec3:
|
||||
"""
|
||||
return self.__abs__()
|
||||
|
||||
def __add__(self, other):
|
||||
def __add__(self, other: Vec3) -> Vec3:
|
||||
return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
|
||||
|
||||
def __sub__(self, other):
|
||||
def __sub__(self, other: Vec3) -> Vec3:
|
||||
return Vec3(self.x - other.x, self.y - other.y, self.z - other.z)
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other: Vec3) -> Vec3:
|
||||
return Vec3(self.x * other.x, self.y * other.y, self.z * other.z)
|
||||
|
||||
def __truediv__(self, other):
|
||||
def __truediv__(self, other: Vec3) -> Vec3:
|
||||
return Vec3(self.x / other.x, self.y / other.y, self.z / other.z)
|
||||
|
||||
def __abs__(self):
|
||||
def __abs__(self) -> float:
|
||||
return _math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2)
|
||||
|
||||
def __neg__(self):
|
||||
def __neg__(self) -> Vec3:
|
||||
return Vec3(-self.x, -self.y, -self.z)
|
||||
|
||||
def __round__(self, ndigits=None):
|
||||
def __round__(self, ndigits: int | None = None) -> Vec3:
|
||||
return Vec3(*(round(v, ndigits) for v in self))
|
||||
|
||||
def __radd__(self, other):
|
||||
def __radd__(self, other: Vec3 | int) -> Vec3:
|
||||
"""Reverse add. Required for functionality with sum()
|
||||
"""
|
||||
if other == 0:
|
||||
return self
|
||||
else:
|
||||
return self.__add__(other)
|
||||
return self.__add__(cast(Vec3, other))
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y and self.z == other.z
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return isinstance(object, Vec3) and 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 __ne__(self, other: object) -> bool:
|
||||
return not isinstance(object, Vec3) or self.x != other.x or self.y != other.y or self.z != other.z
|
||||
|
||||
def from_magnitude(self, magnitude):
|
||||
def from_magnitude(self, magnitude: float) -> Vec3:
|
||||
"""Create a new Vector of the given magnitude by normalizing,
|
||||
then scaling the vector. The rotation remains unchanged.
|
||||
|
||||
@ -386,7 +407,7 @@ class Vec3:
|
||||
"""
|
||||
return self.normalize().scale(magnitude)
|
||||
|
||||
def limit(self, maximum):
|
||||
def limit(self, maximum: float) -> Vec3:
|
||||
"""Limit the magnitude of the vector to the value used for the max parameter.
|
||||
|
||||
:parameters:
|
||||
@ -397,10 +418,10 @@ class Vec3:
|
||||
:rtype: Vec3
|
||||
"""
|
||||
if self.x ** 2 + self.y ** 2 + self.z ** 2 > maximum * maximum * maximum:
|
||||
return self.from_magnitude(max)
|
||||
return self.from_magnitude(maximum)
|
||||
return self
|
||||
|
||||
def cross(self, other):
|
||||
def cross(self, other: Vec3) -> Vec3:
|
||||
"""Calculate the cross product of this vector and another 3D vector.
|
||||
|
||||
:parameters:
|
||||
@ -414,7 +435,7 @@ class Vec3:
|
||||
(self.z * other.x) - (self.x * other.z),
|
||||
(self.x * other.y) - (self.y * other.x))
|
||||
|
||||
def dot(self, other):
|
||||
def dot(self, other: Vec3) -> float:
|
||||
"""Calculate the dot product of this vector and another 3D vector.
|
||||
|
||||
:parameters:
|
||||
@ -426,12 +447,12 @@ class Vec3:
|
||||
"""
|
||||
return self.x * other.x + self.y * other.y + self.z * other.z
|
||||
|
||||
def lerp(self, other, alpha):
|
||||
"""Create a new vector lineraly interpolated between this vector and another vector.
|
||||
def lerp(self, other: Vec3, alpha: float) -> Vec3:
|
||||
"""Create a new Vec3 linearly interpolated between this vector and another Vec3.
|
||||
|
||||
:parameters:
|
||||
`other` : Vec3 :
|
||||
The vector to be linerly interpolated to.
|
||||
The vector to linearly interpolate with.
|
||||
`alpha` : float or int :
|
||||
The amount of interpolation.
|
||||
Some value between 0.0 (this vector) and 1.0 (other vector).
|
||||
@ -444,19 +465,19 @@ class Vec3:
|
||||
self.y + (alpha * (other.y - self.y)),
|
||||
self.z + (alpha * (other.z - self.z)))
|
||||
|
||||
def scale(self, value):
|
||||
def scale(self, value: float) -> Vec3:
|
||||
"""Multiply the vector by a scalar value.
|
||||
|
||||
:parameters:
|
||||
`value` : int or float :
|
||||
The ammount to be scaled by
|
||||
The value to scale the vector by.
|
||||
|
||||
:returns: A new vector scaled by the value.
|
||||
:rtype: Vec3
|
||||
"""
|
||||
return Vec3(self.x * value, self.y * value, self.z * value)
|
||||
|
||||
def distance(self, other):
|
||||
def distance(self, other: Vec3) -> float:
|
||||
"""Calculate the distance between this vector and another 3D vector.
|
||||
|
||||
:parameters:
|
||||
@ -470,7 +491,7 @@ class Vec3:
|
||||
((other.y - self.y) ** 2) +
|
||||
((other.z - self.z) ** 2))
|
||||
|
||||
def normalize(self):
|
||||
def normalize(self) -> Vec3:
|
||||
"""Normalize the vector to have a magnitude of 1. i.e. make it a unit vector.
|
||||
|
||||
:returns: A unit vector with the same rotation.
|
||||
@ -481,7 +502,7 @@ class Vec3:
|
||||
return Vec3(self.x / d, self.y / d, self.z / d)
|
||||
return self
|
||||
|
||||
def clamp(self, min_val, max_val):
|
||||
def clamp(self, min_val: float, max_val: float) -> Vec3:
|
||||
"""Restrict the value of the X, Y and Z components of the vector to be within the given values.
|
||||
|
||||
:parameters:
|
||||
@ -497,15 +518,17 @@ class Vec3:
|
||||
clamp(self.y, min_val, max_val),
|
||||
clamp(self.z, min_val, max_val))
|
||||
|
||||
def __getattr__(self, attrs):
|
||||
def __getattr__(self, attrs: str) -> Vec2 | Vec3 | Vec4:
|
||||
try:
|
||||
# Allow swizzed getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}.get(len(attrs))
|
||||
# Allow swizzled getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}[len(attrs)]
|
||||
return vec_class(*(self['xyz'.index(c)] for c in attrs))
|
||||
except Exception:
|
||||
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attrs}'")
|
||||
raise AttributeError(
|
||||
f"'{self.__class__.__name__}' object has no attribute '{attrs}'"
|
||||
) from None
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return f"Vec3({self.x}, {self.y}, {self.z})"
|
||||
|
||||
|
||||
@ -527,100 +550,144 @@ class Vec4:
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, x=0.0, y=0.0, z=0.0, w=0.0):
|
||||
def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0, w: float = 0.0) -> None:
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
self.w = w
|
||||
|
||||
def __iter__(self):
|
||||
def __iter__(self) -> Iterator[float]:
|
||||
yield self.x
|
||||
yield self.y
|
||||
yield self.z
|
||||
yield self.w
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: int) -> float:
|
||||
...
|
||||
|
||||
@overload
|
||||
def __getitem__(self, item: slice) -> tuple[float, ...]:
|
||||
...
|
||||
|
||||
def __getitem__(self, item):
|
||||
return (self.x, self.y, self.z, self.w)[item]
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
return 4
|
||||
|
||||
def __add__(self, other):
|
||||
def __add__(self, other: Vec4) -> Vec4:
|
||||
return Vec4(self.x + other.x, self.y + other.y, self.z + other.z, self.w + other.w)
|
||||
|
||||
def __sub__(self, other):
|
||||
def __sub__(self, other: Vec4) -> Vec4:
|
||||
return Vec4(self.x - other.x, self.y - other.y, self.z - other.z, self.w - other.w)
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other: Vec4) -> Vec4:
|
||||
return Vec4(self.x * other.x, self.y * other.y, self.z * other.z, self.w * other.w)
|
||||
|
||||
def __truediv__(self, other):
|
||||
def __truediv__(self, other: Vec4) -> Vec4:
|
||||
return Vec4(self.x / other.x, self.y / other.y, self.z / other.z, self.w / other.w)
|
||||
|
||||
def __abs__(self):
|
||||
def __abs__(self) -> float:
|
||||
return _math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2 + self.w ** 2)
|
||||
|
||||
def __neg__(self):
|
||||
def __neg__(self) -> Vec4:
|
||||
return Vec4(-self.x, -self.y, -self.z, -self.w)
|
||||
|
||||
def __round__(self, ndigits=None):
|
||||
def __round__(self, ndigits: int | None = None) -> Vec4:
|
||||
return Vec4(*(round(v, ndigits) for v in self))
|
||||
|
||||
def __radd__(self, other):
|
||||
def __radd__(self, other: Vec4 | int) -> Vec4:
|
||||
if other == 0:
|
||||
return self
|
||||
else:
|
||||
return self.__add__(other)
|
||||
return self.__add__(cast(Vec4, 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 __eq__(self, other: object) -> bool:
|
||||
return (
|
||||
isinstance(other, Vec4)
|
||||
and 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 __ne__(self, other: object) -> bool:
|
||||
return (
|
||||
not isinstance(other, Vec4)
|
||||
or self.x != other.x
|
||||
or self.y != other.y
|
||||
or self.z != other.z
|
||||
or self.w != other.w
|
||||
)
|
||||
|
||||
def lerp(self, other, alpha):
|
||||
def lerp(self, other: Vec4, alpha: float) -> Vec4:
|
||||
"""Create a new Vec4 linearly interpolated between this one and another Vec4.
|
||||
|
||||
:parameters:
|
||||
`other` : Vec4 :
|
||||
The vector to linearly interpolate with.
|
||||
`alpha` : float or int :
|
||||
The amount of interpolation.
|
||||
Some value between 0.0 (this vector) and 1.0 (other vector).
|
||||
0.5 is halfway inbetween.
|
||||
|
||||
:returns: A new interpolated vector.
|
||||
:rtype: Vec4
|
||||
"""
|
||||
return Vec4(self.x + (alpha * (other.x - self.x)),
|
||||
self.y + (alpha * (other.y - self.y)),
|
||||
self.z + (alpha * (other.z - self.z)),
|
||||
self.w + (alpha * (other.w - self.w)))
|
||||
|
||||
def scale(self, value):
|
||||
def scale(self, value: float) -> Vec4:
|
||||
"""Multiply the vector by a scalar value.
|
||||
|
||||
:parameters:
|
||||
`value` : int or float :
|
||||
The value to scale the vector by.
|
||||
|
||||
:returns: A new vector scaled by the value.
|
||||
:rtype: Vec4
|
||||
"""
|
||||
return Vec4(self.x * value, self.y * value, self.z * value, self.w * value)
|
||||
|
||||
def distance(self, other):
|
||||
def distance(self, other: Vec4) -> float:
|
||||
return _math.sqrt(((other.x - self.x) ** 2) +
|
||||
((other.y - self.y) ** 2) +
|
||||
((other.z - self.z) ** 2) +
|
||||
((other.w - self.w) ** 2))
|
||||
|
||||
def normalize(self):
|
||||
def normalize(self) -> Vec4:
|
||||
d = self.__abs__()
|
||||
if d:
|
||||
return Vec4(self.x / d, self.y / d, self.z / d, self.w / d)
|
||||
return self
|
||||
|
||||
def clamp(self, min_val, max_val):
|
||||
def clamp(self, min_val: float, max_val: float) -> Vec4:
|
||||
return Vec4(clamp(self.x, min_val, max_val),
|
||||
clamp(self.y, min_val, max_val),
|
||||
clamp(self.z, min_val, max_val),
|
||||
clamp(self.w, min_val, max_val))
|
||||
|
||||
def dot(self, other):
|
||||
def dot(self, other: Vec4) -> float:
|
||||
return self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
|
||||
|
||||
def __getattr__(self, attrs):
|
||||
def __getattr__(self, attrs: str) -> Vec2 | Vec3 | Vec4:
|
||||
try:
|
||||
# Allow swizzed getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}.get(len(attrs))
|
||||
# Allow swizzled getting of attrs
|
||||
vec_class = {2: Vec2, 3: Vec3, 4: Vec4}[len(attrs)]
|
||||
return vec_class(*(self['xyzw'.index(c)] for c in attrs))
|
||||
except Exception:
|
||||
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attrs}'")
|
||||
raise AttributeError(
|
||||
f"'{self.__class__.__name__}' object has no attribute '{attrs}'"
|
||||
) from None
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return f"Vec4({self.x}, {self.y}, {self.z}, {self.w})"
|
||||
|
||||
|
||||
class Mat3(tuple):
|
||||
class Mat3(Tuple[float, float, float, float, float, float, float, float, float]):
|
||||
"""A 3x3 Matrix class
|
||||
|
||||
`Mat3` is an immutable 3x3 Matrix, including most common
|
||||
@ -628,7 +695,9 @@ class Mat3(tuple):
|
||||
the "@" operator.
|
||||
"""
|
||||
|
||||
def __new__(cls, values=None) -> 'Mat3':
|
||||
def __new__(
|
||||
cls, values: Iterable[float] = (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
|
||||
) -> Mat3:
|
||||
"""Create a 3x3 Matrix
|
||||
|
||||
A Mat3 can be created with a list or tuple of 9 values.
|
||||
@ -640,49 +709,56 @@ class Mat3(tuple):
|
||||
`values` : tuple of float or int
|
||||
A tuple or list containing 9 floats or ints.
|
||||
"""
|
||||
assert values is None or len(values) == 9, "A 3x3 Matrix requires 9 values"
|
||||
return super().__new__(Mat3, values or (1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0))
|
||||
new = super().__new__(Mat3, values)
|
||||
assert len(new) == 9, "A 3x3 Matrix requires 9 values"
|
||||
return new
|
||||
|
||||
def scale(self, sx: float, sy: float):
|
||||
return self @ (1.0 / sx, 0.0, 0.0, 0.0, 1.0 / sy, 0.0, 0.0, 0.0, 1.0)
|
||||
def scale(self, sx: float, sy: float) -> Mat3:
|
||||
return self @ Mat3((1.0 / sx, 0.0, 0.0, 0.0, 1.0 / sy, 0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
def translate(self, tx: float, ty: float):
|
||||
return self @ (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, -tx, ty, 1.0)
|
||||
def translate(self, tx: float, ty: float) -> Mat3:
|
||||
return self @ Mat3((1.0, 0.0, 0.0, 0.0, 1.0, 0.0, -tx, ty, 1.0))
|
||||
|
||||
def rotate(self, phi: float):
|
||||
def rotate(self, phi: float) -> Mat3:
|
||||
s = _math.sin(_math.radians(phi))
|
||||
c = _math.cos(_math.radians(phi))
|
||||
return self @ (c, s, 0.0, -s, c, 0.0, 0.0, 0.0, 1.0)
|
||||
return self @ Mat3((c, s, 0.0, -s, c, 0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
def shear(self, sx: float, sy: float):
|
||||
return self @ (1.0, sy, 0.0, sx, 1.0, 0.0, 0.0, 0.0, 1.0)
|
||||
def shear(self, sx: float, sy: float) -> Mat3:
|
||||
return self @ Mat3((1.0, sy, 0.0, sx, 1.0, 0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
def __add__(self, other) -> 'Mat3':
|
||||
assert len(other) == 9, "Can only add to other Mat3 types"
|
||||
return Mat3(tuple(s + o for s, o in zip(self, other)))
|
||||
def __add__(self, other: Mat3) -> Mat3:
|
||||
if not isinstance(other, Mat3):
|
||||
raise TypeError("Can only add to other Mat3 types")
|
||||
return Mat3(s + o for s, o in zip(self, other))
|
||||
|
||||
def __sub__(self, other) -> 'Mat3':
|
||||
assert len(other) == 9, "Can only subtract from other Mat3 types"
|
||||
return Mat3(tuple(s - o for s, o in zip(self, other)))
|
||||
def __sub__(self, other: Mat3) -> Mat3:
|
||||
if not isinstance(other, Mat3):
|
||||
raise TypeError("Can only subtract from other Mat3 types")
|
||||
return Mat3(s - o for s, o in zip(self, other))
|
||||
|
||||
def __pos__(self):
|
||||
def __pos__(self) -> Mat3:
|
||||
return self
|
||||
|
||||
def __neg__(self) -> 'Mat3':
|
||||
return Mat3(tuple(-v for v in self))
|
||||
def __neg__(self) -> Mat3:
|
||||
return Mat3(-v for v in self)
|
||||
|
||||
def __round__(self, ndigits=None) -> 'Mat3':
|
||||
return Mat3(tuple(round(v, ndigits) for v in self))
|
||||
def __round__(self, ndigits: int | None = None) -> Mat3:
|
||||
return Mat3(round(v, ndigits) for v in self)
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other: object) -> NoReturn:
|
||||
raise NotImplementedError("Please use the @ operator for Matrix multiplication.")
|
||||
|
||||
def __matmul__(self, other) -> 'Mat3' or 'Vec3':
|
||||
assert len(other) in (3, 9), "Can only multiply with Mat3 or Vec3 types"
|
||||
@overload
|
||||
def __matmul__(self, other: Vec3) -> Vec3:
|
||||
...
|
||||
|
||||
if type(other) is Vec3:
|
||||
@overload
|
||||
def __matmul__(self, other: Mat3) -> Mat3:
|
||||
...
|
||||
|
||||
def __matmul__(self, other):
|
||||
if isinstance(other, Vec3):
|
||||
# Columns:
|
||||
c0 = self[0::3]
|
||||
c1 = self[1::3]
|
||||
@ -691,6 +767,9 @@ class Mat3(tuple):
|
||||
sum(map(_mul, c1, other)),
|
||||
sum(map(_mul, c2, other)))
|
||||
|
||||
if not isinstance(other, Mat3):
|
||||
raise TypeError("Can only multiply with Mat3 or Vec3 types")
|
||||
|
||||
# Rows:
|
||||
r0 = self[0:3]
|
||||
r1 = self[3:6]
|
||||
@ -717,7 +796,17 @@ class Mat3(tuple):
|
||||
return f"{self.__class__.__name__}{self[0:3]}\n {self[3:6]}\n {self[6:9]}"
|
||||
|
||||
|
||||
class Mat4(tuple):
|
||||
Mat4T = TypeVar("Mat4T", bound="Mat4")
|
||||
|
||||
|
||||
class Mat4(
|
||||
Tuple[
|
||||
float, float, float, float,
|
||||
float, float, float, float,
|
||||
float, float, float, float,
|
||||
float, float, float, float,
|
||||
]
|
||||
):
|
||||
"""A 4x4 Matrix class
|
||||
|
||||
`Mat4` is an immutable 4x4 Matrix, including most common
|
||||
@ -727,7 +816,15 @@ class Mat4(tuple):
|
||||
and perspective projections matrixes.
|
||||
"""
|
||||
|
||||
def __new__(cls, values=None) -> 'Mat4':
|
||||
def __new__(
|
||||
cls,
|
||||
values: Iterable[float] = (
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
),
|
||||
) -> Mat4:
|
||||
"""Create a 4x4 Matrix
|
||||
|
||||
A Matrix can be created with a list or tuple of 16 values.
|
||||
@ -739,14 +836,21 @@ class Mat4(tuple):
|
||||
`values` : tuple of float or int
|
||||
A tuple or list containing 16 floats or ints.
|
||||
"""
|
||||
assert values is None or len(values) == 16, "A 4x4 Matrix requires 16 values"
|
||||
return super().__new__(Mat4, values or (1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
new = super().__new__(Mat4, values)
|
||||
assert len(new) == 16, "A 4x4 Matrix requires 16 values"
|
||||
return new
|
||||
|
||||
@classmethod
|
||||
def orthogonal_projection(cls, left, right, bottom, top, z_near, z_far) -> 'Mat4':
|
||||
def orthogonal_projection(
|
||||
cls: type[Mat4T],
|
||||
left: float,
|
||||
right: float,
|
||||
bottom: float,
|
||||
top: float,
|
||||
z_near: float,
|
||||
z_far: float
|
||||
) -> Mat4T:
|
||||
"""Create a Mat4 orthographic projection matrix."""
|
||||
width = right - left
|
||||
height = top - bottom
|
||||
@ -766,7 +870,13 @@ class Mat4(tuple):
|
||||
tx, ty, tz, 1.0))
|
||||
|
||||
@classmethod
|
||||
def perspective_projection(cls, aspect, z_near, z_far, fov=60) -> 'Mat4':
|
||||
def perspective_projection(
|
||||
cls: type[Mat4T],
|
||||
aspect: float,
|
||||
z_near: float,
|
||||
z_far: float,
|
||||
fov: float = 60
|
||||
) -> Mat4T:
|
||||
"""
|
||||
Create a Mat4 perspective projection matrix.
|
||||
|
||||
@ -796,7 +906,7 @@ class Mat4(tuple):
|
||||
0, 0, qn, 0))
|
||||
|
||||
@classmethod
|
||||
def from_translation(cls, vector: Vec3) -> 'Mat4':
|
||||
def from_translation(cls: type[Mat4T], vector: Vec3) -> Mat4T:
|
||||
"""Create a translation matrix from a Vec3.
|
||||
|
||||
:Parameters:
|
||||
@ -809,7 +919,7 @@ class Mat4(tuple):
|
||||
vector[0], vector[1], vector[2], 1.0))
|
||||
|
||||
@classmethod
|
||||
def from_rotation(cls, angle: float, vector: Vec3) -> 'Mat4':
|
||||
def from_rotation(cls, angle: float, vector: Vec3) -> Mat4:
|
||||
"""Create a rotation matrix from an angle and Vec3.
|
||||
|
||||
:Parameters:
|
||||
@ -821,10 +931,10 @@ class Mat4(tuple):
|
||||
return cls().rotate(angle, vector)
|
||||
|
||||
@classmethod
|
||||
def look_at_direction(cls, direction: Vec3, up: Vec3) -> 'Mat4':
|
||||
def look_at_direction(cls: type[Mat4T], direction: Vec3, up: Vec3) -> Mat4T:
|
||||
vec_z = direction.normalize()
|
||||
vec_x = direction.cross_product(up).normalize()
|
||||
vec_y = direction.cross_product(vec_z).normalize()
|
||||
vec_x = direction.cross(up).normalize()
|
||||
vec_y = direction.cross(vec_z).normalize()
|
||||
|
||||
return cls((vec_x.x, vec_y.x, vec_z.x, 0.0,
|
||||
vec_x.y, vec_y.y, vec_z.y, 0.0,
|
||||
@ -832,21 +942,21 @@ class Mat4(tuple):
|
||||
0.0, 0.0, 0.0, 1.0))
|
||||
|
||||
@classmethod
|
||||
def look_at(cls, position: Vec3, target: Vec3, up: Vec3) -> 'Mat4':
|
||||
def look_at(cls, position: Vec3, target: Vec3, up: Vec3) -> Mat4:
|
||||
direction = target - position
|
||||
direction_mat4 = cls.look_at_direction(direction, up)
|
||||
position_mat4 = cls.from_translation(position.negate())
|
||||
position_mat4 = cls.from_translation(-position)
|
||||
return direction_mat4 @ position_mat4
|
||||
|
||||
def row(self, index: int):
|
||||
def row(self, index: int) -> tuple:
|
||||
"""Get a specific row as a tuple."""
|
||||
return self[index*4:index*4+4]
|
||||
return self[index * 4 : index * 4 + 4]
|
||||
|
||||
def column(self, index: int):
|
||||
def column(self, index: int) -> tuple:
|
||||
"""Get a specific column as a tuple."""
|
||||
return self[index::4]
|
||||
|
||||
def scale(self, vector: Vec3) -> 'Mat4':
|
||||
def scale(self, vector: Vec3) -> Mat4:
|
||||
"""Get a scale Matrix on x, y, or z axis."""
|
||||
temp = list(self)
|
||||
temp[0] *= vector[0]
|
||||
@ -854,13 +964,14 @@ class Mat4(tuple):
|
||||
temp[10] *= vector[2]
|
||||
return Mat4(temp)
|
||||
|
||||
def translate(self, vector: Vec3) -> 'Mat4':
|
||||
def translate(self, vector: Vec3) -> Mat4:
|
||||
"""Get a translation Matrix along x, y, and z axis."""
|
||||
return Mat4(self) @ Mat4((1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, *vector, 1))
|
||||
return self @ Mat4((1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, *vector, 1))
|
||||
|
||||
def rotate(self, angle: float, vector: Vec3) -> 'Mat4':
|
||||
def rotate(self, angle: float, vector: Vec3) -> Mat4:
|
||||
"""Get a rotation Matrix on x, y, or z axis."""
|
||||
assert all(abs(n) <= 1 for n in vector), "vector must be normalized (<=1)"
|
||||
if not all(abs(n) <= 1 for n in vector):
|
||||
raise ValueError("vector must be normalized (<=1)")
|
||||
x, y, z = vector
|
||||
c = _math.cos(angle)
|
||||
s = _math.sin(angle)
|
||||
@ -884,25 +995,27 @@ class Mat4(tuple):
|
||||
|
||||
return Mat4(self) @ Mat4((ra, rb, rc, 0, re, rf, rg, 0, ri, rj, rk, 0, 0, 0, 0, 1))
|
||||
|
||||
def transpose(self) -> 'Mat4':
|
||||
def transpose(self) -> Mat4:
|
||||
"""Get a transpose of this Matrix."""
|
||||
return Mat4(self[0::4] + self[1::4] + self[2::4] + self[3::4])
|
||||
|
||||
def __add__(self, other) -> 'Mat4':
|
||||
assert len(other) == 16, "Can only add to other Mat4 types"
|
||||
return Mat4(tuple(s + o for s, o in zip(self, other)))
|
||||
def __add__(self, other: Mat4) -> Mat4:
|
||||
if not isinstance(other, Mat4):
|
||||
raise TypeError("Can only add to other Mat4 types")
|
||||
return Mat4(s + o for s, o in zip(self, other))
|
||||
|
||||
def __sub__(self, other) -> 'Mat4':
|
||||
assert len(other) == 16, "Can only subtract from other Mat4 types"
|
||||
return Mat4(tuple(s - o for s, o in zip(self, other)))
|
||||
def __sub__(self, other: Mat4) -> Mat4:
|
||||
if not isinstance(other, Mat4):
|
||||
raise TypeError("Can only subtract from other Mat4 types")
|
||||
return Mat4(s - o for s, o in zip(self, other))
|
||||
|
||||
def __pos__(self):
|
||||
def __pos__(self) -> Mat4:
|
||||
return self
|
||||
|
||||
def __neg__(self) -> 'Mat4':
|
||||
return Mat4(tuple(-v for v in self))
|
||||
def __neg__(self) -> Mat4:
|
||||
return Mat4(-v for v in self)
|
||||
|
||||
def __invert__(self) -> 'Mat4':
|
||||
def __invert__(self) -> Mat4:
|
||||
a = self[10] * self[15] - self[11] * self[14]
|
||||
b = self[9] * self[15] - self[11] * self[13]
|
||||
c = self[9] * self[14] - self[10] * self[13]
|
||||
@ -951,16 +1064,22 @@ class Mat4(tuple):
|
||||
ndet * (self[0] * i - self[1] * n + self[2] * q),
|
||||
pdet * (self[0] * l - self[1] * p + self[2] * r)))
|
||||
|
||||
def __round__(self, ndigits=None) -> 'Mat4':
|
||||
return Mat4(tuple(round(v, ndigits) for v in self))
|
||||
def __round__(self, ndigits: int | None = None) -> Mat4:
|
||||
return Mat4(round(v, ndigits) for v in self)
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other: int) -> NoReturn:
|
||||
raise NotImplementedError("Please use the @ operator for Matrix multiplication.")
|
||||
|
||||
def __matmul__(self, other) -> 'Mat4' or 'Vec4':
|
||||
assert len(other) in (4, 16), "Can only multiply with Mat4 or Vec4 types"
|
||||
@overload
|
||||
def __matmul__(self, other: Vec4) -> Vec4:
|
||||
...
|
||||
|
||||
if type(other) is Vec4:
|
||||
@overload
|
||||
def __matmul__(self, other: Mat4) -> Mat4:
|
||||
...
|
||||
|
||||
def __matmul__(self, other):
|
||||
if isinstance(other, Vec4):
|
||||
# Columns:
|
||||
c0 = self[0::4]
|
||||
c1 = self[1::4]
|
||||
@ -971,6 +1090,8 @@ class Mat4(tuple):
|
||||
sum(map(_mul, c2, other)),
|
||||
sum(map(_mul, c3, other)))
|
||||
|
||||
if not isinstance(other, Mat4):
|
||||
raise TypeError("Can only multiply with Mat4 or Vec4 types")
|
||||
# Rows:
|
||||
r0 = self[0:4]
|
||||
r1 = self[4:8]
|
||||
|
@ -123,7 +123,7 @@ class AudioData:
|
||||
length (int): Size of sample data, in bytes.
|
||||
timestamp (float): Time of the first sample, in seconds.
|
||||
duration (float): Total data duration, in seconds.
|
||||
events (List[:class:`pyglet.media.events.MediaEvent`]): List of events
|
||||
events (List[:class:`pyglet.media.drivers.base.MediaEvent`]): List of events
|
||||
contained within this packet. Events are timestamped relative to
|
||||
this audio packet.
|
||||
"""
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -356,6 +356,7 @@ class Caret:
|
||||
m2 = len(self._layout.document.text)
|
||||
else:
|
||||
m2 = m2.start()
|
||||
|
||||
self._position = m2
|
||||
self._update(line=line)
|
||||
self._next_attributes.clear()
|
||||
@ -436,6 +437,7 @@ class Caret:
|
||||
elif self._position > 0:
|
||||
self._position -= 1
|
||||
self._layout.document.delete_text(self._position, self._position + 1)
|
||||
self._update()
|
||||
elif motion == key.MOTION_DELETE:
|
||||
if self.mark is not None:
|
||||
self._delete_selection()
|
||||
|
@ -347,7 +347,7 @@ class _GlyphBox(_AbstractBox):
|
||||
v2 += x1
|
||||
v1 += y + baseline
|
||||
v3 += y + baseline
|
||||
vertices.extend(map(int, [v0, v1, v2, v1, v2, v3, v0, v3]))
|
||||
vertices.extend(map(round, [v0, v1, v2, v1, v2, v3, v0, v3]))
|
||||
t = glyph.tex_coords
|
||||
tex_coords.extend(t)
|
||||
x1 += glyph.advance
|
||||
@ -412,17 +412,19 @@ class _GlyphBox(_AbstractBox):
|
||||
if background_vertices:
|
||||
background_indices = []
|
||||
bg_count = len(background_vertices) // 2
|
||||
for glyph_idx in range(bg_count):
|
||||
background_indices.extend([element + (glyph_idx * 4) for element in [0, 1, 2, 0, 2, 3]])
|
||||
decoration_program = get_default_decoration_shader()
|
||||
for bg_idx in range(bg_count):
|
||||
background_indices.extend([element + (bg_idx * 4) for element in [0, 1, 2, 0, 2, 3]])
|
||||
|
||||
background_list = program.vertex_list_indexed(bg_count, GL_TRIANGLES, background_indices,
|
||||
background_list = decoration_program.vertex_list_indexed(bg_count * 4, GL_TRIANGLES, background_indices,
|
||||
layout.batch, layout.background_decoration_group,
|
||||
position=('f', background_vertices),
|
||||
colors=('Bn', background_colors))
|
||||
context.add_list(background_list)
|
||||
|
||||
if underline_vertices:
|
||||
underline_list = program.vertex_list(len(underline_vertices) // 2, GL_LINES,
|
||||
decoration_program = get_default_decoration_shader()
|
||||
underline_list = decoration_program.vertex_list(len(underline_vertices) // 2, GL_LINES,
|
||||
layout.batch, layout.foreground_decoration_group,
|
||||
position=('f',underline_vertices),
|
||||
colors=('Bn', underline_colors))
|
||||
@ -778,6 +780,14 @@ class ScrollableTextDecorationGroup(graphics.Group):
|
||||
glDisable(GL_BLEND)
|
||||
self.program.stop()
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}(scissor={self.scissor_area})"
|
||||
|
||||
def __eq__(self, other):
|
||||
return self is other
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
class IncrementalTextDecorationGroup(ScrollableTextDecorationGroup):
|
||||
# Subclass so that the scissor_area isn't shared with the
|
||||
@ -1797,6 +1807,9 @@ class ScrollableTextLayout(TextLayout):
|
||||
for group in self.group_cache.values():
|
||||
group.scissor_area = area
|
||||
|
||||
self.background_decoration_group.scissor_area = area
|
||||
self.foreground_decoration_group.scissor_area = area
|
||||
|
||||
def _update(self):
|
||||
super()._update()
|
||||
self._update_scissor_area()
|
||||
@ -1951,6 +1964,8 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
|
||||
area = self._get_left(), self._get_bottom(self._get_lines()), self._width, self._height
|
||||
for group in self.group_cache.values():
|
||||
group.scissor_area = area
|
||||
self.background_decoration_group.scissor_area = area
|
||||
self.foreground_decoration_group.scissor_area = area
|
||||
|
||||
def _init_document(self):
|
||||
assert self._document, 'Cannot remove document from IncrementalTextLayout'
|
||||
@ -2532,7 +2547,7 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
|
||||
position -= box.length
|
||||
x += box.advance
|
||||
|
||||
return x + self._translate_x, line.y + self._translate_y + baseline
|
||||
return x - self._translate_x, line.y + self._translate_y + baseline
|
||||
|
||||
def get_line_from_point(self, x, y):
|
||||
"""Get the closest line index to a point.
|
||||
@ -2610,6 +2625,8 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
|
||||
:rtype: int
|
||||
"""
|
||||
line = self.lines[line]
|
||||
|
||||
x += self._translate_x
|
||||
x -= self._x
|
||||
|
||||
if x < line.x:
|
||||
@ -2659,6 +2676,8 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
|
||||
X coordinate
|
||||
|
||||
"""
|
||||
x += self.view_x - self._x
|
||||
|
||||
if x <= self.view_x + 10:
|
||||
self.view_x = x - 10
|
||||
elif x >= self.view_x + self.width:
|
||||
|
@ -321,6 +321,7 @@ class Win32Window(BaseWindow):
|
||||
return
|
||||
|
||||
_user32.DestroyWindow(self._hwnd)
|
||||
_user32.UnregisterClassW(self._view_window_class.lpszClassName, 0)
|
||||
_user32.UnregisterClassW(self._window_class.lpszClassName, 0)
|
||||
|
||||
self._window_class = None
|
||||
|
Loading…
Reference in New Issue
Block a user