1 /** @file dmu_lib.cpp Helper routines for accessing the DMU API.
2 *
3 * @authors Copyright © 2006-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4 * @authors Copyright © 2006-2013 Daniel Swanson <danij@dengine.net>
5 *
6 * @par License
7 * GPL: http://www.gnu.org/licenses/gpl.html
8 *
9 * <small>This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. This program is distributed in the hope that it
13 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details. You should have received a copy of the GNU
16 * General Public License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA</small>
19 */
20
21 #include <cstdio>
22 #include <cstring>
23
24 #include "common.h"
25 #include "dmu_lib.h"
26 #include "p_terraintype.h"
27
28 #include "dmu_lib.h"
29
P_PathXYTraverse2(coord_t fromX,coord_t fromY,coord_t toX,coord_t toY,int flags,traverser_t callback,void * context)30 int P_PathXYTraverse2(coord_t fromX, coord_t fromY, coord_t toX, coord_t toY,
31 int flags, traverser_t callback, void *context)
32 {
33 vec2d_t from = { fromX, fromY };
34 vec2d_t to = { toX, toY };
35 return P_PathTraverse2(from, to, flags, callback, context);
36 }
37
P_PathXYTraverse(coord_t fromX,coord_t fromY,coord_t toX,coord_t toY,traverser_t callback,void * context)38 int P_PathXYTraverse(coord_t fromX, coord_t fromY, coord_t toX, coord_t toY,
39 traverser_t callback, void *context)
40 {
41 vec2d_t from = { fromX, fromY };
42 vec2d_t to = { toX, toY };
43 return P_PathTraverse(from, to, callback, context);
44 }
45
46 struct TagList
47 {
48 iterlist_t *list;
49 int tag;
50 };
51
52 static TagList *lineTagLists;
53 static uint numLineTagLists;
54
55 static TagList *sectorTagLists;
56 static uint numSectorTagLists;
57
P_AllocDummyLine()58 Line *P_AllocDummyLine()
59 {
60 xline_t *extra = (xline_t *)Z_Calloc(sizeof(xline_t), PU_GAMESTATIC, 0);
61 return (Line *)P_AllocDummy(DMU_LINE, extra);
62 }
63
P_FreeDummyLine(Line * line)64 void P_FreeDummyLine(Line *line)
65 {
66 Z_Free(P_DummyExtraData(line));
67 P_FreeDummy(line);
68 }
69
P_CopyLine(Line * dest,Line * src)70 void P_CopyLine(Line *dest, Line *src)
71 {
72 xline_t *xsrc = P_ToXLine(src);
73 xline_t *xdest = P_ToXLine(dest);
74
75 if(src == dest)
76 return; // no point copying self
77
78 // Copy the built-in properties
79 for(int i = 0; i < 2; ++i) // For each side
80 {
81 int sidx = (i==0? DMU_FRONT : DMU_BACK);
82
83 Side *sidefrom = (Side *)P_GetPtrp(src, sidx);
84 Side *sideto = (Side *)P_GetPtrp(dest, sidx);
85
86 if(!sidefrom || !sideto)
87 continue;
88
89 float temp[4];
90 coord_t itemp[2];
91
92 P_SetPtrp (sideto, DMU_TOP_MATERIAL, P_GetPtrp(sidefrom, DMU_TOP_MATERIAL));
93 P_GetDoublepv(sidefrom, DMU_TOP_MATERIAL_OFFSET_XY, itemp);
94 P_SetDoublepv(sideto, DMU_TOP_MATERIAL_OFFSET_XY, itemp);
95 P_GetFloatpv (sidefrom, DMU_TOP_COLOR, temp);
96 P_SetFloatpv (sideto, DMU_TOP_COLOR, temp);
97
98 P_SetPtrp (sideto, DMU_MIDDLE_MATERIAL, P_GetPtrp(sidefrom, DMU_MIDDLE_MATERIAL));
99 P_GetDoublepv(sidefrom, DMU_MIDDLE_MATERIAL_OFFSET_XY, itemp);
100 P_SetDoublepv(sideto, DMU_MIDDLE_MATERIAL_OFFSET_XY, itemp);
101 P_SetFloatpv (sideto, DMU_MIDDLE_COLOR, temp);
102 P_SetIntp (sideto, DMU_MIDDLE_BLENDMODE, P_GetIntp(sidefrom, DMU_MIDDLE_BLENDMODE));
103
104 P_SetPtrp (sideto, DMU_BOTTOM_MATERIAL, P_GetPtrp(sidefrom, DMU_BOTTOM_MATERIAL));
105 P_GetDoublepv(sidefrom, DMU_BOTTOM_MATERIAL_OFFSET_XY, itemp);
106 P_SetDoublepv(sideto, DMU_BOTTOM_MATERIAL_OFFSET_XY, itemp);
107 P_GetFloatpv (sidefrom, DMU_BOTTOM_COLOR, temp);
108 P_SetFloatpv (sideto, DMU_BOTTOM_COLOR, temp);
109 }
110
111 // Copy the extended properties too
112 #if __JDOOM__ || __JHERETIC__ || __JDOOM64__
113 xdest->special = xsrc->special;
114 xdest->tag = xsrc->tag;
115 if(xsrc->xg && xdest->xg)
116 std::memcpy(xdest->xg, xsrc->xg, sizeof(*xdest->xg));
117 else
118 xdest->xg = 0;
119 #else
120 xdest->special = xsrc->special;
121 xdest->arg1 = xsrc->arg1;
122 xdest->arg2 = xsrc->arg2;
123 xdest->arg3 = xsrc->arg3;
124 xdest->arg4 = xsrc->arg4;
125 xdest->arg5 = xsrc->arg5;
126 #endif
127 }
128
P_CopySector(Sector * dest,Sector * src)129 void P_CopySector(Sector *dest, Sector *src)
130 {
131 xsector_t *xsrc = P_ToXSector(src);
132 xsector_t *xdest = P_ToXSector(dest);
133
134 if(src == dest)
135 return; // no point copying self.
136
137 // Copy the built-in properties.
138 float ftemp[4];
139 coord_t dtemp[2];
140
141 P_SetFloatp (dest, DMU_LIGHT_LEVEL, P_GetFloatp(src, DMU_LIGHT_LEVEL));
142 P_GetFloatpv (src, DMU_COLOR, ftemp);
143 P_SetFloatpv (dest, DMU_COLOR, ftemp);
144
145 P_SetDoublep (dest, DMU_FLOOR_HEIGHT, P_GetDoublep(src, DMU_FLOOR_HEIGHT));
146 P_SetPtrp (dest, DMU_FLOOR_MATERIAL, P_GetPtrp(src, DMU_FLOOR_MATERIAL));
147 P_GetFloatpv (src, DMU_FLOOR_COLOR, ftemp);
148 P_SetFloatpv (dest, DMU_FLOOR_COLOR, ftemp);
149 P_GetDoublepv(src, DMU_FLOOR_MATERIAL_OFFSET_XY, dtemp);
150 P_SetDoublepv(dest, DMU_FLOOR_MATERIAL_OFFSET_XY, dtemp);
151 P_SetIntp (dest, DMU_FLOOR_SPEED, P_GetIntp(src, DMU_FLOOR_SPEED));
152 P_SetDoublep (dest, DMU_FLOOR_TARGET_HEIGHT, P_GetFloatp(src, DMU_FLOOR_TARGET_HEIGHT));
153
154 P_SetDoublep (dest, DMU_CEILING_HEIGHT, P_GetDoublep(src, DMU_CEILING_HEIGHT));
155 P_SetPtrp (dest, DMU_CEILING_MATERIAL, P_GetPtrp(src, DMU_CEILING_MATERIAL));
156 P_GetFloatpv (src, DMU_CEILING_COLOR, ftemp);
157 P_SetFloatpv (dest, DMU_CEILING_COLOR, ftemp);
158 P_GetDoublepv(src, DMU_CEILING_MATERIAL_OFFSET_XY, dtemp);
159 P_SetDoublepv(dest, DMU_CEILING_MATERIAL_OFFSET_XY, dtemp);
160 P_SetIntp (dest, DMU_CEILING_SPEED, P_GetIntp(src, DMU_CEILING_SPEED));
161 P_SetDoublep (dest, DMU_CEILING_TARGET_HEIGHT, P_GetFloatp(src, DMU_CEILING_TARGET_HEIGHT));
162
163 // Copy the extended properties too
164 #if __JDOOM__ || __JHERETIC__ || __JDOOM64__
165 xdest->special = xsrc->special;
166 xdest->soundTraversed = xsrc->soundTraversed;
167 xdest->soundTarget = xsrc->soundTarget;
168 #if __JHERETIC__
169 xdest->seqType = xsrc->seqType;
170 #endif
171 xdest->SP_floororigheight = xsrc->SP_floororigheight;
172 xdest->SP_ceilorigheight = xsrc->SP_ceilorigheight;
173 xdest->origLight = xsrc->origLight;
174 std::memcpy(xdest->origRGB, xsrc->origRGB, sizeof(float) * 3);
175 if(xsrc->xg && xdest->xg)
176 std::memcpy(xdest->xg, xsrc->xg, sizeof(*xdest->xg));
177 else
178 xdest->xg = 0;
179 #else
180 xdest->special = xsrc->special;
181 xdest->soundTraversed = xsrc->soundTraversed;
182 xdest->soundTarget = xsrc->soundTarget;
183 xdest->seqType = xsrc->seqType;
184 #endif
185 }
186
P_BuildLineTagLists()187 void P_BuildLineTagLists()
188 {
189 P_DestroyLineTagLists();
190
191 for(int i = 0; i < numlines; ++i)
192 {
193 Line *line = (Line *)P_ToPtr(DMU_LINE, i);
194 xline_t *xline = P_ToXLine(line);
195
196 #if !__JHEXEN__
197 if(xline->tag)
198 {
199 iterlist_t *list = P_GetLineIterListForTag(xline->tag, true);
200 IterList_PushBack(list, line);
201 }
202 #else
203 switch(xline->special)
204 {
205 default: break;
206 case 121: ///< Line_SetIdentification.
207 if(xline->arg1)
208 {
209 iterlist_t *list = P_GetLineIterListForTag((int) xline->arg1, true);
210 IterList_PushBack(list, line);
211 }
212 xline->special = 0;
213 break;
214 }
215 #endif
216 }
217 }
218
P_DestroyLineTagLists()219 void P_DestroyLineTagLists()
220 {
221 if(numLineTagLists == 0)
222 return;
223
224 for(uint i = 0; i < numLineTagLists; ++i)
225 {
226 IterList_Clear(lineTagLists[i].list);
227 IterList_Delete(lineTagLists[i].list);
228 }
229
230 free(lineTagLists);
231 lineTagLists = 0;
232 numLineTagLists = 0;
233 }
234
P_GetLineIterListForTag(int tag,dd_bool createNewList)235 iterlist_t *P_GetLineIterListForTag(int tag, dd_bool createNewList)
236 {
237 // Do we have an existing list for this tag?
238 for(uint i = 0; i < numLineTagLists; ++i)
239 {
240 if(lineTagLists[i].tag == tag)
241 return lineTagLists[i].list;
242 }
243
244 if(!createNewList)
245 return 0;
246
247 // Nope, we need to allocate another.
248 numLineTagLists++;
249 lineTagLists = (TagList *)realloc(lineTagLists, sizeof(TagList) * numLineTagLists);
250 TagList *tagList = &lineTagLists[numLineTagLists - 1];
251 tagList->tag = tag;
252
253 return (tagList->list = IterList_New());
254 }
255
P_BuildSectorTagLists()256 void P_BuildSectorTagLists()
257 {
258 P_DestroySectorTagLists();
259
260 for(int i = 0; i < numsectors; ++i)
261 {
262 Sector *sec = (Sector *)P_ToPtr(DMU_SECTOR, i);
263 xsector_t *xsec = P_ToXSector(sec);
264
265 if(xsec->tag)
266 {
267 iterlist_t *list = P_GetSectorIterListForTag(xsec->tag, true);
268 IterList_PushBack(list, sec);
269 }
270 }
271 }
272
P_DestroySectorTagLists()273 void P_DestroySectorTagLists()
274 {
275 if(numSectorTagLists == 0)
276 return;
277
278 for(uint i = 0; i < numSectorTagLists; ++i)
279 {
280 IterList_Clear(sectorTagLists[i].list);
281 IterList_Delete(sectorTagLists[i].list);
282 }
283
284 free(sectorTagLists);
285 sectorTagLists = 0;
286 numSectorTagLists = 0;
287 }
288
P_GetSectorIterListForTag(int tag,dd_bool createNewList)289 iterlist_t *P_GetSectorIterListForTag(int tag, dd_bool createNewList)
290 {
291 // Do we have an existing list for this tag?
292 for(uint i = 0; i < numSectorTagLists; ++i)
293 {
294 if(sectorTagLists[i].tag == tag)
295 return sectorTagLists[i].list;
296 }
297
298 if(!createNewList)
299 return 0;
300
301 // Nope, we need to allocate another.
302 numSectorTagLists++;
303 sectorTagLists = (TagList *)realloc(sectorTagLists, sizeof(TagList) * numSectorTagLists);
304 TagList *tagList = §orTagLists[numSectorTagLists - 1];
305 tagList->tag = tag;
306
307 return (tagList->list = IterList_New());
308 }
309
P_BuildAllTagLists()310 void P_BuildAllTagLists()
311 {
312 P_BuildSectorTagLists();
313 P_BuildLineTagLists();
314 }
315
P_DestroyAllTagLists()316 void P_DestroyAllTagLists()
317 {
318 P_DestroyLineTagLists();
319 P_DestroySectorTagLists();
320 }
321
P_GetNextSector(Line * line,Sector * sec)322 Sector *P_GetNextSector(Line *line, Sector *sec)
323 {
324 if(!sec || !line)
325 return 0;
326
327 if(!(P_ToXLine(line)->flags & ML_TWOSIDED))
328 return 0;
329
330 Sector *frontSec = (Sector *)P_GetPtrp(line, DMU_FRONT_SECTOR);
331 if(frontSec == sec)
332 return (Sector *)P_GetPtrp(line, DMU_BACK_SECTOR);
333 return frontSec;
334 }
335
findExtremalLightLevelInAdjacentSectors(void * ptr,void * context)336 int findExtremalLightLevelInAdjacentSectors(void *ptr, void *context)
337 {
338 findlightlevelparams_t *params = (findlightlevelparams_t *) context;
339 Sector *other = P_GetNextSector((Line *) ptr, params->baseSec);
340
341 if(!other)
342 return false; // Continue iteration.
343
344 float lightLevel = P_GetFloatp(other, DMU_LIGHT_LEVEL);
345 if(params->flags & FELLF_MIN)
346 {
347 if(lightLevel < params->val)
348 {
349 params->val = lightLevel;
350 params->foundSec = other;
351 if(params->val <= 0)
352 return true; // Stop iteration. Can't get any darker.
353 }
354 }
355 else if(lightLevel > params->val)
356 {
357 params->val = lightLevel;
358 params->foundSec = other;
359 if(params->val >= 1)
360 return true; // Stop iteration. Can't get any brighter.
361 }
362 return false; // Continue iteration.
363 }
364
P_FindSectorSurroundingLowestLight(Sector * sec,float * val)365 Sector *P_FindSectorSurroundingLowestLight(Sector *sec, float *val)
366 {
367 findlightlevelparams_t params;
368 params.flags = FELLF_MIN;
369 params.val = DDMAXFLOAT;
370 params.baseSec = sec;
371 params.foundSec = 0;
372 P_Iteratep(sec, DMU_LINE, findExtremalLightLevelInAdjacentSectors, ¶ms);
373 if(*val)
374 *val = params.val;
375 return params.foundSec;
376 }
377
P_FindSectorSurroundingHighestLight(Sector * sec,float * val)378 Sector *P_FindSectorSurroundingHighestLight(Sector *sec, float *val)
379 {
380 findlightlevelparams_t params;
381 params.flags = 0;
382 params.val = DDMINFLOAT;
383 params.baseSec = sec;
384 params.foundSec = 0;
385 P_Iteratep(sec, DMU_LINE, findExtremalLightLevelInAdjacentSectors, ¶ms);
386 if(val)
387 *val = params.val;
388 return params.foundSec;
389 }
390
findNextLightLevel(void * ptr,void * context)391 int findNextLightLevel(void* ptr, void *context)
392 {
393 findnextlightlevelparams_t *params = (findnextlightlevelparams_t *) context;
394 Line *li = (Line *) ptr;
395
396 Sector *other = P_GetNextSector(li, params->baseSec);
397 if(!other)
398 return false; // Continue iteration.
399
400 float otherLight = P_GetFloatp(other, DMU_LIGHT_LEVEL);
401 if(params->flags & FNLLF_ABOVE)
402 {
403 if(otherLight < params->val && otherLight > params->baseLight)
404 {
405 params->val = otherLight;
406 params->foundSec = other;
407
408 if(!(params->val > 0))
409 return true; // Stop iteration. Can't get any darker.
410 }
411 }
412 else if(otherLight > params->val && otherLight < params->baseLight)
413 {
414 params->val = otherLight;
415 params->foundSec = other;
416
417 if(!(params->val < 1))
418 return true; // Stop iteration. Can't get any brighter.
419 }
420 return false; // Continue iteration.
421 }
422
P_FindSectorSurroundingNextLowestLight(Sector * sec,float baseLight,float * val)423 Sector *P_FindSectorSurroundingNextLowestLight(Sector *sec, float baseLight, float *val)
424 {
425 findnextlightlevelparams_t params;
426 params.flags = 0;
427 params.val = DDMINFLOAT;
428 params.baseSec = sec;
429 params.baseLight = baseLight;
430 params.foundSec = 0;
431 P_Iteratep(sec, DMU_LINE, findNextLightLevel, ¶ms);
432 if(*val)
433 *val = params.val;
434 return params.foundSec;
435 }
436
P_FindSectorSurroundingNextHighestLight(Sector * sec,float baseLight,float * val)437 Sector *P_FindSectorSurroundingNextHighestLight(Sector *sec, float baseLight, float *val)
438 {
439 findnextlightlevelparams_t params;
440 params.flags = FNLLF_ABOVE;
441 params.val = DDMAXFLOAT;
442 params.baseSec = sec;
443 params.baseLight = baseLight;
444 params.foundSec = 0;
445 P_Iteratep(sec, DMU_LINE, findNextLightLevel, ¶ms);
446 if(*val)
447 *val = params.val;
448 return params.foundSec;
449 }
450
findExtremalPlaneHeight(void * ptr,void * context)451 int findExtremalPlaneHeight(void *ptr, void *context)
452 {
453 findextremalplaneheightparams_t *params = (findextremalplaneheightparams_t *) context;
454 Sector *other = P_GetNextSector((Line *) ptr, params->baseSec);
455
456 if(!other)
457 return false; // Continue iteration.
458
459 coord_t height = P_GetDoublep(other, ((params->flags & FEPHF_FLOOR)? DMU_FLOOR_HEIGHT : DMU_CEILING_HEIGHT));
460 if(params->flags & FEPHF_MIN)
461 {
462 if(height < params->val)
463 {
464 params->val = height;
465 params->foundSec = other;
466 }
467 }
468 else if(height > params->val)
469 {
470 params->val = height;
471 params->foundSec = other;
472 }
473
474 return false; // Continue iteration.
475 }
476
P_FindSectorSurroundingLowestFloor(Sector * sec,coord_t max,coord_t * val)477 Sector *P_FindSectorSurroundingLowestFloor(Sector *sec, coord_t max, coord_t *val)
478 {
479 findextremalplaneheightparams_t params;
480 params.flags = FEPHF_MIN | FEPHF_FLOOR;
481 params.val = max;
482 params.baseSec = sec;
483 params.foundSec = 0;
484 P_Iteratep(sec, DMU_LINE, findExtremalPlaneHeight, ¶ms);
485 if(val)
486 *val = params.val;
487 return params.foundSec;
488 }
489
P_FindSectorSurroundingHighestFloor(Sector * sec,coord_t min,coord_t * val)490 Sector *P_FindSectorSurroundingHighestFloor(Sector *sec, coord_t min, coord_t *val)
491 {
492 findextremalplaneheightparams_t params;
493 params.flags = FEPHF_FLOOR;
494 params.val = min;
495 params.baseSec = sec;
496 params.foundSec = 0;
497 P_Iteratep(sec, DMU_LINE, findExtremalPlaneHeight, ¶ms);
498 if(val)
499 *val = params.val;
500 return params.foundSec;
501 }
502
P_FindSectorSurroundingLowestCeiling(Sector * sec,coord_t max,coord_t * val)503 Sector *P_FindSectorSurroundingLowestCeiling(Sector *sec, coord_t max, coord_t *val)
504 {
505 findextremalplaneheightparams_t params;
506 params.flags = FEPHF_MIN;
507 params.val = max;
508 params.baseSec = sec;
509 params.foundSec = 0;
510 P_Iteratep(sec, DMU_LINE, findExtremalPlaneHeight, ¶ms);
511 if(val)
512 *val = params.val;
513 return params.foundSec;
514 }
515
P_FindSectorSurroundingHighestCeiling(Sector * sec,coord_t min,coord_t * val)516 Sector *P_FindSectorSurroundingHighestCeiling(Sector *sec, coord_t min, coord_t *val)
517 {
518 findextremalplaneheightparams_t params;
519 params.flags = 0;
520 params.val = min;
521 params.baseSec = sec;
522 params.foundSec = 0;
523 P_Iteratep(sec, DMU_LINE, findExtremalPlaneHeight, ¶ms);
524 if(val)
525 *val = params.val;
526 return params.foundSec;
527 }
528
findNextPlaneHeight(void * ptr,void * context)529 int findNextPlaneHeight(void *ptr, void *context)
530 {
531 findnextplaneheightparams_t *params = (findnextplaneheightparams_t *) context;
532 Sector *other = P_GetNextSector((Line *) ptr, params->baseSec);
533
534 if(!other)
535 return false; // Continue iteration.
536
537 coord_t otherHeight = P_GetDoublep(other, ((params->flags & FNPHF_FLOOR)? DMU_FLOOR_HEIGHT : DMU_CEILING_HEIGHT));
538 if(params->flags & FNPHF_ABOVE)
539 {
540 if(otherHeight < params->val && otherHeight > params->baseHeight)
541 {
542 params->val = otherHeight;
543 params->foundSec = other;
544 }
545 }
546 else if(otherHeight > params->val && otherHeight < params->baseHeight)
547 {
548 params->val = otherHeight;
549 params->foundSec = other;
550 }
551 return false; // Continue iteration.
552 }
553
P_FindSectorSurroundingNextHighestFloor(Sector * sec,coord_t baseHeight,coord_t * val)554 Sector *P_FindSectorSurroundingNextHighestFloor(Sector *sec, coord_t baseHeight, coord_t *val)
555 {
556 findnextplaneheightparams_t params;
557 params.flags = FNPHF_FLOOR | FNPHF_ABOVE;
558 params.val = DDMAXFLOAT;
559 params.baseSec = sec;
560 params.baseHeight = baseHeight;
561 params.foundSec = 0;
562 P_Iteratep(sec, DMU_LINE, findNextPlaneHeight, ¶ms);
563 if(val)
564 *val = params.val;
565 return params.foundSec;
566 }
567
P_FindSectorSurroundingNextHighestCeiling(Sector * sec,coord_t baseHeight,coord_t * val)568 Sector *P_FindSectorSurroundingNextHighestCeiling(Sector *sec, coord_t baseHeight, coord_t *val)
569 {
570 findnextplaneheightparams_t params;
571 params.flags = FNPHF_ABOVE;
572 params.val = DDMAXFLOAT;
573 params.baseSec = sec;
574 params.baseHeight = baseHeight;
575 params.foundSec = 0;
576 P_Iteratep(sec, DMU_LINE, findNextPlaneHeight, ¶ms);
577 if(val)
578 *val = params.val;
579 return params.foundSec;
580 }
581
P_FindSectorSurroundingNextLowestFloor(Sector * sec,coord_t baseHeight,coord_t * val)582 Sector *P_FindSectorSurroundingNextLowestFloor(Sector *sec, coord_t baseHeight, coord_t *val)
583 {
584 findnextplaneheightparams_t params;
585 params.flags = FNPHF_FLOOR;
586 params.val = DDMINFLOAT;
587 params.baseSec = sec;
588 params.baseHeight = baseHeight;
589 params.foundSec = 0;
590 P_Iteratep(sec, DMU_LINE, findNextPlaneHeight, ¶ms);
591 if(val)
592 *val = params.val;
593 return params.foundSec;
594 }
595
P_FindSectorSurroundingNextLowestCeiling(Sector * sec,coord_t baseHeight,coord_t * val)596 Sector *P_FindSectorSurroundingNextLowestCeiling(Sector *sec, coord_t baseHeight, coord_t *val)
597 {
598 findnextplaneheightparams_t params;
599 params.flags = 0;
600 params.val = DDMINFLOAT;
601 params.baseSec = sec;
602 params.baseHeight = baseHeight;
603 params.foundSec = 0;
604 P_Iteratep(sec, DMU_LINE, findNextPlaneHeight, ¶ms);
605 if(val)
606 *val = params.val;
607 return params.foundSec;
608 }
609
P_SectorLight(Sector * sector)610 float P_SectorLight(Sector *sector)
611 {
612 return P_GetFloatp(sector, DMU_LIGHT_LEVEL);
613 }
614
P_SectorSetLight(Sector * sector,float level)615 void P_SectorSetLight(Sector *sector, float level)
616 {
617 P_SetFloatp(sector, DMU_LIGHT_LEVEL, level);
618 }
619
P_SectorModifyLight(Sector * sector,float value)620 void P_SectorModifyLight(Sector *sector, float value)
621 {
622 float level = MINMAX_OF(0.f, P_SectorLight(sector) + value, 1.f);
623 P_SectorSetLight(sector, level);
624 }
625
P_SectorModifyLightx(Sector * sector,fixed_t value)626 void P_SectorModifyLightx(Sector *sector, fixed_t value)
627 {
628 P_SetFloatp(sector, DMU_LIGHT_LEVEL, P_SectorLight(sector) + FIX2FLT(value) / 255.0f);
629 }
630
P_PlaneMaterialTerrainType(Sector * sec,int plane)631 terraintype_t const *P_PlaneMaterialTerrainType(Sector *sec, int plane)
632 {
633 return P_TerrainTypeForMaterial((world_Material *)P_GetPtrp(sec, (plane? DMU_CEILING_MATERIAL : DMU_FLOOR_MATERIAL)));
634 }
635
P_TranslateSideMaterialOrigin(Side * side,SideSection section,float deltaXY[2])636 void P_TranslateSideMaterialOrigin(Side *side, SideSection section, float deltaXY[2])
637 {
638 DENG_ASSERT(side);
639 DENG_ASSERT(VALID_SIDESECTION(section));
640
641 uint const dmuSurfaceOriginFlags = DMU_OFFSET_XY | DMU_FLAG_FOR_SIDESECTION(section);
642 float origin[2];
643
644 if(IS_ZERO(deltaXY[0]) && IS_ZERO(deltaXY[1])) return;
645
646 P_GetFloatpv(side, dmuSurfaceOriginFlags, origin);
647 if(NON_ZERO(deltaXY[0]))
648 {
649 origin[0] += deltaXY[0];
650 }
651 if(NON_ZERO(deltaXY[1]))
652 {
653 origin[1] += deltaXY[1];
654 }
655 P_SetFloatpv(side, dmuSurfaceOriginFlags, origin);
656 }
657
P_TranslateSideMaterialOriginXY(Side * side,SideSection section,float deltaX,float deltaY)658 void P_TranslateSideMaterialOriginXY(Side *side, SideSection section,
659 float deltaX, float deltaY)
660 {
661 float delta[2];
662 delta[0] = deltaX;
663 delta[1] = deltaY;
664 P_TranslateSideMaterialOrigin(side, section, delta);
665 }
666
P_TranslatePlaneMaterialOrigin(Plane * plane,float deltaXY[2])667 void P_TranslatePlaneMaterialOrigin(Plane *plane, float deltaXY[2])
668 {
669 float origin[2];
670
671 DENG_ASSERT(plane);
672
673 if(IS_ZERO(deltaXY[0]) && IS_ZERO(deltaXY[1])) return;
674
675 P_GetFloatpv(plane, DMU_OFFSET_XY, origin);
676 if(NON_ZERO(deltaXY[0]))
677 {
678 origin[0] += deltaXY[0];
679 }
680 if(NON_ZERO(deltaXY[1]))
681 {
682 origin[1] += deltaXY[1];
683 }
684 P_SetFloatpv(plane, DMU_OFFSET_XY, origin);
685 }
686
P_TranslatePlaneMaterialOriginXY(Plane * plane,float deltaX,float deltaY)687 void P_TranslatePlaneMaterialOriginXY(Plane *plane, float deltaX, float deltaY)
688 {
689 float delta[2];
690 delta[0] = deltaX;
691 delta[1] = deltaY;
692 P_TranslatePlaneMaterialOrigin(plane, delta);
693 }
694