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