00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef NL_CONTEXT_SOUND_H
00026 #define NL_CONTEXT_SOUND_H
00027
00028 #include "sound.h"
00029 #include <hash_map>
00030 #include <nel/misc/fast_mem.h>
00031
00032 namespace NLSOUND {
00033
00034 class ISoundDriver;
00035 class IBuffer;
00036 class CSound;
00037
00038
00039 template <uint NbJoker, bool UseRandom, uint Shift = 5>
00040 struct CContextMatcher
00041 {
00042 CContextMatcher(uint32 *jokersValues, uint32 randomValue)
00043 : HashValue(0)
00044 {
00045 for (uint i=0; i<NbJoker; ++i)
00046 {
00047 JokersValues[i] = jokersValues[i];
00048
00049 uint leftShift = (5*i)&0x1f;
00050 HashValue ^= JokersValues[i] << leftShift;
00051 HashValue ^= JokersValues[i] >> (32-leftShift);
00052 }
00053 if (UseRandom)
00054 {
00055 RandomValue = randomValue;
00056 uint leftShift = (5*i)&0x1f;
00057 HashValue ^= randomValue << leftShift;
00058 HashValue ^= randomValue >> (32-leftShift);
00059 }
00060 else
00061 RandomValue = 0;
00062 }
00063
00064 bool operator ==(const CContextMatcher &other) const
00065 {
00066 if (HashValue != other.HashValue)
00067 return false;
00068 else if (UseRandom)
00069 return RandomValue == other.RandomValue && memcmp(JokersValues, other.JokersValues, sizeof(uint32)*NbJoker) == 0;
00070 else
00071 return memcmp(JokersValues, other.JokersValues, sizeof(uint32)*NbJoker) == 0;
00072 }
00073
00074 size_t getHashValue() const
00075 {
00076 return size_t(HashValue);
00077 }
00078
00079 uint32 HashValue;
00080 uint32 JokersValues[NbJoker];
00081 uint32 RandomValue;
00082
00083 struct CHash : public std::unary_function<CContextMatcher, size_t>
00084 {
00085 size_t operator () (const CContextMatcher &patternMatcher) const
00086 {
00087 return patternMatcher.getHashValue();
00088 }
00089 };
00090
00091 };
00092
00093
00094 class IContextSoundContainer
00095 {
00096 public:
00097 virtual ~IContextSoundContainer() {};
00098 virtual void init(uint *contextArgsIndex) =0;
00099 virtual void addSound(CSound *sound, const std::string &baseName) =0;
00100 virtual CSound *getSound(const CSoundContext &context, uint32 randomValue) =0;
00101 virtual void getSoundList(std::vector<std::pair<std::string, CSound*> > &subsounds) const =0;
00102 };
00103
00104 template <uint NbJoker, bool UseRandom, uint Shift = 5>
00105 class CContextSoundContainer : public IContextSoundContainer
00106 {
00107
00108 typedef std::hash_map<CContextMatcher<NbJoker, UseRandom, Shift>, CSound *, CContextMatcher<NbJoker, UseRandom, Shift>::CHash> THashContextSound;
00109
00110 virtual void init(uint *contextArgsIndex)
00111 {
00112 NLMISC::CFastMem::memcpy(_ContextArgsIndex, contextArgsIndex, sizeof(uint) * NbJoker);
00113 }
00114
00115 virtual void addSound(CSound *sound, const std::string &baseName)
00116 {
00117 const std::string &patternName = sound->getName();
00118 nlassert(patternName.size() >= baseName.size());
00119
00120 std::string arg;
00121 uint32 args[NbJoker];
00122
00123
00124 std::string::const_iterator first(patternName.begin() + baseName.size()), last(patternName.end());
00125
00126
00127
00128
00129
00130 for (uint i=0; i<NbJoker && first != last; ++first)
00131 {
00132 if (isdigit(int(*first)))
00133 {
00134 arg += *first;
00135 }
00136 else if (!arg.empty())
00137 {
00138
00139 args[i++] = atoi(arg.c_str());
00140 arg = "";
00141 }
00142 }
00143
00144 if (!arg.empty())
00145 {
00146
00147 args[i++] = atoi(arg.c_str());
00148 arg = "";
00149 }
00150
00151 if (i != NbJoker)
00152 return;
00153 nlassert(i==NbJoker);
00154
00155 int randomValue;
00156 if (UseRandom)
00157 {
00158 bool ok = false;
00159
00160 for (uint i=0; first != last; ++first)
00161 {
00162 if (isdigit(int(*first)))
00163 {
00164 arg += *first;
00165 }
00166 else if (!arg.empty())
00167 {
00168 nlassert (ok == false);
00169
00170 randomValue = atoi(arg.c_str());
00171 arg = "";
00172 ok = true;
00173 }
00174 }
00175
00176 if (!arg.empty())
00177 {
00178 nlassert (ok == false);
00179
00180 randomValue = atoi(arg.c_str());
00181 arg = "";
00182 ok = true;
00183 }
00184 nlassert (ok == true);
00185
00186 }
00187 else
00188 {
00189 randomValue = 0;
00190 }
00191
00192
00193 CContextMatcher<NbJoker, UseRandom, Shift> cm(args, randomValue);
00194
00195 #ifdef _DEBUG
00196 char tmp[1024];
00197 char tmp2[1024];
00198
00199 smprintf(tmp, 1024, "Adding sound : %s, args = ", patternName.c_str());
00200
00201 for (uint k=0; k<NbJoker; ++k)
00202 {
00203 sprintf(tmp2, "%u", args[k]);
00204 strcat(tmp, tmp2);
00205 }
00206
00207 nldebug(tmp);
00208
00209 #endif
00210
00211 std::pair<THashContextSound::iterator, bool> ret;
00212 ret = _ContextSounds.insert(std::make_pair(cm, sound));
00213 if (!ret.second)
00214 {
00215 THashContextSound::iterator it = _ContextSounds.find(cm);
00216 nlassert(it != _ContextSounds.end());
00217
00218 nlwarning("Sound %s has the same context matcher as the sound %s", sound->getName().c_str(), it->second->getName().c_str());
00219 }
00220 }
00221
00222 virtual CSound *getSound(const CSoundContext &context, uint32 randomValue)
00223 {
00224
00225 uint32 args[NbJoker];
00226 for (uint i=0; i<NbJoker; ++i)
00227 args[i] = context.Args[_ContextArgsIndex[i]];
00228
00229 CContextMatcher<NbJoker, UseRandom, Shift> cm(args, randomValue);
00230
00231 THashContextSound::iterator it = _ContextSounds.find(cm);
00232
00233 if (it != _ContextSounds.end())
00234 return it->second;
00235 else
00236 return 0;
00237 }
00238
00239 void getSoundList(std::vector<std::pair<std::string, CSound*> > &subsounds) const
00240 {
00241 THashContextSound::const_iterator first(_ContextSounds.begin()), last(_ContextSounds.end());
00242 for (; first != last; ++first)
00243 {
00244 subsounds.push_back(std::make_pair(first->second->getName(), first->second));
00245 }
00246 }
00247
00248 private:
00249 uint32 _ContextArgsIndex[NbJoker];
00250 THashContextSound _ContextSounds;
00251 };
00252
00253 class CContextSound : public CSound
00254 {
00255 public:
00257 CContextSound();
00259 ~CContextSound();
00260
00261
00262 TSOUND_TYPE getSoundType() { return CSound::SOUND_CONTEXT; };
00263
00265 virtual void importForm(const std::string& filename, NLGEORGES::UFormElm& formRoot);
00266
00268 virtual bool isDetailed() const;
00270 virtual uint32 getDuration();
00272 virtual void getSubSoundList(std::vector<std::pair<std::string, CSound*> > &subsounds) const;
00273
00274
00275 CSound *getContextSound(CSoundContext &context);
00276
00277 void init();
00278
00279 void serial(NLMISC::IStream &s);
00280
00281
00282 private:
00283
00285 std::string _PatternName;
00287 std::string _BaseName;
00288
00290 uint32 _Random;
00291
00292
00293
00295 IContextSoundContainer *_ContextSounds;
00296
00297 };
00298
00299 }
00300
00301 #endif //NL_CONTEXT_SOUND_H