bascenev1lib.actor.image
Defines Actor(s).
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines Actor(s).""" 4 5from __future__ import annotations 6 7from enum import Enum 8from typing import TYPE_CHECKING, override 9 10import bascenev1 as bs 11 12if TYPE_CHECKING: 13 from typing import Any, Sequence 14 15 16class Image(bs.Actor): 17 """Just a wrapped up image node with a few tricks up its sleeve.""" 18 19 class Transition(Enum): 20 """Transition types we support.""" 21 22 FADE_IN = 'fade_in' 23 IN_RIGHT = 'in_right' 24 IN_LEFT = 'in_left' 25 IN_BOTTOM = 'in_bottom' 26 IN_BOTTOM_SLOW = 'in_bottom_slow' 27 IN_TOP_SLOW = 'in_top_slow' 28 29 class Attach(Enum): 30 """Attach types we support.""" 31 32 CENTER = 'center' 33 TOP_CENTER = 'topCenter' 34 TOP_LEFT = 'topLeft' 35 BOTTOM_CENTER = 'bottomCenter' 36 37 def __init__( 38 self, 39 texture: bs.Texture | dict[str, Any], 40 *, 41 position: tuple[float, float] = (0, 0), 42 transition: Transition | None = None, 43 transition_delay: float = 0.0, 44 attach: Attach = Attach.CENTER, 45 color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), 46 scale: tuple[float, float] = (100.0, 100.0), 47 transition_out_delay: float | None = None, 48 mesh_opaque: bs.Mesh | None = None, 49 mesh_transparent: bs.Mesh | None = None, 50 vr_depth: float = 0.0, 51 host_only: bool = False, 52 front: bool = False, 53 ): 54 # pylint: disable=too-many-statements 55 # pylint: disable=too-many-branches 56 # pylint: disable=too-many-locals 57 super().__init__() 58 59 # If they provided a dict as texture, assume its an icon. 60 # otherwise its just a texture value itself. 61 mask_texture: bs.Texture | None 62 if isinstance(texture, dict): 63 tint_color = texture['tint_color'] 64 tint2_color = texture['tint2_color'] 65 tint_texture = texture['tint_texture'] 66 texture = texture['texture'] 67 mask_texture = bs.gettexture('characterIconMask') 68 else: 69 tint_color = (1, 1, 1) 70 tint2_color = None 71 tint_texture = None 72 mask_texture = None 73 74 self.node = bs.newnode( 75 'image', 76 attrs={ 77 'texture': texture, 78 'tint_color': tint_color, 79 'tint_texture': tint_texture, 80 'position': position, 81 'vr_depth': vr_depth, 82 'scale': scale, 83 'mask_texture': mask_texture, 84 'color': color, 85 'absolute_scale': True, 86 'host_only': host_only, 87 'front': front, 88 'attach': attach.value, 89 }, 90 delegate=self, 91 ) 92 93 if mesh_opaque is not None: 94 self.node.mesh_opaque = mesh_opaque 95 if mesh_transparent is not None: 96 self.node.mesh_transparent = mesh_transparent 97 if tint2_color is not None: 98 self.node.tint2_color = tint2_color 99 if transition is self.Transition.FADE_IN: 100 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 101 if transition_out_delay is not None: 102 keys[transition_delay + transition_out_delay] = color[3] 103 keys[transition_delay + transition_out_delay + 0.5] = 0 104 bs.animate(self.node, 'opacity', keys) 105 cmb = self.position_combine = bs.newnode( 106 'combine', owner=self.node, attrs={'size': 2} 107 ) 108 if transition is self.Transition.IN_RIGHT: 109 keys = { 110 transition_delay: position[0] + 1200, 111 transition_delay + 0.2: position[0], 112 } 113 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 114 bs.animate(cmb, 'input0', keys) 115 cmb.input1 = position[1] 116 bs.animate(self.node, 'opacity', o_keys) 117 elif transition is self.Transition.IN_LEFT: 118 keys = { 119 transition_delay: position[0] - 1200, 120 transition_delay + 0.2: position[0], 121 } 122 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 123 if transition_out_delay is not None: 124 keys[transition_delay + transition_out_delay] = position[0] 125 keys[transition_delay + transition_out_delay + 200] = ( 126 -position[0] - 1200 127 ) 128 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 129 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 130 bs.animate(cmb, 'input0', keys) 131 cmb.input1 = position[1] 132 bs.animate(self.node, 'opacity', o_keys) 133 elif transition is self.Transition.IN_BOTTOM_SLOW: 134 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 135 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 136 cmb.input0 = position[0] 137 bs.animate(cmb, 'input1', keys) 138 bs.animate(self.node, 'opacity', o_keys) 139 elif transition is self.Transition.IN_BOTTOM: 140 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 141 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 142 if transition_out_delay is not None: 143 keys[transition_delay + transition_out_delay] = position[1] 144 keys[transition_delay + transition_out_delay + 0.2] = -400 145 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 146 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 147 cmb.input0 = position[0] 148 bs.animate(cmb, 'input1', keys) 149 bs.animate(self.node, 'opacity', o_keys) 150 elif transition is self.Transition.IN_TOP_SLOW: 151 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 152 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 153 cmb.input0 = position[0] 154 bs.animate(cmb, 'input1', keys) 155 bs.animate(self.node, 'opacity', o_keys) 156 else: 157 assert transition is self.Transition.FADE_IN or transition is None 158 cmb.input0 = position[0] 159 cmb.input1 = position[1] 160 cmb.connectattr('output', self.node, 'position') 161 162 # If we're transitioning out, die at the end of it. 163 if transition_out_delay is not None: 164 bs.timer( 165 transition_delay + transition_out_delay + 1.0, 166 bs.WeakCall(self.handlemessage, bs.DieMessage()), 167 ) 168 169 @override 170 def handlemessage(self, msg: Any) -> Any: 171 assert not self.expired 172 if isinstance(msg, bs.DieMessage): 173 if self.node: 174 self.node.delete() 175 return None 176 return super().handlemessage(msg)
class
Image(bascenev1._actor.Actor):
17class Image(bs.Actor): 18 """Just a wrapped up image node with a few tricks up its sleeve.""" 19 20 class Transition(Enum): 21 """Transition types we support.""" 22 23 FADE_IN = 'fade_in' 24 IN_RIGHT = 'in_right' 25 IN_LEFT = 'in_left' 26 IN_BOTTOM = 'in_bottom' 27 IN_BOTTOM_SLOW = 'in_bottom_slow' 28 IN_TOP_SLOW = 'in_top_slow' 29 30 class Attach(Enum): 31 """Attach types we support.""" 32 33 CENTER = 'center' 34 TOP_CENTER = 'topCenter' 35 TOP_LEFT = 'topLeft' 36 BOTTOM_CENTER = 'bottomCenter' 37 38 def __init__( 39 self, 40 texture: bs.Texture | dict[str, Any], 41 *, 42 position: tuple[float, float] = (0, 0), 43 transition: Transition | None = None, 44 transition_delay: float = 0.0, 45 attach: Attach = Attach.CENTER, 46 color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), 47 scale: tuple[float, float] = (100.0, 100.0), 48 transition_out_delay: float | None = None, 49 mesh_opaque: bs.Mesh | None = None, 50 mesh_transparent: bs.Mesh | None = None, 51 vr_depth: float = 0.0, 52 host_only: bool = False, 53 front: bool = False, 54 ): 55 # pylint: disable=too-many-statements 56 # pylint: disable=too-many-branches 57 # pylint: disable=too-many-locals 58 super().__init__() 59 60 # If they provided a dict as texture, assume its an icon. 61 # otherwise its just a texture value itself. 62 mask_texture: bs.Texture | None 63 if isinstance(texture, dict): 64 tint_color = texture['tint_color'] 65 tint2_color = texture['tint2_color'] 66 tint_texture = texture['tint_texture'] 67 texture = texture['texture'] 68 mask_texture = bs.gettexture('characterIconMask') 69 else: 70 tint_color = (1, 1, 1) 71 tint2_color = None 72 tint_texture = None 73 mask_texture = None 74 75 self.node = bs.newnode( 76 'image', 77 attrs={ 78 'texture': texture, 79 'tint_color': tint_color, 80 'tint_texture': tint_texture, 81 'position': position, 82 'vr_depth': vr_depth, 83 'scale': scale, 84 'mask_texture': mask_texture, 85 'color': color, 86 'absolute_scale': True, 87 'host_only': host_only, 88 'front': front, 89 'attach': attach.value, 90 }, 91 delegate=self, 92 ) 93 94 if mesh_opaque is not None: 95 self.node.mesh_opaque = mesh_opaque 96 if mesh_transparent is not None: 97 self.node.mesh_transparent = mesh_transparent 98 if tint2_color is not None: 99 self.node.tint2_color = tint2_color 100 if transition is self.Transition.FADE_IN: 101 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 102 if transition_out_delay is not None: 103 keys[transition_delay + transition_out_delay] = color[3] 104 keys[transition_delay + transition_out_delay + 0.5] = 0 105 bs.animate(self.node, 'opacity', keys) 106 cmb = self.position_combine = bs.newnode( 107 'combine', owner=self.node, attrs={'size': 2} 108 ) 109 if transition is self.Transition.IN_RIGHT: 110 keys = { 111 transition_delay: position[0] + 1200, 112 transition_delay + 0.2: position[0], 113 } 114 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 115 bs.animate(cmb, 'input0', keys) 116 cmb.input1 = position[1] 117 bs.animate(self.node, 'opacity', o_keys) 118 elif transition is self.Transition.IN_LEFT: 119 keys = { 120 transition_delay: position[0] - 1200, 121 transition_delay + 0.2: position[0], 122 } 123 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 124 if transition_out_delay is not None: 125 keys[transition_delay + transition_out_delay] = position[0] 126 keys[transition_delay + transition_out_delay + 200] = ( 127 -position[0] - 1200 128 ) 129 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 130 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 131 bs.animate(cmb, 'input0', keys) 132 cmb.input1 = position[1] 133 bs.animate(self.node, 'opacity', o_keys) 134 elif transition is self.Transition.IN_BOTTOM_SLOW: 135 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 136 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 137 cmb.input0 = position[0] 138 bs.animate(cmb, 'input1', keys) 139 bs.animate(self.node, 'opacity', o_keys) 140 elif transition is self.Transition.IN_BOTTOM: 141 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 142 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 143 if transition_out_delay is not None: 144 keys[transition_delay + transition_out_delay] = position[1] 145 keys[transition_delay + transition_out_delay + 0.2] = -400 146 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 147 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 148 cmb.input0 = position[0] 149 bs.animate(cmb, 'input1', keys) 150 bs.animate(self.node, 'opacity', o_keys) 151 elif transition is self.Transition.IN_TOP_SLOW: 152 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 153 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 154 cmb.input0 = position[0] 155 bs.animate(cmb, 'input1', keys) 156 bs.animate(self.node, 'opacity', o_keys) 157 else: 158 assert transition is self.Transition.FADE_IN or transition is None 159 cmb.input0 = position[0] 160 cmb.input1 = position[1] 161 cmb.connectattr('output', self.node, 'position') 162 163 # If we're transitioning out, die at the end of it. 164 if transition_out_delay is not None: 165 bs.timer( 166 transition_delay + transition_out_delay + 1.0, 167 bs.WeakCall(self.handlemessage, bs.DieMessage()), 168 ) 169 170 @override 171 def handlemessage(self, msg: Any) -> Any: 172 assert not self.expired 173 if isinstance(msg, bs.DieMessage): 174 if self.node: 175 self.node.delete() 176 return None 177 return super().handlemessage(msg)
Just a wrapped up image node with a few tricks up its sleeve.
Image( texture: _bascenev1.Texture | dict[str, typing.Any], *, position: tuple[float, float] = (0, 0), transition: Image.Transition | None = None, transition_delay: float = 0.0, attach: Image.Attach = <Attach.CENTER: 'center'>, color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), scale: tuple[float, float] = (100.0, 100.0), transition_out_delay: float | None = None, mesh_opaque: _bascenev1.Mesh | None = None, mesh_transparent: _bascenev1.Mesh | None = None, vr_depth: float = 0.0, host_only: bool = False, front: bool = False)
38 def __init__( 39 self, 40 texture: bs.Texture | dict[str, Any], 41 *, 42 position: tuple[float, float] = (0, 0), 43 transition: Transition | None = None, 44 transition_delay: float = 0.0, 45 attach: Attach = Attach.CENTER, 46 color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), 47 scale: tuple[float, float] = (100.0, 100.0), 48 transition_out_delay: float | None = None, 49 mesh_opaque: bs.Mesh | None = None, 50 mesh_transparent: bs.Mesh | None = None, 51 vr_depth: float = 0.0, 52 host_only: bool = False, 53 front: bool = False, 54 ): 55 # pylint: disable=too-many-statements 56 # pylint: disable=too-many-branches 57 # pylint: disable=too-many-locals 58 super().__init__() 59 60 # If they provided a dict as texture, assume its an icon. 61 # otherwise its just a texture value itself. 62 mask_texture: bs.Texture | None 63 if isinstance(texture, dict): 64 tint_color = texture['tint_color'] 65 tint2_color = texture['tint2_color'] 66 tint_texture = texture['tint_texture'] 67 texture = texture['texture'] 68 mask_texture = bs.gettexture('characterIconMask') 69 else: 70 tint_color = (1, 1, 1) 71 tint2_color = None 72 tint_texture = None 73 mask_texture = None 74 75 self.node = bs.newnode( 76 'image', 77 attrs={ 78 'texture': texture, 79 'tint_color': tint_color, 80 'tint_texture': tint_texture, 81 'position': position, 82 'vr_depth': vr_depth, 83 'scale': scale, 84 'mask_texture': mask_texture, 85 'color': color, 86 'absolute_scale': True, 87 'host_only': host_only, 88 'front': front, 89 'attach': attach.value, 90 }, 91 delegate=self, 92 ) 93 94 if mesh_opaque is not None: 95 self.node.mesh_opaque = mesh_opaque 96 if mesh_transparent is not None: 97 self.node.mesh_transparent = mesh_transparent 98 if tint2_color is not None: 99 self.node.tint2_color = tint2_color 100 if transition is self.Transition.FADE_IN: 101 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 102 if transition_out_delay is not None: 103 keys[transition_delay + transition_out_delay] = color[3] 104 keys[transition_delay + transition_out_delay + 0.5] = 0 105 bs.animate(self.node, 'opacity', keys) 106 cmb = self.position_combine = bs.newnode( 107 'combine', owner=self.node, attrs={'size': 2} 108 ) 109 if transition is self.Transition.IN_RIGHT: 110 keys = { 111 transition_delay: position[0] + 1200, 112 transition_delay + 0.2: position[0], 113 } 114 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 115 bs.animate(cmb, 'input0', keys) 116 cmb.input1 = position[1] 117 bs.animate(self.node, 'opacity', o_keys) 118 elif transition is self.Transition.IN_LEFT: 119 keys = { 120 transition_delay: position[0] - 1200, 121 transition_delay + 0.2: position[0], 122 } 123 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 124 if transition_out_delay is not None: 125 keys[transition_delay + transition_out_delay] = position[0] 126 keys[transition_delay + transition_out_delay + 200] = ( 127 -position[0] - 1200 128 ) 129 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 130 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 131 bs.animate(cmb, 'input0', keys) 132 cmb.input1 = position[1] 133 bs.animate(self.node, 'opacity', o_keys) 134 elif transition is self.Transition.IN_BOTTOM_SLOW: 135 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 136 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 137 cmb.input0 = position[0] 138 bs.animate(cmb, 'input1', keys) 139 bs.animate(self.node, 'opacity', o_keys) 140 elif transition is self.Transition.IN_BOTTOM: 141 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 142 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 143 if transition_out_delay is not None: 144 keys[transition_delay + transition_out_delay] = position[1] 145 keys[transition_delay + transition_out_delay + 0.2] = -400 146 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 147 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 148 cmb.input0 = position[0] 149 bs.animate(cmb, 'input1', keys) 150 bs.animate(self.node, 'opacity', o_keys) 151 elif transition is self.Transition.IN_TOP_SLOW: 152 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 153 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 154 cmb.input0 = position[0] 155 bs.animate(cmb, 'input1', keys) 156 bs.animate(self.node, 'opacity', o_keys) 157 else: 158 assert transition is self.Transition.FADE_IN or transition is None 159 cmb.input0 = position[0] 160 cmb.input1 = position[1] 161 cmb.connectattr('output', self.node, 'position') 162 163 # If we're transitioning out, die at the end of it. 164 if transition_out_delay is not None: 165 bs.timer( 166 transition_delay + transition_out_delay + 1.0, 167 bs.WeakCall(self.handlemessage, bs.DieMessage()), 168 )
Instantiates an Actor in the current bascenev1.Activity.
@override
def
handlemessage(self, msg: Any) -> Any:
170 @override 171 def handlemessage(self, msg: Any) -> Any: 172 assert not self.expired 173 if isinstance(msg, bs.DieMessage): 174 if self.node: 175 self.node.delete() 176 return None 177 return super().handlemessage(msg)
General message handling; can be passed any message object.
class
Image.Transition(enum.Enum):
20 class Transition(Enum): 21 """Transition types we support.""" 22 23 FADE_IN = 'fade_in' 24 IN_RIGHT = 'in_right' 25 IN_LEFT = 'in_left' 26 IN_BOTTOM = 'in_bottom' 27 IN_BOTTOM_SLOW = 'in_bottom_slow' 28 IN_TOP_SLOW = 'in_top_slow'
Transition types we support.
class
Image.Attach(enum.Enum):
30 class Attach(Enum): 31 """Attach types we support.""" 32 33 CENTER = 'center' 34 TOP_CENTER = 'topCenter' 35 TOP_LEFT = 'topLeft' 36 BOTTOM_CENTER = 'bottomCenter'
Attach types we support.