1 /*
2 ** p_tags.cpp
3 ** everything to do with tags and their management
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 2015 Christoph Oelckers
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 **
34 */
35
36
37 #include "p_tags.h"
38 #include "c_dispatch.h"
39
40 FTagManager tagManager;
41
42 //-----------------------------------------------------------------------------
43 //
44 //
45 //
46 //-----------------------------------------------------------------------------
47
sectindex(const sector_t * sector)48 static inline int sectindex(const sector_t *sector)
49 {
50 return (int)(intptr_t)(sector - sectors);
51 }
52
lineindex(const line_t * line)53 static inline int lineindex(const line_t *line)
54 {
55 return (int)(intptr_t)(line - lines);
56 }
57
58 //-----------------------------------------------------------------------------
59 //
60 //
61 //
62 //-----------------------------------------------------------------------------
63
AddSectorTag(int sector,int tag)64 void FTagManager::AddSectorTag(int sector, int tag)
65 {
66 if (tag == 0) return;
67
68 // This function assumes that all tags for a single sector get added sequentially.
69 // Should there ever be some need for compatibility.txt to add tags to sectors which already have a tag this function needs to be changed to adjust the startForSector indices.
70 while (startForSector.Size() <= (unsigned int)sector)
71 {
72 startForSector.Push(-1);
73 }
74 if (startForSector[sector] == -1)
75 {
76 startForSector[sector] = allTags.Size();
77 }
78 else
79 {
80 // check if the key was already defined
81 for (unsigned i = startForSector[sector]; i < allTags.Size(); i++)
82 {
83 if (allTags[i].tag == tag)
84 {
85 return;
86 }
87 }
88 }
89 FTagItem it = { sector, tag, -1 };
90 allTags.Push(it);
91 }
92
93 //-----------------------------------------------------------------------------
94 //
95 //
96 //
97 //-----------------------------------------------------------------------------
98
RemoveSectorTags(int sect)99 void FTagManager::RemoveSectorTags(int sect)
100 {
101 if (startForSector.Size() > (unsigned int)sect)
102 {
103 int start = startForSector[sect];
104 if (start >= 0)
105 {
106 while (allTags[start].target == sect)
107 {
108 allTags[start].tag = allTags[start].target = -1;
109 start++;
110 }
111 }
112 }
113 }
114
115 //-----------------------------------------------------------------------------
116 //
117 //
118 //
119 //-----------------------------------------------------------------------------
120
AddLineID(int line,int tag)121 void FTagManager::AddLineID(int line, int tag)
122 {
123 if (tag == -1) return; // For line IDs -1 means 'not set', unlike sectors.
124
125 // This function assumes that all ids for a single line get added sequentially.
126 while (startForLine.Size() <= (unsigned int)line)
127 {
128 startForLine.Push(-1);
129 }
130 if (startForLine[line] == -1)
131 {
132 startForLine[line] = allIDs.Size();
133 }
134 else
135 {
136 // check if the key was already defined
137 for (unsigned i = startForLine[line]; i < allIDs.Size(); i++)
138 {
139 if (allIDs[i].tag == tag)
140 {
141 return;
142 }
143 }
144 }
145 FTagItem it = { line, tag, -1 };
146 allIDs.Push(it);
147 }
148
149 //-----------------------------------------------------------------------------
150 //
151 //
152 //
153 //-----------------------------------------------------------------------------
154
HashTags()155 void FTagManager::HashTags()
156 {
157 // add an end marker so we do not need to check for the array's size in the other functions.
158 static FTagItem it = { -1, -1, -1 };
159 allTags.Push(it);
160 allIDs.Push(it);
161
162 // Initially make all slots empty.
163 memset(TagHashFirst, -1, sizeof(TagHashFirst));
164 memset(IDHashFirst, -1, sizeof(IDHashFirst));
165
166 // Proceed from last to first so that lower targets appear first
167 for (int i = allTags.Size() - 1; i >= 0; i--)
168 {
169 if (allTags[i].target >= 0) // only link valid entries
170 {
171 int hash = ((unsigned int)allTags[i].tag) % FTagManager::TAG_HASH_SIZE;
172 allTags[i].nexttag = TagHashFirst[hash];
173 TagHashFirst[hash] = i;
174 }
175 }
176
177 for (int i = allIDs.Size() - 1; i >= 0; i--)
178 {
179 if (allIDs[i].target >= 0) // only link valid entries
180 {
181 int hash = ((unsigned int)allIDs[i].tag) % FTagManager::TAG_HASH_SIZE;
182 allIDs[i].nexttag = IDHashFirst[hash];
183 IDHashFirst[hash] = i;
184 }
185 }
186
187 }
188
189 //-----------------------------------------------------------------------------
190 //
191 //
192 //
193 //-----------------------------------------------------------------------------
194
SectorHasTags(const sector_t * sector) const195 bool FTagManager::SectorHasTags(const sector_t *sector) const
196 {
197 int i = sectindex(sector);
198 return SectorHasTags(i);
199 }
200
201 //-----------------------------------------------------------------------------
202 //
203 //
204 //
205 //-----------------------------------------------------------------------------
206
GetFirstSectorTag(const sector_t * sect) const207 int FTagManager::GetFirstSectorTag(const sector_t *sect) const
208 {
209 int i = sectindex(sect);
210 return SectorHasTags(i) ? allTags[startForSector[i]].tag : 0;
211 }
212
213 //-----------------------------------------------------------------------------
214 //
215 //
216 //
217 //-----------------------------------------------------------------------------
218
SectorHasTag(int i,int tag) const219 bool FTagManager::SectorHasTag(int i, int tag) const
220 {
221 if (SectorHasTags(i))
222 {
223 int ndx = startForSector[i];
224 while (allTags[ndx].target == i)
225 {
226 if (allTags[ndx].tag == tag) return true;
227 ndx++;
228 }
229 }
230 return false;
231 }
232
233 //-----------------------------------------------------------------------------
234 //
235 //
236 //
237 //-----------------------------------------------------------------------------
238
SectorHasTag(const sector_t * sector,int tag) const239 bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const
240 {
241 return SectorHasTag(sectindex(sector), tag);
242 }
243
244 //-----------------------------------------------------------------------------
245 //
246 //
247 //
248 //-----------------------------------------------------------------------------
249
LineHasID(int i,int tag) const250 bool FTagManager::LineHasID(int i, int tag) const
251 {
252 if (LineHasIDs(i))
253 {
254 int ndx = startForLine[i];
255 while (allIDs[ndx].target == i)
256 {
257 if (allIDs[ndx].tag == tag) return true;
258 ndx++;
259 }
260 }
261 return false;
262 }
263
264 //-----------------------------------------------------------------------------
265 //
266 //
267 //
268 //-----------------------------------------------------------------------------
269
LineHasID(const line_t * line,int tag) const270 bool FTagManager::LineHasID(const line_t *line, int tag) const
271 {
272 return LineHasID(lineindex(line), tag);
273 }
274
275 //-----------------------------------------------------------------------------
276 //
277 //
278 //
279 //-----------------------------------------------------------------------------
280
DumpTags()281 void FTagManager::DumpTags()
282 {
283 for (unsigned i = 0; i < allTags.Size(); i++)
284 {
285 Printf("Sector %d, tag %d\n", allTags[i].target, allTags[i].tag);
286 }
287 for (unsigned i = 0; i < allIDs.Size(); i++)
288 {
289 Printf("Line %d, ID %d\n", allIDs[i].target, allIDs[i].tag);
290 }
291 }
292
CCMD(dumptags)293 CCMD(dumptags)
294 {
295 tagManager.DumpTags();
296 }
297
298 //-----------------------------------------------------------------------------
299 //
300 // RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
301 //
302 // Find the next sector with a specified tag.
303 // Rewritten by Lee Killough to use chained hashing to improve speed
304 //
305 //-----------------------------------------------------------------------------
306
Next()307 int FSectorTagIterator::Next()
308 {
309 int ret;
310 if (searchtag == INT_MIN)
311 {
312 ret = start;
313 start = -1;
314 }
315 else if (searchtag != 0)
316 {
317 while (start >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag;
318 if (start == -1) return -1;
319 ret = tagManager.allTags[start].target;
320 start = tagManager.allTags[start].nexttag;
321 }
322 else
323 {
324 // with the tag manager, searching for tag 0 has to be different, because it won't create entries for untagged sectors.
325 while (start < numsectors && tagManager.SectorHasTags(start))
326 {
327 start++;
328 }
329 if (start == numsectors) return -1;
330 ret = start;
331 start++;
332 }
333 return ret;
334 }
335
336 //-----------------------------------------------------------------------------
337 //
338 // linear search for compatible stair building
339 //
340 //-----------------------------------------------------------------------------
341
NextCompat(bool compat,int start)342 int FSectorTagIterator::NextCompat(bool compat, int start)
343 {
344 if (!compat) return Next();
345
346 for (int i = start + 1; i < numsectors; i++)
347 {
348 if (tagManager.SectorHasTag(i, searchtag)) return i;
349 }
350 return -1;
351 }
352
353
354 //-----------------------------------------------------------------------------
355 //
356 // killough 4/16/98: Same thing, only for linedefs
357 //
358 //-----------------------------------------------------------------------------
359
Next()360 int FLineIdIterator::Next()
361 {
362 while (start >= 0 && tagManager.allIDs[start].tag != searchtag) start = tagManager.allIDs[start].nexttag;
363 if (start == -1) return -1;
364 int ret = tagManager.allIDs[start].target;
365 start = tagManager.allIDs[start].nexttag;
366 return ret;
367 }
368