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

Just a wrapped up image node with a few tricks up its sleeve.

Image( texture: _ba.Texture | dict[str, typing.Any], position: tuple[float, float] = (0, 0), transition: 'Transition | None' = None, transition_delay: float = 0.0, attach: '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, model_opaque: _ba.Model | None = None, model_transparent: _ba.Model | None = None, vr_depth: float = 0.0, host_only: bool = False, front: bool = False)
 36    def __init__(self,
 37                 texture: ba.Texture | dict[str, Any],
 38                 position: tuple[float, float] = (0, 0),
 39                 transition: Transition | None = None,
 40                 transition_delay: float = 0.0,
 41                 attach: Attach = Attach.CENTER,
 42                 color: Sequence[float] = (1.0, 1.0, 1.0, 1.0),
 43                 scale: tuple[float, float] = (100.0, 100.0),
 44                 transition_out_delay: float | None = None,
 45                 model_opaque: ba.Model | None = None,
 46                 model_transparent: ba.Model | None = None,
 47                 vr_depth: float = 0.0,
 48                 host_only: bool = False,
 49                 front: bool = False):
 50        # pylint: disable=too-many-statements
 51        # pylint: disable=too-many-branches
 52        # pylint: disable=too-many-locals
 53        super().__init__()
 54
 55        # If they provided a dict as texture, assume its an icon.
 56        # otherwise its just a texture value itself.
 57        mask_texture: ba.Texture | None
 58        if isinstance(texture, dict):
 59            tint_color = texture['tint_color']
 60            tint2_color = texture['tint2_color']
 61            tint_texture = texture['tint_texture']
 62            texture = texture['texture']
 63            mask_texture = ba.gettexture('characterIconMask')
 64        else:
 65            tint_color = (1, 1, 1)
 66            tint2_color = None
 67            tint_texture = None
 68            mask_texture = None
 69
 70        self.node = ba.newnode('image',
 71                               attrs={
 72                                   'texture': texture,
 73                                   'tint_color': tint_color,
 74                                   'tint_texture': tint_texture,
 75                                   'position': position,
 76                                   'vr_depth': vr_depth,
 77                                   'scale': scale,
 78                                   'mask_texture': mask_texture,
 79                                   'color': color,
 80                                   'absolute_scale': True,
 81                                   'host_only': host_only,
 82                                   'front': front,
 83                                   'attach': attach.value
 84                               },
 85                               delegate=self)
 86
 87        if model_opaque is not None:
 88            self.node.model_opaque = model_opaque
 89        if model_transparent is not None:
 90            self.node.model_transparent = model_transparent
 91        if tint2_color is not None:
 92            self.node.tint2_color = tint2_color
 93        if transition is self.Transition.FADE_IN:
 94            keys = {transition_delay: 0, transition_delay + 0.5: color[3]}
 95            if transition_out_delay is not None:
 96                keys[transition_delay + transition_out_delay] = color[3]
 97                keys[transition_delay + transition_out_delay + 0.5] = 0
 98            ba.animate(self.node, 'opacity', keys)
 99        cmb = self.position_combine = ba.newnode('combine',
100                                                 owner=self.node,
101                                                 attrs={'size': 2})
102        if transition is self.Transition.IN_RIGHT:
103            keys = {
104                transition_delay: position[0] + 1200,
105                transition_delay + 0.2: position[0]
106            }
107            o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0}
108            ba.animate(cmb, 'input0', keys)
109            cmb.input1 = position[1]
110            ba.animate(self.node, 'opacity', o_keys)
111        elif transition is self.Transition.IN_LEFT:
112            keys = {
113                transition_delay: position[0] - 1200,
114                transition_delay + 0.2: position[0]
115            }
116            o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0}
117            if transition_out_delay is not None:
118                keys[transition_delay + transition_out_delay] = position[0]
119                keys[transition_delay + transition_out_delay +
120                     200] = -position[0] - 1200
121                o_keys[transition_delay + transition_out_delay + 0.15] = 1.0
122                o_keys[transition_delay + transition_out_delay + 0.2] = 0.0
123            ba.animate(cmb, 'input0', keys)
124            cmb.input1 = position[1]
125            ba.animate(self.node, 'opacity', o_keys)
126        elif transition is self.Transition.IN_BOTTOM_SLOW:
127            keys = {
128                transition_delay: -400,
129                transition_delay + 3.5: position[1]
130            }
131            o_keys = {transition_delay: 0.0, transition_delay + 2.0: 1.0}
132            cmb.input0 = position[0]
133            ba.animate(cmb, 'input1', keys)
134            ba.animate(self.node, 'opacity', o_keys)
135        elif transition is self.Transition.IN_BOTTOM:
136            keys = {
137                transition_delay: -400,
138                transition_delay + 0.2: position[1]
139            }
140            o_keys = {transition_delay: 0.0, transition_delay + 0.05: 1.0}
141            if transition_out_delay is not None:
142                keys[transition_delay + transition_out_delay] = position[1]
143                keys[transition_delay + transition_out_delay + 0.2] = -400
144                o_keys[transition_delay + transition_out_delay + 0.15] = 1.0
145                o_keys[transition_delay + transition_out_delay + 0.2] = 0.0
146            cmb.input0 = position[0]
147            ba.animate(cmb, 'input1', keys)
148            ba.animate(self.node, 'opacity', o_keys)
149        elif transition is self.Transition.IN_TOP_SLOW:
150            keys = {transition_delay: 400, transition_delay + 3.5: position[1]}
151            o_keys = {transition_delay: 0.0, transition_delay + 1.0: 1.0}
152            cmb.input0 = position[0]
153            ba.animate(cmb, 'input1', keys)
154            ba.animate(self.node, 'opacity', o_keys)
155        else:
156            assert transition is self.Transition.FADE_IN or transition is None
157            cmb.input0 = position[0]
158            cmb.input1 = position[1]
159        cmb.connectattr('output', self.node, 'position')
160
161        # If we're transitioning out, die at the end of it.
162        if transition_out_delay is not None:
163            ba.timer(transition_delay + transition_out_delay + 1.0,
164                     ba.WeakCall(self.handlemessage, ba.DieMessage()))

Instantiates an Actor in the current ba.Activity.

def handlemessage(self, msg: Any) -> Any:
166    def handlemessage(self, msg: Any) -> Any:
167        assert not self.expired
168        if isinstance(msg, ba.DieMessage):
169            if self.node:
170                self.node.delete()
171            return None
172        return super().handlemessage(msg)

General message handling; can be passed any message object.

Inherited Members
ba._actor.Actor
autoretain
on_expire
expired
exists
is_alive
activity
getactivity
class Image.Transition(enum.Enum):
20    class Transition(Enum):
21        """Transition types we support."""
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'

Transition types we support.

FADE_IN = <Transition.FADE_IN: 'fade_in'>
IN_RIGHT = <Transition.IN_RIGHT: 'in_right'>
IN_LEFT = <Transition.IN_LEFT: 'in_left'>
IN_BOTTOM = <Transition.IN_BOTTOM: 'in_bottom'>
IN_BOTTOM_SLOW = <Transition.IN_BOTTOM_SLOW: 'in_bottom_slow'>
IN_TOP_SLOW = <Transition.IN_TOP_SLOW: 'in_top_slow'>
Inherited Members
enum.Enum
name
value
class Image.Attach(enum.Enum):
29    class Attach(Enum):
30        """Attach types we support."""
31        CENTER = 'center'
32        TOP_CENTER = 'topCenter'
33        TOP_LEFT = 'topLeft'
34        BOTTOM_CENTER = 'bottomCenter'

Attach types we support.

CENTER = <Attach.CENTER: 'center'>
TOP_CENTER = <Attach.TOP_CENTER: 'topCenter'>
TOP_LEFT = <Attach.TOP_LEFT: 'topLeft'>
BOTTOM_CENTER = <Attach.BOTTOM_CENTER: 'bottomCenter'>
Inherited Members
enum.Enum
name
value