1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 February 21, 2000 (Loren Petrich)
21
22 Animated-textures file. This implements animated wall textures,
23 which are now read off of XML configuration files.
24
25 May 12, 2000 (Loren Petrich)
26
27 Modified to abolish the ATxr resources, and also to add XML support.
28 A "select" feature was added, so as to be able to translate only some specified texture.
29
30 Oct 13, 2000 (Loren Petrich)
31 Converted the animated-texture accounting into Standard Template Library vectors
32 */
33
34 #include <vector>
35 #include <string.h>
36 #include "cseries.h"
37 #include "AnimatedTextures.h"
38 #include "interface.h"
39 #include "InfoTree.h"
40
41
42 class AnimTxtr
43 {
44 // Frame data: private, because the frame list is only supposed
45 vector<short> FrameList;
46
47 // Control info: private, because they need to stay self-consistent
48 // How long the animator stays on a frame;
49 // negative means animate in reverse direction
50 short NumTicks;
51
52 // Phases: which frame, and which tick in a frame
53 // These must be in ranges (0 to NumFrames - 1) and (0 to abs(NumTicks) - 1)
54 size_t FramePhase, TickPhase;
55
56 public:
57 // How many frames
GetNumFrames()58 size_t GetNumFrames() {return FrameList.size();}
59
60 // Frame ID (writable)
GetFrame(size_t Index)61 short& GetFrame(size_t Index) {return FrameList[Index];}
62
63 // Clear the list
Clear()64 void Clear() {FrameList.clear();}
65
66 // Load from list:
67 void Load(vector<short>& _FrameList);
68
69 // Translate the frame; indicate whether the frame was translated.
70 // Its argument is the frame ID, which gets changed in place
71 bool Translate(short& Frame);
72
73 // Set the timing info: number of ticks per frame, and tick and frame phases
74 void SetTiming(short _NumTicks, size_t _FramePhase, size_t _TickPhase);
75
76 // Update the phases:
77 void Update();
78
79 // Which texture to select (if -1 [NONE], then select all those in the frame list);
80 // the selected texture is the one that gets translated,
81 // and if this is set, then it gets translated into the equivalent of the
82 // first member of the loop.
83 short Select;
84
85 // Possible addition:
86 // whether the texture is active or not;
87 // one could include some extra data to indicate whether to activate
88 // the texture or not, as when a switch tag changes state.
89
90 // Constructor has defaults of everything
AnimTxtr()91 AnimTxtr()
92 {
93 NumTicks = 30; // Once a second
94 FramePhase = 0;
95 TickPhase = 0;
96 Select = -1;
97 }
98 };
99
100
101
Load(vector<short> & _FrameList)102 void AnimTxtr::Load(vector<short>& _FrameList)
103 {
104 // Quick way to transfer the frame data
105 FrameList.swap(_FrameList);
106 if (FrameList.empty()) return;
107
108 // Just in case it was set to something out-of-range...
109 FramePhase = FramePhase % FrameList.size();
110 }
111
112
Translate(short & Frame)113 bool AnimTxtr::Translate(short& Frame)
114 {
115 // Sanity check
116 size_t NumFrames = FrameList.size();
117 if (NumFrames == 0) return false;
118
119 // Find the index in the loop; default: first one.
120 size_t FrameIndex = 0;
121 if (Select >= 0)
122 {
123 if (Frame != Select) return false;
124 }
125 else
126 {
127 bool FrameFound = false;
128 for (size_t f=0; f<NumFrames; f++)
129 if (FrameList[f] == Frame)
130 {
131 FrameFound = true;
132 FrameIndex = f;
133 }
134 if (!FrameFound) return false;
135 }
136 FrameIndex += FramePhase;
137 FrameIndex %= NumFrames;
138
139 Frame = FrameList[FrameIndex];
140 return true;
141 }
142
143
SetTiming(short _NumTicks,size_t _FramePhase,size_t _TickPhase)144 void AnimTxtr::SetTiming(short _NumTicks, size_t _FramePhase, size_t _TickPhase)
145 {
146 NumTicks = _NumTicks;
147 FramePhase = _FramePhase;
148 TickPhase = _TickPhase;
149
150 // Correct for possible overshooting of limits:
151 if (NumTicks)
152 {
153 int TickPhaseFrames = static_cast<int>(TickPhase) / NumTicks;
154 if (static_cast<int>(TickPhase) < NumTicks*TickPhaseFrames)
155 {
156 TickPhase += abs(NumTicks) - NumTicks*TickPhaseFrames;
157 TickPhaseFrames--;
158 }
159 else
160 { TickPhase -= NumTicks*TickPhaseFrames; }
161
162 FramePhase += TickPhaseFrames;
163 }
164
165 size_t NumFrames = FrameList.size();
166 if (NumFrames != 0)
167 { FramePhase = FramePhase % NumFrames; }
168 }
169
170
Update()171 void AnimTxtr::Update()
172 {
173 // Be careful to wrap around in the appropriate direction
174 size_t NumFrames = FrameList.size();
175 if (NumTicks > 0)
176 {
177 if (static_cast<int>(++TickPhase) >= NumTicks)
178 {
179 TickPhase = 0;
180 if (++FramePhase >= NumFrames)
181 FramePhase = 0;
182 }
183 }
184 else if (NumTicks < 0)
185 {
186 if (TickPhase == 0)
187 {
188 TickPhase = - NumTicks - 1;
189 if (FramePhase != 0)
190 FramePhase--;
191 else
192 FramePhase = NumFrames - 1;
193 }
194 else
195 { TickPhase--; }
196 }
197 }
198
199
200 // Separate animated-texture sequence lists for each collection ID,
201 // to speed up searching
202 static vector<AnimTxtr> AnimTxtrList[NUMBER_OF_COLLECTIONS];
203
204
205 // Deletes a collection's animated-texture sequences
ATDelete(int c)206 static void ATDelete(int c)
207 {
208 AnimTxtrList[c].clear();
209 }
210
211
212 // Deletes all of them
ATDeleteAll()213 static void ATDeleteAll()
214 {
215 for (int c=0; c<NUMBER_OF_COLLECTIONS; c++) ATDelete(c);
216 }
217
218
219 // Updates the animated textures
AnimTxtr_Update()220 void AnimTxtr_Update()
221 {
222 for (int c=0; c<NUMBER_OF_COLLECTIONS; c++)
223 {
224 vector<AnimTxtr>& ATL = AnimTxtrList[c];
225 for (vector<AnimTxtr>::iterator ATIter = ATL.begin(); ATIter < ATL.end(); ATIter++)
226 ATIter->Update();
227 }
228 }
229
230
231 // Does animated-texture translation in place
AnimTxtr_Translate(shape_descriptor Texture)232 shape_descriptor AnimTxtr_Translate(shape_descriptor Texture)
233 {
234 if (Texture == UNONE) return UNONE;
235
236 // Pull out frame and collection ID's:
237 short Frame = GET_DESCRIPTOR_SHAPE(Texture);
238 short CollCT = GET_DESCRIPTOR_COLLECTION(Texture);
239 short Collection = GET_COLLECTION(CollCT);
240 short ColorTable = GET_COLLECTION_CLUT(CollCT);
241
242 // This will assume that the collection is loaded;
243 // that could be handled as map preprocessing, by turning
244 // all shape descriptors that refer to unloaded shapes to NONE
245
246 vector<AnimTxtr>& ATL = AnimTxtrList[Collection];
247 for (vector<AnimTxtr>::iterator ATIter = ATL.begin(); ATIter < ATL.end(); ATIter++)
248 if (ATIter->Translate(Frame)) break;
249
250 // Check the frame for being in range
251 if (Frame < 0) return UNONE;
252 if (Frame >= get_number_of_collection_frames(Collection)) return UNONE;
253
254 // All done:
255 CollCT = BUILD_COLLECTION(Collection,ColorTable);
256 Texture = BUILD_DESCRIPTOR(CollCT,Frame);
257 return Texture;
258 }
259
reset_mml_animated_textures()260 void reset_mml_animated_textures()
261 {
262 ATDeleteAll();
263 }
264
parse_mml_animated_textures(const InfoTree & root)265 void parse_mml_animated_textures(const InfoTree& root)
266 {
267 BOOST_FOREACH(const InfoTree::value_type &v, root)
268 {
269 std::string name = v.first;
270 const InfoTree& child = v.second;
271
272 if (v.first == "clear")
273 {
274 int16 coll = -1;
275 if (child.read_indexed("coll", coll, NUMBER_OF_COLLECTIONS))
276 ATDelete(coll);
277 else
278 ATDeleteAll();
279 }
280 else if (v.first == "sequence")
281 {
282 int16 coll = -1;
283 int16 numticks = -1;
284 if (!child.read_indexed("coll", coll, NUMBER_OF_COLLECTIONS) ||
285 !child.read_attr("numticks", numticks))
286 continue;
287
288 vector<short> frames;
289 BOOST_FOREACH(InfoTree frame, child.children_named("frame"))
290 {
291 int16 index = -1;
292 if (frame.read_indexed("index", index, 255))
293 frames.push_back(index);
294 }
295 if (!frames.size())
296 continue;
297
298 uint16 frame_phase = 0;
299 child.read_attr("framephase", frame_phase);
300 uint16 tick_phase = 0;
301 child.read_attr("tickphase", tick_phase);
302 int16 select = -1;
303 child.read_attr("select", select);
304
305 AnimTxtr new_anim;
306 new_anim.Load(frames);
307 new_anim.SetTiming(numticks, frame_phase, tick_phase);
308 new_anim.Select = select;
309 AnimTxtrList[coll].push_back(new_anim);
310 }
311 }
312 }
313
314