Compare commits

...

2 Commits

Author SHA1 Message Date
100c123bb9
sync pyglet 2023-10-31 23:55:58 +08:00
d9bd54c90a
sync pyglet 2023-10-28 22:01:14 +08:00
6 changed files with 145 additions and 13 deletions

View File

@ -336,7 +336,7 @@ class GDIPlusGlyphRenderer(Win32GlyphRenderer):
pass pass
def _create_bitmap(self, width, height): def _create_bitmap(self, width, height):
self._data = (ctypes.c_byte * (4 * width * height))() self._data = (BYTE * (4 * width * height))()
self._bitmap = ctypes.c_void_p() self._bitmap = ctypes.c_void_p()
self._format = PixelFormat32bppARGB self._format = PixelFormat32bppARGB
gdiplus.GdipCreateBitmapFromScan0(width, height, width * 4, gdiplus.GdipCreateBitmapFromScan0(width, height, width * 4,
@ -532,6 +532,12 @@ class GDIPlusFont(Win32Font):
self._name = name self._name = name
family = ctypes.c_void_p() family = ctypes.c_void_p()
# GDI will add @ in front of a localized font for some Asian languages. However, GDI will also not find it
# based on that name (???). Here we remove it before checking font collections.
if name[0] == "@":
name = name[1:]
name = ctypes.c_wchar_p(name) name = ctypes.c_wchar_p(name)
# Look in private collection first: # Look in private collection first:
@ -540,6 +546,9 @@ class GDIPlusFont(Win32Font):
# Then in system collection: # Then in system collection:
if not family: if not family:
if _debug_font:
print(f"Warning: Font '{name}' was not found. Defaulting to: {self._default_name}")
gdiplus.GdipCreateFontFamilyFromName(name, None, ctypes.byref(family)) gdiplus.GdipCreateFontFamilyFromName(name, None, ctypes.byref(family))
# Nothing found, use default font. # Nothing found, use default font.

View File

@ -244,7 +244,7 @@ class Win32ARBContext(_BaseWin32Context):
if self.config.forward_compatible: if self.config.forward_compatible:
flags |= wglext_arb.WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB flags |= wglext_arb.WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
if self.config.debug: if self.config.debug:
flags |= wglext_arb.WGL_DEBUG_BIT_ARB flags |= wglext_arb.WGL_CONTEXT_DEBUG_BIT_ARB
if flags: if flags:
attribs.extend([wglext_arb.WGL_CONTEXT_FLAGS_ARB, flags]) attribs.extend([wglext_arb.WGL_CONTEXT_FLAGS_ARB, flags])
attribs.append(0) attribs.append(0)

View File

@ -601,7 +601,7 @@ class WICEncoder(ImageEncoder):
frame.SetPixelFormat(byref(default_format)) frame.SetPixelFormat(byref(default_format))
data = (c_byte * size).from_buffer(bytearray(image_data)) data = (BYTE * size).from_buffer(bytearray(image_data))
frame.WritePixels(image.height, pitch, size, data) frame.WritePixels(image.height, pitch, size, data)

View File

@ -113,8 +113,8 @@ ERROR_SUCCESS = 0
class XINPUT_GAMEPAD(Structure): class XINPUT_GAMEPAD(Structure):
_fields_ = [ _fields_ = [
('wButtons', WORD), ('wButtons', WORD),
('bLeftTrigger', UBYTE), ('bLeftTrigger', BYTE),
('bRightTrigger', UBYTE), ('bRightTrigger', BYTE),
('sThumbLX', SHORT), ('sThumbLX', SHORT),
('sThumbLY', SHORT), ('sThumbLY', SHORT),
('sThumbRX', SHORT), ('sThumbRX', SHORT),

View File

@ -1,4 +1,5 @@
import ctypes import ctypes
import sys
from ctypes import * from ctypes import *
from ctypes.wintypes import * from ctypes.wintypes import *
@ -45,7 +46,6 @@ def POINTER_(obj):
c_void_p = POINTER_(c_void) c_void_p = POINTER_(c_void)
INT = c_int INT = c_int
UBYTE = c_ubyte
LPVOID = c_void_p LPVOID = c_void_p
HCURSOR = HANDLE HCURSOR = HANDLE
LRESULT = LPARAM LRESULT = LPARAM
@ -62,6 +62,11 @@ HDROP = HANDLE
LPTSTR = LPWSTR LPTSTR = LPWSTR
LPSTREAM = c_void_p LPSTREAM = c_void_p
# Fixed in python 3.12. Is c_byte on other versions.
# Ensure it's the same across all versions.
if sys.version_info < (3, 12):
BYTE = c_ubyte
LF_FACESIZE = 32 LF_FACESIZE = 32
CCHDEVICENAME = 32 CCHDEVICENAME = 32
CCHFORMNAME = 32 CCHFORMNAME = 32
@ -572,6 +577,7 @@ class IStream(com.pIUnknown):
com.STDMETHOD()), com.STDMETHOD()),
] ]
class DEV_BROADCAST_HDR(Structure): class DEV_BROADCAST_HDR(Structure):
_fields_ = ( _fields_ = (
('dbch_size', DWORD), ('dbch_size', DWORD),
@ -579,6 +585,7 @@ class DEV_BROADCAST_HDR(Structure):
('dbch_reserved', DWORD), ('dbch_reserved', DWORD),
) )
class DEV_BROADCAST_DEVICEINTERFACE(Structure): class DEV_BROADCAST_DEVICEINTERFACE(Structure):
_fields_ = ( _fields_ = (
('dbcc_size', DWORD), ('dbcc_size', DWORD),

View File

@ -5,12 +5,11 @@ such as Rectangles, Circles, and Lines. These shapes are made
internally from OpenGL primitives, and provide excellent performance internally from OpenGL primitives, and provide excellent performance
when drawn as part of a :py:class:`~pyglet.graphics.Batch`. when drawn as part of a :py:class:`~pyglet.graphics.Batch`.
Convenience methods are provided for positioning, changing color Convenience methods are provided for positioning, changing color
and opacity, and rotation (where applicable). To create more and opacity, and rotation (where applicable).
complex shapes than what is provided here, the lower level The Python ``in`` operator to check whether a point is inside a shape.
graphics API is more appropriate.
You can also use the ``in`` operator to check whether a point is To create more complex shapes than what is provided here, the lower level
inside a shape. graphics API is more appropriate. See the :ref:`guide_graphics` for more details.
See the :ref:`guide_graphics` for more details.
A simple example of drawing shapes:: A simple example of drawing shapes::
@ -1466,6 +1465,122 @@ class BorderedRectangle(ShapeBase):
self._update_color() self._update_color()
class Box(ShapeBase):
def __init__(self, x, y, width, height, thickness=1, color=(255, 255, 255, 255), batch=None, group=None):
"""Create an unfilled rectangular shape, with optional thickness.
The box's anchor point defaults to the (x, y) coordinates,
which are at the bottom left.
Changing the thickness of the box will extend the walls inward;
the outward dimesions will not be affected.
:Parameters:
`x` : float
The X coordinate of the box.
`y` : float
The Y coordinate of the box.
`width` : float
The width of the box.
`height` : float
The height of the box.
`thickness` : float
The thickness of the lines that make up the box.
`color` : (int, int, int, int)
The RGB or RGBA color of the box, specified as a tuple
of 3 or 4 ints in the range of 0-255. RGB colors will
be treated as having an opacity of 255.
`batch` : `~pyglet.graphics.Batch`
Optional batch to add the box to.
`group` : `~pyglet.graphics.Group`
Optional parent group of the box.
"""
self._x = x
self._y = y
self._width = width
self._height = height
self._thickness = thickness
self._num_verts = 8
r, g, b, *a = color
self._rgba = r, g, b, a[0] if a else 255
program = get_default_shader()
self._batch = batch or Batch()
self._group = self.group_class(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, program, group)
self._create_vertex_list()
self._update_vertices()
def __contains__(self, point):
assert len(point) == 2
point = _rotate_point((self._x, self._y), point, math.radians(self._rotation))
x, y = self._x - self._anchor_x, self._y - self._anchor_y
return x < point[0] < x + self._width and y < point[1] < y + self._height
def _create_vertex_list(self):
# 3 6
# 2 7
# 1 4
# 0 5
indices = [0, 1, 2, 0, 2, 3, 0, 5, 4, 0, 4, 1, 4, 5, 6, 4, 6, 7, 2, 7, 6, 2, 6, 3]
self._vertex_list = self._group.program.vertex_list_indexed(
self._num_verts, self._draw_mode, indices, self._batch, self._group,
colors=('Bn', self._rgba * self._num_verts),
translation=('f', (self._x, self._y) * self._num_verts))
def _update_color(self):
self._vertex_list.colors[:] = self._rgba * self._num_verts
def _update_vertices(self):
if not self._visible:
self._vertex_list.position[:] = (0, 0) * self._num_verts
else:
t = self._thickness
left = -self._anchor_x
bottom = -self._anchor_y
right = left + self._width
top = bottom + self._height
x1 = left
x2 = left + t
x3 = right - t
x4 = right
y1 = bottom
y2 = bottom + t
y3 = top - t
y4 = top
# 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
self._vertex_list.position[:] = x1, y1, x2, y2, x2, y3, x1, y4, x3, y2, x4, y1, x4, y4, x3, y3
@property
def width(self):
"""The width of the Box.
:type: float
"""
return self._width
@width.setter
def width(self, value):
self._width = value
self._update_vertices()
@property
def height(self):
"""The height of the Box.
:type: float
"""
return self._height
@height.setter
def height(self, value):
self._height = value
self._update_vertices()
class Triangle(ShapeBase): class Triangle(ShapeBase):
def __init__(self, x, y, x2, y2, x3, y3, color=(255, 255, 255, 255), def __init__(self, x, y, x2, y2, x3, y3, color=(255, 255, 255, 255),
batch=None, group=None): batch=None, group=None):
@ -1776,4 +1891,5 @@ class Polygon(ShapeBase):
self._vertex_list.position[:] = tuple(value for coordinate in triangles for value in coordinate) self._vertex_list.position[:] = tuple(value for coordinate in triangles for value in coordinate)
__all__ = 'Arc', 'BezierCurve', 'Circle', 'Ellipse', 'Line', 'Rectangle', 'BorderedRectangle', 'Triangle', 'Star', 'Polygon', 'Sector' __all__ = ('Arc', 'Box', 'BezierCurve', 'Circle', 'Ellipse', 'Line', 'Rectangle',
'BorderedRectangle', 'Triangle', 'Star', 'Polygon', 'Sector', 'ShapeBase')