Torque3D Documentation / _generateds / afxEA_PhraseEffect.cpp

afxEA_PhraseEffect.cpp

Engine/source/afx/ea/afxEA_PhraseEffect.cpp

More...

Classes:

Detailed Description

  1
  2
  3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  5// Copyright (C) 2015 Faust Logic, Inc.
  6//
  7// Permission is hereby granted, free of charge, to any person obtaining a copy
  8// of this software and associated documentation files (the "Software"), to
  9// deal in the Software without restriction, including without limitation the
 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 11// sell copies of the Software, and to permit persons to whom the Software is
 12// furnished to do so, subject to the following conditions:
 13//
 14// The above copyright notice and this permission notice shall be included in
 15// all copies or substantial portions of the Software.
 16//
 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 23// IN THE SOFTWARE.
 24//
 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 26
 27#include <typeinfo>
 28#include "afx/arcaneFX.h"
 29
 30#include "console/compiler.h"
 31#include "T3D/player.h"
 32
 33#include "afx/afxEffectDefs.h"
 34#include "afx/afxPhrase.h"
 35#include "afx/afxEffectWrapper.h"
 36#include "afx/afxChoreographer.h"
 37#include "afx/ce/afxPhraseEffect.h"
 38
 39//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 40// afxEA_PhraseEffect 
 41
 42class afxEA_PhraseEffect : public afxEffectWrapper
 43{
 44  typedef afxEffectWrapper Parent;
 45
 46  afxPhraseEffectData*  phrase_fx_data;
 47  Vector<afxPhrase*>*   active_phrases;
 48  U32                   last_trigger_mask;
 49
 50  Vector<afxPhrase*>    _phrases_a;
 51  Vector<afxPhrase*>    _phrases_b;
 52
 53  void                  grab_constraint_triggers(U32& trigger_mask);
 54  void                  grab_player_triggers(U32& trigger_mask);
 55
 56  void                  do_runtime_substitutions();
 57  void                  trigger_new_phrase();
 58  void                  update_active_phrases(F32 dt);
 59  void                  cleanup_finished_phrases();
 60
 61public:
 62  /*C*/                 afxEA_PhraseEffect();
 63  /*D*/                 ~afxEA_PhraseEffect();
 64
 65  virtual void          ea_set_datablock(SimDataBlock*);
 66  virtual bool          ea_start();
 67  virtual bool          ea_update(F32 dt);
 68  virtual void          ea_finish(bool was_stopped);
 69
 70  virtual bool          ea_is_enabled() { return true; }
 71};
 72
 73//~~~~~~~~~~~~~~~~~~~~//
 74
 75afxEA_PhraseEffect::afxEA_PhraseEffect()
 76{
 77  phrase_fx_data = 0;
 78  active_phrases = &_phrases_a;
 79  last_trigger_mask = 0;
 80}
 81
 82afxEA_PhraseEffect::~afxEA_PhraseEffect()
 83{
 84  if (phrase_fx_data && phrase_fx_data->isTempClone())
 85    delete phrase_fx_data;
 86  phrase_fx_data = 0;
 87
 88  for (S32 i = 0; i < _phrases_a.size(); i++)
 89  {
 90    if (_phrases_a[i])
 91      delete _phrases_a[i];
 92  }
 93
 94  for (S32 i = 0; i < _phrases_b.size(); i++)
 95  {
 96    if (_phrases_b[i])
 97      delete _phrases_b[i];
 98  }
 99}
100
101void afxEA_PhraseEffect::ea_set_datablock(SimDataBlock* db)
102{
103  phrase_fx_data = dynamic_cast<afxPhraseEffectData*>(db);
104}
105
106bool afxEA_PhraseEffect::ea_start()
107{
108  if (!phrase_fx_data)
109  {
110    Con::errorf("afxEA_PhraseEffect::ea_start() -- missing or incompatible datablock.");
111    return false;
112  }
113
114  //last_trigger_mask = choreographer->getTriggerMask();
115  last_trigger_mask = 0xffffffff;
116
117  return true;
118}
119
120void afxEA_PhraseEffect::grab_constraint_triggers(U32& trigger_mask)
121{
122  afxConstraint* pos_cons = getPosConstraint();
123  if (pos_cons)
124    trigger_mask |= pos_cons->getTriggers();
125}
126
127void afxEA_PhraseEffect::grab_player_triggers(U32& trigger_mask)
128{
129  afxConstraint* pos_cons = getPosConstraint();
130  Player* player = (pos_cons) ? dynamic_cast<Player*>(pos_cons->getSceneObject()) : 0;
131  if (player)
132  {
133    if (player->isClientObject())
134      trigger_mask |= player->getClientEventTriggers();
135    else
136      trigger_mask |= player->getServerEventTriggers();
137  }
138}
139
140bool afxEA_PhraseEffect::ea_update(F32 dt)
141{
142  if (mFade_value >= 1.0f)
143  {
144    //
145    // Choreographer Triggers:
146    //    These triggers can come from the choreographer owning this effect.
147    //    They must be set explicitly by calls to afxChoreographer
148    //    console-methods, setTriggerBit(), or clearTriggerBit().
149    //
150    U32 trigger_mask = (phrase_fx_data->no_choreographer_trigs) ? 0 : mChoreographer->getTriggerMask();
151
152    //
153    // Constraint Triggers:
154    //    These triggers can come from the position contraint if it is:
155    //      -- a TSStatic or ShapeBase derived object with dts triggers. 
156    //      -- a trigger producing effect such as afxModel.
157    //
158    if (!phrase_fx_data->no_cons_trigs)
159      grab_constraint_triggers(trigger_mask);
160
161    //
162    // Player Triggers:
163    //    These triggers can come from the position contraint if it is
164    //    a Player or Player-derived object.
165    //
166    if (!phrase_fx_data->no_player_trigs)
167      grab_player_triggers(trigger_mask);
168
169    // any change in the triggers?
170    if (trigger_mask != last_trigger_mask)
171    {
172      if (phrase_fx_data->phrase_type == afxPhraseEffectData::PHRASE_CONTINUOUS)
173      {
174        bool last_state, new_state;
175        if (phrase_fx_data->match_type == afxPhraseEffectData::MATCH_ANY)
176        {
177          last_state = ((last_trigger_mask & phrase_fx_data->trigger_mask) != 0);
178          new_state = ((trigger_mask & phrase_fx_data->trigger_mask) != 0);
179        }
180        else
181        {
182          last_state = ((last_trigger_mask & phrase_fx_data->trigger_mask) == phrase_fx_data->trigger_mask);
183          new_state = ((trigger_mask & phrase_fx_data->trigger_mask) == phrase_fx_data->trigger_mask);
184        }
185        if (new_state != last_state)
186        {
187          bool state_on = phrase_fx_data->match_state & afxPhraseEffectData::STATE_ON;
188          if (new_state == state_on) // start trigger
189          {
190            trigger_new_phrase();
191          }
192          else // stop trigger
193          {
194            for (S32 i = 0; i < active_phrases->size(); i++)
195            {
196              (*active_phrases)[i]->stop(mLife_elapsed);
197            }          
198          }
199        }
200     }
201      else // if (phrase_fx_data->phrase_type == afxPhraseEffectData::PHRASE_TRIGGERED)
202      {
203        bool did_trigger = false;
204        U32 changed_bits = (last_trigger_mask ^ trigger_mask);
205
206        if ((phrase_fx_data->match_state & afxPhraseEffectData::STATE_ON) != 0)
207        {
208          // check for trigger bits that just switched to on state
209          U32 changed_on_bits = (changed_bits & trigger_mask);
210          if (phrase_fx_data->match_type == afxPhraseEffectData::MATCH_ANY)
211            did_trigger = ((changed_on_bits & phrase_fx_data->trigger_mask) != 0);
212          else
213            did_trigger = ((changed_on_bits & phrase_fx_data->trigger_mask) == phrase_fx_data->trigger_mask);
214        }
215
216        if (!did_trigger && ((phrase_fx_data->match_state & afxPhraseEffectData::STATE_OFF) != 0))
217        {
218          // check for trigger bits that just switched to off state
219          U32 changed_off_bits = (changed_bits & last_trigger_mask);
220          if (phrase_fx_data->match_type == afxPhraseEffectData::MATCH_ANY)
221            did_trigger = ((changed_off_bits & phrase_fx_data->trigger_mask) != 0);
222          else
223            did_trigger = ((changed_off_bits & phrase_fx_data->trigger_mask) == phrase_fx_data->trigger_mask);
224        }
225
226        if (did_trigger)
227          trigger_new_phrase();
228      }
229
230      last_trigger_mask = trigger_mask;
231    }
232  }
233
234  update_active_phrases(dt);
235
236  cleanup_finished_phrases();
237
238  return true;
239}
240
241void afxEA_PhraseEffect::ea_finish(bool was_stopped)
242{
243  for (S32 i = 0; i < active_phrases->size(); i++)
244  {
245    (*active_phrases)[i]->stop(mLife_elapsed);
246  }
247}
248
249void afxEA_PhraseEffect::do_runtime_substitutions()
250{
251  // only clone the datablock if there are substitutions
252  if (phrase_fx_data->getSubstitutionCount() > 0)
253  {
254    // clone the datablock and perform substitutions
255    afxPhraseEffectData* orig_db = phrase_fx_data;
256    phrase_fx_data = new afxPhraseEffectData(*orig_db, true);
257    orig_db->performSubstitutions(phrase_fx_data, mChoreographer, mGroup_index);
258  }
259}
260
261void afxEA_PhraseEffect::trigger_new_phrase()
262{
263  //afxPhrase* phrase = new afxPhrase(choreographer->isServerObject(), /*willStop=*/false);
264  bool will_stop = phrase_fx_data->phrase_type == afxPhraseEffectData::PHRASE_CONTINUOUS;
265  afxPhrase* phrase = new afxPhrase(mChoreographer->isServerObject(), will_stop);
266  phrase->init(phrase_fx_data->fx_list, mDatablock->ewd_timing.lifetime, mChoreographer, mTime_factor, phrase_fx_data->n_loops, mGroup_index);
267  phrase->start(0, 0);
268  if (phrase->isEmpty())
269  {
270    delete phrase;
271    return;
272  }
273
274  if (phrase_fx_data->on_trig_cmd != ST_NULLSTRING)
275  {
276    char obj_str[32];
277    dStrcpy(obj_str, Con::getIntArg(mChoreographer->getId()), 32);
278
279    char index_str[32];
280    dStrcpy(index_str, Con::getIntArg(mGroup_index), 32);
281
282    char buffer[1024];
283    char* b = buffer;
284    const char* v = phrase_fx_data->on_trig_cmd;
285    while (*v != '\0')
286    {
287      if (v[0] == '%' && v[1] == '%')
288      {
289        const char* s = obj_str;
290        while (*s != '\0')
291        {
292          b[0] = s[0];
293          b++;
294          s++;
295        }
296        v += 2;
297      }
298      else if (v[0] == '#' && v[1] == '#')
299      {
300        const char* s = index_str;
301        while (*s != '\0')
302        {
303          b[0] = s[0];
304          b++;
305          s++;
306        }
307        v += 2;
308      }
309      else
310      {
311        b[0] = v[0];
312        b++; 
313        v++;
314      }
315    }
316    b[0] = '\0';
317
318    Compiler::gSyntaxError = false;
319    //Con::errorf("EVAL [%s]", avar("%s;", buffer));
320    Con::evaluate(avar("%s;", buffer), false, 0);
321    if (Compiler::gSyntaxError)
322    {
323      Con::errorf("onTriggerCommand \"%s\" -- syntax error", phrase_fx_data->on_trig_cmd);
324      Compiler::gSyntaxError = false;
325    }
326  }
327
328  active_phrases->push_back(phrase);
329}
330
331void afxEA_PhraseEffect::update_active_phrases(F32 dt)
332{
333  for (S32 i = 0; i < active_phrases->size(); i++)
334  {
335    afxPhrase* phrase = (*active_phrases)[i];
336    if (phrase->expired(mLife_elapsed))
337      phrase->recycle(mLife_elapsed);
338    phrase->update(dt, mLife_elapsed);
339  }
340}
341
342void afxEA_PhraseEffect::cleanup_finished_phrases()
343{
344  Vector<afxPhrase*>* surviving_phrases = (active_phrases == &_phrases_a) ? &_phrases_b : &_phrases_a;
345  
346  surviving_phrases->clear();
347  for (S32 i = 0; i < active_phrases->size(); i++)
348  {
349    afxPhrase* phrase = (*active_phrases)[i];
350    if (!phrase->isEmpty())
351      surviving_phrases->push_back(phrase);
352    else
353      delete phrase;
354  }  
355
356  active_phrases->clear();
357  active_phrases = surviving_phrases;
358}
359
360//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
361
362class afxEA_PhraseEffectDesc : public afxEffectAdapterDesc, public afxEffectDefs 
363{
364  static afxEA_PhraseEffectDesc desc;
365
366public:
367  virtual bool  testEffectType(const SimDataBlock*) const;
368  virtual bool  requiresStop(const afxEffectWrapperData*, const afxEffectTimingData&) const;
369  virtual bool  runsOnServer(const afxEffectWrapperData*) const { return true; }
370  virtual bool  runsOnClient(const afxEffectWrapperData*) const { return true; }
371
372  virtual afxEffectWrapper* create() const { return new afxEA_PhraseEffect; }
373};
374
375afxEA_PhraseEffectDesc afxEA_PhraseEffectDesc::desc;
376
377bool afxEA_PhraseEffectDesc::testEffectType(const SimDataBlock* db) const
378{
379  return (typeid(afxPhraseEffectData) == typeid(*db));
380}
381
382bool afxEA_PhraseEffectDesc::requiresStop(const afxEffectWrapperData* ew, const afxEffectTimingData& timing) const
383{
384  return (timing.lifetime < 0);
385}
386
387//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
388