Compare commits
31 Commits
e658fa3188
...
5cb642ea3c
Author | SHA1 | Date | |
---|---|---|---|
5cb642ea3c | |||
2e9e3afc39 | |||
2e509575cd | |||
33d5788826 | |||
6dbffb322d | |||
bff9649ca9 | |||
5f335fa9b5 | |||
4b639c37e0 | |||
cc5dec9122 | |||
05ac9871da | |||
dd5dca1099 | |||
804dbfc992 | |||
8e494faa63 | |||
42eef6743d | |||
6fefb4460b | |||
8dfa5b230a | |||
726ba4ac17 | |||
ede6f9ff6e | |||
d6f0caf2ae | |||
d398ed1af9 | |||
e888ddfdad | |||
82111be30b | |||
39379c1621 | |||
3595f98dc1 | |||
aa8af9ebef | |||
692483320b | |||
09e386e0fe | |||
55e83b708f | |||
7278368b4c | |||
a2f12c2e77 | |||
47d2629610 |
@ -10,7 +10,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from Difficult_Rocket.api.types import Options, Version
|
from Difficult_Rocket.api.types import Options, Version
|
||||||
|
|
||||||
sdk_version = Version("0.8.6.0") # SDK 版本
|
sdk_version = Version("0.8.7.0") # SDK 版本
|
||||||
build_version = Version("2.1.3.0") # 编译文件版本(与游戏本体无关)
|
build_version = Version("2.1.3.0") # 编译文件版本(与游戏本体无关)
|
||||||
Api_version = Version("0.1.1.0") # API 版本
|
Api_version = Version("0.1.1.0") # API 版本
|
||||||
__version__ = sdk_version
|
__version__ = sdk_version
|
||||||
|
@ -4,9 +4,14 @@
|
|||||||
# All rights reserved
|
# All rights reserved
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
|
|
||||||
from Difficult_Rocket.utils.camera import (Camera, CenterCamera)
|
from Difficult_Rocket.utils.camera import (Camera,
|
||||||
|
CenterCamera,
|
||||||
|
GroupCamera,
|
||||||
|
CenterGroupCamera)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Camera',
|
'Camera',
|
||||||
'CenterCamera'
|
'CenterCamera',
|
||||||
|
'GroupCamera',
|
||||||
|
'CenterGroupCamera'
|
||||||
]
|
]
|
||||||
|
9
Difficult_Rocket/api/gui/__init__.py
Normal file
9
Difficult_Rocket/api/gui/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# -------------------------------
|
||||||
|
# Difficult Rocket
|
||||||
|
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||||
|
# All rights reserved
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'widget'
|
||||||
|
]
|
11
Difficult_Rocket/api/gui/widget/__init__.py
Normal file
11
Difficult_Rocket/api/gui/widget/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# -------------------------------
|
||||||
|
# Difficult Rocket
|
||||||
|
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||||
|
# All rights reserved
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
from Difficult_Rocket.gui.widget.button import PressTextButton
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'PressTextButton'
|
||||||
|
]
|
@ -112,6 +112,7 @@ class BaseScreen(EventDispatcher):
|
|||||||
:event:
|
:event:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# def on_draw(self, dt: float, window: ClientWindow): # TODO: wait for pyglet 2.1
|
||||||
def on_draw(self, window: ClientWindow):
|
def on_draw(self, window: ClientWindow):
|
||||||
"""The window contents must be redrawn.
|
"""The window contents must be redrawn.
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ class ClientWindow(Window):
|
|||||||
batch=self.main_batch, text='', group=Group(1000, parent=self.main_group)) # 实例化
|
batch=self.main_batch, text='', group=Group(1000, parent=self.main_group)) # 实例化
|
||||||
self.input_box.push_handlers(self)
|
self.input_box.push_handlers(self)
|
||||||
self.input_box.set_handler('on_commit', self.on_input)
|
self.input_box.set_handler('on_commit', self.on_input)
|
||||||
self.set_handlers(self.input_box)
|
self.push_handlers(self.input_box)
|
||||||
self.input_box.enabled = True
|
self.input_box.enabled = True
|
||||||
# 设置刷新率
|
# 设置刷新率
|
||||||
# pyglet.clock.schedule_interval(self.draw_update, float(self.SPF))
|
# pyglet.clock.schedule_interval(self.draw_update, float(self.SPF))
|
||||||
@ -275,7 +275,10 @@ class ClientWindow(Window):
|
|||||||
def start_game(self) -> None:
|
def start_game(self) -> None:
|
||||||
self.set_icon(pyglet.image.load('assets/textures/icon.png'))
|
self.set_icon(pyglet.image.load('assets/textures/icon.png'))
|
||||||
try:
|
try:
|
||||||
pyglet.app.run(1 / self.main_config['runtime']['fps'])
|
# pyglet.clock.schedule_interval(self.on_draw, float(self.SPF))
|
||||||
|
# pyglet.app.run()
|
||||||
|
# TODO: wait for pyglet 2.1
|
||||||
|
pyglet.app.run(float(self.SPF))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
self.logger.warning("==========client stop. KeyboardInterrupt info==========")
|
self.logger.warning("==========client stop. KeyboardInterrupt info==========")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@ -314,11 +317,13 @@ class ClientWindow(Window):
|
|||||||
self.fps_log.update_tick(now_FPS, decimal_tick)
|
self.fps_log.update_tick(now_FPS, decimal_tick)
|
||||||
|
|
||||||
@_call_screen_after
|
@_call_screen_after
|
||||||
def on_draw(self, *dt):
|
# def on_draw(self, dt: float): # TODO: wait for pyglet 2.1
|
||||||
|
def on_draw(self):
|
||||||
while (command := self.game.console.get_command()) is not None:
|
while (command := self.game.console.get_command()) is not None:
|
||||||
self.on_command(line.CommandText(command))
|
self.on_command(line.CommandText(command))
|
||||||
pyglet.gl.glClearColor(0.1, 0, 0, 0.0)
|
pyglet.gl.glClearColor(0.1, 0, 0, 0.0)
|
||||||
self.clear()
|
self.clear()
|
||||||
|
# self.draw_update(dt) # TODO: wait for pyglet 2.1
|
||||||
self.draw_update(float(self.SPF))
|
self.draw_update(float(self.SPF))
|
||||||
self.draw_batch()
|
self.draw_batch()
|
||||||
|
|
||||||
@ -419,7 +424,7 @@ class ClientWindow(Window):
|
|||||||
...
|
...
|
||||||
|
|
||||||
@_call_screen_after
|
@_call_screen_after
|
||||||
def on_mouse_motion(self, x, y, dx, dy) -> None:
|
def on_mouse_motion(self, x, y, dx, dy):
|
||||||
...
|
...
|
||||||
|
|
||||||
@_call_screen_after
|
@_call_screen_after
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
# -------------------------------
|
|
||||||
# Difficult Rocket
|
|
||||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
|
||||||
# All rights reserved
|
|
||||||
# -------------------------------
|
|
||||||
|
|
||||||
"""
|
|
||||||
writen by shenjackyuanjie
|
|
||||||
mail: 3695888@qq.com
|
|
||||||
github: @shenjackyuanjie
|
|
||||||
gitee: @shenjackyuanjie
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Optional, Union, Tuple
|
|
||||||
|
|
||||||
# from libs import pyglet
|
|
||||||
# from pyglet import font
|
|
||||||
from pyglet.text import Label, HTMLLabel
|
|
||||||
# from pyglet.window import key
|
|
||||||
from pyglet.gui import widgets
|
|
||||||
# from pyglet.sprite import Sprite
|
|
||||||
from pyglet.shapes import Rectangle
|
|
||||||
# from pyglet.image import AbstractImage
|
|
||||||
from pyglet.graphics import Batch, Group
|
|
||||||
from pyglet.text.caret import Caret
|
|
||||||
from pyglet.text.document import UnformattedDocument
|
|
||||||
from pyglet.text.layout import IncrementalTextLayout
|
|
||||||
|
|
||||||
# from libs import pyperclip
|
|
||||||
# from libs.pyperclip import paste
|
|
||||||
|
|
||||||
from Difficult_Rocket.api.types import FontData, Fonts
|
|
||||||
# from Difficult_Rocket.client.guis.format import html
|
|
||||||
from Difficult_Rocket import DR_status
|
|
||||||
|
|
||||||
__all__ = ['InputBox']
|
|
||||||
|
|
||||||
|
|
||||||
class TextButton(widgets.WidgetBase):
|
|
||||||
"""
|
|
||||||
自带字符的按钮,就不用单独做材质了
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
x: int, y: int, width: int, height: int,
|
|
||||||
text: str,
|
|
||||||
font: str = Fonts.鸿蒙简体, font_size: int = 13):
|
|
||||||
super().__init__(x, y, width, height)
|
|
||||||
self.text = text
|
|
||||||
self.text_label = Label(
|
|
||||||
font_name=font, font_size=font_size)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def value(self):
|
|
||||||
return self.text
|
|
||||||
|
|
||||||
def _update_position(self):
|
|
||||||
self.text_label.position = self._x, self._y
|
|
||||||
...
|
|
125
Difficult_Rocket/gui/widget/button.py
Normal file
125
Difficult_Rocket/gui/widget/button.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# -------------------------------
|
||||||
|
# Difficult Rocket
|
||||||
|
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||||
|
# All rights reserved
|
||||||
|
# -------------------------------
|
||||||
|
|
||||||
|
"""
|
||||||
|
writen by shenjackyuanjie
|
||||||
|
mail: 3695888@qq.com
|
||||||
|
github: @shenjackyuanjie
|
||||||
|
gitee: @shenjackyuanjie
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Optional, Union, Tuple
|
||||||
|
|
||||||
|
# from libs import pyglet
|
||||||
|
# from pyglet import font
|
||||||
|
from pyglet.text import Label
|
||||||
|
from pyglet.window import mouse
|
||||||
|
from pyglet.gui import widgets
|
||||||
|
# from pyglet.sprite import Sprite
|
||||||
|
from pyglet.shapes import Rectangle
|
||||||
|
# from pyglet.image import AbstractImage
|
||||||
|
from pyglet.graphics import Batch, Group
|
||||||
|
|
||||||
|
from Difficult_Rocket.api.types import Fonts
|
||||||
|
|
||||||
|
# from Difficult_Rocket import DR_status
|
||||||
|
|
||||||
|
|
||||||
|
RGBA = Tuple[int, int, int, int]
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTheme:
|
||||||
|
"""
|
||||||
|
用于定义主题的类
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
main_color: RGBA = (39, 73, 114, 256),
|
||||||
|
secondary_color: RGBA = (66, 150, 250, 256),
|
||||||
|
main_font: str = Fonts.鸿蒙简体,
|
||||||
|
):
|
||||||
|
self.main_color = main_color
|
||||||
|
self.secondary_color = secondary_color
|
||||||
|
self.main_font = main_font
|
||||||
|
|
||||||
|
|
||||||
|
class PressTextButton(widgets.WidgetBase):
|
||||||
|
"""
|
||||||
|
自带 字符 + 材质 的按钮,就不用单独做材质了
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
text: str,
|
||||||
|
font: str = Fonts.鸿蒙简体,
|
||||||
|
font_size: int = 13,
|
||||||
|
batch: Optional[Batch] = None,
|
||||||
|
group: Optional[Group] = None,
|
||||||
|
):
|
||||||
|
super().__init__(x, y, width, height)
|
||||||
|
self.back_ground_batch = batch or Batch()
|
||||||
|
self.front_batch = batch or Batch()
|
||||||
|
if group:
|
||||||
|
self.front_group = Group(order=10, parent=group)
|
||||||
|
self.back_ground_group = Group(order=5, parent=group)
|
||||||
|
else:
|
||||||
|
self.front_group = Group(order=5)
|
||||||
|
self.back_ground_group = Group(order=10)
|
||||||
|
|
||||||
|
self.pressed = False
|
||||||
|
|
||||||
|
self.untouched_color = (39, 73, 114, 255)
|
||||||
|
self.touched_color = (66, 150, 250, 255)
|
||||||
|
self.hit_color = (15, 135, 250, 255)
|
||||||
|
# from ImGui
|
||||||
|
|
||||||
|
self.text = text
|
||||||
|
self.text_label = Label(font_name=font, font_size=font_size,
|
||||||
|
batch=self.front_batch, group=self.front_group,
|
||||||
|
x=self._x, y=self._y, text=self.text)
|
||||||
|
self.back_rec = Rectangle(x=self._x, y=self._y, width=self._width, height=self._height,
|
||||||
|
color=self.untouched_color, # ImGui color
|
||||||
|
batch=self.back_ground_batch, group=self.back_ground_group)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
return self.text
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return item in self.back_rec
|
||||||
|
|
||||||
|
def on_mouse_motion(self, x, y, dx, dy):
|
||||||
|
if (x, y) in self.back_rec:
|
||||||
|
self.back_rec.color = self.touched_color
|
||||||
|
else:
|
||||||
|
self.pressed = False
|
||||||
|
self.back_rec.color = self.untouched_color
|
||||||
|
|
||||||
|
def on_mouse_press(self, x, y, buttons, modifiers) -> bool:
|
||||||
|
if (x, y) in self and buttons == mouse.LEFT:
|
||||||
|
self.back_rec.color = self.hit_color
|
||||||
|
self.dispatch_event('on_press', x, y)
|
||||||
|
self.pressed = True
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_mouse_release(self, x, y, buttons, modifiers):
|
||||||
|
if self.pressed and (x, y) in self:
|
||||||
|
self.back_rec.color = self.touched_color
|
||||||
|
self.pressed = False
|
||||||
|
|
||||||
|
def _update_position(self):
|
||||||
|
self.text_label.position = self._x, self._y
|
||||||
|
self.back_rec.position = self._x, self._y
|
||||||
|
self.back_rec.width = self._width
|
||||||
|
self.back_rec.height = self._height
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
PressTextButton.register_event_type('on_press')
|
@ -3,11 +3,14 @@
|
|||||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||||
# All rights reserved
|
# All rights reserved
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
|
|
||||||
# Huge thanks to pyglet developers
|
# Huge thanks to pyglet developers
|
||||||
|
|
||||||
from typing import Tuple, Optional
|
from typing import Tuple, Optional
|
||||||
|
|
||||||
|
from pyglet.gl import gl_compat, gl
|
||||||
|
from pyglet.math import Mat4, Vec3
|
||||||
|
from pyglet.graphics import Group
|
||||||
|
|
||||||
|
|
||||||
class Camera:
|
class Camera:
|
||||||
"""
|
"""
|
||||||
@ -24,8 +27,9 @@ class Camera:
|
|||||||
>>> camera.end()
|
>>> camera.end()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
window,
|
def __init__(self,
|
||||||
|
window,
|
||||||
zoom: Optional[float] = 1.0,
|
zoom: Optional[float] = 1.0,
|
||||||
dx: Optional[float] = 1.0,
|
dx: Optional[float] = 1.0,
|
||||||
dy: Optional[float] = 1.0,
|
dy: Optional[float] = 1.0,
|
||||||
@ -68,11 +72,16 @@ class Camera:
|
|||||||
|
|
||||||
def end(self) -> None:
|
def end(self) -> None:
|
||||||
self.window.view = self._stored_view
|
self.window.view = self._stored_view
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.zoom = 1
|
||||||
|
self.dx = 0
|
||||||
|
self.dy = 0
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.begin()
|
self.begin()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
self.end()
|
self.end()
|
||||||
|
|
||||||
@ -91,8 +100,8 @@ class CenterCamera(Camera):
|
|||||||
>>> camera.begin()
|
>>> camera.begin()
|
||||||
>>> window.clear()
|
>>> window.clear()
|
||||||
>>> camera.end()
|
>>> camera.end()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def begin(self) -> None:
|
def begin(self) -> None:
|
||||||
view = self.window.view
|
view = self.window.view
|
||||||
self._stored_view = view
|
self._stored_view = view
|
||||||
@ -106,4 +115,149 @@ class CenterCamera(Camera):
|
|||||||
|
|
||||||
def end(self) -> None:
|
def end(self) -> None:
|
||||||
self.window.view = self._stored_view
|
self.window.view = self._stored_view
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCamera(Group):
|
||||||
|
"""
|
||||||
|
A camera by group
|
||||||
|
can be used by just added to your widget
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
window,
|
||||||
|
order: int = 0,
|
||||||
|
parent: Optional[Group] = None,
|
||||||
|
view_x: Optional[int] = 0,
|
||||||
|
view_y: Optional[int] = 0,
|
||||||
|
zoom: Optional[float] = 1.0,
|
||||||
|
min_zoom: Optional[float] = 1.0,
|
||||||
|
max_zoom: Optional[float] = 1.0):
|
||||||
|
super().__init__(order=order, parent=parent)
|
||||||
|
self._window = window
|
||||||
|
self._previous_view = None
|
||||||
|
|
||||||
|
self._view_x = view_x
|
||||||
|
self._view_y = view_y
|
||||||
|
self._zoom = zoom
|
||||||
|
self.min_zoom = min_zoom
|
||||||
|
self.max_zoom = max_zoom
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view_x(self) -> int:
|
||||||
|
return self._view_x
|
||||||
|
|
||||||
|
@view_x.setter
|
||||||
|
def view_x(self, value: int):
|
||||||
|
self._view_x = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view_y(self) -> int:
|
||||||
|
return self._view_y
|
||||||
|
|
||||||
|
@view_y.setter
|
||||||
|
def view_y(self, value: int):
|
||||||
|
self._view_y = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zoom(self) -> float:
|
||||||
|
return min(max(self._zoom, self.min_zoom), self.max_zoom)
|
||||||
|
|
||||||
|
@zoom.setter
|
||||||
|
def zoom(self, value: float):
|
||||||
|
self._zoom = value
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._view_x = 0
|
||||||
|
self._view_y = 0
|
||||||
|
self.zoom = 1
|
||||||
|
|
||||||
|
def set_state(self):
|
||||||
|
self._previous_view = self._window.view
|
||||||
|
|
||||||
|
view = Mat4.from_translation(Vec3(self._view_x, self._view_y, 0))
|
||||||
|
if self._zoom == 1.0:
|
||||||
|
self._window.view = view
|
||||||
|
else:
|
||||||
|
view = view.scale(Vec3(self._zoom, self._zoom, 1))
|
||||||
|
self._window.view = view
|
||||||
|
|
||||||
|
def unset_state(self):
|
||||||
|
self._window.view = self._previous_view
|
||||||
|
|
||||||
|
|
||||||
|
class CenterGroupCamera(GroupCamera):
|
||||||
|
"""
|
||||||
|
A camera by group
|
||||||
|
can be used by just added to your widget
|
||||||
|
"""
|
||||||
|
|
||||||
|
def set_state(self):
|
||||||
|
self._previous_view = self._window.view
|
||||||
|
x = (self._window.width / 2) / self._zoom + (self._view_x / self._zoom)
|
||||||
|
y = (self._window.height / 2) / self._zoom + (self._view_y / self._zoom)
|
||||||
|
|
||||||
|
view = Mat4.from_translation(Vec3(x * self._zoom, y * self._zoom, 0))
|
||||||
|
# 不懂就问 为啥这里 * zoom 下面还 * zoom
|
||||||
|
if self._zoom == 1.0:
|
||||||
|
self._window.view = view
|
||||||
|
else:
|
||||||
|
view = view.scale(Vec3(self._zoom, self._zoom, 1))
|
||||||
|
self._window.view = view
|
||||||
|
|
||||||
|
def unset_state(self):
|
||||||
|
self._window.view = self._previous_view
|
||||||
|
|
||||||
|
|
||||||
|
class CenterGroupFrame(Group):
|
||||||
|
"""
|
||||||
|
A camera by group
|
||||||
|
can be used by just added to your widget
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
window,
|
||||||
|
order: int = 0,
|
||||||
|
parent: Optional[Group] = None,
|
||||||
|
dx: Optional[int] = 0,
|
||||||
|
dy: Optional[int] = 0,
|
||||||
|
width: Optional[int] = 0,
|
||||||
|
height: Optional[int] = 0,
|
||||||
|
zoom: Optional[float] = 1.0,
|
||||||
|
min_zoom: Optional[float] = 1.0,
|
||||||
|
max_zoom: Optional[float] = 1.0):
|
||||||
|
super().__init__(order=order, parent=parent)
|
||||||
|
self.window = window
|
||||||
|
self.dx = dx
|
||||||
|
self.dy = dy
|
||||||
|
self._width = width
|
||||||
|
self._height = height
|
||||||
|
self._zoom = zoom
|
||||||
|
self.min_zoom = min_zoom
|
||||||
|
self.max_zoom = max_zoom
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zoom(self) -> float:
|
||||||
|
return self._zoom
|
||||||
|
|
||||||
|
@zoom.setter
|
||||||
|
def zoom(self, value: float):
|
||||||
|
self._zoom = min(max(value, self.min_zoom), self.max_zoom)
|
||||||
|
|
||||||
|
def set_state(self):
|
||||||
|
self._previous_view = self.window.view
|
||||||
|
|
||||||
|
gl.glScissor(int(self.dx), int(self.dy), int(self._width), int(self._height))
|
||||||
|
gl.glViewport(int(self.dx), int(self.dy), int(self.window.width), int(self.window.height))
|
||||||
|
gl.glEnable(gl.GL_SCISSOR_TEST)
|
||||||
|
|
||||||
|
x = (self.window.width / 2) / self._zoom + (self.dx / self._zoom)
|
||||||
|
y = (self.window.height / 2) / self._zoom + (self.dy / self._zoom)
|
||||||
|
|
||||||
|
view = Mat4.from_translation(Vec3(x * self._zoom, y * self._zoom, 0))
|
||||||
|
view.scale(Vec3(self._zoom, self._zoom, 1))
|
||||||
|
self.window.view = view
|
||||||
|
|
||||||
|
def unset_state(self):
|
||||||
|
self.window.view = self._previous_view
|
||||||
|
gl.glDisable(gl.GL_SCISSOR_TEST)
|
||||||
|
gl.glViewport(0, 0, int(self.window.width), int(self.window.height))
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
# All rights reserved
|
# All rights reserved
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
|
|
||||||
|
import shutil
|
||||||
import traceback
|
import traceback
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@ -175,15 +176,12 @@ class Options:
|
|||||||
self.cached_options = self.option()
|
self.cached_options = self.option()
|
||||||
return self.cached_options
|
return self.cached_options
|
||||||
|
|
||||||
def option_with_len(self, longest: Optional[int] = None) -> Tuple[List[Tuple[str, Union[Any, Type], Type]], int, int, int]:
|
def option_with_len(self) -> Tuple[List[Tuple[str, Any, Type]], int, int, int]:
|
||||||
"""
|
"""
|
||||||
返回一个可以用于打印的 option 列表
|
返回一个可以用于打印的 option 列表
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if longest is None:
|
options = self.flush_option()
|
||||||
options = self.flush_option()
|
|
||||||
else:
|
|
||||||
options = self.str_option(longest)
|
|
||||||
max_len_key = 1
|
max_len_key = 1
|
||||||
max_len_value = 1
|
max_len_value = 1
|
||||||
max_len_value_t = 1
|
max_len_value_t = 1
|
||||||
@ -193,19 +191,61 @@ class Options:
|
|||||||
max_len_key = max(max_len_key, len(key))
|
max_len_key = max(max_len_key, len(key))
|
||||||
max_len_value = max(max_len_value, len(str(value)))
|
max_len_value = max(max_len_value, len(str(value)))
|
||||||
max_len_value_t = max(max_len_value_t, len(str(value_t)))
|
max_len_value_t = max(max_len_value_t, len(str(value_t)))
|
||||||
option_list.append((key, value, value_t))
|
option_list.append([key, value, value_t])
|
||||||
return option_list, max_len_key, max_len_value, max_len_value_t
|
return [option_list, max_len_key, max_len_value, max_len_value_t] # noqa
|
||||||
|
|
||||||
def as_markdown(self, longest: Optional[int] = None) -> str:
|
def as_markdown(self, longest: Optional[int] = None) -> str:
|
||||||
"""
|
"""
|
||||||
返回一个 markdown 格式的 option 字符串
|
返回一个 markdown 格式的 option 字符串
|
||||||
|
:param longest: 最长的输出长度
|
||||||
:return: markdown 格式的 option 字符串
|
:return: markdown 格式的 option 字符串
|
||||||
"""
|
"""
|
||||||
value = self.option_with_len(longest)
|
value = self.option_with_len()
|
||||||
cache = StringIO()
|
cache = StringIO()
|
||||||
option_len = max(value[1], len('Option'))
|
option_len = max(value[1], len('Option'))
|
||||||
value_len = max(value[2], len('Value'))
|
value_len = max(value[2], len('Value'))
|
||||||
value_type_len = max(value[3], len('Value Type'))
|
value_type_len = max(value[3], len('Value Type'))
|
||||||
|
|
||||||
|
# | Option | Value | Value Type |
|
||||||
|
shortest = len('Option" "Value" "Value Type')
|
||||||
|
|
||||||
|
if longest is not None:
|
||||||
|
console_width = max(longest, shortest)
|
||||||
|
else:
|
||||||
|
console_width = shutil.get_terminal_size(fallback=(100, 80)).columns
|
||||||
|
console_width = max(console_width, shortest)
|
||||||
|
|
||||||
|
# 为每一栏 预分配 1/3 或者 需要的宽度 (如果不需要 1/3)
|
||||||
|
option_len = min(option_len, console_width // 3)
|
||||||
|
value_len = min(value_len, console_width // 3)
|
||||||
|
value_type_len = min(value_type_len, console_width // 3)
|
||||||
|
|
||||||
|
# 先指定每一个列的输出最窄宽度, 然后去尝试增加宽度
|
||||||
|
# 循环分配新空间之前 首先检查是否已经不需要多分配 (and 后面)
|
||||||
|
while option_len + value_len + value_type_len + 16 < console_width\
|
||||||
|
and (option_len < value[1]
|
||||||
|
or value_len < value[2]
|
||||||
|
or value_type_len < value[3]):
|
||||||
|
# 每一个部分的逻辑都是
|
||||||
|
# 如果现在的输出长度小于原始长度
|
||||||
|
# 并且长度 + 1 之后的总长度依然在允许范围内
|
||||||
|
# 那么就 + 1
|
||||||
|
if option_len < value[1] and option_len + value_len + value_type_len + 15 < console_width:
|
||||||
|
option_len += 1
|
||||||
|
if value_len < value[2] and option_len + value_len + value_type_len + 15 < console_width:
|
||||||
|
value_len += 1
|
||||||
|
if value_type_len < value[3] and option_len + value_len + value_type_len + 15 < console_width:
|
||||||
|
value_type_len += 1
|
||||||
|
# 实际上 对于列表(可变对象) for 出来的这个值是一个引用
|
||||||
|
# 所以可以直接修改 string
|
||||||
|
for v in value[0]:
|
||||||
|
if len(str(v[0])) > option_len:
|
||||||
|
v[0] = f'{str(v[0])[:value_len - 3]}...'
|
||||||
|
if len(str(v[1])) > value_len:
|
||||||
|
v[1] = f'{str(v[1])[:value_len - 3]}...'
|
||||||
|
if len(str(v[2])) > value_type_len:
|
||||||
|
v[2] = f'{str(v[2])[:value_len - 3]}..'
|
||||||
|
|
||||||
cache.write(
|
cache.write(
|
||||||
f"| Option{' ' * (option_len - 3)}| Value{' ' * (value_len - 2)}| Value Type{' ' * (value_type_len - 7)}|\n")
|
f"| Option{' ' * (option_len - 3)}| Value{' ' * (value_len - 2)}| Value Type{' ' * (value_type_len - 7)}|\n")
|
||||||
cache.write(f'|:{"-" * (option_len + 3)}|:{"-" * (value_len + 3)}|:{"-" * (value_type_len + 3)}|\n')
|
cache.write(f'|:{"-" * (option_len + 3)}|:{"-" * (value_len + 3)}|:{"-" * (value_type_len + 3)}|\n')
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
## 请注意 这个仓库未来只会发布 `DR SDK` 的更新 `DR game` 的更新会在 [这里](https://github.com/shenjackyuanjie/DR-game) 发布
|
## 请注意 这个仓库未来只会发布 `DR SDK` 的更新 `DR game` 的更新会在 [这里](https://github.com/shenjackyuanjie/DR-game) 发布
|
||||||
|
|
||||||
|
![demo](docs/src/demo.png)
|
||||||
|
|
||||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
<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/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/编写于_Python_版本-3.8.10-blue.svg)](https://Python.org)
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
## Notice: This repo will only publish `DR SDK` updates, `DR game` updates will be published [here](https://github.com/shenjackyuanjie/DR-game)
|
## Notice: This repo will only publish `DR SDK` updates, `DR game` updates will be published [here](https://github.com/shenjackyuanjie/DR-game)
|
||||||
|
|
||||||
|
![demo](/src/demo.png)
|
||||||
|
|
||||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg" alt="996.icu" /></a>
|
<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/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_Python-3.8.10-blue.svg)](https://Python.org)
|
||||||
|
@ -2,8 +2,38 @@
|
|||||||
# DR game/DR rs 更新日志
|
# DR game/DR rs 更新日志
|
||||||
|
|
||||||
- 最新版本号
|
- 最新版本号
|
||||||
- DR game: 0.3.2.0
|
- DR game: 0.3.3.0
|
||||||
- DR rs: 0.2.20.2
|
- DR rs: 0.2.21.0
|
||||||
|
|
||||||
|
## 20230812 DR game 0.3.3.0
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- 将 `sr1_ship` 渲染器使用的 Camera 改成 `CenterGroupCamera`
|
||||||
|
- 删除了之前的 Camera 相关代码
|
||||||
|
- 将用于渲染到材质的代码部分改为使用 `glScissor` 和 `glViewport`
|
||||||
|
- 优化了一点性能 ( 毕竟是OpenGL )
|
||||||
|
|
||||||
|
## 20230809 DR game 0.3.2.1
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- 因为把部件加载图片的数据源改成从 `SR1PartType_rs` 里取
|
||||||
|
- 所以修改了 `SR1Textures` 的加载逻辑
|
||||||
|
- 可以自动忽略文件名最后的 `.png`
|
||||||
|
|
||||||
|
## 20230808 DR rs 0.2.21.0
|
||||||
|
|
||||||
|
### Add
|
||||||
|
|
||||||
|
- 在 `__init__.py` 里添加了
|
||||||
|
- `sprite`
|
||||||
|
- `type`
|
||||||
|
- 的导出 (实际上就是 typing)
|
||||||
|
- `SR1PartType_rs`
|
||||||
|
- 添加了 `type` getter
|
||||||
|
|
||||||
|
摸鱼真开心
|
||||||
|
|
||||||
## 20230724 DR rs 0.2.20.2
|
## 20230724 DR rs 0.2.20.2
|
||||||
|
|
||||||
|
@ -2,7 +2,30 @@
|
|||||||
# DR SDK 更新日志
|
# DR SDK 更新日志
|
||||||
|
|
||||||
- 最新版本号
|
- 最新版本号
|
||||||
- DR sdk: 0.8.6.0
|
- DR sdk: 0.8.7.0
|
||||||
|
- DR api: 0.1.1.0
|
||||||
|
|
||||||
|
## DR sdk 0.8.7.0
|
||||||
|
|
||||||
|
### Add
|
||||||
|
|
||||||
|
- 添加了 `Difficult_Rocket.utils.camera.GroupCamera`
|
||||||
|
- 和 `Difficult_Rocket.utils.camera.CenterGroupCamera`
|
||||||
|
- 实际上就是使用 `pyglet.graphics.Group` 来实现的 `Camera`
|
||||||
|
- 具有相同的功能
|
||||||
|
- 顺便同样在 `api.camera` 里添加了导出
|
||||||
|
- 这次我一定不会再忘记导出了
|
||||||
|
- Added `Difficult_Rocket.utils.camera.GroupCamera`
|
||||||
|
- And `Difficult_Rocket.utils.camera.CenterGroupCamera`
|
||||||
|
- Actually, it is implemented `Camera` using `pyglet.graphics.Group`
|
||||||
|
- Has the same function
|
||||||
|
- By the way, the export was also added in `api.camera`
|
||||||
|
- This time I will never forget to export it again
|
||||||
|
- 为所有 `xxCamera` 添加了
|
||||||
|
- `reset` 方法
|
||||||
|
- 用于一键重置缩放+平移
|
||||||
|
- Added `reset` method for all `xxCamera`
|
||||||
|
- Used to reset zoom + translation with one click
|
||||||
|
|
||||||
## DR sdk 0.8.6.1
|
## DR sdk 0.8.6.1
|
||||||
|
|
||||||
|
BIN
docs/src/demo.png
Normal file
BIN
docs/src/demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 408 KiB |
@ -208,7 +208,6 @@ class ObjectSpace:
|
|||||||
# the next time this object space is active.
|
# the next time this object space is active.
|
||||||
self.doomed_textures = []
|
self.doomed_textures = []
|
||||||
self.doomed_buffers = []
|
self.doomed_buffers = []
|
||||||
self.doomed_vaos = []
|
|
||||||
self.doomed_shader_programs = []
|
self.doomed_shader_programs = []
|
||||||
|
|
||||||
|
|
||||||
@ -231,6 +230,8 @@ class Context:
|
|||||||
self.context_share = context_share
|
self.context_share = context_share
|
||||||
self.canvas = None
|
self.canvas = None
|
||||||
|
|
||||||
|
self.doomed_vaos = []
|
||||||
|
|
||||||
if context_share:
|
if context_share:
|
||||||
self.object_space = context_share.object_space
|
self.object_space = context_share.object_space
|
||||||
else:
|
else:
|
||||||
@ -276,15 +277,15 @@ class Context:
|
|||||||
buffers = (gl.GLuint * len(buffers))(*buffers)
|
buffers = (gl.GLuint * len(buffers))(*buffers)
|
||||||
gl.glDeleteBuffers(len(buffers), buffers)
|
gl.glDeleteBuffers(len(buffers), buffers)
|
||||||
self.object_space.doomed_buffers.clear()
|
self.object_space.doomed_buffers.clear()
|
||||||
if self.object_space.doomed_vaos:
|
|
||||||
vaos = self.object_space.doomed_vaos[:]
|
|
||||||
vaos = (gl.GLuint * len(vaos))(*vaos)
|
|
||||||
gl.glDeleteVertexArrays(len(vaos), vaos)
|
|
||||||
self.object_space.doomed_vaos.clear()
|
|
||||||
if self.object_space.doomed_shader_programs:
|
if self.object_space.doomed_shader_programs:
|
||||||
for program_id in self.object_space.doomed_shader_programs:
|
for program_id in self.object_space.doomed_shader_programs:
|
||||||
gl.glDeleteProgram(program_id)
|
gl.glDeleteProgram(program_id)
|
||||||
self.object_space.doomed_shader_programs.clear()
|
self.object_space.doomed_shader_programs.clear()
|
||||||
|
if self.doomed_vaos:
|
||||||
|
vaos = self.doomed_vaos[:]
|
||||||
|
vaos = (gl.GLuint * len(vaos))(*vaos)
|
||||||
|
gl.glDeleteVertexArrays(len(vaos), vaos)
|
||||||
|
self.doomed_vaos.clear()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
"""Release the context.
|
"""Release the context.
|
||||||
@ -351,10 +352,10 @@ class Context:
|
|||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
"""
|
"""
|
||||||
if gl.current_context and self.object_space is gl.current_context.object_space and False:
|
if gl.current_context is self:
|
||||||
gl.glDeleteVertexArrays(1, gl.GLuint(vao_id))
|
gl.glDeleteVertexArrays(1, gl.GLuint(vao_id))
|
||||||
else:
|
else:
|
||||||
self.object_space.doomed_vaos.append(vao_id)
|
self.doomed_vaos.append(vao_id)
|
||||||
|
|
||||||
def delete_shader_program(self, program_id):
|
def delete_shader_program(self, program_id):
|
||||||
"""Safely delete a Shader Program belonging to this context.
|
"""Safely delete a Shader Program belonging to this context.
|
||||||
|
@ -68,12 +68,12 @@ class Win32Config(Config):
|
|||||||
if pf:
|
if pf:
|
||||||
return [Win32CanvasConfig(canvas, pf, self)]
|
return [Win32CanvasConfig(canvas, pf, self)]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _get_arb_pixel_format_matching_configs(self, canvas):
|
def _get_arb_pixel_format_matching_configs(self, canvas):
|
||||||
"""Get configs using the WGL_ARB_pixel_format extension.
|
"""Get configs using the WGL_ARB_pixel_format extension.
|
||||||
This method assumes a (dummy) GL context is already created."""
|
This method assumes a (dummy) GL context is already created."""
|
||||||
|
|
||||||
# Check for required extensions
|
# Check for required extensions
|
||||||
if self.sample_buffers or self.samples:
|
if self.sample_buffers or self.samples:
|
||||||
if not gl_info.have_extension('GL_ARB_multisample'):
|
if not gl_info.have_extension('GL_ARB_multisample'):
|
||||||
@ -85,7 +85,7 @@ class Win32Config(Config):
|
|||||||
attr = Win32CanvasConfigARB.attribute_ids.get(name, None)
|
attr = Win32CanvasConfigARB.attribute_ids.get(name, None)
|
||||||
if attr and value is not None:
|
if attr and value is not None:
|
||||||
attrs.extend([attr, int(value)])
|
attrs.extend([attr, int(value)])
|
||||||
attrs.append(0)
|
attrs.append(0)
|
||||||
attrs = (c_int * len(attrs))(*attrs)
|
attrs = (c_int * len(attrs))(*attrs)
|
||||||
|
|
||||||
pformats = (c_int * 16)()
|
pformats = (c_int * 16)()
|
||||||
@ -98,7 +98,7 @@ class Win32Config(Config):
|
|||||||
|
|
||||||
class Win32CanvasConfig(CanvasConfig):
|
class Win32CanvasConfig(CanvasConfig):
|
||||||
def __init__(self, canvas, pf, config):
|
def __init__(self, canvas, pf, config):
|
||||||
super(Win32CanvasConfig, self).__init__(canvas, config)
|
super().__init__(canvas, config)
|
||||||
self._pf = pf
|
self._pf = pf
|
||||||
self._pfd = PIXELFORMATDESCRIPTOR()
|
self._pfd = PIXELFORMATDESCRIPTOR()
|
||||||
|
|
||||||
@ -153,14 +153,14 @@ class Win32CanvasConfigARB(CanvasConfig):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, canvas, pf, config):
|
def __init__(self, canvas, pf, config):
|
||||||
super(Win32CanvasConfigARB, self).__init__(canvas, config)
|
super().__init__(canvas, config)
|
||||||
self._pf = pf
|
self._pf = pf
|
||||||
|
|
||||||
names = list(self.attribute_ids.keys())
|
names = list(self.attribute_ids.keys())
|
||||||
attrs = list(self.attribute_ids.values())
|
attrs = list(self.attribute_ids.values())
|
||||||
attrs = (c_int * len(attrs))(*attrs)
|
attrs = (c_int * len(attrs))(*attrs)
|
||||||
values = (c_int * len(attrs))()
|
values = (c_int * len(attrs))()
|
||||||
|
|
||||||
wglext_arb.wglGetPixelFormatAttribivARB(canvas.hdc, pf, 0, len(attrs), attrs, values)
|
wglext_arb.wglGetPixelFormatAttribivARB(canvas.hdc, pf, 0, len(attrs), attrs, values)
|
||||||
|
|
||||||
for name, value in zip(names, values):
|
for name, value in zip(names, values):
|
||||||
@ -182,35 +182,21 @@ class Win32CanvasConfigARB(CanvasConfig):
|
|||||||
_gdi32.SetPixelFormat(canvas.hdc, self._pf, None)
|
_gdi32.SetPixelFormat(canvas.hdc, self._pf, None)
|
||||||
|
|
||||||
|
|
||||||
class Win32Context(Context):
|
class _BaseWin32Context(Context):
|
||||||
def __init__(self, config, share):
|
def __init__(self, config, share):
|
||||||
super(Win32Context, self).__init__(config, share)
|
super().__init__(config, share)
|
||||||
self._context = None
|
self._context = None
|
||||||
|
|
||||||
def attach(self, canvas):
|
|
||||||
super(Win32Context, self).attach(canvas)
|
|
||||||
|
|
||||||
if not self._context:
|
|
||||||
self.config._set_pixel_format(canvas)
|
|
||||||
self._context = wgl.wglCreateContext(canvas.hdc)
|
|
||||||
|
|
||||||
share = self.context_share
|
|
||||||
if share:
|
|
||||||
if not share.canvas:
|
|
||||||
raise RuntimeError('Share context has no canvas.')
|
|
||||||
if not wgl.wglShareLists(share._context, self._context):
|
|
||||||
raise gl.ContextException('Unable to share contexts.')
|
|
||||||
|
|
||||||
def set_current(self):
|
def set_current(self):
|
||||||
if self._context is not None and self != gl.current_context:
|
if self._context is not None and self != gl.current_context:
|
||||||
wgl.wglMakeCurrent(self.canvas.hdc, self._context)
|
wgl.wglMakeCurrent(self.canvas.hdc, self._context)
|
||||||
super(Win32Context, self).set_current()
|
super().set_current()
|
||||||
|
|
||||||
def detach(self):
|
def detach(self):
|
||||||
if self.canvas:
|
if self.canvas:
|
||||||
wgl.wglDeleteContext(self._context)
|
wgl.wglDeleteContext(self._context)
|
||||||
self._context = None
|
self._context = None
|
||||||
super(Win32Context, self).detach()
|
super().detach()
|
||||||
|
|
||||||
def flip(self):
|
def flip(self):
|
||||||
_gdi32.SwapBuffers(self.canvas.hdc)
|
_gdi32.SwapBuffers(self.canvas.hdc)
|
||||||
@ -224,9 +210,23 @@ class Win32Context(Context):
|
|||||||
wglext_arb.wglSwapIntervalEXT(int(vsync))
|
wglext_arb.wglSwapIntervalEXT(int(vsync))
|
||||||
|
|
||||||
|
|
||||||
class Win32ARBContext(Win32Context):
|
class Win32Context(_BaseWin32Context):
|
||||||
def __init__(self, config, share):
|
def attach(self, canvas):
|
||||||
super(Win32ARBContext, self).__init__(config, share)
|
super().attach(canvas)
|
||||||
|
|
||||||
|
if not self._context:
|
||||||
|
self.config._set_pixel_format(canvas)
|
||||||
|
self._context = wgl.wglCreateContext(canvas.hdc)
|
||||||
|
|
||||||
|
share = self.context_share
|
||||||
|
if share:
|
||||||
|
if not share.canvas:
|
||||||
|
raise RuntimeError('Share context has no canvas.')
|
||||||
|
if not wgl.wglShareLists(share._context, self._context):
|
||||||
|
raise gl.ContextException('Unable to share contexts.')
|
||||||
|
|
||||||
|
|
||||||
|
class Win32ARBContext(_BaseWin32Context):
|
||||||
|
|
||||||
def attach(self, canvas):
|
def attach(self, canvas):
|
||||||
share = self.context_share
|
share = self.context_share
|
||||||
@ -252,4 +252,4 @@ class Win32ARBContext(Win32Context):
|
|||||||
|
|
||||||
self.config._set_pixel_format(canvas)
|
self.config._set_pixel_format(canvas)
|
||||||
self._context = wglext_arb.wglCreateContextAttribsARB(canvas.hdc, share, attribs)
|
self._context = wglext_arb.wglCreateContextAttribsARB(canvas.hdc, share, attribs)
|
||||||
super(Win32ARBContext, self).attach(canvas)
|
super().attach(canvas)
|
||||||
|
@ -148,11 +148,8 @@ class InterfacePtrMeta(type(ctypes.POINTER(COMInterface))):
|
|||||||
return super(InterfacePtrMeta, cls).__new__(cls, name, bases, dct)
|
return super(InterfacePtrMeta, cls).__new__(cls, name, bases, dct)
|
||||||
|
|
||||||
|
|
||||||
# pyglet.util.with_metaclass does not work here, as the base class is from _ctypes.lib
|
class pInterface(ctypes.POINTER(COMInterface), metaclass=InterfacePtrMeta):
|
||||||
# See https://wiki.python.org/moin/PortingToPy3k/BilingualQuickRef
|
"""Base COM interface pointer."""
|
||||||
pInterface = InterfacePtrMeta(str('Interface'),
|
|
||||||
(ctypes.POINTER(COMInterface),),
|
|
||||||
{'__doc__': 'Base COM interface pointer.'})
|
|
||||||
|
|
||||||
|
|
||||||
class COMInterfaceMeta(type):
|
class COMInterfaceMeta(type):
|
||||||
|
@ -3,7 +3,6 @@ from enum import Enum, auto
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from pyglet import event
|
from pyglet import event
|
||||||
from pyglet.util import with_metaclass
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceState(Enum):
|
class DeviceState(Enum):
|
||||||
@ -37,7 +36,7 @@ class AudioDevice:
|
|||||||
self.__class__.__name__, self.name, self.platform_state[self.state].name, self.platform_flow[self.flow].name)
|
self.__class__.__name__, self.name, self.platform_state[self.state].name, self.platform_flow[self.flow].name)
|
||||||
|
|
||||||
|
|
||||||
class AbstractAudioDeviceManager(with_metaclass(ABCMeta, event.EventDispatcher, object)):
|
class AbstractAudioDeviceManager(event.EventDispatcher, metaclass=ABCMeta):
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"""Required to remove handlers before exit, as it can cause problems with the event system's weakrefs."""
|
"""Required to remove handlers before exit, as it can cause problems with the event system's weakrefs."""
|
||||||
|
@ -4,10 +4,9 @@ import weakref
|
|||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import pyglet
|
import pyglet
|
||||||
from pyglet.util import with_metaclass
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractAudioPlayer(with_metaclass(ABCMeta)):
|
class AbstractAudioPlayer(metaclass=ABCMeta):
|
||||||
"""Base class for driver audio players.
|
"""Base class for driver audio players.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -176,7 +175,7 @@ class AbstractAudioPlayer(with_metaclass(ABCMeta)):
|
|||||||
self._source = weakref.proxy(value)
|
self._source = weakref.proxy(value)
|
||||||
|
|
||||||
|
|
||||||
class AbstractAudioDriver(with_metaclass(ABCMeta)):
|
class AbstractAudioDriver(metaclass=ABCMeta):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_audio_player(self, source, player):
|
def create_audio_player(self, source, player):
|
||||||
pass
|
pass
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
from pyglet.util import with_metaclass
|
|
||||||
|
|
||||||
|
class AbstractListener(metaclass=ABCMeta):
|
||||||
class AbstractListener(with_metaclass(ABCMeta, object)):
|
|
||||||
"""The listener properties for positional audio.
|
"""The listener properties for positional audio.
|
||||||
|
|
||||||
You can obtain the singleton instance of this class by calling
|
You can obtain the singleton instance of this class by calling
|
||||||
|
@ -31,37 +31,6 @@ def asstr(s):
|
|||||||
return s.decode("utf-8")
|
return s.decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
def with_metaclass(meta, *bases):
|
|
||||||
"""
|
|
||||||
Function from jinja2/_compat.py. License: BSD.
|
|
||||||
Use it like this::
|
|
||||||
class BaseForm:
|
|
||||||
pass
|
|
||||||
class FormType(type):
|
|
||||||
pass
|
|
||||||
class Form(with_metaclass(FormType, BaseForm)):
|
|
||||||
pass
|
|
||||||
This requires a bit of explanation: the basic idea is to make a
|
|
||||||
dummy metaclass for one level of class instantiation that replaces
|
|
||||||
itself with the actual metaclass. Because of internal type checks
|
|
||||||
we also need to make sure that we downgrade the custom metaclass
|
|
||||||
for one level to something closer to type (that's why __call__ and
|
|
||||||
__init__ comes back from type etc.).
|
|
||||||
This has the advantage over six.with_metaclass of not introducing
|
|
||||||
dummy classes into the final MRO.
|
|
||||||
"""
|
|
||||||
class MetaClass(meta):
|
|
||||||
__call__ = type.__call__
|
|
||||||
__init__ = type.__init__
|
|
||||||
|
|
||||||
def __new__(cls, name, this_bases, d):
|
|
||||||
if this_bases is None:
|
|
||||||
return type.__new__(cls, name, (), d)
|
|
||||||
return meta(name, bases, d)
|
|
||||||
|
|
||||||
return MetaClass('temporary_class', None, {})
|
|
||||||
|
|
||||||
|
|
||||||
def debug_print(enabled_or_option='debug'):
|
def debug_print(enabled_or_option='debug'):
|
||||||
"""Get a debug printer that is enabled based on a boolean input or a pyglet option.
|
"""Get a debug printer that is enabled based on a boolean input or a pyglet option.
|
||||||
The debug print function returned should be used in an assert. This way it can be
|
The debug print function returned should be used in an assert. This way it can be
|
||||||
|
@ -99,7 +99,6 @@ from pyglet import gl
|
|||||||
from pyglet.math import Mat4
|
from pyglet.math import Mat4
|
||||||
from pyglet.event import EventDispatcher
|
from pyglet.event import EventDispatcher
|
||||||
from pyglet.window import key, event
|
from pyglet.window import key, event
|
||||||
from pyglet.util import with_metaclass
|
|
||||||
from pyglet.graphics import shader
|
from pyglet.graphics import shader
|
||||||
|
|
||||||
|
|
||||||
@ -256,7 +255,7 @@ class _WindowMetaclass(type):
|
|||||||
super(_WindowMetaclass, cls).__init__(name, bases, dict)
|
super(_WindowMetaclass, cls).__init__(name, bases, dict)
|
||||||
|
|
||||||
|
|
||||||
class BaseWindow(with_metaclass(_WindowMetaclass, EventDispatcher)):
|
class BaseWindow(EventDispatcher, metaclass=_WindowMetaclass):
|
||||||
"""Platform-independent application window.
|
"""Platform-independent application window.
|
||||||
|
|
||||||
A window is a "heavyweight" object occupying operating system resources.
|
A window is a "heavyweight" object occupying operating system resources.
|
||||||
|
@ -45,6 +45,7 @@ class CompilerHelper(Options):
|
|||||||
|
|
||||||
show_progress: bool = True # --show-progress
|
show_progress: bool = True # --show-progress
|
||||||
show_memory: bool = False # --show-memory
|
show_memory: bool = False # --show-memory
|
||||||
|
remove_output: bool = True # --remove-output
|
||||||
save_xml: bool = False # --xml
|
save_xml: bool = False # --xml
|
||||||
xml_path: Path = Path('build/compile_data.xml')
|
xml_path: Path = Path('build/compile_data.xml')
|
||||||
|
|
||||||
@ -147,6 +148,7 @@ class CompilerHelper(Options):
|
|||||||
_add_cmd(cmd_list, '--disable-ccache' if not self.use_ccache else None)
|
_add_cmd(cmd_list, '--disable-ccache' if not self.use_ccache else None)
|
||||||
_add_cmd(cmd_list, '--show-progress' if self.show_progress else None)
|
_add_cmd(cmd_list, '--show-progress' if self.show_progress else None)
|
||||||
_add_cmd(cmd_list, '--show-memory' if self.show_memory else None)
|
_add_cmd(cmd_list, '--show-memory' if self.show_memory else None)
|
||||||
|
_add_cmd(cmd_list, '--remove-output' if self.remove_output else None)
|
||||||
_add_cmd(cmd_list, '--assume-yes-for-download' if self.download_confirm else None)
|
_add_cmd(cmd_list, '--assume-yes-for-download' if self.download_confirm else None)
|
||||||
_add_cmd(cmd_list, '--run' if self.run_after_build else None)
|
_add_cmd(cmd_list, '--run' if self.run_after_build else None)
|
||||||
_add_cmd(cmd_list, '--enable-console' if self.enable_console else '--disable-console')
|
_add_cmd(cmd_list, '--enable-console' if self.enable_console else '--disable-console')
|
||||||
|
@ -60,6 +60,10 @@ if TYPE_CHECKING:
|
|||||||
def description(self) -> str:
|
def description(self) -> str:
|
||||||
""" 零件的描述 """
|
""" 零件的描述 """
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sprite(self) -> str:
|
||||||
|
""" 零件的贴图 """
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mass(self) -> float:
|
def mass(self) -> float:
|
||||||
""" 零件的质量 """
|
""" 零件的质量 """
|
||||||
@ -80,6 +84,10 @@ if TYPE_CHECKING:
|
|||||||
def hidden(self) -> bool:
|
def hidden(self) -> bool:
|
||||||
""" 零件是否隐藏 """
|
""" 零件是否隐藏 """
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
""" 零件的类型 """
|
||||||
|
|
||||||
|
|
||||||
class SR1PartList_rs: # NOQA
|
class SR1PartList_rs: # NOQA
|
||||||
""" 用于从 rust 中读取 SR1PartList """
|
""" 用于从 rust 中读取 SR1PartList """
|
||||||
|
20
mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock
generated
20
mods/dr_game/Difficult_Rocket_rs/src/Cargo.lock
generated
@ -348,9 +348,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ffb88ae05f306b4bfcde40ac4a51dc0b05936a9207a4b75b798c7729c4258a59"
|
checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"indoc",
|
"indoc",
|
||||||
@ -365,9 +365,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "554db24f0b3c180a9c0b1268f91287ab3f17c162e15b54caaae5a6b3773396b0"
|
checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
@ -375,9 +375,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-ffi"
|
name = "pyo3-ffi"
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "922ede8759e8600ad4da3195ae41259654b9c55da4f7eec84a0ccc7d067a70a4"
|
checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
@ -385,9 +385,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a5caec6a1dd355964a841fcbeeb1b89fe4146c87295573f94228911af3cc5a2"
|
checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
@ -397,9 +397,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0b78ccbb160db1556cdb6fd96c50334c5d4ec44dc5e0a968d0a1208fa0efa8b"
|
checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -40,5 +40,5 @@ version = "0.17.2"
|
|||||||
features = ["simd-stable"]
|
features = ["simd-stable"]
|
||||||
|
|
||||||
[dependencies.pyo3]
|
[dependencies.pyo3]
|
||||||
version = "0.19.1"
|
version = "0.19.2"
|
||||||
features = ["extension-module"]
|
features = ["extension-module" , "macros"]
|
||||||
|
@ -12,7 +12,7 @@ package_path = 'Difficult_Rocket_rs'
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='Difficult_Rocket_rs',
|
name='Difficult_Rocket_rs',
|
||||||
version="0.2.18.0",
|
version="0.2.21.0",
|
||||||
author='shenjackyuanjie',
|
author='shenjackyuanjie',
|
||||||
author_email='3695888@qq.com',
|
author_email='3695888@qq.com',
|
||||||
rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs",
|
rust_extensions=[RustExtension(target="Difficult_Rocket_rs.Difficult_Rocket_rs",
|
||||||
|
@ -24,7 +24,7 @@ enum LoadState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn get_version_str() -> String { "0.2.20.2".to_string() }
|
fn get_version_str() -> String { "0.2.21.0".to_string() }
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn test_call(py_obj: &PyAny) -> PyResult<bool> {
|
fn test_call(py_obj: &PyAny) -> PyResult<bool> {
|
||||||
|
@ -51,6 +51,10 @@ pub mod data {
|
|||||||
pub data: SR1PartType,
|
pub data: SR1PartType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PySR1PartType {
|
||||||
|
pub fn new(data: SR1PartType) -> Self { Self { data } }
|
||||||
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl PySR1PartType {
|
impl PySR1PartType {
|
||||||
#[getter]
|
#[getter]
|
||||||
@ -76,10 +80,9 @@ pub mod data {
|
|||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
fn get_hidden(&self) -> bool { self.data.hidden }
|
fn get_hidden(&self) -> bool { self.data.hidden }
|
||||||
}
|
|
||||||
|
|
||||||
impl PySR1PartType {
|
#[getter]
|
||||||
pub fn new(data: SR1PartType) -> Self { Self { data } }
|
fn get_type(&self) -> String { self.data.p_type.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -41,6 +41,27 @@ pub mod part_list {
|
|||||||
lander,
|
lander,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<String> for SR1PartTypeEnum {
|
||||||
|
fn into(self) -> String {
|
||||||
|
match self {
|
||||||
|
SR1PartTypeEnum::pod => "pod".to_string(),
|
||||||
|
SR1PartTypeEnum::detacher => "detacher".to_string(),
|
||||||
|
SR1PartTypeEnum::wheel => "wheel".to_string(),
|
||||||
|
SR1PartTypeEnum::fuselage => "fuselage".to_string(),
|
||||||
|
SR1PartTypeEnum::strut => "strut".to_string(),
|
||||||
|
SR1PartTypeEnum::tank => "tank".to_string(),
|
||||||
|
SR1PartTypeEnum::engine => "engine".to_string(),
|
||||||
|
SR1PartTypeEnum::parachute => "parachute".to_string(),
|
||||||
|
SR1PartTypeEnum::nosecone => "nosecone".to_string(),
|
||||||
|
SR1PartTypeEnum::rcs => "rcs".to_string(),
|
||||||
|
SR1PartTypeEnum::solar => "solar".to_string(),
|
||||||
|
SR1PartTypeEnum::dockconnector => "dockconnector".to_string(),
|
||||||
|
SR1PartTypeEnum::dockport => "dockport".to_string(),
|
||||||
|
SR1PartTypeEnum::lander => "lander".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
||||||
pub enum Location {
|
pub enum Location {
|
||||||
Top,
|
Top,
|
||||||
|
@ -16,7 +16,7 @@ from Difficult_Rocket.api.mod import ModInfo
|
|||||||
from Difficult_Rocket.client import ClientWindow
|
from Difficult_Rocket.client import ClientWindow
|
||||||
from Difficult_Rocket.api.types import Options, Version
|
from Difficult_Rocket.api.types import Options, Version
|
||||||
|
|
||||||
DR_rust_version = Version("0.2.20.2") # DR_mod 的 Rust 编写部分的兼容版本
|
DR_rust_version = Version("0.2.21.0") # DR_mod 的 Rust 编写部分的兼容版本
|
||||||
|
|
||||||
logger = logging.getLogger('client.dr_game')
|
logger = logging.getLogger('client.dr_game')
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ DR_mod_runtime = _DR_mod_runtime()
|
|||||||
class DR_mod(ModInfo): # NOQA
|
class DR_mod(ModInfo): # NOQA
|
||||||
mod_id = "difficult_rocket_mod"
|
mod_id = "difficult_rocket_mod"
|
||||||
name = "Difficult Rocket mod"
|
name = "Difficult Rocket mod"
|
||||||
version = Version("0.3.2.0")
|
version = Version("0.3.3.0")
|
||||||
|
|
||||||
writer = "shenjackyuanjie"
|
writer = "shenjackyuanjie"
|
||||||
link = "shenjack.top"
|
link = "shenjack.top"
|
||||||
|
@ -10,36 +10,33 @@ import logging
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, TYPE_CHECKING, Union, Dict, Optional, Generator, Tuple
|
from typing import List, TYPE_CHECKING, Dict, Optional, Generator, Tuple
|
||||||
|
|
||||||
from pyglet.math import Vec4
|
from pyglet.gl import gl
|
||||||
|
from pyglet.math import Mat4
|
||||||
from pyglet.text import Label
|
from pyglet.text import Label
|
||||||
from pyglet.sprite import Sprite
|
from pyglet.sprite import Sprite
|
||||||
# from pyglet.image import Texture
|
|
||||||
from pyglet.graphics import Batch, Group
|
from pyglet.graphics import Batch, Group
|
||||||
from pyglet.shapes import Line, Rectangle
|
from pyglet.shapes import Line, Rectangle
|
||||||
from pyglet.image import Framebuffer, Texture
|
|
||||||
|
|
||||||
from . import DR_mod_runtime
|
from . import DR_mod_runtime
|
||||||
|
from .types import SR1Textures, SR1Rotation
|
||||||
|
|
||||||
# Difficult Rocket
|
# Difficult Rocket
|
||||||
from Difficult_Rocket import DR_status
|
from Difficult_Rocket import DR_status
|
||||||
from Difficult_Rocket.utils.translate import Tr
|
from Difficult_Rocket.utils.translate import Tr
|
||||||
from Difficult_Rocket.api.camera import CenterCamera
|
from Difficult_Rocket.client import ClientWindow
|
||||||
from Difficult_Rocket.api.types import Fonts, Options
|
from Difficult_Rocket.api.types import Fonts, Options
|
||||||
from Difficult_Rocket.command.line import CommandText
|
from Difficult_Rocket.command.line import CommandText
|
||||||
from Difficult_Rocket.client.screen import BaseScreen
|
from Difficult_Rocket.client.screen import BaseScreen
|
||||||
from .types import SR1Textures, SR1Rotation
|
from Difficult_Rocket.api.camera import CenterGroupCamera
|
||||||
|
from Difficult_Rocket.api.gui.widget import PressTextButton
|
||||||
if TYPE_CHECKING:
|
|
||||||
from Difficult_Rocket.client import ClientWindow
|
|
||||||
|
|
||||||
if DR_mod_runtime.use_DR_rust:
|
if DR_mod_runtime.use_DR_rust:
|
||||||
from .Difficult_Rocket_rs import (SR1PartList_rs,
|
from .Difficult_Rocket_rs import (SR1PartList_rs,
|
||||||
SR1Ship_rs,
|
SR1Ship_rs,
|
||||||
SR1PartData_rs,
|
SR1PartData_rs,
|
||||||
SR1PartType_rs,
|
SR1PartType_rs)
|
||||||
map_ptype_textures)
|
|
||||||
|
|
||||||
logger = logging.getLogger('client.dr_game_sr1_ship')
|
logger = logging.getLogger('client.dr_game_sr1_ship')
|
||||||
logger.level = logging.DEBUG
|
logger.level = logging.DEBUG
|
||||||
@ -65,7 +62,7 @@ class SR1ShipRender(BaseScreen):
|
|||||||
"""用于渲染 sr1 船的类"""
|
"""用于渲染 sr1 船的类"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
main_window: "ClientWindow"):
|
main_window: ClientWindow):
|
||||||
super().__init__(main_window)
|
super().__init__(main_window)
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
logger.info(sr_tr().mod.info.setup.start())
|
logger.info(sr_tr().mod.info.setup.start())
|
||||||
@ -75,14 +72,16 @@ class SR1ShipRender(BaseScreen):
|
|||||||
|
|
||||||
self.dx = 0
|
self.dx = 0
|
||||||
self.dy = 0
|
self.dy = 0
|
||||||
self.width = main_window.width - 100
|
self.width = main_window.width
|
||||||
self.height = main_window.height - 100
|
self.height = main_window.height
|
||||||
self.buffer = Framebuffer()
|
|
||||||
self.render_texture = Texture.create(self.width, self.height)
|
|
||||||
self.buffer.attach_texture(self.render_texture)
|
|
||||||
|
|
||||||
self.main_batch = Batch()
|
self.main_batch = Batch()
|
||||||
self.part_group = Group(10, parent=main_window.main_group)
|
self.group_camera = CenterGroupCamera(window=main_window,
|
||||||
|
order=10,
|
||||||
|
parent=main_window.main_group,
|
||||||
|
min_zoom=(1 / 2) ** 10,
|
||||||
|
max_zoom=10)
|
||||||
|
self.part_group = Group(0, parent=self.group_camera)
|
||||||
|
|
||||||
self.debug_label = Label(x=20, y=main_window.height - 100, font_size=DR_status.std_font_size,
|
self.debug_label = Label(x=20, y=main_window.height - 100, font_size=DR_status.std_font_size,
|
||||||
text='SR1 render!', font_name=Fonts.微软等宽无线,
|
text='SR1 render!', font_name=Fonts.微软等宽无线,
|
||||||
@ -95,7 +94,12 @@ class SR1ShipRender(BaseScreen):
|
|||||||
self.render_d_label = Label('debug label NODATA', font_name=Fonts.微软等宽无线,
|
self.render_d_label = Label('debug label NODATA', font_name=Fonts.微软等宽无线,
|
||||||
x=main_window.width / 2, y=main_window.height / 2)
|
x=main_window.width / 2, y=main_window.height / 2)
|
||||||
self.render_d_label.visible = self.status.draw_d_pos
|
self.render_d_label.visible = self.status.draw_d_pos
|
||||||
self.camera = CenterCamera(main_window, min_zoom=(1 / 2) ** 10, max_zoom=10)
|
|
||||||
|
self.test_button = PressTextButton(x=100, y=100,
|
||||||
|
width=100, height=20, text='test button',
|
||||||
|
batch=self.main_batch, group=Group(5, parent=main_window.main_group))
|
||||||
|
# self.test_button.push_handlers(main_window)
|
||||||
|
main_window.push_handlers(self.test_button)
|
||||||
|
|
||||||
# Optional data
|
# Optional data
|
||||||
self.textures: SR1Textures = SR1Textures()
|
self.textures: SR1Textures = SR1Textures()
|
||||||
@ -127,8 +131,6 @@ class SR1ShipRender(BaseScreen):
|
|||||||
def size(self, value: Tuple[int, int]):
|
def size(self, value: Tuple[int, int]):
|
||||||
if not self.width == value[0] or not self.height == value[1]:
|
if not self.width == value[0] or not self.height == value[1]:
|
||||||
self.width, self.height = value
|
self.width, self.height = value
|
||||||
self.render_texture = Texture.create(self.width, self.height)
|
|
||||||
self.buffer.attach_texture(self.render_texture)
|
|
||||||
|
|
||||||
def load_xml(self, file_path: str) -> bool:
|
def load_xml(self, file_path: str) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -163,13 +165,15 @@ class SR1ShipRender(BaseScreen):
|
|||||||
# rust 渲染
|
# rust 渲染
|
||||||
if DR_mod_runtime.use_DR_rust:
|
if DR_mod_runtime.use_DR_rust:
|
||||||
cache = self.rust_ship.as_dict()
|
cache = self.rust_ship.as_dict()
|
||||||
|
part_group = Group(2, parent=self.part_group)
|
||||||
|
line_box_group = Group(6, parent=self.part_group)
|
||||||
for p_id, parts in cache.items():
|
for p_id, parts in cache.items():
|
||||||
p_id: int
|
p_id: int
|
||||||
parts: List[Tuple[SR1PartType_rs, SR1PartData_rs]]
|
parts: List[Tuple[SR1PartType_rs, SR1PartData_rs]]
|
||||||
part_group = Group(2, parent=self.part_group)
|
|
||||||
batch = []
|
batch = []
|
||||||
for p_type, p_data in parts:
|
for p_type, p_data in parts:
|
||||||
part_sprite = Sprite(img=self.textures.get_texture(map_ptype_textures(p_data.part_type_id)),
|
sprite_name = self.part_list_rs.get_part_type(p_data.part_type_id).sprite
|
||||||
|
part_sprite = Sprite(img=self.textures.get_texture(sprite_name),
|
||||||
x=p_data.x * 60, y=p_data.y * 60, z=random.random(),
|
x=p_data.x * 60, y=p_data.y * 60, z=random.random(),
|
||||||
batch=self.main_batch, group=part_group)
|
batch=self.main_batch, group=part_group)
|
||||||
part_sprite.rotation = p_data.angle_r
|
part_sprite.rotation = p_data.angle_r
|
||||||
@ -177,7 +181,6 @@ class SR1ShipRender(BaseScreen):
|
|||||||
part_sprite.scale_y = -1 if p_data.flip_y else 1
|
part_sprite.scale_y = -1 if p_data.flip_y else 1
|
||||||
|
|
||||||
batch.append(part_sprite)
|
batch.append(part_sprite)
|
||||||
line_box_group = Group(6, parent=self.part_group)
|
|
||||||
part_box = self.rust_ship.get_part_box(p_id)
|
part_box = self.rust_ship.get_part_box(p_id)
|
||||||
if part_box:
|
if part_box:
|
||||||
# 线框
|
# 线框
|
||||||
@ -253,9 +256,7 @@ class SR1ShipRender(BaseScreen):
|
|||||||
self.parts_sprite: Dict[int, Sprite] = {}
|
self.parts_sprite: Dict[int, Sprite] = {}
|
||||||
self.part_line_box = {}
|
self.part_line_box = {}
|
||||||
self.part_line_list = []
|
self.part_line_list = []
|
||||||
self.camera.zoom = 1.0
|
self.group_camera.reset()
|
||||||
self.camera.dx = 0
|
|
||||||
self.camera.dy = 0
|
|
||||||
# 调用生成器 减少卡顿
|
# 调用生成器 减少卡顿
|
||||||
try:
|
try:
|
||||||
self.gen_draw = self.gen_sprite()
|
self.gen_draw = self.gen_sprite()
|
||||||
@ -273,21 +274,24 @@ class SR1ShipRender(BaseScreen):
|
|||||||
len(self.rust_ship.as_list()),
|
len(self.rust_ship.as_list()),
|
||||||
f'{full_mass}kg' if DR_mod_runtime.use_DR_rust else sr_tr().game.require_DR_rs()))
|
f'{full_mass}kg' if DR_mod_runtime.use_DR_rust else sr_tr().game.require_DR_rs()))
|
||||||
|
|
||||||
def draw_batch(self, window: "ClientWindow"):
|
def draw_batch(self, window: ClientWindow):
|
||||||
if self.status.draw_done:
|
if self.status.draw_done:
|
||||||
self.render_d_label.text = f'x: {self.camera.dx} y: {self.camera.dy}'
|
self.render_d_label.text = f'x: {self.group_camera.view_x} y: {self.group_camera.view_y}'
|
||||||
self.render_d_label.position = self.camera.dx + (self.window_pointer.width / 2), self.camera.dy + (
|
self.render_d_label.position = self.group_camera.view_x + (self.window_pointer.width / 2), self.group_camera.view_y + (
|
||||||
self.window_pointer.height / 2) + 10, 0 # 0 for z
|
self.window_pointer.height / 2) + 10, 0 # 0 for z
|
||||||
self.render_d_line.x2 = self.camera.dx
|
self.render_d_line.x2 = self.group_camera.view_x
|
||||||
self.render_d_line.y2 = self.camera.dy
|
self.render_d_line.y2 = self.group_camera.view_y
|
||||||
self.buffer.bind()
|
|
||||||
window.clear()
|
|
||||||
with self.camera:
|
|
||||||
self.main_batch.draw()
|
|
||||||
self.buffer.unbind()
|
|
||||||
self.render_texture.blit(x=self.dx, y=self.dy, z=0, width=self.width, height=self.height)
|
|
||||||
|
|
||||||
def on_draw(self, window: "ClientWindow"):
|
gl.glEnable(gl.GL_SCISSOR_TEST)
|
||||||
|
gl.glScissor(int(self.dx), int(self.dy), int(self.width), int(self.height))
|
||||||
|
gl.glViewport(int(self.dx), int(self.dy), self.window_pointer.width, self.window_pointer.height)
|
||||||
|
self.main_batch.draw() # use group camera, no need to with
|
||||||
|
gl.glViewport(0, 0, self.window_pointer.width, self.window_pointer.height)
|
||||||
|
gl.glScissor(0, 0, self.window_pointer.width, self.window_pointer.height)
|
||||||
|
gl.glDisable(gl.GL_SCISSOR_TEST)
|
||||||
|
|
||||||
|
# def on_draw(self, dt: float, window): # TODO: wait for pyglet 2.1
|
||||||
|
def on_draw(self, window: ClientWindow):
|
||||||
if self.status.draw_call:
|
if self.status.draw_call:
|
||||||
self.render_ship()
|
self.render_ship()
|
||||||
|
|
||||||
@ -302,38 +306,39 @@ class SR1ShipRender(BaseScreen):
|
|||||||
|
|
||||||
self.debug_label.draw()
|
self.debug_label.draw()
|
||||||
|
|
||||||
def on_resize(self, width: int, height: int, window: "ClientWindow"):
|
def on_resize(self, width: int, height: int, window: ClientWindow):
|
||||||
self.debug_label.y = height - 100
|
self.debug_label.y = height - 100
|
||||||
if not self.status.draw_done:
|
if not self.status.draw_done:
|
||||||
return
|
return
|
||||||
self.render_d_line.x2 = width // 2
|
self.render_d_line.x2 = width // 2
|
||||||
self.render_d_line.y2 = height // 2
|
self.render_d_line.y2 = height // 2
|
||||||
|
self.test_button._update_position()
|
||||||
|
|
||||||
def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int, window: "ClientWindow"):
|
def on_mouse_scroll(self, x: int, y: int, scroll_x: int, scroll_y: int, window: ClientWindow):
|
||||||
if not self.status.draw_done:
|
if not self.status.draw_done:
|
||||||
return
|
return
|
||||||
if self.status.focus:
|
if self.status.focus:
|
||||||
mouse_dx = x - (window.width / 2)
|
mouse_dx = x - (self.width / 2) + self.dx
|
||||||
mouse_dy = y - (window.height / 2)
|
mouse_dy = y - (self.height / 2) + self.dy
|
||||||
# 鼠标缩放位置相对于屏幕中心的位置
|
# 鼠标缩放位置相对于屏幕中心的位置
|
||||||
mouse_dx_d = mouse_dx - self.camera.dx
|
mouse_dx_d = mouse_dx - self.group_camera.view_x
|
||||||
mouse_dy_d = mouse_dy - self.camera.dy
|
mouse_dy_d = mouse_dy - self.group_camera.view_y
|
||||||
# 鼠标相对偏移量的偏移量
|
# 鼠标相对偏移量的偏移量
|
||||||
if scroll_y == 0:
|
if scroll_y == 0:
|
||||||
zoom_d = 1
|
zoom_d = 1
|
||||||
else:
|
else:
|
||||||
zoom_d = ((2 ** scroll_y) - 1) * 0.5 + 1
|
zoom_d = ((2 ** scroll_y) - 1) * 0.5 + 1
|
||||||
# 缩放的变换量
|
# 缩放的变换量
|
||||||
if not (self.camera.zoom == 10 and scroll_y > 0):
|
if not (self.group_camera.zoom == 10 and scroll_y > 0):
|
||||||
if self.camera.zoom * zoom_d >= 10:
|
if self.group_camera.zoom * zoom_d >= 10:
|
||||||
zoom_d = 10 / self.camera.zoom
|
zoom_d = 10 / self.group_camera.zoom
|
||||||
self.camera.zoom = 10
|
self.group_camera.zoom = 10
|
||||||
else:
|
else:
|
||||||
self.camera.zoom *= zoom_d
|
self.group_camera.zoom *= zoom_d
|
||||||
mouse_dx_d *= (1 - zoom_d)
|
mouse_dx_d *= (1 - zoom_d)
|
||||||
mouse_dy_d *= (1 - zoom_d)
|
mouse_dy_d *= (1 - zoom_d)
|
||||||
self.camera.dx += mouse_dx_d
|
self.group_camera.view_x += mouse_dx_d
|
||||||
self.camera.dy += mouse_dy_d
|
self.group_camera.view_y += mouse_dy_d
|
||||||
elif self.status.moving:
|
elif self.status.moving:
|
||||||
# 如果是在移动整体渲染位置
|
# 如果是在移动整体渲染位置
|
||||||
size_x, size_y = self.size
|
size_x, size_y = self.size
|
||||||
@ -345,15 +350,12 @@ class SR1ShipRender(BaseScreen):
|
|||||||
size_y = 10
|
size_y = 10
|
||||||
self.size = size_x, size_y
|
self.size = size_x, size_y
|
||||||
|
|
||||||
def on_command(self, command: CommandText, window: "ClientWindow"):
|
def on_command(self, command: CommandText, window: ClientWindow):
|
||||||
""" 解析命令 """
|
""" 解析命令 """
|
||||||
self.logger.info(f'command: {command}')
|
self.logger.info(f'command: {command}')
|
||||||
if command.find('render'):
|
if command.find('render'):
|
||||||
if command.find('reset'):
|
if command.find('reset'):
|
||||||
self.camera.zoom = 1
|
self.group_camera.reset()
|
||||||
self.camera.dx = 0
|
|
||||||
self.camera.dy = 0
|
|
||||||
self.window_pointer.view = Vec4()
|
|
||||||
else:
|
else:
|
||||||
self.status.draw_call = True
|
self.status.draw_call = True
|
||||||
print('应该渲染飞船的')
|
print('应该渲染飞船的')
|
||||||
@ -438,17 +440,17 @@ class SR1ShipRender(BaseScreen):
|
|||||||
logger.info(sr_tr().sr1.ship.save.start().format(self.rust_ship))
|
logger.info(sr_tr().sr1.ship.save.start().format(self.rust_ship))
|
||||||
self.rust_ship.save('./test-save.xml')
|
self.rust_ship.save('./test-save.xml')
|
||||||
|
|
||||||
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int, window: "ClientWindow"):
|
def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifiers: int, window: ClientWindow):
|
||||||
if self.status.focus:
|
if self.status.focus:
|
||||||
self.camera.dx += dx
|
self.group_camera.view_x += dx
|
||||||
self.camera.dy += dy
|
self.group_camera.view_y += dy
|
||||||
self.status.update_call = True
|
self.status.update_call = True
|
||||||
elif self.status.moving:
|
elif self.status.moving:
|
||||||
# 如果是在移动整体渲染位置
|
# 如果是在移动整体渲染位置
|
||||||
self.dx += dx
|
self.dx += dx
|
||||||
self.dy += dy
|
self.dy += dy
|
||||||
|
|
||||||
def on_file_drop(self, x: int, y: int, paths: List[str], window: "ClientWindow"):
|
def on_file_drop(self, x: int, y: int, paths: List[str], window: ClientWindow):
|
||||||
if len(paths) > 1:
|
if len(paths) > 1:
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
@ -469,6 +471,15 @@ class SR1ShipRender(BaseScreen):
|
|||||||
# break
|
# break
|
||||||
# self.render_ship()
|
# self.render_ship()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view(self):
|
||||||
|
return self.window_pointer.view
|
||||||
|
|
||||||
|
@view.setter
|
||||||
|
def view(self, value: Mat4):
|
||||||
|
self.window_pointer.view = value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from objprint import op
|
from objprint import op
|
||||||
|
@ -33,8 +33,10 @@ class SR1Textures(Options):
|
|||||||
"""
|
"""
|
||||||
if name in self.cached_options:
|
if name in self.cached_options:
|
||||||
return self.cached_options.get(name)
|
return self.cached_options.get(name)
|
||||||
|
elif name.split('.')[0] in self.cached_options:
|
||||||
|
return self.cached_options.get(name.split('.')[0])
|
||||||
else:
|
else:
|
||||||
img = load(f'assets/textures/parts/{name}.png')
|
img = load(f'assets/textures/parts/{name}')
|
||||||
img.anchor_x = img.width // 2
|
img.anchor_x = img.width // 2
|
||||||
img.anchor_y = img.height // 2
|
img.anchor_y = img.height // 2
|
||||||
setattr(self, name, img)
|
setattr(self, name, img)
|
||||||
|
@ -46,9 +46,10 @@ if __name__ == '__main__':
|
|||||||
# 检测 --output xx 参数
|
# 检测 --output xx 参数
|
||||||
if '--output' in sys.argv:
|
if '--output' in sys.argv:
|
||||||
# 输入的是输出目录
|
# 输入的是输出目录
|
||||||
compiler.output_path = sys.argv[sys.argv.index('--output') + 1]
|
out_path = sys.argv[sys.argv.index('--output') + 1]
|
||||||
|
compiler.output_path = Path(out_path)
|
||||||
sys.argv.remove('--output')
|
sys.argv.remove('--output')
|
||||||
sys.argv.remove(compiler.output_path)
|
sys.argv.remove(out_path)
|
||||||
|
|
||||||
# 检测 --no-pyglet-opt 参数
|
# 检测 --no-pyglet-opt 参数
|
||||||
pyglet_optimizations = True
|
pyglet_optimizations = True
|
||||||
@ -83,7 +84,7 @@ if __name__ == '__main__':
|
|||||||
else:
|
else:
|
||||||
compiler.output_path = Path(f'./build/nuitka-{platform.system().lower()}')
|
compiler.output_path = Path(f'./build/nuitka-{platform.system().lower()}')
|
||||||
|
|
||||||
print(compiler.as_markdown(longest=70))
|
print(compiler.as_markdown())
|
||||||
|
|
||||||
print(compiler.gen_subprocess_cmd())
|
print(compiler.gen_subprocess_cmd())
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user