123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- # author: Ethosa
- ## Provides animation in most nodes
- import
- ../thirdparty/gl,
- ../core/enums,
- ../core/tools,
- ../private/templates,
- node
- type
- AnimationObject* = object
- states: seq[tuple[tick: int, value: float]]
- obj: ptr float
- AnimationPlayerObj* {.final.} = object of NodeObj
- objects*: seq[AnimationObject]
- duration*: int64
- tick*: int64
- is_played*: bool
- loop*: bool
- bezier*: tuple[p0, p1: float]
- mode*: AnimationMode
- AnimationPlayerRef* = ref AnimationPlayerObj
- proc AnimationPlayer*(name: string = "AnimationPlayer"): AnimationPlayerRef =
- runnableExamples:
- var animplayer = AnimationPlayer("AnimationPlayer")
- nodepattern(AnimationPlayerRef)
- result.objects = @[]
- result.bezier = (0.25, 0.75)
- result.duration = 180
- result.tick = 0
- result.is_played = false
- result.loop = true
- result.kind = ANIMATION_PLAYER_NODE
- result.type_of_node = NODE_TYPE_DEFAULT
- result.mode = ANIMATION_NORMAL
- # --- Private --- #
- proc ease(self: AnimationPlayerRef,
- states: seq[tuple[tick: int, value: float]]): float =
- var time = (self.tick - states[0].tick).float /
- ((states[1].tick - states[0].tick).float / 2.0)
- let diff = states[1].value - states[0].value
- if time < 1:
- return diff / 2 * time * time + states[0].value
- time -= 1
- -diff / 2 * (time * (time - 2) - 1) + states[0].value
- proc bezier(self: AnimationPlayerRef,
- states: seq[tuple[tick: int, value: float]], current: float): float =
- let
- step = 1f / (states[1].tick - states[0].tick).float
- t = step * (self.tick - states[0].tick).float
- diff = states[1].value - states[0].value
- result = cubic_bezier(t, 0.0, self.bezier[0], self.bezier[1], 1.0)
- return states[0].value + diff*result
- # --- Public --- #
- method addState*(self: AnimationPlayerRef, obj: ptr float, states: seq[tuple[tick: int, value: float]]) {.base.} =
- ## Adds a new state to AnimationPlayer.
- self.objects.add(AnimationObject(
- states: states,
- obj: obj
- ))
- method draw*(self: AnimationPlayerRef, w: GLfloat, h: GLfloat) =
- ## This uses in the `window.nim`.
- {.warning[LockLevel]: off.}
- if self.is_played:
- if self.tick > self.duration:
- self.tick = 0
- if not self.loop:
- self.is_played = false
- return
- var
- current_states: seq[tuple[tick: int, value: float]] = @[]
- current: ptr float
- for obj in self.objects:
- current = obj.obj
- for i in countdown(obj.states.high, 0):
- if self.tick >= obj.states[i].tick:
- current_states.add(obj.states[i])
- if self.tick == obj.states[i].tick:
- current[] = obj.states[i].value
- break
- if current_states.len == 1:
- for i in 0..obj.states.high:
- if current_states[0].tick < obj.states[i].tick:
- current_states.add(obj.states[i])
- break
-
- if current_states.len == 2:
- case self.mode
- of ANIMATION_NORMAL:
- let
- diff_time: float = (current_states[1].tick - current_states[0].tick).float
- diff: float = current_states[1].value - current_states[0].value
- current[] = current_states[0].value + (self.tick - current_states[0].tick).float/diff_time * diff
- of ANIMATION_EASE:
- current[] = ease(self, current_states)
- of ANIMATION_BEZIER:
- current[] = bezier(self, current_states, current[])
- current_states = @[]
- self.tick += 1
- method play*(self: AnimationPlayerRef) {.base.} =
- ## Plays animation.
- self.is_played = true
- method setDuration*(self: AnimationPlayerRef, duration: int) {.base.} =
- ## Changes animation duration.
- self.duration = duration
- method stop*(self: AnimationPlayerRef) {.base.} =
- ## Stops animation.
- self.is_played = false
|