1 //----------------------------------------------------------------------------
2 // EDGE Data Definition File Code (Animated textures)
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2008 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 // Animated Texture/Flat Setup and Parser Code
20 //
21
22 #include "local.h"
23
24 #include "anim.h"
25
26 static animdef_c *dynamic_anim;
27
28 static void DDF_AnimGetType(const char *info, void *storage);
29 static void DDF_AnimGetPic (const char *info, void *storage);
30
31 // -ACB- 1998/08/10 Use DDF_MainGetLumpName for getting the..lump name.
32 // -KM- 1998/09/27 Use DDF_MainGetTime for getting tics
33
34 #define DDF_CMD_BASE dummy_anim
35 static animdef_c dummy_anim;
36
37 static const commandlist_t anim_commands[] =
38 {
39 DDF_FIELD("TYPE", type, DDF_AnimGetType),
40 DDF_FIELD("SEQUENCE", pics, DDF_AnimGetPic),
41 DDF_FIELD("SPEED", speed, DDF_MainGetTime),
42 DDF_FIELD("FIRST", startname, DDF_MainGetLumpName),
43 DDF_FIELD("LAST", endname, DDF_MainGetLumpName),
44
45 DDF_CMD_END
46 };
47
48 // Floor/ceiling animation sequences, defined by first and last frame,
49 // i.e. the flat (64x64 tile) name or texture name to be used.
50 //
51 // The full animation sequence is given using all the flats between
52 // the start and end entry, in the order found in the WAD file.
53 //
54
55 // -ACB- 2004/06/03 Replaced array and size with purpose-built class
56 animdef_container_c animdefs;
57
58
animdefs_Lookup(const char * name)59 static animdef_c * animdefs_Lookup(const char *name)
60 {
61 epi::array_iterator_c it;
62
63 for (it = animdefs.GetBaseIterator(); it.IsValid(); it++)
64 {
65 animdef_c *a = ITERATOR_TO_TYPE(it, animdef_c*);
66
67 if (DDF_CompareName(a->name.c_str(), name) == 0)
68 return a;
69 }
70
71 return NULL; // not found
72 }
73
74
75 //
76 // DDF PARSE ROUTINES
77 //
AnimStartEntry(const char * name,bool extend)78 static void AnimStartEntry(const char *name, bool extend)
79 {
80 if (!name || !name[0])
81 {
82 DDF_WarnError("New anim entry is missing a name!");
83 name = "ANIM_WITH_NO_NAME";
84 }
85
86 dynamic_anim = animdefs_Lookup(name);
87
88 if (extend)
89 {
90 if (! dynamic_anim)
91 DDF_Error("Unknown animdef to extend: %s\n", name);
92 return;
93 }
94
95 // replaces an existing entry
96 if (dynamic_anim)
97 {
98 dynamic_anim->Default();
99 return;
100 }
101
102 // not found, create a new one
103 dynamic_anim = new animdef_c;
104
105 dynamic_anim->name = name;
106
107 animdefs.Insert(dynamic_anim);
108 }
109
110
AnimParseField(const char * field,const char * contents,int index,bool is_last)111 static void AnimParseField(const char *field, const char *contents, int index, bool is_last)
112 {
113 #if (DEBUG_DDF)
114 I_Debugf("ANIM_PARSE: %s = %s;\n", field, contents);
115 #endif
116
117 if (DDF_MainParseField(anim_commands, field, contents, (byte *)dynamic_anim))
118 return;
119
120 DDF_WarnError("Unknown anims.ddf command: %s\n", field);
121 }
122
AnimFinishEntry(void)123 static void AnimFinishEntry(void)
124 {
125 if (dynamic_anim->speed <= 0)
126 {
127 DDF_WarnError("Bad TICS value for anim: %d\n", dynamic_anim->speed);
128 dynamic_anim->speed = 8;
129 }
130
131 if (dynamic_anim->pics.GetSize() == 0)
132 {
133 if (!dynamic_anim->startname || !dynamic_anim->startname[0] ||
134 !dynamic_anim->endname || !dynamic_anim->endname[0])
135 {
136 DDF_Error("Missing animation sequence.\n");
137 }
138
139 if (dynamic_anim->type == animdef_c::A_Graphic)
140 DDF_Error("TYPE=GRAPHIC animations must use the SEQUENCE command.\n");
141 }
142 }
143
144
AnimClearAll(void)145 static void AnimClearAll(void)
146 {
147 // 100% safe to delete all animations
148 animdefs.Clear();
149 }
150
151
DDF_ReadAnims(void * data,int size)152 bool DDF_ReadAnims(void *data, int size)
153 {
154 readinfo_t anims;
155
156 anims.memfile = (char*)data;
157 anims.memsize = size;
158 anims.tag = "ANIMATIONS";
159 anims.entries_per_dot = 2;
160
161 if (anims.memfile)
162 {
163 anims.message = NULL;
164 anims.filename = NULL;
165 anims.lumpname = "DDFANIM";
166 }
167 else
168 {
169 anims.message = "DDF_InitAnimations";
170 anims.filename = "anims.ddf";
171 anims.lumpname = NULL;
172 }
173
174 anims.start_entry = AnimStartEntry;
175 anims.parse_field = AnimParseField;
176 anims.finish_entry = AnimFinishEntry;
177 anims.clear_all = AnimClearAll;
178
179 return DDF_MainReadFile(&anims);
180 }
181
182 //
183 // DDF_AnimInit
184 //
DDF_AnimInit(void)185 void DDF_AnimInit(void)
186 {
187 animdefs.Clear(); // <-- Consistent with existing behaviour (-ACB- 2004/05/04)
188 }
189
190 //
191 // DDF_AnimCleanUp
192 //
DDF_AnimCleanUp(void)193 void DDF_AnimCleanUp(void)
194 {
195 animdefs.Trim(); // <-- Reduce to allocated size
196 }
197
198 //
199 // DDF_AnimGetType
200 //
DDF_AnimGetType(const char * info,void * storage)201 static void DDF_AnimGetType(const char *info, void *storage)
202 {
203 SYS_ASSERT(storage);
204
205 int *type = (int *) storage;
206
207 if (DDF_CompareName(info, "FLAT") == 0)
208 (*type) = animdef_c::A_Flat;
209 else if (DDF_CompareName(info, "TEXTURE") == 0)
210 (*type) = animdef_c::A_Texture;
211 else if (DDF_CompareName(info, "GRAPHIC") == 0)
212 (*type) = animdef_c::A_Graphic;
213 else
214 {
215 DDF_WarnError("Unknown animation type: %s\n", info);
216 (*type) = animdef_c::A_Flat;
217 }
218 }
219
220 //
221 // DDF_AnimGetPic
222 //
DDF_AnimGetPic(const char * info,void * storage)223 static void DDF_AnimGetPic (const char *info, void *storage)
224 {
225 dynamic_anim->pics.Insert(info);
226 }
227
DDF_ParseANIMATED(const byte * data,int size)228 void DDF_ParseANIMATED(const byte *data, int size)
229 {
230 for (; size >= 23; data += 23, size -= 23)
231 {
232 if (data[0] & 0x80) // end marker
233 break;
234
235 int speed = data[19] + (data[20] << 8);
236
237 char first[10];
238 char last[10];
239
240 // make sure names are NUL-terminated
241 memcpy(first, data+10, 9); last[8] = 0;
242 memcpy( last, data+ 1, 9); first[8] = 0;
243
244 I_Debugf("- ANIMATED LUMP: start '%s' : end '%s'\n", first, last);
245
246 // ignore zero-length names
247 if (!first[0] || !last[0])
248 continue;
249
250 animdef_c *def = new animdef_c;
251
252 def->name = "BOOM_ANIM";
253
254 def->Default();
255
256 def->type = (data[0] & 1) ? animdef_c::A_Texture : animdef_c::A_Flat;
257 def->speed = MAX(1, speed);
258
259 def->startname.Set(first);
260 def->endname .Set(last);
261
262 animdefs.Insert(def);
263 }
264 }
265
266
267 // ---> animdef_c class
268
269 //
270 // animdef_c constructor
271 //
animdef_c()272 animdef_c::animdef_c() : name()
273 {
274 Default();
275 }
276
277
278 //
279 // animdef_c::CopyDetail()
280 //
281 // Copies all the detail with the exception of ddf info
282 //
CopyDetail(animdef_c & src)283 void animdef_c::CopyDetail(animdef_c &src)
284 {
285 type = src.type;
286 pics = src.pics;
287 startname = src.startname;
288 endname = src.endname;
289 speed = src.speed;
290 }
291
292 //
293 // animdef_c::Default()
294 //
Default()295 void animdef_c::Default()
296 {
297 type = A_Texture;
298
299 pics.Clear();
300
301 startname.clear();
302 endname.clear();
303
304 speed = 8;
305 }
306
307
308 // ---> animdef_container_c class
309
310 //
311 // animdef_container_c::CleanupObject()
312 //
CleanupObject(void * obj)313 void animdef_container_c::CleanupObject(void *obj)
314 {
315 animdef_c *a = *(animdef_c**)obj;
316
317 if (a)
318 delete a;
319
320 return;
321 }
322
323
324 //--- editor settings ---
325 // vi:ts=4:sw=4:noexpandtab
326