Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarNetworkedAnimator.hpp
blob: f3f6568971e8616ed4774d3cbf3aba580073e83d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
#pragma once

#include "StarPeriodicFunction.hpp"
#include "StarAnimatedPartSet.hpp"
#include "StarNetElementSystem.hpp"
#include "StarDrawable.hpp"
#include "StarParticle.hpp"
#include "StarLightSource.hpp"
#include "StarMixer.hpp"

namespace Star {

STAR_CLASS(NetworkedAnimator);
STAR_EXCEPTION(NetworkedAnimatorException, StarException);

// Wraps an AnimatedPartSet with a set of optional light sources and particle
// emitters to produce a network capable animation system.
class NetworkedAnimator : public NetElementSyncGroup {
public:
  // Target for dynamic render data such as sounds and particles that are not
  // persistent and are instead produced during a call to update, and may need
  // to be tracked over time.
  class DynamicTarget {
  public:
    // Calls stopAudio()
    ~DynamicTarget();

    List<AudioInstancePtr> pullNewAudios();
    List<Particle> pullNewParticles();

    // Stops all looping audio immediately and lets non-looping audio finish
    // normally
    void stopAudio();

    // Updates the base position of all un-pulled particles and all active
    // audio.  Not necessary to call, but if not called all pulled data will be
    // relative to (0, 0).
    void updatePosition(Vec2F const& position);

  private:
    friend class NetworkedAnimator;

    void clearFinishedAudio();

    struct PersistentSound {
      Json sound;
      AudioInstancePtr audio;
      float stopRampTime;
    };

    struct ImmediateSound {
      Json sound;
      AudioInstancePtr audio;
    };

    Vec2F position;
    List<AudioInstancePtr> pendingAudios;
    List<Particle> pendingParticles;
    StringMap<PersistentSound> statePersistentSounds;
    StringMap<ImmediateSound> stateImmediateSounds;
    StringMap<List<AudioInstancePtr>> independentSounds;
    HashMap<AudioInstancePtr, Vec2F> currentAudioBasePositions;
  };

  NetworkedAnimator();
  // If passed a string as config, NetworkedAnimator will interpret this as a
  // config path, otherwise it is interpreted as the literal config.
  NetworkedAnimator(Json config, String relativePath = String());

  NetworkedAnimator(NetworkedAnimator&& animator);
  NetworkedAnimator(NetworkedAnimator const& animator);

  NetworkedAnimator& operator=(NetworkedAnimator&& animator);
  NetworkedAnimator& operator=(NetworkedAnimator const& animator);

  StringList stateTypes() const;
  StringList states(String const& stateType) const;

  // Returns whether a state change occurred.  If startNew is true, always
  // forces a state change and starts the state off at the beginning even if
  // this state is already the current state.
  bool setState(String const& stateType, String const& state, bool startNew = false, bool reverse = false);
  bool setLocalState(String const& stateType, String const& state, bool startNew = false, bool reverse = false);
  String state(String const& stateType) const;
  int stateFrame(String const& stateType) const;
  float stateFrameProgress(String const& stateType) const;
  float stateTimer(String const& stateType) const;
  bool stateReverse(String const& stateType) const;

  StringMap<AnimatedPartSet::Part> const& constParts() const;
  StringMap<AnimatedPartSet::Part>& parts();
  StringList partNames() const;

  // Queries, if it exists, a property value from the underlying
  // AnimatedPartSet for the given state or part.  If the property does not
  // exist, returns null.
  Json stateProperty(String const& stateType, String const& propertyName) const;
  Json stateNextProperty(String const& stateType, String const& propertyName) const;
  Json partProperty(String const& partName, String const& propertyName) const;

  // Returns the transformation from flipping and zooming that is applied to
  // all parts in the NetworkedAnimator.
  Mat3F globalTransformation() const;
  // The transformation applied from the given set of transformation groups
  Mat3F groupTransformation(StringList const& transformationGroups) const;
  // The transformation that is applied to the given part NOT including the
  // global transformation
  Mat3F partTransformation(String const& partName) const;
  // Returns the total transformation for the given part, which includes the
  // globalTransformation, as well as the part rotation, scaling, and
  // translation.
  Mat3F finalPartTransformation(String const& partName) const;

  // partPoint / partPoly takes a propertyName and looks up the associated part
  // property and interprets is a Vec2F or a PolyF, then applies the final part
  // transformation and returns it.
  Maybe<Vec2F> partPoint(String const& partName, String const& propertyName) const;
  Maybe<PolyF> partPoly(String const& partName, String const& propertyName) const;

  // Every part image can have one or more <tag> directives in it, which if set
  // here will be replaced by the tag value when constructing Drawables.  All
  // Drawables can also have a <frame> tag which will be set to whatever the
  // current state frame is (1 indexed, so the first frame is 1).
  void setGlobalTag(String tagName, String tagValue);
  void removeGlobalTag(String const& tagName);
  String const* globalTagPtr(String const& tagName) const;
  void setPartTag(String const& partType, String tagName, String tagValue);

  void setPartDrawables(String const& partName, List<Drawable> drawables);
  void addPartDrawables(String const& partName, List<Drawable> drawables);

  String applyPartTags(String const& partName, String apply);

  void setProcessingDirectives(Directives const& directives);
  void setZoom(float zoom);
  bool flipped() const;
  float flippedRelativeCenterLine() const;
  void setFlipped(bool flipped, float relativeCenterLine = 0.0f);

  // Animation rate defaults to 1.0, which means normal animation speed.  This
  // can be used to globally speed up or slow down all components of
  // NetworkedAnimator together.
  void setAnimationRate(float rate);

  // Given angle is an absolute angle.  Will rotate over time at the configured
  // angular velocity unless the immediate flag is set.
  bool hasRotationGroup(String const& rotationGroup) const;
  void rotateGroup(String const& rotationGroup, float targetAngle, bool immediate = false);
  float currentRotationAngle(String const& rotationGroup) const;

  // Transformation groups can be used for arbitrary part transforamtions.
  // They apply immediately, and are optionally interpolated on slaves.
  bool hasTransformationGroup(String const& transformationGroup) const;
  void translateTransformationGroup(String const& transformationGroup, Vec2F const& translation);
  void rotateTransformationGroup(String const& transformationGroup, float rotation, Vec2F const& rotationCenter = Vec2F());
  void scaleTransformationGroup(String const& transformationGroup, float scale, Vec2F const& scaleCenter = Vec2F());
  void scaleTransformationGroup(String const& transformationGroup, Vec2F const& scale, Vec2F const& scaleCenter = Vec2F());
  void transformTransformationGroup(String const& transformationGroup, float a, float b, float c, float d, float tx, float ty);
  void resetTransformationGroup(String const& transformationGroup);

  void translateLocalTransformationGroup(String const& transformationGroup, Vec2F const& translation);
  void rotateLocalTransformationGroup(String const& transformationGroup, float rotation, Vec2F const& rotationCenter = Vec2F());
  void scaleLocalTransformationGroup(String const& transformationGroup, float scale, Vec2F const& scaleCenter = Vec2F());
  void scaleLocalTransformationGroup(String const& transformationGroup, Vec2F const& scale, Vec2F const& scaleCenter = Vec2F());
  void transformLocalTransformationGroup(String const& transformationGroup, float a, float b, float c, float d, float tx, float ty);
  void resetLocalTransformationGroup(String const& transformationGroup);

  bool hasParticleEmitter(String const& emitterName) const;
  // Active particle emitters emit over time based on emission rate/variance.
  void setParticleEmitterActive(String const& emitterName, bool active);
  // Set the emission rate in particles / sec for a given emitter
  void setParticleEmitterEmissionRate(String const& emitterName, float emissionRate);
  // Set the optional particle emitter offset region, which particles will be
  // spread around randomly before being spawned
  void setParticleEmitterOffsetRegion(String const& emitterName, RectF const& offsetRegion);

  // Number of times to cycle when emitting a burst of particles.
  void setParticleEmitterBurstCount(String const& emitterName, unsigned burstCount);

  // Cause one time burst of all types of particles in an emitter looping around
  // burstCount times
  void burstParticleEmitter(String const& emitterName);

  bool hasLight(String const& lightName) const;
  void setLightActive(String const& lightName, bool active);
  void setLightPosition(String const& lightName, Vec2F position);
  void setLightColor(String const& lightName, Color color);
  void setLightPointAngle(String const& lightName, float angle);

  bool hasSound(String const& soundName) const;
  void setSoundPool(String const& soundName, StringList soundPool);
  // Plays a sound from the given independent sound pool.  Multiple sounds may
  // be played as part of this group, and playing a new one will not interrupt
  // an older one.
  void playSound(String const& soundName, int loops = 0);

  // Setting the sound position, volume, and speed will affect future sounds in
  // this group, as well as any still active sounds from this group.
  void setSoundPosition(String const& soundName, Vec2F const& position);

  void setSoundVolume(String const& soundName, float volume, float rampTime = 0.0f);
  void setSoundPitchMultiplier(String const& soundName, float pitchMultiplier, float rampTime = 0.0f);

  // Stop all sounds played from this sound group
  void stopAllSounds(String const& soundName, float rampTime = 0.0f);

  void setEffectEnabled(String const& effect, bool enabled);

  List<Drawable> drawables(Vec2F const& translate = Vec2F()) const;
  List<pair<Drawable, float>> drawablesWithZLevel(Vec2F const& translate = Vec2F()) const;

  List<LightSource> lightSources(Vec2F const& translate = Vec2F()) const;

  // Dynamic target is optional, if not given, generated particles and sounds
  // will be discarded
  void update(float dt, DynamicTarget* dynamicTarget);

  // Run through the current animations until the final frame, including any
  // transition animations.
  void finishAnimations();
  uint8_t version() const;

private:
  struct RotationGroup {
    float angularVelocity;
    Vec2F rotationCenter;

    NetElementFloat targetAngle;
    float currentAngle;

    NetElementEvent netImmediateEvent;
  };

  struct TransformationGroup {
    Mat3F affineTransform() const;
    void setAffineTransform(Mat3F const& matrix);

    Mat3F localAffineTransform() const;
    void setLocalAffineTransform(Mat3F const& matrix);

    Mat3F animationAffineTransform() const;
    void setAnimationAffineTransform(Mat3F const& matrix);
    void setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress);

    bool interpolated;

    Mat3F localTransform;

    NetElementFloat xTranslation;
    NetElementFloat yTranslation;
    NetElementFloat xScale;
    NetElementFloat yScale;
    NetElementFloat xShear;
    NetElementFloat yShear;

    float xTranslationAnimation;
    float yTranslationAnimation;
    float xScaleAnimation;
    float yScaleAnimation;
    float xShearAnimation;
    float yShearAnimation;

  };

  struct ParticleEmitter {
    struct ParticleConfig {
      ParticleVariantCreator creator;
      unsigned count;
      Vec2F offset;
      bool flip;
    };

    NetElementFloat emissionRate;
    float emissionRateVariance;
    NetElementData<RectF> offsetRegion;
    Maybe<String> anchorPart;
    StringList transformationGroups;
    Maybe<String> rotationGroup;
    Maybe<Vec2F> rotationCenter;

    List<ParticleConfig> particleList;

    NetElementBool active;
    NetElementUInt burstCount;
    NetElementUInt randomSelectCount;
    NetElementEvent burstEvent;

    float timer;
  };

  struct Light {
    NetElementBool active;
    NetElementFloat xPosition;
    NetElementFloat yPosition;
    NetElementData<Color> color;
    NetElementFloat pointAngle;
    Maybe<String> anchorPart;
    StringList transformationGroups;
    Maybe<String> rotationGroup;
    Maybe<Vec2F> rotationCenter;

    Maybe<PeriodicFunction<float>> flicker;
    bool pointLight;
    float pointBeam;
    float beamAmbience;
  };

  enum class SoundSignal {
    Play,
    StopAll
  };

  struct Sound {
    float rangeMultiplier;
    NetElementData<StringList> soundPool;
    NetElementFloat xPosition;
    NetElementFloat yPosition;
    NetElementFloat volumeTarget;
    NetElementFloat volumeRampTime;
    NetElementFloat pitchMultiplierTarget;
    NetElementFloat pitchMultiplierRampTime;
    NetElementInt loops;
    NetElementSignal<SoundSignal> signals;
  };

  struct Effect {
    String type;
    float time;
    Directives directives;

    NetElementBool enabled;
    float timer;
  };

  struct StateInfo {
    NetElementSize stateIndex;
    NetElementEvent startedEvent;
    bool wasUpdated;
    NetElementBool reverse;
  };

  void setupNetStates();

  void netElementsNeedLoad(bool full) override;
  void netElementsNeedStore() override;

  Json mergeIncludes(Json config, Json includes, String relativePath);

  String m_relativePath;
  uint8_t m_animatorVersion;

  AnimatedPartSet m_animatedParts;
  OrderedHashMap<String, StateInfo> m_stateInfo;
  OrderedHashMap<String, RotationGroup> m_rotationGroups;
  OrderedHashMap<String, TransformationGroup> m_transformationGroups;
  OrderedHashMap<String, ParticleEmitter> m_particleEmitters;
  OrderedHashMap<String, Light> m_lights;
  OrderedHashMap<String, Sound> m_sounds;
  OrderedHashMap<String, Effect> m_effects;

  NetElementData<Directives> m_processingDirectives;
  NetElementFloat m_zoom;

  NetElementBool m_flipped;
  NetElementFloat m_flippedRelativeCenterLine;

  NetElementFloat m_animationRate;

  NetElementHashMap<String, String> m_globalTags;
  StableStringMap<NetElementHashMap<String, String>> m_partTags;

  HashMap<String,List<Drawable>> m_partDrawables;

  mutable StringMap<std::pair<size_t, Drawable>> m_cachedPartDrawables;
};

}