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, use it to wire up extended 60 # stuff like tints and masks. 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 67 # Assume we're dealing with a character icon but allow 68 # overriding. 69 mask_tex_name = texture.get('mask_texture', 'characterIconMask') 70 mask_texture = ( 71 None if mask_tex_name is None else bs.gettexture(mask_tex_name) 72 ) 73 texture = texture['texture'] 74 else: 75 tint_color = (1, 1, 1) 76 tint2_color = None 77 tint_texture = None 78 mask_texture = None 79 80 self.node = bs.newnode( 81 'image', 82 attrs={ 83 'texture': texture, 84 'tint_color': tint_color, 85 'tint_texture': tint_texture, 86 'position': position, 87 'vr_depth': vr_depth, 88 'scale': scale, 89 'mask_texture': mask_texture, 90 'color': color, 91 'absolute_scale': True, 92 'host_only': host_only, 93 'front': front, 94 'attach': attach.value, 95 }, 96 delegate=self, 97 ) 98 99 if mesh_opaque is not None: 100 self.node.mesh_opaque = mesh_opaque 101 if mesh_transparent is not None: 102 self.node.mesh_transparent = mesh_transparent 103 if tint2_color is not None: 104 self.node.tint2_color = tint2_color 105 if transition is self.Transition.FADE_IN: 106 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 107 if transition_out_delay is not None: 108 keys[transition_delay + transition_out_delay] = color[3] 109 keys[transition_delay + transition_out_delay + 0.5] = 0 110 bs.animate(self.node, 'opacity', keys) 111 cmb = self.position_combine = bs.newnode( 112 'combine', owner=self.node, attrs={'size': 2} 113 ) 114 if transition is self.Transition.IN_RIGHT: 115 keys = { 116 transition_delay: position[0] + 1200, 117 transition_delay + 0.2: position[0], 118 } 119 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 120 bs.animate(cmb, 'input0', keys) 121 cmb.input1 = position[1] 122 bs.animate(self.node, 'opacity', o_keys) 123 elif transition is self.Transition.IN_LEFT: 124 keys = { 125 transition_delay: position[0] - 1200, 126 transition_delay + 0.2: position[0], 127 } 128 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 129 if transition_out_delay is not None: 130 keys[transition_delay + transition_out_delay] = position[0] 131 keys[transition_delay + transition_out_delay + 200] = ( 132 -position[0] - 1200 133 ) 134 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 135 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 136 bs.animate(cmb, 'input0', keys) 137 cmb.input1 = position[1] 138 bs.animate(self.node, 'opacity', o_keys) 139 elif transition is self.Transition.IN_BOTTOM_SLOW: 140 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 141 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 142 cmb.input0 = position[0] 143 bs.animate(cmb, 'input1', keys) 144 bs.animate(self.node, 'opacity', o_keys) 145 elif transition is self.Transition.IN_BOTTOM: 146 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 147 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 148 if transition_out_delay is not None: 149 keys[transition_delay + transition_out_delay] = position[1] 150 keys[transition_delay + transition_out_delay + 0.2] = -400 151 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 152 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 153 cmb.input0 = position[0] 154 bs.animate(cmb, 'input1', keys) 155 bs.animate(self.node, 'opacity', o_keys) 156 elif transition is self.Transition.IN_TOP_SLOW: 157 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 158 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 159 cmb.input0 = position[0] 160 bs.animate(cmb, 'input1', keys) 161 bs.animate(self.node, 'opacity', o_keys) 162 else: 163 assert transition is self.Transition.FADE_IN or transition is None 164 cmb.input0 = position[0] 165 cmb.input1 = position[1] 166 cmb.connectattr('output', self.node, 'position') 167 168 # If we're transitioning out, die at the end of it. 169 if transition_out_delay is not None: 170 bs.timer( 171 transition_delay + transition_out_delay + 1.0, 172 bs.WeakCall(self.handlemessage, bs.DieMessage()), 173 ) 174 175 @override 176 def handlemessage(self, msg: Any) -> Any: 177 assert not self.expired 178 if isinstance(msg, bs.DieMessage): 179 if self.node: 180 self.node.delete() 181 return None 182 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, use it to wire up extended 61 # stuff like tints and masks. 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 68 # Assume we're dealing with a character icon but allow 69 # overriding. 70 mask_tex_name = texture.get('mask_texture', 'characterIconMask') 71 mask_texture = ( 72 None if mask_tex_name is None else bs.gettexture(mask_tex_name) 73 ) 74 texture = texture['texture'] 75 else: 76 tint_color = (1, 1, 1) 77 tint2_color = None 78 tint_texture = None 79 mask_texture = None 80 81 self.node = bs.newnode( 82 'image', 83 attrs={ 84 'texture': texture, 85 'tint_color': tint_color, 86 'tint_texture': tint_texture, 87 'position': position, 88 'vr_depth': vr_depth, 89 'scale': scale, 90 'mask_texture': mask_texture, 91 'color': color, 92 'absolute_scale': True, 93 'host_only': host_only, 94 'front': front, 95 'attach': attach.value, 96 }, 97 delegate=self, 98 ) 99 100 if mesh_opaque is not None: 101 self.node.mesh_opaque = mesh_opaque 102 if mesh_transparent is not None: 103 self.node.mesh_transparent = mesh_transparent 104 if tint2_color is not None: 105 self.node.tint2_color = tint2_color 106 if transition is self.Transition.FADE_IN: 107 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 108 if transition_out_delay is not None: 109 keys[transition_delay + transition_out_delay] = color[3] 110 keys[transition_delay + transition_out_delay + 0.5] = 0 111 bs.animate(self.node, 'opacity', keys) 112 cmb = self.position_combine = bs.newnode( 113 'combine', owner=self.node, attrs={'size': 2} 114 ) 115 if transition is self.Transition.IN_RIGHT: 116 keys = { 117 transition_delay: position[0] + 1200, 118 transition_delay + 0.2: position[0], 119 } 120 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 121 bs.animate(cmb, 'input0', keys) 122 cmb.input1 = position[1] 123 bs.animate(self.node, 'opacity', o_keys) 124 elif transition is self.Transition.IN_LEFT: 125 keys = { 126 transition_delay: position[0] - 1200, 127 transition_delay + 0.2: position[0], 128 } 129 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 130 if transition_out_delay is not None: 131 keys[transition_delay + transition_out_delay] = position[0] 132 keys[transition_delay + transition_out_delay + 200] = ( 133 -position[0] - 1200 134 ) 135 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 136 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 137 bs.animate(cmb, 'input0', keys) 138 cmb.input1 = position[1] 139 bs.animate(self.node, 'opacity', o_keys) 140 elif transition is self.Transition.IN_BOTTOM_SLOW: 141 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 142 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 143 cmb.input0 = position[0] 144 bs.animate(cmb, 'input1', keys) 145 bs.animate(self.node, 'opacity', o_keys) 146 elif transition is self.Transition.IN_BOTTOM: 147 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 148 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 149 if transition_out_delay is not None: 150 keys[transition_delay + transition_out_delay] = position[1] 151 keys[transition_delay + transition_out_delay + 0.2] = -400 152 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 153 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 154 cmb.input0 = position[0] 155 bs.animate(cmb, 'input1', keys) 156 bs.animate(self.node, 'opacity', o_keys) 157 elif transition is self.Transition.IN_TOP_SLOW: 158 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 159 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 160 cmb.input0 = position[0] 161 bs.animate(cmb, 'input1', keys) 162 bs.animate(self.node, 'opacity', o_keys) 163 else: 164 assert transition is self.Transition.FADE_IN or transition is None 165 cmb.input0 = position[0] 166 cmb.input1 = position[1] 167 cmb.connectattr('output', self.node, 'position') 168 169 # If we're transitioning out, die at the end of it. 170 if transition_out_delay is not None: 171 bs.timer( 172 transition_delay + transition_out_delay + 1.0, 173 bs.WeakCall(self.handlemessage, bs.DieMessage()), 174 ) 175 176 @override 177 def handlemessage(self, msg: Any) -> Any: 178 assert not self.expired 179 if isinstance(msg, bs.DieMessage): 180 if self.node: 181 self.node.delete() 182 return None 183 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, use it to wire up extended 61 # stuff like tints and masks. 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 68 # Assume we're dealing with a character icon but allow 69 # overriding. 70 mask_tex_name = texture.get('mask_texture', 'characterIconMask') 71 mask_texture = ( 72 None if mask_tex_name is None else bs.gettexture(mask_tex_name) 73 ) 74 texture = texture['texture'] 75 else: 76 tint_color = (1, 1, 1) 77 tint2_color = None 78 tint_texture = None 79 mask_texture = None 80 81 self.node = bs.newnode( 82 'image', 83 attrs={ 84 'texture': texture, 85 'tint_color': tint_color, 86 'tint_texture': tint_texture, 87 'position': position, 88 'vr_depth': vr_depth, 89 'scale': scale, 90 'mask_texture': mask_texture, 91 'color': color, 92 'absolute_scale': True, 93 'host_only': host_only, 94 'front': front, 95 'attach': attach.value, 96 }, 97 delegate=self, 98 ) 99 100 if mesh_opaque is not None: 101 self.node.mesh_opaque = mesh_opaque 102 if mesh_transparent is not None: 103 self.node.mesh_transparent = mesh_transparent 104 if tint2_color is not None: 105 self.node.tint2_color = tint2_color 106 if transition is self.Transition.FADE_IN: 107 keys = {transition_delay: 0, transition_delay + 0.5: color[3]} 108 if transition_out_delay is not None: 109 keys[transition_delay + transition_out_delay] = color[3] 110 keys[transition_delay + transition_out_delay + 0.5] = 0 111 bs.animate(self.node, 'opacity', keys) 112 cmb = self.position_combine = bs.newnode( 113 'combine', owner=self.node, attrs={'size': 2} 114 ) 115 if transition is self.Transition.IN_RIGHT: 116 keys = { 117 transition_delay: position[0] + 1200, 118 transition_delay + 0.2: position[0], 119 } 120 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 121 bs.animate(cmb, 'input0', keys) 122 cmb.input1 = position[1] 123 bs.animate(self.node, 'opacity', o_keys) 124 elif transition is self.Transition.IN_LEFT: 125 keys = { 126 transition_delay: position[0] - 1200, 127 transition_delay + 0.2: position[0], 128 } 129 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 130 if transition_out_delay is not None: 131 keys[transition_delay + transition_out_delay] = position[0] 132 keys[transition_delay + transition_out_delay + 200] = ( 133 -position[0] - 1200 134 ) 135 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 136 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 137 bs.animate(cmb, 'input0', keys) 138 cmb.input1 = position[1] 139 bs.animate(self.node, 'opacity', o_keys) 140 elif transition is self.Transition.IN_BOTTOM_SLOW: 141 keys = {transition_delay: -400, transition_delay + 3.5: position[1]} 142 o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0} 143 cmb.input0 = position[0] 144 bs.animate(cmb, 'input1', keys) 145 bs.animate(self.node, 'opacity', o_keys) 146 elif transition is self.Transition.IN_BOTTOM: 147 keys = {transition_delay: -400, transition_delay + 0.2: position[1]} 148 o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0} 149 if transition_out_delay is not None: 150 keys[transition_delay + transition_out_delay] = position[1] 151 keys[transition_delay + transition_out_delay + 0.2] = -400 152 o_keys[transition_delay + transition_out_delay + 0.15] = 1.0 153 o_keys[transition_delay + transition_out_delay + 0.2] = 0.0 154 cmb.input0 = position[0] 155 bs.animate(cmb, 'input1', keys) 156 bs.animate(self.node, 'opacity', o_keys) 157 elif transition is self.Transition.IN_TOP_SLOW: 158 keys = {transition_delay: 400, transition_delay + 3.5: position[1]} 159 o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0} 160 cmb.input0 = position[0] 161 bs.animate(cmb, 'input1', keys) 162 bs.animate(self.node, 'opacity', o_keys) 163 else: 164 assert transition is self.Transition.FADE_IN or transition is None 165 cmb.input0 = position[0] 166 cmb.input1 = position[1] 167 cmb.connectattr('output', self.node, 'position') 168 169 # If we're transitioning out, die at the end of it. 170 if transition_out_delay is not None: 171 bs.timer( 172 transition_delay + transition_out_delay + 1.0, 173 bs.WeakCall(self.handlemessage, bs.DieMessage()), 174 )
Instantiates an Actor in the current bascenev1.Activity.
@override
def
handlemessage(self, msg: Any) -> Any:
176 @override 177 def handlemessage(self, msg: Any) -> Any: 178 assert not self.expired 179 if isinstance(msg, bs.DieMessage): 180 if self.node: 181 self.node.delete() 182 return None 183 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.