use new pyglet local
[build skip] docs try hard link 非得更新一下是吧 [build skip]
This commit is contained in:
parent
46f21e607a
commit
f16807715c
@ -1,7 +1,5 @@
|
||||
# Difficult Rocket
|
||||
|
||||
[comment]: <> ([中文](./docs/README-cn.md) | English)
|
||||
|
||||
中文 | [English](/docs/README-en.md)
|
||||
|
||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
|
@ -1,7 +1,5 @@
|
||||
# Difficult Rocket
|
||||
|
||||
[comment]: <> (中文 | [English](https://github.com/shenjackyuanjie/Difficult-Rocket).)
|
||||
|
||||
[中文](../README.md) | English
|
||||
|
||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 嘿 看啥呢
|
||||
# 嘿 看啥呢 404!
|
||||
|
||||
- 很明显,这里没有你想要的东西
|
||||
|
||||
|
116
docs/src/README-en.md
Normal file
116
docs/src/README-en.md
Normal file
@ -0,0 +1,116 @@
|
||||
# Difficult Rocket
|
||||
|
||||
[中文](../README.md) | English
|
||||
|
||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [gitee](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [discord](https://discord.gg/kWzw2JrG6M)
|
||||
- [kook](https://kook.top/sRPjFG)
|
||||
|
||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||
[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
|
||||
[![Generic badge](https://img.shields.io/badge/Write_with_Python-3.8.10-blue.svg)](https://Python.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Write_with_Pyglet-2.0.4-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
|
||||
|
||||
## Version
|
||||
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.7.2-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
|
||||
## 中文README请移步 [这里](../README.md)
|
||||
|
||||
> Difficult-rocket is a Simple Rocket liked game build with Python (in short: rocket simulator)
|
||||
|
||||
## Advantage
|
||||
|
||||
> Lighter than Vanilla SR
|
||||
|
||||
## [Plan feature list](/docs/src/plan_features.md)
|
||||
|
||||
- [microsoft TODO](https://to-do.microsoft.com/sharing?InvitationToken=Q6SN1kdtitK8cwFktFl71gSnsRMNmrH7CC7kHY_Tq6ReMRwHgInP4_q5ie2IwrHx8)
|
||||
|
||||
## [Update logs](/docs/src/update_logs.md)
|
||||
|
||||
## Environment (been tested / developed on)
|
||||
|
||||
- `Develop platform 1 - Windows 10 x64 22H2`
|
||||
- `Python 3.8.10`
|
||||
- `pillow 9.3.0`
|
||||
- `pyperclip 1.8.2`
|
||||
- `pyglet 2.0`
|
||||
- `psutil 5.9.4`
|
||||
- `objprint 0.2.2`
|
||||
- `rtoml 0.9.0`
|
||||
- `xmltodict 0.13.0`
|
||||
- `tomlkit 0.11.6`
|
||||
- `AMD R5 5600X`
|
||||
- `AMD RX 550 4G`
|
||||
|
||||
## Required python modules
|
||||
|
||||
- `rtoml`
|
||||
- `tomlkit`
|
||||
- `pyglet` (pre-installed V2.0.4 path:`./libs/pyglet`)
|
||||
- `xmltodict` (pre-installed V0.12.0 path:`./libs/xmltodict`)
|
||||
- `pyperclip` (pre-installed V1.8.2 path: `./libs/pyperclip`)
|
||||
- `pillow`
|
||||
- `defusedxml`
|
||||
- `objprint`
|
||||
- `psutil`
|
||||
|
||||
## thanks to
|
||||
|
||||
- Open Source Projects
|
||||
- [pyglet](https://github.com/pyglet/pyglet): GUI and graphics
|
||||
- `tomlkit` / `rtoml` toml parser
|
||||
- `xmltodict`: translate data between xml and dict
|
||||
- `pyperclip`: paste board!
|
||||
- `rapier2d`: Phy simulate engine
|
||||
|
||||
- Main contributors
|
||||
- [@Rayawa](https://github.com/Rayawa) : check mistake in docs & some translates
|
||||
- [@rouxiao-you](https://github.com/ruoxiao-you) : translate chinese to English
|
||||
- [@Billchyi](https://github.com/Billchyi) : check mistake in docs
|
||||
|
||||
## Other links
|
||||
|
||||
## About License
|
||||
|
||||
#### https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
#### Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
||||
|
||||
This is a human-readable summary of (and not a substitute for) the license. Disclaimer.
|
||||
|
||||
You are free to:
|
||||
|
||||
Share — copy and redistribute the material in any medium or format
|
||||
|
||||
Adapt — remix, transform, and build upon the material
|
||||
|
||||
The licensor cannot revoke these freedoms as long as you follow the license terms.
|
||||
|
||||
Under the following terms:
|
||||
|
||||
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You
|
||||
may do so in any reasonable manner, but not in any way
|
||||
|
||||
that suggests the licensor endorses you or your use.
|
||||
|
||||
NonCommercial — You may not use the material for commercial purposes.
|
||||
|
||||
ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same
|
||||
license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from
|
||||
doing anything the license permits.
|
||||
|
||||
Notices:
|
||||
|
||||
You do not have to comply with the license for elements of the material in the public domain or where your use is
|
||||
permitted by an applicable exception or limitation.
|
||||
|
||||
No warranties are given. The license may not give you all the permissions necessary for your intended use. For example,
|
||||
other rights such as publicity, privacy, or moral rights may limit how you use the material.
|
110
docs/src/README.md
Symbolic link
110
docs/src/README.md
Symbolic link
@ -0,0 +1,110 @@
|
||||
# Difficult Rocket
|
||||
|
||||
中文 | [English](/docs/README-en.md)
|
||||
|
||||
- [GitHub](https://github.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [gitee](https://gitee.com/shenjackyuanjie/Difficult-Rocket)
|
||||
- [discord](https://discord.gg/kWzw2JrG6M)
|
||||
- [kook](https://kook.top/sRPjFG)
|
||||
|
||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
||||
[![Generic badge](https://img.shields.io/badge/SemVer-2.0.0-blue.svg)](https://Semver.org/)
|
||||
[![Generic badge](https://img.shields.io/badge/编写于_Python_版本-3.8.10-blue.svg)](https://Python.org)
|
||||
[![Generic badge](https://img.shields.io/badge/编写于_Pyglet_版本-2.0.4-blue.svg)](https://pyglet.org)
|
||||
[![Generic badge](https://img.shields.io/badge/Python-_3.8_|_3.9_|_3.10_|_3.11_-blue.svg)](https://Python.org)
|
||||
|
||||
## 版本
|
||||
|
||||
[![Generic badge](https://img.shields.io/badge/Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Pre_Release-0.7.1.1-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
[![Generic badge](https://img.shields.io/badge/Devloping-0.7.2-blue.svg)](https://github.com/shenjackyuanjie/Difficult-Rocket/releases)
|
||||
|
||||
## English README please look [here](./docs/README-en.md)
|
||||
|
||||
> 这是一个用Python制作的类Simple Rocket游戏(简称:火箭模拟器)
|
||||
|
||||
## 优势
|
||||
|
||||
> 相对于原版SR比较“轻量化”
|
||||
|
||||
## [计划特性列表](/docs/plan_features)
|
||||
|
||||
- [microsoft TODO](https://to-do.microsoft.com/sharing?InvitationToken=Q6SN1kdtitK8cwFktFl71gSnsRMNmrH7CC7kHY_Tq6ReMRwHgInP4_q5ie2IwrHx8)
|
||||
|
||||
## [更新日志](/docs/update_logs.md)
|
||||
|
||||
## 环境需求 (测试过的 / 开发平台)
|
||||
|
||||
- `开发平台 1 - Windows 10 x64 22H2`
|
||||
- `Python 3.8.10`
|
||||
- `pillow 9.3.0`
|
||||
- `pyperclip 1.8.2`
|
||||
- `pyglet 2.0`
|
||||
- `psutil 5.9.4`
|
||||
- `objprint 0.2.2`
|
||||
- `rtoml 0.9.0`
|
||||
- `xmltodict 0.13.0`
|
||||
- `tomlkit 0.11.6`
|
||||
- `AMD R5 5600X`
|
||||
- `AMD RX 550 4G`
|
||||
|
||||
## 需要的Python模块
|
||||
|
||||
- `rtoml`
|
||||
- `tomlkit`
|
||||
- `pyglet` (已经内置 V2.0.4 路径:`./libs/pyglet`)
|
||||
- `xmltodict` (已经内置 V0.12.0 路径:`./libs/xmltodict`)
|
||||
- `pyperclip` (已经内置 V1.8.2 路径: `./libs/pyperclip`)
|
||||
- `pillow`
|
||||
- `defusedxml`
|
||||
- `objprint`
|
||||
- `psutil`
|
||||
|
||||
## 感谢
|
||||
|
||||
- 开源项目
|
||||
- [pyglet](https://github.com/pyglet/pyglet) : GUI 和画面渲染
|
||||
- `tomlkit` / `rtoml` : toml 解析器
|
||||
- `xmltodict`: xml 与 dict 转换器
|
||||
- `pyperclip`: 剪贴板!
|
||||
- `rapier2d`: 物理模拟引擎
|
||||
|
||||
- 主要贡献者
|
||||
- [@Rayawa](https://github.com/Rayawa) : 文档矫正 & 翻译部分 lang
|
||||
- [@rouxiao-you](https://github.com/ruoxiao-you) : 翻译 lang
|
||||
- [@Billchyi](https://github.com/Billchyi) : 文档矫正
|
||||
- [@MSDNicrosoft]()
|
||||
|
||||
## 相关链接
|
||||
|
||||
## 关于分享协议
|
||||
|
||||
#### https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
#### 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
|
||||
|
||||
这是一份普通人可以理解的许可协议概要 (但不是替代) 。 免责声明.
|
||||
|
||||
您可以自由地:
|
||||
|
||||
共享 — 在任何媒介以任何形式复制、发行本作品
|
||||
|
||||
演绎 — 修改、转换或以本作品为基础进行创作
|
||||
|
||||
只要你遵守许可协议条款,许可人就无法收回你的这些权利。
|
||||
|
||||
惟须遵守下列条件:
|
||||
|
||||
署名 — 您必须给出地当的署名,提供指向本许可协议的链接,同时标明是否(对原始作品)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示许可人为您或您的使用背书。
|
||||
|
||||
非商业性使用 — 您不得将本作品用于商业目的。
|
||||
|
||||
相同方式共享 — 如果您再混合、转换或者基于本作品进行创作,您必须基于与原先许可协议地同的许可协议 分发您贡献的作品。
|
||||
|
||||
没有附加限制 — 您不得适用法律术语或者 技术措施 从而限制其他人做许可协议允许的事情。
|
||||
|
||||
声明:
|
||||
|
||||
您不必因为公共领域的作品要素而遵守许可协议,或者您的使用被可适用的 例外或限制所允许。
|
||||
|
||||
不提供担保。许可协议可能不会给与您意图使用的所必须的所有许可。例如,其他权利比如形象权、隐私权或人格权可能限制您如何使用作品。
|
@ -1,5 +1,8 @@
|
||||
# Summary
|
||||
|
||||
- [README](./README.md)
|
||||
- [README-en](./README-en.md)
|
||||
|
||||
- [update logs](./update_logs.md)
|
||||
- [contributors](./contributors.md)
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
# 如何帮助 DR 开发
|
||||
|
||||
aaaa
|
||||
## 需要准备的工具
|
||||
|
||||
1. Powershell 7+
|
||||
2. Python3.8 +
|
||||
3. gcc / clang 编译器
|
||||
4. git
|
||||
|
@ -415,6 +415,7 @@ objc.sel_isEqual.argtypes = [c_void_p, c_void_p]
|
||||
objc.sel_registerName.restype = c_void_p
|
||||
objc.sel_registerName.argtypes = [c_char_p]
|
||||
|
||||
|
||||
######################################################################
|
||||
# void *objc_autoreleasePoolPush(void)
|
||||
objc.objc_autoreleasePoolPush.restype = c_void_p
|
||||
@ -644,8 +645,8 @@ def parse_type_encoding(encoding):
|
||||
def cfunctype_for_encoding(encoding):
|
||||
# Check if we've already created a CFUNCTYPE for this encoding.
|
||||
# If so, then return the cached CFUNCTYPE.
|
||||
#if encoding in cfunctype_table:
|
||||
# return cfunctype_table[encoding]
|
||||
if encoding in cfunctype_table:
|
||||
return cfunctype_table[encoding]
|
||||
|
||||
# Otherwise, create a new CFUNCTYPE for the encoding.
|
||||
typecodes = {b'c': c_char, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
|
||||
@ -668,7 +669,7 @@ def cfunctype_for_encoding(encoding):
|
||||
# Cache the new CFUNCTYPE in the cfunctype_table.
|
||||
# We do this mainly because it prevents the CFUNCTYPE
|
||||
# from being garbage-collected while we need it.
|
||||
#cfunctype_table[encoding] = cfunctype
|
||||
cfunctype_table[encoding] = cfunctype
|
||||
return cfunctype
|
||||
|
||||
|
||||
@ -728,12 +729,12 @@ class ObjCMethod:
|
||||
# Note, need to map 'c' to c_byte rather than c_char, because otherwise
|
||||
# ctypes converts the value into a one-character string which is generally
|
||||
# not what we want at all, especially when the 'c' represents a bool var.
|
||||
typecodes = {b'c': c_byte, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
|
||||
b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong,
|
||||
b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'Vv': None, b'*': c_char_p,
|
||||
b'@': c_void_p, b'#': c_void_p, b':': c_void_p, b'^v': c_void_p, b'?': c_void_p,
|
||||
NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect,
|
||||
NSRangeEncoding: NSRange,
|
||||
typecodes = {b'c': c_byte, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong,
|
||||
b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong,
|
||||
b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'Vv': None, b'*': c_char_p,
|
||||
b'@': c_void_p, b'#': c_void_p, b':': c_void_p, b'^v': c_void_p, b'?': c_void_p,
|
||||
NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect,
|
||||
NSRangeEncoding: NSRange,
|
||||
PyObjectEncoding: py_object}
|
||||
|
||||
cfunctype_table = {}
|
||||
|
@ -861,7 +861,7 @@ class Mat4(tuple):
|
||||
def look_at(cls: type[Mat4T], position: Vec3, target: Vec3, up: Vec3):
|
||||
f = (target - position).normalize()
|
||||
u = up.normalize()
|
||||
s = f.cross(u)
|
||||
s = f.cross(u).normalize()
|
||||
u = s.cross(f)
|
||||
|
||||
return cls([s.x, u.x, -f.x, 0.0,
|
||||
|
@ -135,17 +135,6 @@ class AudioData:
|
||||
self.duration -= num_bytes / audio_format.bytes_per_second
|
||||
self.timestamp += num_bytes / audio_format.bytes_per_second
|
||||
|
||||
def get_string_data(self):
|
||||
"""Return data as a bytestring.
|
||||
|
||||
Returns:
|
||||
bytes: Data as a (byte)string.
|
||||
"""
|
||||
if self.data is None:
|
||||
return b''
|
||||
|
||||
return memoryview(self.data).tobytes()[:self.length]
|
||||
|
||||
|
||||
class SourceInfo:
|
||||
"""Source metadata information.
|
||||
@ -409,7 +398,7 @@ class StaticSource(Source):
|
||||
audio_data = source.get_audio_data(buffer_size)
|
||||
if not audio_data:
|
||||
break
|
||||
data.write(audio_data.get_string_data())
|
||||
data.write(audio_data.data)
|
||||
self._data = data.getvalue()
|
||||
|
||||
self._duration = len(self._data) / self.audio_format.bytes_per_second
|
||||
|
@ -1,9 +1,8 @@
|
||||
import math
|
||||
import time
|
||||
import weakref
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import pyglet
|
||||
from pyglet.util import with_metaclass
|
||||
|
||||
|
||||
@ -185,36 +184,3 @@ class AbstractAudioDriver(with_metaclass(ABCMeta)):
|
||||
@abstractmethod
|
||||
def delete(self):
|
||||
pass
|
||||
|
||||
|
||||
class MediaEvent:
|
||||
"""Representation of a media event.
|
||||
|
||||
These events are used internally by some audio driver implementation to
|
||||
communicate events to the :class:`~pyglet.media.player.Player`.
|
||||
One example is the ``on_eos`` event.
|
||||
|
||||
Args:
|
||||
event (str): Event description.
|
||||
timestamp (float): The time when this event happens.
|
||||
*args: Any required positional argument to go along with this event.
|
||||
"""
|
||||
|
||||
__slots__ = 'event', 'timestamp', 'args'
|
||||
|
||||
def __init__(self, event, timestamp=0, *args):
|
||||
# Meaning of timestamp is dependent on context; and not seen by application.
|
||||
self.event = event
|
||||
self.timestamp = timestamp
|
||||
self.args = args
|
||||
|
||||
def sync_dispatch_to_player(self, player):
|
||||
pyglet.app.platform_event_loop.post_event(player, self.event, *self.args)
|
||||
time.sleep(0)
|
||||
# TODO sync with media.dispatch_events
|
||||
|
||||
def __repr__(self):
|
||||
return f"MediaEvent({self.event}, {self.timestamp}, {self.args})"
|
||||
|
||||
def __lt__(self, other):
|
||||
return hash(self) < hash(other)
|
||||
|
@ -1,10 +1,11 @@
|
||||
import math
|
||||
import ctypes
|
||||
|
||||
import pyglet.app
|
||||
from . import interface
|
||||
from pyglet.util import debug_print
|
||||
from pyglet.media.mediathreads import PlayerWorkerThread
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
|
||||
_debug = debug_print('debug_media')
|
||||
@ -75,7 +76,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
||||
self._play_cursor_ring = 0
|
||||
self._write_cursor_ring = 0
|
||||
|
||||
# List of (play_cursor, MediaEvent), in sort order
|
||||
# List of play_cursor, in sort order
|
||||
self._events = []
|
||||
|
||||
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
||||
@ -157,9 +158,6 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
||||
return (self._eos_cursor is not None
|
||||
and self._play_cursor > self._eos_cursor)
|
||||
|
||||
def _dispatch_new_event(self, event_name):
|
||||
MediaEvent(event_name).sync_dispatch_to_player(self.player)
|
||||
|
||||
def _get_audiodata(self):
|
||||
if self._audiodata_buffer is None or self._audiodata_buffer.length == 0:
|
||||
self._get_new_audiodata()
|
||||
@ -246,7 +244,7 @@ class DirectSoundAudioPlayer(AbstractAudioPlayer):
|
||||
if self._playing and self._has_underrun():
|
||||
assert _debug('underrun, stopping')
|
||||
self.stop()
|
||||
self._dispatch_new_event('on_eos')
|
||||
pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
|
||||
|
||||
def _get_write_size(self):
|
||||
self.update_play_cursor()
|
||||
|
@ -1,8 +1,9 @@
|
||||
import weakref
|
||||
|
||||
import pyglet.app
|
||||
from . import interface
|
||||
from pyglet.util import debug_print
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.mediathreads import PlayerWorkerThread
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
|
||||
@ -111,7 +112,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
|
||||
# of underrun)
|
||||
self._underrun_timestamp = None
|
||||
|
||||
# List of (cursor, MediaEvent)
|
||||
# List of cursor
|
||||
self._events = []
|
||||
|
||||
# Desired play state (True even if stopped due to underrun)
|
||||
@ -280,7 +281,7 @@ class OpenALAudioPlayer(AbstractAudioPlayer):
|
||||
assert _debug('No audio data left')
|
||||
if self._has_underrun():
|
||||
assert _debug('Underrun')
|
||||
MediaEvent('on_eos').sync_dispatch_to_player(self.player)
|
||||
pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
|
||||
|
||||
def _queue_audio_data(self, audio_data, length):
|
||||
buf = self.alsource.get_buffer()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import weakref
|
||||
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
import pyglet.app
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
from pyglet.util import debug_print
|
||||
|
||||
@ -217,7 +218,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
||||
if self._has_audio_data():
|
||||
self._write_to_stream()
|
||||
else:
|
||||
self._add_event_at_write_index('on_eos')
|
||||
self._events.append('on_eos')
|
||||
|
||||
def _process_events(self):
|
||||
assert _debug('PulseAudioPlayer: Process events')
|
||||
@ -235,13 +236,9 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
||||
assert _debug('PulseAudioPlayer: Dispatch events at index {}'.format(read_index))
|
||||
|
||||
while self._events and self._events[0][0] <= read_index:
|
||||
_, event = self._events.pop(0)
|
||||
assert _debug('PulseAudioPlayer: Dispatch event', event)
|
||||
event._sync_dispatch_to_player(self.player)
|
||||
|
||||
def _add_event_at_write_index(self, event_name):
|
||||
assert _debug('PulseAudioPlayer: Add event at index {}'.format(self._write_index))
|
||||
self._events.append((self._write_index, MediaEvent(event_name)))
|
||||
event_name = self._events.pop(0)
|
||||
assert _debug('PulseAudioPlayer: Dispatch event', event_name)
|
||||
pyglet.app.platform_event_loop.post_event(self.player, event_name)
|
||||
|
||||
def delete(self):
|
||||
assert _debug('Delete PulseAudioPlayer')
|
||||
@ -255,7 +252,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
|
||||
|
||||
if driver.mainloop is None:
|
||||
assert _debug('PulseAudioDriver already deleted. '
|
||||
'PulseAudioPlayer could not clean up properly.')
|
||||
'PulseAudioPlayer could not clean up properly.')
|
||||
return
|
||||
|
||||
if self._time_sync_operation is not None:
|
||||
|
@ -1,7 +1,7 @@
|
||||
import math
|
||||
|
||||
import pyglet
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer, MediaEvent
|
||||
from pyglet.media.drivers.base import AbstractAudioDriver, AbstractAudioPlayer
|
||||
from pyglet.media.drivers.listener import AbstractListener
|
||||
from pyglet.util import debug_print
|
||||
from . import interface
|
||||
@ -48,7 +48,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
self._write_cursor = 0
|
||||
self._play_cursor = 0
|
||||
|
||||
# List of (play_cursor, MediaEvent), in sort order
|
||||
# List of play_cursor, in sort order
|
||||
self._events = []
|
||||
|
||||
# List of (cursor, timestamp), in sort order (cursor gives expiry
|
||||
@ -89,7 +89,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
if not self._buffers:
|
||||
self._xa2_driver.return_voice(self._xa2_source_voice)
|
||||
|
||||
|
||||
def play(self):
|
||||
assert _debug('XAudio2 play')
|
||||
|
||||
@ -168,7 +167,7 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
if self.buffer_end_submitted:
|
||||
if buffers_queued == 0:
|
||||
self._xa2_source_voice.stop()
|
||||
MediaEvent("on_eos").sync_dispatch_to_player(self.player)
|
||||
pyglet.app.platform_event_loop.post_event(self.player, 'on_eos')
|
||||
else:
|
||||
current_buffers = []
|
||||
while buffers_queued < self.max_buffer_count:
|
||||
@ -206,9 +205,6 @@ class XAudio2AudioPlayer(AbstractAudioPlayer):
|
||||
|
||||
self._dispatch_pending_events()
|
||||
|
||||
def _dispatch_new_event(self, event_name):
|
||||
MediaEvent(event_name).sync_dispatch_to_player(self.player)
|
||||
|
||||
def _add_audiodata_events(self, audio_data):
|
||||
for event in audio_data.events:
|
||||
event_cursor = self._write_cursor + event.timestamp * self.source.audio_format.bytes_per_second
|
||||
|
@ -623,6 +623,80 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
# Public methods (sort alphabetically):
|
||||
def activate(self):
|
||||
"""Attempt to restore keyboard focus to the window.
|
||||
|
||||
Depending on the window manager or operating system, this may not
|
||||
be successful. For example, on Windows XP an application is not
|
||||
allowed to "steal" focus from another application. Instead, the
|
||||
window's taskbar icon will flash, indicating it requires attention.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
@staticmethod
|
||||
def clear():
|
||||
"""Clear the window.
|
||||
|
||||
This is a convenience method for clearing the color and depth
|
||||
buffer. The window must be the active context (see `switch_to`).
|
||||
"""
|
||||
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
|
||||
|
||||
def close(self):
|
||||
"""Close the window.
|
||||
|
||||
After closing the window, the GL context will be invalid. The
|
||||
window instance cannot be reused once closed (see also `set_visible`).
|
||||
|
||||
The `pyglet.app.EventLoop.on_window_close` event is dispatched on
|
||||
`pyglet.app.event_loop` when this method is called.
|
||||
"""
|
||||
from pyglet import app
|
||||
if not self._context:
|
||||
return
|
||||
app.windows.remove(self)
|
||||
self._context.destroy()
|
||||
self._config = None
|
||||
self._context = None
|
||||
if app.event_loop:
|
||||
app.event_loop.dispatch_event('on_window_close', self)
|
||||
self._event_queue = []
|
||||
|
||||
def dispatch_event(self, *args):
|
||||
if not self._enable_event_queue or self._allow_dispatch_event:
|
||||
super().dispatch_event(*args)
|
||||
else:
|
||||
self._event_queue.append(args)
|
||||
|
||||
def dispatch_events(self):
|
||||
"""Poll the operating system event queue for new events and call
|
||||
attached event handlers.
|
||||
|
||||
This method is provided for legacy applications targeting pyglet 1.0,
|
||||
and advanced applications that must integrate their event loop
|
||||
into another framework.
|
||||
|
||||
Typical applications should use `pyglet.app.run`.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def draw_mouse_cursor(self):
|
||||
"""Draw the custom mouse cursor.
|
||||
|
||||
If the current mouse cursor has ``drawable`` set, this method
|
||||
is called before the buffers are flipped to render it.
|
||||
|
||||
There is little need to override this method; instead, subclass
|
||||
:py:class:`MouseCursor` and provide your own
|
||||
:py:meth:`~MouseCursor.draw` method.
|
||||
"""
|
||||
# Draw mouse cursor if set and visible.
|
||||
|
||||
if self._mouse_cursor.gl_drawable and self._mouse_visible and self._mouse_in_window:
|
||||
# TODO: consider projection differences
|
||||
self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
|
||||
|
||||
def flip(self):
|
||||
"""Swap the OpenGL front and back buffers.
|
||||
|
||||
@ -635,13 +709,124 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def switch_to(self):
|
||||
"""Make this window the current OpenGL rendering context.
|
||||
def get_framebuffer_size(self):
|
||||
"""Return the size in actual pixels of the Window framebuffer.
|
||||
|
||||
When using HiDPI screens, the size of the Window's framebuffer
|
||||
can be higher than that of the Window size requested. If you
|
||||
are performing operations that require knowing the actual number
|
||||
of pixels in the window, this method should be used instead of
|
||||
:py:func:`Window.get_size()`. For example, setting the Window
|
||||
projection or setting the glViewport size.
|
||||
|
||||
:rtype: (int, int)
|
||||
:return: The width and height of the Window's framebuffer, in pixels.
|
||||
"""
|
||||
return self.get_size()
|
||||
|
||||
def get_location(self):
|
||||
"""Return the current position of the window.
|
||||
|
||||
:rtype: (int, int)
|
||||
:return: The distances of the left and top edges from their respective
|
||||
edges on the virtual desktop, in pixels.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def get_pixel_ratio(self):
|
||||
"""Return the framebuffer/window size ratio.
|
||||
|
||||
Some platforms and/or window systems support subpixel scaling,
|
||||
making the framebuffer size larger than the window size.
|
||||
Retina screens on OS X and Gnome on Linux are some examples.
|
||||
|
||||
On a Retina systems the returned ratio would usually be 2.0 as a
|
||||
window of size 500 x 500 would have a framebuffer of 1000 x 1000.
|
||||
Fractional values between 1.0 and 2.0, as well as values above
|
||||
2.0 may also be encountered.
|
||||
|
||||
:rtype: float
|
||||
:return: The framebuffer/window size ratio
|
||||
"""
|
||||
return self.get_framebuffer_size()[0] / self.width
|
||||
|
||||
def get_size(self) -> Tuple[int, int]:
|
||||
"""Return the current size of the window.
|
||||
|
||||
This does not include the windows' border or title bar.
|
||||
|
||||
:rtype: (int, int)
|
||||
:return: The width and height of the window, in pixels.
|
||||
"""
|
||||
return self._width, self._height
|
||||
|
||||
def get_system_mouse_cursor(self, name):
|
||||
"""Obtain a system mouse cursor.
|
||||
|
||||
Use `set_mouse_cursor` to make the cursor returned by this method
|
||||
active. The names accepted by this method are the ``CURSOR_*``
|
||||
constants defined on this class.
|
||||
|
||||
:Parameters:
|
||||
`name` : str
|
||||
Name describing the mouse cursor to return. For example,
|
||||
``CURSOR_WAIT``, ``CURSOR_HELP``, etc.
|
||||
|
||||
:rtype: `MouseCursor`
|
||||
:return: A mouse cursor which can be used with `set_mouse_cursor`.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def minimize(self):
|
||||
"""Minimize the window.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def maximize(self):
|
||||
"""Maximize the window.
|
||||
|
||||
The behaviour of this method is somewhat dependent on the user's
|
||||
display setup. On a multi-monitor system, the window may maximize
|
||||
to either a single screen or the entire virtual desktop.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def on_close(self):
|
||||
"""Default on_close handler."""
|
||||
self.has_exit = True
|
||||
from pyglet import app
|
||||
if app.event_loop.is_running:
|
||||
self.close()
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
"""Default on_key_press handler."""
|
||||
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
|
||||
key.MOD_CAPSLOCK |
|
||||
key.MOD_SCROLLLOCK)):
|
||||
self.dispatch_event('on_close')
|
||||
|
||||
def on_resize(self, width, height):
|
||||
"""A default resize event handler.
|
||||
|
||||
This default handler updates the GL viewport to cover the entire
|
||||
window. The bottom-left corner is (0, 0) and the top-right
|
||||
corner is the width and height of the window's framebuffer.
|
||||
In addition, the projection matrix is set to an orghogonal
|
||||
projection based on the same dimensions.
|
||||
"""
|
||||
gl.glViewport(0, 0, *self.get_framebuffer_size())
|
||||
self.projection = Mat4.orthogonal_projection(0, width, 0, height, -255, 255)
|
||||
|
||||
def set_caption(self, caption):
|
||||
"""Set the window's caption.
|
||||
|
||||
The caption appears in the titlebar of the window, if it has one,
|
||||
and in the taskbar on Windows and many X11 window managers.
|
||||
|
||||
:Parameters:
|
||||
`caption` : str or unicode
|
||||
The caption to set.
|
||||
|
||||
Only one OpenGL context can be active at a time. This method sets
|
||||
the current window's context to be current. You should use this
|
||||
method in preference to `pyglet.gl.Context.set_current`, as it may
|
||||
perform additional initialisation functions.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
@ -740,69 +925,233 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
height = self.screen.height
|
||||
return width, height
|
||||
|
||||
def on_resize(self, width, height):
|
||||
"""A default resize event handler.
|
||||
def set_minimum_size(self, width: int, height: int) -> None:
|
||||
"""Set the minimum size of the window.
|
||||
|
||||
Once set, the user will not be able to resize the window smaller
|
||||
than the given dimensions. There is no way to remove the
|
||||
minimum size constraint on a window (but you could set it to 0,0).
|
||||
|
||||
The behaviour is undefined if the minimum size is set larger than
|
||||
the current size of the window.
|
||||
|
||||
The window size does not include the border or title bar.
|
||||
|
||||
:Parameters:
|
||||
`width` : int
|
||||
Minimum width of the window, in pixels.
|
||||
`height` : int
|
||||
Minimum height of the window, in pixels.
|
||||
|
||||
This default handler updates the GL viewport to cover the entire
|
||||
window. The bottom-left corner is (0, 0) and the top-right
|
||||
corner is the width and height of the window's framebuffer.
|
||||
In addition, the projection matrix is set to an orghogonal
|
||||
projection based on the same dimensions.
|
||||
"""
|
||||
gl.glViewport(0, 0, *self.get_framebuffer_size())
|
||||
self.projection = Mat4.orthogonal_projection(0, width, 0, height, -255, 255)
|
||||
if width < 1 or height < 1:
|
||||
raise ValueError('width and height must be positive integers')
|
||||
|
||||
def on_close(self):
|
||||
"""Default on_close handler."""
|
||||
self.has_exit = True
|
||||
from pyglet import app
|
||||
if app.event_loop.is_running:
|
||||
self.close()
|
||||
self._minimum_size = width, height
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
"""Default on_key_press handler."""
|
||||
if symbol == key.ESCAPE and not (modifiers & ~(key.MOD_NUMLOCK |
|
||||
key.MOD_CAPSLOCK |
|
||||
key.MOD_SCROLLLOCK)):
|
||||
self.dispatch_event('on_close')
|
||||
def set_maximum_size(self, width: int, height: int) -> None:
|
||||
"""Set the maximum size of the window.
|
||||
|
||||
def close(self):
|
||||
"""Close the window.
|
||||
Once set, the user will not be able to resize the window larger
|
||||
than the given dimensions. There is no way to remove the
|
||||
maximum size constraint on a window (but you could set it to a large
|
||||
value).
|
||||
|
||||
After closing the window, the GL context will be invalid. The
|
||||
window instance cannot be reused once closed (see also `set_visible`).
|
||||
The behaviour is undefined if the maximum size is set smaller than
|
||||
the current size of the window.
|
||||
|
||||
The window size does not include the border or title bar.
|
||||
|
||||
:Parameters:
|
||||
`width` : int
|
||||
Maximum width of the window, in pixels.
|
||||
`height` : int
|
||||
Maximum height of the window, in pixels.
|
||||
|
||||
The `pyglet.app.EventLoop.on_window_close` event is dispatched on
|
||||
`pyglet.app.event_loop` when this method is called.
|
||||
"""
|
||||
from pyglet import app
|
||||
if not self._context:
|
||||
return
|
||||
app.windows.remove(self)
|
||||
self._context.destroy()
|
||||
self._config = None
|
||||
self._context = None
|
||||
if app.event_loop:
|
||||
app.event_loop.dispatch_event('on_window_close', self)
|
||||
self._event_queue = []
|
||||
if width < 1 or height < 1:
|
||||
raise ValueError('width and height must be positive integers')
|
||||
|
||||
def draw_mouse_cursor(self):
|
||||
"""Draw the custom mouse cursor.
|
||||
self._maximum_size = width, height
|
||||
|
||||
If the current mouse cursor has ``drawable`` set, this method
|
||||
is called before the buffers are flipped to render it.
|
||||
def set_size(self, width: int, height: int) -> None:
|
||||
"""Resize the window.
|
||||
|
||||
The behaviour is undefined if the window is not resizable, or if
|
||||
it is currently fullscreen.
|
||||
|
||||
The window size does not include the border or title bar.
|
||||
|
||||
:Parameters:
|
||||
`width` : int
|
||||
New width of the window, in pixels.
|
||||
`height` : int
|
||||
New height of the window, in pixels.
|
||||
|
||||
There is little need to override this method; instead, subclass
|
||||
:py:class:`MouseCursor` and provide your own
|
||||
:py:meth:`~MouseCursor.draw` method.
|
||||
"""
|
||||
# Draw mouse cursor if set and visible.
|
||||
if self._fullscreen:
|
||||
raise WindowException('Cannot set size of fullscreen window.')
|
||||
if width < 1 or height < 1:
|
||||
raise ValueError('width and height must be positive integers')
|
||||
|
||||
if self._mouse_cursor.gl_drawable and self._mouse_visible and self._mouse_in_window:
|
||||
# TODO: consider projection differences
|
||||
self._mouse_cursor.draw(self._mouse_x, self._mouse_y)
|
||||
self._width, self._height = width, height
|
||||
|
||||
# These properties provide read-only access to instance variables.
|
||||
def set_location(self, x, y):
|
||||
"""Set the position of the window.
|
||||
|
||||
:Parameters:
|
||||
`x` : int
|
||||
Distance of the left edge of the window from the left edge
|
||||
of the virtual desktop, in pixels.
|
||||
`y` : int
|
||||
Distance of the top edge of the window from the top edge of
|
||||
the virtual desktop, in pixels.
|
||||
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
def set_visible(self, visible: bool = True) -> None:
|
||||
"""Show or hide the window.
|
||||
|
||||
:Parameters:
|
||||
`visible` : bool
|
||||
If True, the window will be shown; otherwise it will be
|
||||
hidden.
|
||||
"""
|
||||
self._visible = visible
|
||||
|
||||
def set_vsync(self, vsync: bool) -> None:
|
||||
"""Enable or disable vertical sync control.
|
||||
|
||||
When enabled, this option ensures flips from the back to the front
|
||||
buffer are performed only during the vertical retrace period of the
|
||||
primary display. This can prevent "tearing" or flickering when
|
||||
the buffer is updated in the middle of a video scan.
|
||||
|
||||
Note that LCD monitors have an analogous time in which they are not
|
||||
reading from the video buffer; while it does not correspond to
|
||||
a vertical retrace it has the same effect.
|
||||
|
||||
Also note that with multi-monitor systems the secondary monitor
|
||||
cannot be synchronised to, so tearing and flicker cannot be avoided
|
||||
when the window is positioned outside of the primary display.
|
||||
|
||||
:Parameters:
|
||||
`vsync` : bool
|
||||
If True, vsync is enabled, otherwise it is disabled.
|
||||
|
||||
"""
|
||||
self._vsync = vsync
|
||||
|
||||
def set_mouse_visible(self, visible=True):
|
||||
"""Show or hide the mouse cursor.
|
||||
|
||||
The mouse cursor will only be hidden while it is positioned within
|
||||
this window. Mouse events will still be processed as usual.
|
||||
|
||||
:Parameters:
|
||||
`visible` : bool
|
||||
If True, the mouse cursor will be visible, otherwise it
|
||||
will be hidden.
|
||||
|
||||
"""
|
||||
self._mouse_visible = visible
|
||||
self.set_mouse_platform_visible()
|
||||
|
||||
def set_mouse_platform_visible(self, platform_visible=None):
|
||||
"""Set the platform-drawn mouse cursor visibility. This is called
|
||||
automatically after changing the mouse cursor or exclusive mode.
|
||||
|
||||
Applications should not normally need to call this method, see
|
||||
`set_mouse_visible` instead.
|
||||
|
||||
:Parameters:
|
||||
`platform_visible` : bool or None
|
||||
If None, sets platform visibility to the required visibility
|
||||
for the current exclusive mode and cursor type. Otherwise,
|
||||
a bool value will override and force a visibility.
|
||||
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_mouse_cursor(self, cursor=None):
|
||||
"""Change the appearance of the mouse cursor.
|
||||
|
||||
The appearance of the mouse cursor is only changed while it is
|
||||
within this window.
|
||||
|
||||
:Parameters:
|
||||
`cursor` : `MouseCursor`
|
||||
The cursor to set, or None to restore the default cursor.
|
||||
|
||||
"""
|
||||
if cursor is None:
|
||||
cursor = DefaultMouseCursor()
|
||||
self._mouse_cursor = cursor
|
||||
self.set_mouse_platform_visible()
|
||||
|
||||
def set_exclusive_mouse(self, exclusive=True):
|
||||
"""Hide the mouse cursor and direct all mouse events to this
|
||||
window.
|
||||
|
||||
When enabled, this feature prevents the mouse leaving the window. It
|
||||
is useful for certain styles of games that require complete control of
|
||||
the mouse. The position of the mouse as reported in subsequent events
|
||||
is meaningless when exclusive mouse is enabled; you should only use
|
||||
the relative motion parameters ``dx`` and ``dy``.
|
||||
|
||||
:Parameters:
|
||||
`exclusive` : bool
|
||||
If True, exclusive mouse is enabled, otherwise it is disabled.
|
||||
|
||||
"""
|
||||
self._mouse_exclusive = exclusive
|
||||
|
||||
def set_exclusive_keyboard(self, exclusive=True):
|
||||
"""Prevent the user from switching away from this window using
|
||||
keyboard accelerators.
|
||||
|
||||
When enabled, this feature disables certain operating-system specific
|
||||
key combinations such as Alt+Tab (Command+Tab on OS X). This can be
|
||||
useful in certain kiosk applications, it should be avoided in general
|
||||
applications or games.
|
||||
|
||||
:Parameters:
|
||||
`exclusive` : bool
|
||||
If True, exclusive keyboard is enabled, otherwise it is
|
||||
disabled.
|
||||
|
||||
"""
|
||||
self._keyboard_exclusive = exclusive
|
||||
|
||||
def set_icon(self, *images):
|
||||
"""Set the window icon.
|
||||
|
||||
If multiple images are provided, one with an appropriate size
|
||||
will be selected (if the correct size is not provided, the image
|
||||
will be scaled).
|
||||
|
||||
Useful sizes to provide are 16x16, 32x32, 64x64 (Mac only) and
|
||||
128x128 (Mac only).
|
||||
|
||||
:Parameters:
|
||||
`images` : sequence of `pyglet.image.AbstractImage`
|
||||
List of images to use for the window icon.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def switch_to(self):
|
||||
"""Make this window the current OpenGL rendering context.
|
||||
|
||||
Only one OpenGL context can be active at a time. This method sets
|
||||
the current window's context to be current. You should use this
|
||||
method in preference to `pyglet.gl.Context.set_current`, as it may
|
||||
perform additional initialisation functions.
|
||||
"""
|
||||
raise NotImplementedError('abstract')
|
||||
|
||||
# Attributes (sort alphabetically):
|
||||
@property
|
||||
def caption(self):
|
||||
"""The window caption (title). Read-only.
|
||||
@ -935,6 +1284,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
def projection(self):
|
||||
"""The OpenGL window projection matrix. Read-write.
|
||||
|
||||
This matrix is used to transform vertices when using any of the built-in
|
||||
drawable classes. `view` is done first, then `projection`.
|
||||
|
||||
The default projection matrix is orthographic (2D),
|
||||
but a custom :py:class:`pyglet.math.Mat4` instance
|
||||
can be set. Alternatively, you can supply a flat
|
||||
@ -959,6 +1311,9 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
def view(self):
|
||||
"""The OpenGL window view matrix. Read-write.
|
||||
|
||||
This matrix is used to transform vertices when using any of the built-in
|
||||
drawable classes. `view` is done first, then `projection`.
|
||||
|
||||
The default view is an identity matrix, but a custom
|
||||
:py:class:`pyglet.math.Mat4` instance can be set.
|
||||
Alternatively, you can supply a flat tuple of 16 values.
|
||||
@ -1344,6 +1699,118 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
# If documenting, show the event methods. Otherwise, leave them out
|
||||
# as they are not really methods.
|
||||
if _is_pyglet_doc_run:
|
||||
def on_activate(self):
|
||||
"""The window was activated.
|
||||
|
||||
This event can be triggered by clicking on the title bar, bringing
|
||||
it to the foreground; or by some platform-specific method.
|
||||
|
||||
When a window is "active" it has the keyboard focus.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_close(self):
|
||||
"""The user attempted to close the window.
|
||||
|
||||
This event can be triggered by clicking on the "X" control box in
|
||||
the window title bar, or by some other platform-dependent manner.
|
||||
|
||||
The default handler sets `has_exit` to ``True``. In pyglet 1.1, if
|
||||
`pyglet.app.event_loop` is being used, `close` is also called,
|
||||
closing the window immediately.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_context_lost(self):
|
||||
"""The window's GL context was lost.
|
||||
|
||||
When the context is lost no more GL methods can be called until it
|
||||
is recreated. This is a rare event, triggered perhaps by the user
|
||||
switching to an incompatible video mode. When it occurs, an
|
||||
application will need to reload all objects (display lists, texture
|
||||
objects, shaders) as well as restore the GL state.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_context_state_lost(self):
|
||||
"""The state of the window's GL context was lost.
|
||||
|
||||
pyglet may sometimes need to recreate the window's GL context if
|
||||
the window is moved to another video device, or between fullscreen
|
||||
or windowed mode. In this case it will try to share the objects
|
||||
(display lists, texture objects, shaders) between the old and new
|
||||
contexts. If this is possible, only the current state of the GL
|
||||
context is lost, and the application should simply restore state.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_deactivate(self):
|
||||
"""The window was deactivated.
|
||||
|
||||
This event can be triggered by clicking on another application
|
||||
window. When a window is deactivated it no longer has the
|
||||
keyboard focus.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_draw(self, dt):
|
||||
"""The window contents must be redrawn.
|
||||
|
||||
The `EventLoop` will dispatch this event when the window
|
||||
should be redrawn. This will happen during idle time after
|
||||
any window events and after any scheduled functions were called.
|
||||
|
||||
The window will already have the GL context, so there is no
|
||||
need to call `switch_to`. The window's `flip` method will
|
||||
be called after this event, so your event handler should not.
|
||||
|
||||
You should make no assumptions about the window contents when
|
||||
this event is triggered; a resize or expose event may have
|
||||
invalidated the framebuffer since the last time it was drawn.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_expose(self):
|
||||
"""A portion of the window needs to be redrawn.
|
||||
|
||||
This event is triggered when the window first appears, and any time
|
||||
the contents of the window is invalidated due to another window
|
||||
obscuring it.
|
||||
|
||||
There is no way to determine which portion of the window needs
|
||||
redrawing. Note that the use of this method is becoming
|
||||
increasingly uncommon, as newer window managers composite windows
|
||||
automatically and keep a backing store of the window contents.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_file_drop(self, x, y, paths):
|
||||
"""File(s) were dropped into the window, will return the position of the cursor and
|
||||
a list of paths to the files that were dropped.
|
||||
|
||||
.. versionadded:: 1.5.1
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_hide(self):
|
||||
"""The window was hidden.
|
||||
|
||||
This event is triggered when a window is minimised
|
||||
or hidden by the user.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
"""A key on the keyboard was pressed (and held down).
|
||||
|
||||
@ -1371,96 +1838,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text(self, text):
|
||||
"""The user input some text.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is held down (key repeating); or called without key presses if
|
||||
another input method was used (e.g., a pen input).
|
||||
|
||||
You should always use this method for interpreting text, as the
|
||||
key symbols often have complex mappings to their unicode
|
||||
representation which this event takes care of.
|
||||
|
||||
:Parameters:
|
||||
`text` : unicode
|
||||
The text entered by the user.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text_motion(self, motion):
|
||||
"""The user moved the text input cursor.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is help down (key repeating).
|
||||
|
||||
You should always use this method for moving the text input cursor
|
||||
(caret), as different platforms have different default keyboard
|
||||
mappings, and key repeats are handled correctly.
|
||||
|
||||
The values that `motion` can take are defined in
|
||||
:py:mod:`pyglet.window.key`:
|
||||
|
||||
* MOTION_UP
|
||||
* MOTION_RIGHT
|
||||
* MOTION_DOWN
|
||||
* MOTION_LEFT
|
||||
* MOTION_NEXT_WORD
|
||||
* MOTION_PREVIOUS_WORD
|
||||
* MOTION_BEGINNING_OF_LINE
|
||||
* MOTION_END_OF_LINE
|
||||
* MOTION_NEXT_PAGE
|
||||
* MOTION_PREVIOUS_PAGE
|
||||
* MOTION_BEGINNING_OF_FILE
|
||||
* MOTION_END_OF_FILE
|
||||
* MOTION_BACKSPACE
|
||||
* MOTION_DELETE
|
||||
|
||||
:Parameters:
|
||||
`motion` : int
|
||||
The direction of motion; see remarks.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text_motion_select(self, motion):
|
||||
"""The user moved the text input cursor while extending the
|
||||
selection.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is help down (key repeating).
|
||||
|
||||
You should always use this method for responding to text selection
|
||||
events rather than the raw :py:meth:`~pyglet.window.Window.on_key_press`, as different platforms
|
||||
have different default keyboard mappings, and key repeats are
|
||||
handled correctly.
|
||||
|
||||
The values that `motion` can take are defined in :py:mod:`pyglet.window.key`:
|
||||
|
||||
* MOTION_UP
|
||||
* MOTION_RIGHT
|
||||
* MOTION_DOWN
|
||||
* MOTION_LEFT
|
||||
* MOTION_NEXT_WORD
|
||||
* MOTION_PREVIOUS_WORD
|
||||
* MOTION_BEGINNING_OF_LINE
|
||||
* MOTION_END_OF_LINE
|
||||
* MOTION_NEXT_PAGE
|
||||
* MOTION_PREVIOUS_PAGE
|
||||
* MOTION_BEGINNING_OF_FILE
|
||||
* MOTION_END_OF_FILE
|
||||
|
||||
:Parameters:
|
||||
`motion` : int
|
||||
The direction of selection motion; see remarks.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_motion(self, x, y, dx, dy):
|
||||
"""The mouse was moved with no buttons held down.
|
||||
|
||||
@ -1556,19 +1933,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_close(self):
|
||||
"""The user attempted to close the window.
|
||||
|
||||
This event can be triggered by clicking on the "X" control box in
|
||||
the window title bar, or by some other platform-dependent manner.
|
||||
|
||||
The default handler sets `has_exit` to ``True``. In pyglet 1.1, if
|
||||
`pyglet.app.event_loop` is being used, `close` is also called,
|
||||
closing the window immediately.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_mouse_enter(self, x, y):
|
||||
"""The mouse was moved into the window.
|
||||
|
||||
@ -1600,36 +1964,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_expose(self):
|
||||
"""A portion of the window needs to be redrawn.
|
||||
|
||||
This event is triggered when the window first appears, and any time
|
||||
the contents of the window is invalidated due to another window
|
||||
obscuring it.
|
||||
|
||||
There is no way to determine which portion of the window needs
|
||||
redrawing. Note that the use of this method is becoming
|
||||
increasingly uncommon, as newer window managers composite windows
|
||||
automatically and keep a backing store of the window contents.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_resize(self, width, height):
|
||||
"""The window was resized.
|
||||
|
||||
The window will have the GL context when this event is dispatched;
|
||||
there is no need to call `switch_to` in this handler.
|
||||
|
||||
:Parameters:
|
||||
`width` : int
|
||||
The new width of the window, in pixels.
|
||||
`height` : int
|
||||
The new height of the window, in pixels.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_move(self, x, y):
|
||||
"""The window was moved.
|
||||
|
||||
@ -1645,99 +1979,6 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_activate(self):
|
||||
"""The window was activated.
|
||||
|
||||
This event can be triggered by clicking on the title bar, bringing
|
||||
it to the foreground; or by some platform-specific method.
|
||||
|
||||
When a window is "active" it has the keyboard focus.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_deactivate(self):
|
||||
"""The window was deactivated.
|
||||
|
||||
This event can be triggered by clicking on another application
|
||||
window. When a window is deactivated it no longer has the
|
||||
keyboard focus.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_show(self):
|
||||
"""The window was shown.
|
||||
|
||||
This event is triggered when a window is restored after being
|
||||
minimised, hidden, or after being displayed for the first time.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_hide(self):
|
||||
"""The window was hidden.
|
||||
|
||||
This event is triggered when a window is minimised
|
||||
or hidden by the user.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_context_lost(self):
|
||||
"""The window's GL context was lost.
|
||||
|
||||
When the context is lost no more GL methods can be called until it
|
||||
is recreated. This is a rare event, triggered perhaps by the user
|
||||
switching to an incompatible video mode. When it occurs, an
|
||||
application will need to reload all objects (display lists, texture
|
||||
objects, shaders) as well as restore the GL state.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_context_state_lost(self):
|
||||
"""The state of the window's GL context was lost.
|
||||
|
||||
pyglet may sometimes need to recreate the window's GL context if
|
||||
the window is moved to another video device, or between fullscreen
|
||||
or windowed mode. In this case it will try to share the objects
|
||||
(display lists, texture objects, shaders) between the old and new
|
||||
contexts. If this is possible, only the current state of the GL
|
||||
context is lost, and the application should simply restore state.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_file_drop(self, x, y, paths):
|
||||
"""File(s) were dropped into the window, will return the position of the cursor and
|
||||
a list of paths to the files that were dropped.
|
||||
|
||||
.. versionadded:: 1.5.1
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_draw(self, dt):
|
||||
"""The window contents must be redrawn.
|
||||
|
||||
The `EventLoop` will dispatch this event when the window
|
||||
should be redrawn. This will happen during idle time after
|
||||
any window events and after any scheduled functions were called.
|
||||
|
||||
The window will already have the GL context, so there is no
|
||||
need to call `switch_to`. The window's `flip` method will
|
||||
be called after this event, so your event handler should not.
|
||||
|
||||
You should make no assumptions about the window contents when
|
||||
this event is triggered; a resize or expose event may have
|
||||
invalidated the framebuffer since the last time it was drawn.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_refresh(self, dt):
|
||||
"""The window contents must be redrawn.
|
||||
|
||||
@ -1757,6 +1998,120 @@ class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_resize(self, width, height):
|
||||
"""The window was resized.
|
||||
|
||||
The window will have the GL context when this event is dispatched;
|
||||
there is no need to call `switch_to` in this handler.
|
||||
|
||||
:Parameters:
|
||||
`width` : int
|
||||
The new width of the window, in pixels.
|
||||
`height` : int
|
||||
The new height of the window, in pixels.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_show(self):
|
||||
"""The window was shown.
|
||||
|
||||
This event is triggered when a window is restored after being
|
||||
minimised, hidden, or after being displayed for the first time.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text(self, text):
|
||||
"""The user input some text.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is held down (key repeating); or called without key presses if
|
||||
another input method was used (e.g., a pen input).
|
||||
|
||||
You should always use this method for interpreting text, as the
|
||||
key symbols often have complex mappings to their unicode
|
||||
representation which this event takes care of.
|
||||
|
||||
:Parameters:
|
||||
`text` : unicode
|
||||
The text entered by the user.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text_motion(self, motion):
|
||||
"""The user moved the text input cursor.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is help down (key repeating).
|
||||
|
||||
You should always use this method for moving the text input cursor
|
||||
(caret), as different platforms have different default keyboard
|
||||
mappings, and key repeats are handled correctly.
|
||||
|
||||
The values that `motion` can take are defined in
|
||||
:py:mod:`pyglet.window.key`:
|
||||
|
||||
* MOTION_UP
|
||||
* MOTION_RIGHT
|
||||
* MOTION_DOWN
|
||||
* MOTION_LEFT
|
||||
* MOTION_NEXT_WORD
|
||||
* MOTION_PREVIOUS_WORD
|
||||
* MOTION_BEGINNING_OF_LINE
|
||||
* MOTION_END_OF_LINE
|
||||
* MOTION_NEXT_PAGE
|
||||
* MOTION_PREVIOUS_PAGE
|
||||
* MOTION_BEGINNING_OF_FILE
|
||||
* MOTION_END_OF_FILE
|
||||
* MOTION_BACKSPACE
|
||||
* MOTION_DELETE
|
||||
|
||||
:Parameters:
|
||||
`motion` : int
|
||||
The direction of motion; see remarks.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
def on_text_motion_select(self, motion):
|
||||
"""The user moved the text input cursor while extending the
|
||||
selection.
|
||||
|
||||
Typically this is called after :py:meth:`~pyglet.window.Window.on_key_press` and before
|
||||
:py:meth:`~pyglet.window.Window.on_key_release`, but may also be called multiple times if the key
|
||||
is help down (key repeating).
|
||||
|
||||
You should always use this method for responding to text selection
|
||||
events rather than the raw :py:meth:`~pyglet.window.Window.on_key_press`, as different platforms
|
||||
have different default keyboard mappings, and key repeats are
|
||||
handled correctly.
|
||||
|
||||
The values that `motion` can take are defined in :py:mod:`pyglet.window.key`:
|
||||
|
||||
* MOTION_UP
|
||||
* MOTION_RIGHT
|
||||
* MOTION_DOWN
|
||||
* MOTION_LEFT
|
||||
* MOTION_NEXT_WORD
|
||||
* MOTION_PREVIOUS_WORD
|
||||
* MOTION_BEGINNING_OF_LINE
|
||||
* MOTION_END_OF_LINE
|
||||
* MOTION_NEXT_PAGE
|
||||
* MOTION_PREVIOUS_PAGE
|
||||
* MOTION_BEGINNING_OF_FILE
|
||||
* MOTION_END_OF_FILE
|
||||
|
||||
:Parameters:
|
||||
`motion` : int
|
||||
The direction of selection motion; see remarks.
|
||||
|
||||
:event:
|
||||
"""
|
||||
|
||||
|
||||
BaseWindow.register_event_type('on_key_press')
|
||||
BaseWindow.register_event_type('on_key_release')
|
||||
|
Loading…
Reference in New Issue
Block a user