diff options
author | Dave Chapman <dave@dchapman.com> | 2006-03-28 15:44:01 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2006-03-28 15:44:01 +0000 |
commit | 47f4a458d636a889e955e68f896708f1276febc0 (patch) | |
tree | 99f770c02ef606f0abbdcd332ac39e69830d8007 /apps/plugins/doom/r_things.c | |
parent | fff7d6157d56f233cad5c2003475e47a5ff809a7 (diff) | |
download | rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.gz rockbox-47f4a458d636a889e955e68f896708f1276febc0.zip |
Patch #2969 - Doom! Currently only working on the H300.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/doom/r_things.c')
-rw-r--r-- | apps/plugins/doom/r_things.c | 976 |
1 files changed, 976 insertions, 0 deletions
diff --git a/apps/plugins/doom/r_things.c b/apps/plugins/doom/r_things.c new file mode 100644 index 0000000000..2e1f72e34c --- /dev/null +++ b/apps/plugins/doom/r_things.c | |||
@@ -0,0 +1,976 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
5 | * PrBoom a Doom port merged with LxDoom and LSDLDoom | ||
6 | * based on BOOM, a modified and improved DOOM engine | ||
7 | * Copyright (C) 1999 by | ||
8 | * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman | ||
9 | * Copyright (C) 1999-2000 by | ||
10 | * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
25 | * 02111-1307, USA. | ||
26 | * | ||
27 | * DESCRIPTION: | ||
28 | * Refresh of things, i.e. objects represented by sprites. | ||
29 | * | ||
30 | *-----------------------------------------------------------------------------*/ | ||
31 | |||
32 | #include "doomdef.h" | ||
33 | #include "m_swap.h" | ||
34 | |||
35 | #include "doomstat.h" | ||
36 | #include "w_wad.h" | ||
37 | #include "r_main.h" | ||
38 | #include "r_bsp.h" | ||
39 | #include "r_segs.h" | ||
40 | #include "r_draw.h" | ||
41 | #include "r_things.h" | ||
42 | #include "i_system.h" | ||
43 | //#include "lprintf.h" | ||
44 | #include "rockmacros.h" | ||
45 | |||
46 | #define MINZ (FRACUNIT*4) | ||
47 | #define BASEYCENTER 100 | ||
48 | |||
49 | typedef struct { | ||
50 | int x1; | ||
51 | int x2; | ||
52 | int column; | ||
53 | int topclip; | ||
54 | int bottomclip; | ||
55 | } maskdraw_t; | ||
56 | |||
57 | // | ||
58 | // Sprite rotation 0 is facing the viewer, | ||
59 | // rotation 1 is one angle turn CLOCKWISE around the axis. | ||
60 | // This is not the same as the angle, | ||
61 | // which increases counter clockwise (protractor). | ||
62 | // There was a lot of stuff grabbed wrong, so I changed it... | ||
63 | // | ||
64 | fixed_t pspritescale; | ||
65 | fixed_t pspriteiscale; | ||
66 | |||
67 | static lighttable_t** spritelights; | ||
68 | |||
69 | // constant arrays | ||
70 | // used for psprite clipping and initializing clipping | ||
71 | short negonearray[SCREENWIDTH]; | ||
72 | short screenheightarray[SCREENWIDTH]; | ||
73 | |||
74 | |||
75 | // | ||
76 | // INITIALIZATION FUNCTIONS | ||
77 | // | ||
78 | |||
79 | // variables used to look up and range check thing_t sprites patches | ||
80 | |||
81 | spritedef_t* sprites; | ||
82 | int numsprites; | ||
83 | |||
84 | #define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */ | ||
85 | |||
86 | static spriteframe_t sprtemp[MAX_SPRITE_FRAMES]; | ||
87 | static int maxframe; | ||
88 | |||
89 | // | ||
90 | // R_InstallSpriteLump | ||
91 | // Local function for R_InitSprites. | ||
92 | // | ||
93 | |||
94 | static void R_InstallSpriteLump(int lump, unsigned frame, | ||
95 | unsigned rotation, boolean flipped) | ||
96 | { | ||
97 | |||
98 | if (frame >= MAX_SPRITE_FRAMES || rotation > 8) | ||
99 | I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump); | ||
100 | |||
101 | if ((int)frame > maxframe) | ||
102 | maxframe = frame; | ||
103 | |||
104 | if (rotation == 0) | ||
105 | { // the lump should be used for all rotations | ||
106 | int r; | ||
107 | for (r=0 ; r<8 ; r++) | ||
108 | if (sprtemp[frame].lump[r]==-1) | ||
109 | { | ||
110 | sprtemp[frame].lump[r] = lump - firstspritelump; | ||
111 | sprtemp[frame].flip[r] = (byte) flipped; | ||
112 | sprtemp[frame].rotate = false; //jff 4/24/98 if any subbed, rotless | ||
113 | } | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | // the lump is only used for one rotation | ||
118 | |||
119 | if (sprtemp[frame].lump[--rotation] == -1) | ||
120 | { | ||
121 | sprtemp[frame].lump[rotation] = lump - firstspritelump; | ||
122 | sprtemp[frame].flip[rotation] = (byte) flipped; | ||
123 | sprtemp[frame].rotate = true; //jff 4/24/98 only change if rot used | ||
124 | } | ||
125 | } | ||
126 | |||
127 | // | ||
128 | // R_InitSpriteDefs | ||
129 | // Pass a null terminated list of sprite names | ||
130 | // (4 chars exactly) to be used. | ||
131 | // | ||
132 | // Builds the sprite rotation matrixes to account | ||
133 | // for horizontally flipped sprites. | ||
134 | // | ||
135 | // Will report an error if the lumps are inconsistent. | ||
136 | // Only called at startup. | ||
137 | // | ||
138 | // Sprite lump names are 4 characters for the actor, | ||
139 | // a letter for the frame, and a number for the rotation. | ||
140 | // | ||
141 | // A sprite that is flippable will have an additional | ||
142 | // letter/number appended. | ||
143 | // | ||
144 | // The rotation character can be 0 to signify no rotations. | ||
145 | // | ||
146 | // 1/25/98, 1/31/98 killough : Rewritten for performance | ||
147 | // | ||
148 | // Empirically verified to have excellent hash | ||
149 | // properties across standard Doom sprites: | ||
150 | |||
151 | #define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2)) | ||
152 | |||
153 | void R_InitSpriteDefs(const char * const * namelist) | ||
154 | { | ||
155 | size_t numentries = lastspritelump-firstspritelump+1; | ||
156 | struct { int index, next; } *hash; | ||
157 | int i; | ||
158 | |||
159 | if (!numentries || !*namelist) | ||
160 | return; | ||
161 | |||
162 | // count the number of sprite names | ||
163 | for (i=0; namelist[i]; i++) | ||
164 | ; | ||
165 | |||
166 | numsprites = i; | ||
167 | |||
168 | sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL); | ||
169 | |||
170 | // Create hash table based on just the first four letters of each sprite | ||
171 | // killough 1/31/98 | ||
172 | |||
173 | hash = malloc(sizeof(*hash)*numentries); // allocate hash table | ||
174 | |||
175 | for (i=0; (size_t)i<numentries; i++) // initialize hash table as empty | ||
176 | hash[i].index = -1; | ||
177 | |||
178 | for (i=0; (size_t)i<numentries; i++) // Prepend each sprite to hash chain | ||
179 | { // prepend so that later ones win | ||
180 | int j = R_SpriteNameHash(lumpinfo[i+firstspritelump].name) % numentries; | ||
181 | hash[i].next = hash[j].index; | ||
182 | hash[j].index = i; | ||
183 | } | ||
184 | |||
185 | // scan all the lump names for each of the names, | ||
186 | // noting the highest frame letter. | ||
187 | |||
188 | for (i=0 ; i<numsprites ; i++) | ||
189 | { | ||
190 | const char *spritename = namelist[i]; | ||
191 | int j = hash[R_SpriteNameHash(spritename) % numentries].index; | ||
192 | |||
193 | if (j >= 0) | ||
194 | { | ||
195 | memset(sprtemp, -1, sizeof(sprtemp)); | ||
196 | maxframe = -1; | ||
197 | do | ||
198 | { | ||
199 | register lumpinfo_t *lump = lumpinfo + j + firstspritelump; | ||
200 | |||
201 | // Fast portable comparison -- killough | ||
202 | // (using int pointer cast is nonportable): | ||
203 | |||
204 | if (!((lump->name[0] ^ spritename[0]) | | ||
205 | (lump->name[1] ^ spritename[1]) | | ||
206 | (lump->name[2] ^ spritename[2]) | | ||
207 | (lump->name[3] ^ spritename[3]))) | ||
208 | { | ||
209 | R_InstallSpriteLump(j+firstspritelump, | ||
210 | lump->name[4] - 'A', | ||
211 | lump->name[5] - '0', | ||
212 | false); | ||
213 | if (lump->name[6]) | ||
214 | R_InstallSpriteLump(j+firstspritelump, | ||
215 | lump->name[6] - 'A', | ||
216 | lump->name[7] - '0', | ||
217 | true); | ||
218 | } | ||
219 | } | ||
220 | while ((j = hash[j].next) >= 0); | ||
221 | |||
222 | // check the frames that were found for completeness | ||
223 | if ((sprites[i].numframes = ++maxframe)) // killough 1/31/98 | ||
224 | { | ||
225 | int frame; | ||
226 | for (frame = 0; frame < maxframe; frame++) | ||
227 | switch ((int) sprtemp[frame].rotate) | ||
228 | { | ||
229 | case -1: | ||
230 | // no rotations were found for that frame at all | ||
231 | I_Error ("R_InitSprites: No patches found " | ||
232 | "for %.8s frame %c", namelist[i], frame+'A'); | ||
233 | break; | ||
234 | |||
235 | case 0: | ||
236 | // only the first rotation is needed | ||
237 | break; | ||
238 | |||
239 | case 1: | ||
240 | // must have all 8 frames | ||
241 | { | ||
242 | int rotation; | ||
243 | for (rotation=0 ; rotation<8 ; rotation++) | ||
244 | if (sprtemp[frame].lump[rotation] == -1) | ||
245 | I_Error ("R_InitSprites: Sprite %.8s frame %c " | ||
246 | "is missing rotations", | ||
247 | namelist[i], frame+'A'); | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | // allocate space for the frames present and copy sprtemp to it | ||
252 | sprites[i].spriteframes = | ||
253 | Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL); | ||
254 | memcpy (sprites[i].spriteframes, sprtemp, | ||
255 | maxframe*sizeof(spriteframe_t)); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | free(hash); // free hash table | ||
260 | } | ||
261 | |||
262 | // | ||
263 | // GAME FUNCTIONS | ||
264 | // | ||
265 | |||
266 | static vissprite_t *vissprites, **vissprite_ptrs; // killough | ||
267 | static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs; | ||
268 | |||
269 | |||
270 | // | ||
271 | // R_InitSprites | ||
272 | // Called at program start. | ||
273 | // | ||
274 | void R_InitSprites(const char * const *namelist) | ||
275 | { | ||
276 | int i; | ||
277 | |||
278 | for (i=0 ; i<SCREENWIDTH ; i++) | ||
279 | negonearray[i] = -1; | ||
280 | R_InitSpriteDefs (namelist); | ||
281 | } | ||
282 | |||
283 | void R_ClearSprites (void) | ||
284 | { | ||
285 | num_vissprite = 0; // killough | ||
286 | } | ||
287 | |||
288 | // | ||
289 | // R_NewVisSprite | ||
290 | // | ||
291 | |||
292 | vissprite_t *R_NewVisSprite(void) | ||
293 | { | ||
294 | if (num_vissprite >= num_vissprite_alloc) // killough | ||
295 | { | ||
296 | num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128; | ||
297 | vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites)); | ||
298 | } | ||
299 | return vissprites + num_vissprite++; | ||
300 | } | ||
301 | |||
302 | // | ||
303 | // R_DrawMaskedColumn | ||
304 | // Used for sprites and masked mid textures. | ||
305 | // Masked means: partly transparent, i.e. stored | ||
306 | // in posts/runs of opaque pixels. | ||
307 | // | ||
308 | |||
309 | short* mfloorclip; | ||
310 | short* mceilingclip; | ||
311 | fixed_t spryscale; | ||
312 | fixed_t sprtopscreen; | ||
313 | |||
314 | void R_DrawMaskedColumn(const column_t *column) | ||
315 | { | ||
316 | int topscreen; | ||
317 | int bottomscreen; | ||
318 | fixed_t basetexturemid = dc_texturemid; | ||
319 | |||
320 | dc_texheight = 0; // killough 11/98 | ||
321 | while (column->topdelta != 0xff) | ||
322 | { | ||
323 | // calculate unclipped screen coordinates for post | ||
324 | topscreen = sprtopscreen + spryscale*column->topdelta; | ||
325 | bottomscreen = topscreen + spryscale*column->length; | ||
326 | |||
327 | dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; | ||
328 | dc_yh = (bottomscreen-1)>>FRACBITS; | ||
329 | |||
330 | if (dc_yh >= mfloorclip[dc_x]) | ||
331 | dc_yh = mfloorclip[dc_x]-1; | ||
332 | |||
333 | if (dc_yl <= mceilingclip[dc_x]) | ||
334 | dc_yl = mceilingclip[dc_x]+1; | ||
335 | |||
336 | // killough 3/2/98, 3/27/98: Failsafe against overflow/crash: | ||
337 | if (dc_yl <= dc_yh && dc_yh < viewheight) | ||
338 | { | ||
339 | dc_source = (byte *)column + 3; | ||
340 | dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS); | ||
341 | |||
342 | // Drawn by either R_DrawColumn | ||
343 | // or (SHADOW) R_DrawFuzzColumn. | ||
344 | colfunc (); | ||
345 | } | ||
346 | column = (const column_t *)( (byte *)column + column->length + 4); | ||
347 | } | ||
348 | dc_texturemid = basetexturemid; | ||
349 | } | ||
350 | |||
351 | // | ||
352 | // R_DrawVisSprite | ||
353 | // mfloorclip and mceilingclip should also be set. | ||
354 | // | ||
355 | // CPhipps - new wad lump handling, *'s to const*'s | ||
356 | void R_DrawVisSprite(vissprite_t *vis, int x1, int x2) | ||
357 | { | ||
358 | (void)x1; | ||
359 | (void)x2; | ||
360 | const column_t *column; | ||
361 | int texturecolumn; | ||
362 | fixed_t frac; | ||
363 | const patch_t *patch = W_CacheLumpNum (vis->patch+firstspritelump); | ||
364 | |||
365 | dc_colormap = vis->colormap; | ||
366 | |||
367 | // killough 4/11/98: rearrange and handle translucent sprites | ||
368 | // mixed with translucent/non-translucenct 2s normals | ||
369 | |||
370 | if (!dc_colormap) // NULL colormap = shadow draw | ||
371 | colfunc = R_DrawFuzzColumn; // killough 3/14/98 | ||
372 | else | ||
373 | if (vis->mobjflags & MF_TRANSLATION) | ||
374 | { | ||
375 | colfunc = R_DrawTranslatedColumn; | ||
376 | dc_translation = translationtables - 256 + | ||
377 | ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) ); | ||
378 | } | ||
379 | else | ||
380 | if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares | ||
381 | { | ||
382 | colfunc = R_DrawTLColumn; | ||
383 | tranmap = main_tranmap; // killough 4/11/98 | ||
384 | } | ||
385 | else | ||
386 | colfunc = R_DrawColumn; // killough 3/14/98, 4/11/98 | ||
387 | |||
388 | |||
389 | // proff 11/06/98: Changed for high-res | ||
390 | dc_iscale = D_abs(vis->xiscale); | ||
391 | dc_texturemid = vis->texturemid; | ||
392 | frac = vis->startfrac; | ||
393 | spryscale = vis->scale; | ||
394 | sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale); | ||
395 | |||
396 | for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale) | ||
397 | { | ||
398 | texturecolumn = frac>>FRACBITS; | ||
399 | |||
400 | #ifdef RANGECHECK | ||
401 | if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) | ||
402 | I_Error ("R_DrawSpriteRange: Bad texturecolumn"); | ||
403 | #endif | ||
404 | |||
405 | column = (const column_t *)((const byte *) patch + | ||
406 | LONG(patch->columnofs[texturecolumn])); | ||
407 | R_DrawMaskedColumn (column); | ||
408 | } | ||
409 | colfunc = R_DrawColumn; // killough 3/14/98 | ||
410 | W_UnlockLumpNum(vis->patch+firstspritelump); // cph - release lump | ||
411 | } | ||
412 | |||
413 | // | ||
414 | // R_ProjectSprite | ||
415 | // Generates a vissprite for a thing if it might be visible. | ||
416 | // | ||
417 | |||
418 | void R_ProjectSprite (mobj_t* thing) | ||
419 | { | ||
420 | fixed_t gzt; // killough 3/27/98 | ||
421 | fixed_t tx; | ||
422 | fixed_t xscale; | ||
423 | int x1; | ||
424 | int x2; | ||
425 | spritedef_t *sprdef; | ||
426 | spriteframe_t *sprframe; | ||
427 | int lump; | ||
428 | boolean flip; | ||
429 | vissprite_t *vis; | ||
430 | #ifndef GL_DOOM | ||
431 | fixed_t iscale; | ||
432 | #endif | ||
433 | int heightsec; // killough 3/27/98 | ||
434 | |||
435 | // transform the origin point | ||
436 | fixed_t tr_x = thing->x - viewx; | ||
437 | fixed_t tr_y = thing->y - viewy; | ||
438 | |||
439 | fixed_t gxt = FixedMul(tr_x,viewcos); | ||
440 | fixed_t gyt = -FixedMul(tr_y,viewsin); | ||
441 | |||
442 | fixed_t tz = gxt-gyt; | ||
443 | |||
444 | // thing is behind view plane? | ||
445 | if (tz < MINZ) | ||
446 | return; | ||
447 | |||
448 | xscale = FixedDiv(projection, tz); | ||
449 | |||
450 | gxt = -FixedMul(tr_x,viewsin); | ||
451 | gyt = FixedMul(tr_y,viewcos); | ||
452 | tx = -(gyt+gxt); | ||
453 | |||
454 | // too far off the side? | ||
455 | if (D_abs(tx)>(tz<<2)) | ||
456 | return; | ||
457 | |||
458 | // decide which patch to use for sprite relative to player | ||
459 | #ifdef RANGECHECK | ||
460 | if ((unsigned) thing->sprite >= (unsigned)numsprites) | ||
461 | I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite); | ||
462 | #endif | ||
463 | |||
464 | sprdef = &sprites[thing->sprite]; | ||
465 | |||
466 | #ifdef RANGECHECK | ||
467 | if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes) | ||
468 | I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite, | ||
469 | thing->frame); | ||
470 | #endif | ||
471 | |||
472 | sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; | ||
473 | |||
474 | if (sprframe->rotate) | ||
475 | { | ||
476 | // choose a different rotation based on player view | ||
477 | angle_t ang = R_PointToAngle(thing->x, thing->y); | ||
478 | unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29; | ||
479 | lump = sprframe->lump[rot]; | ||
480 | flip = (boolean) sprframe->flip[rot]; | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | // use single rotation for all views | ||
485 | lump = sprframe->lump[0]; | ||
486 | flip = (boolean) sprframe->flip[0]; | ||
487 | } | ||
488 | |||
489 | /* calculate edges of the shape | ||
490 | * cph 2003/08/1 - fraggle points out that this offset must be flipped if the | ||
491 | * sprite is flipped; e.g. FreeDoom imp is messed up by this. */ | ||
492 | tx -= flip ? spritewidth[lump] - spriteoffset[lump] : spriteoffset[lump]; | ||
493 | x1 = (centerxfrac + FixedMul(tx,xscale)) >>FRACBITS; | ||
494 | |||
495 | // off the right side? | ||
496 | if (x1 > viewwidth) | ||
497 | return; | ||
498 | |||
499 | tx += spritewidth[lump]; | ||
500 | x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1; | ||
501 | |||
502 | // off the left side | ||
503 | if (x2 < 0) | ||
504 | return; | ||
505 | |||
506 | gzt = thing->z + spritetopoffset[lump]; | ||
507 | |||
508 | // killough 4/9/98: clip things which are out of view due to height | ||
509 | if (thing->z > viewz + FixedDiv(centeryfrac, xscale) || | ||
510 | gzt < viewz - FixedDiv(centeryfrac-viewheight, xscale)) | ||
511 | return; | ||
512 | |||
513 | // killough 3/27/98: exclude things totally separated | ||
514 | // from the viewer, by either water or fake ceilings | ||
515 | // killough 4/11/98: improve sprite clipping for underwater/fake ceilings | ||
516 | |||
517 | heightsec = thing->subsector->sector->heightsec; | ||
518 | |||
519 | if (heightsec != -1) // only clip things which are in special sectors | ||
520 | { | ||
521 | int phs = viewplayer->mo->subsector->sector->heightsec; | ||
522 | if (phs != -1 && viewz < sectors[phs].floorheight ? | ||
523 | thing->z >= sectors[heightsec].floorheight : | ||
524 | gzt < sectors[heightsec].floorheight) | ||
525 | return; | ||
526 | if (phs != -1 && viewz > sectors[phs].ceilingheight ? | ||
527 | gzt < sectors[heightsec].ceilingheight && | ||
528 | viewz >= sectors[heightsec].ceilingheight : | ||
529 | thing->z >= sectors[heightsec].ceilingheight) | ||
530 | return; | ||
531 | } | ||
532 | |||
533 | // store information in a vissprite | ||
534 | vis = R_NewVisSprite (); | ||
535 | |||
536 | // killough 3/27/98: save sector for special clipping later | ||
537 | vis->heightsec = heightsec; | ||
538 | |||
539 | vis->mobjflags = thing->flags; | ||
540 | // proff 11/06/98: Changed for high-res | ||
541 | vis->scale = xscale; | ||
542 | vis->gx = thing->x; | ||
543 | vis->gy = thing->y; | ||
544 | vis->gz = thing->z; | ||
545 | vis->gzt = gzt; // killough 3/27/98 | ||
546 | vis->texturemid = vis->gzt - viewz; | ||
547 | vis->x1 = x1 < 0 ? 0 : x1; | ||
548 | vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; | ||
549 | iscale = FixedDiv (FRACUNIT, xscale); | ||
550 | |||
551 | if (flip) | ||
552 | { | ||
553 | vis->startfrac = spritewidth[lump]-1; | ||
554 | vis->xiscale = -iscale; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | vis->startfrac = 0; | ||
559 | vis->xiscale = iscale; | ||
560 | } | ||
561 | |||
562 | if (vis->x1 > x1) | ||
563 | vis->startfrac += vis->xiscale*(vis->x1-x1); | ||
564 | vis->patch = lump; | ||
565 | |||
566 | // get light level | ||
567 | if (thing->flags & MF_SHADOW) | ||
568 | vis->colormap = NULL; // shadow draw | ||
569 | else if (fixedcolormap) | ||
570 | vis->colormap = fixedcolormap; // fixed map | ||
571 | else if (thing->frame & FF_FULLBRIGHT) | ||
572 | vis->colormap = fullcolormap; // full bright // killough 3/20/98 | ||
573 | else | ||
574 | { // diminished light | ||
575 | int index = xscale>>LIGHTSCALESHIFT; | ||
576 | if (index >= MAXLIGHTSCALE) | ||
577 | index = MAXLIGHTSCALE-1; | ||
578 | vis->colormap = spritelights[index]; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | // | ||
583 | // R_AddSprites | ||
584 | // During BSP traversal, this adds sprites by sector. | ||
585 | // | ||
586 | // killough 9/18/98: add lightlevel as parameter, fixing underwater lighting | ||
587 | void R_AddSprites(subsector_t* subsec, int lightlevel) | ||
588 | { | ||
589 | sector_t* sec=subsec->sector; | ||
590 | mobj_t *thing; | ||
591 | int lightnum; | ||
592 | |||
593 | // BSP is traversed by subsector. | ||
594 | // A sector might have been split into several | ||
595 | // subsectors during BSP building. | ||
596 | // Thus we check whether its already added. | ||
597 | |||
598 | if (sec->validcount == validcount) | ||
599 | return; | ||
600 | |||
601 | // Well, now it will be done. | ||
602 | sec->validcount = validcount; | ||
603 | |||
604 | lightnum = (lightlevel >> LIGHTSEGSHIFT)+extralight; | ||
605 | |||
606 | if (lightnum < 0) | ||
607 | spritelights = scalelight[0]; | ||
608 | else if (lightnum >= LIGHTLEVELS) | ||
609 | spritelights = scalelight[LIGHTLEVELS-1]; | ||
610 | else | ||
611 | spritelights = scalelight[lightnum]; | ||
612 | |||
613 | // Handle all things in sector. | ||
614 | |||
615 | for (thing = sec->thinglist; thing; thing = thing->snext) | ||
616 | R_ProjectSprite(thing); | ||
617 | } | ||
618 | |||
619 | // | ||
620 | // R_DrawPSprite | ||
621 | // | ||
622 | |||
623 | void R_DrawPSprite (pspdef_t *psp) | ||
624 | { | ||
625 | fixed_t tx; | ||
626 | int x1, x2; | ||
627 | spritedef_t *sprdef; | ||
628 | spriteframe_t *sprframe; | ||
629 | int lump; | ||
630 | boolean flip; | ||
631 | vissprite_t *vis; | ||
632 | vissprite_t avis; | ||
633 | |||
634 | // decide which patch to use | ||
635 | |||
636 | #ifdef RANGECHECK | ||
637 | if ( (unsigned)psp->state->sprite >= (unsigned)numsprites) | ||
638 | I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite); | ||
639 | #endif | ||
640 | |||
641 | sprdef = &sprites[psp->state->sprite]; | ||
642 | |||
643 | #ifdef RANGECHECK | ||
644 | if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes) | ||
645 | I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li", | ||
646 | psp->state->sprite, psp->state->frame); | ||
647 | #endif | ||
648 | |||
649 | sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK]; | ||
650 | |||
651 | lump = sprframe->lump[0]; | ||
652 | flip = (boolean) sprframe->flip[0]; | ||
653 | |||
654 | // calculate edges of the shape | ||
655 | tx = psp->sx-160*FRACUNIT; | ||
656 | |||
657 | tx -= spriteoffset[lump]; | ||
658 | x1 = (centerxfrac + FixedMul (tx,pspritescale))>>FRACBITS; | ||
659 | |||
660 | // off the right side | ||
661 | if (x1 > viewwidth) | ||
662 | return; | ||
663 | |||
664 | tx += spritewidth[lump]; | ||
665 | x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; | ||
666 | |||
667 | // off the left side | ||
668 | if (x2 < 0) | ||
669 | return; | ||
670 | |||
671 | // store information in a vissprite | ||
672 | vis = &avis; | ||
673 | vis->mobjflags = 0; | ||
674 | // killough 12/98: fix psprite positioning problem | ||
675 | vis->texturemid = (BASEYCENTER<<FRACBITS) /* + FRACUNIT/2 */ - | ||
676 | (psp->sy-spritetopoffset[lump]); | ||
677 | vis->x1 = x1 < 0 ? 0 : x1; | ||
678 | vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; | ||
679 | // proff 11/06/98: Added for high-res | ||
680 | vis->scale = pspritescale; | ||
681 | |||
682 | if (flip) | ||
683 | { | ||
684 | vis->xiscale = -pspriteiscale; | ||
685 | vis->startfrac = spritewidth[lump]-1; | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | vis->xiscale = pspriteiscale; | ||
690 | vis->startfrac = 0; | ||
691 | } | ||
692 | |||
693 | if (vis->x1 > x1) | ||
694 | vis->startfrac += vis->xiscale*(vis->x1-x1); | ||
695 | |||
696 | vis->patch = lump; | ||
697 | |||
698 | if (viewplayer->powers[pw_invisibility] > 4*32 | ||
699 | || viewplayer->powers[pw_invisibility] & 8) | ||
700 | vis->colormap = NULL; // shadow draw | ||
701 | else if (fixedcolormap) | ||
702 | vis->colormap = fixedcolormap; // fixed color | ||
703 | else if (psp->state->frame & FF_FULLBRIGHT) | ||
704 | vis->colormap = fullcolormap; // full bright // killough 3/20/98 | ||
705 | else | ||
706 | vis->colormap = spritelights[MAXLIGHTSCALE-1]; // local light | ||
707 | |||
708 | R_DrawVisSprite(vis, vis->x1, vis->x2); | ||
709 | } | ||
710 | |||
711 | // | ||
712 | // R_DrawPlayerSprites | ||
713 | // | ||
714 | |||
715 | void R_DrawPlayerSprites(void) | ||
716 | { | ||
717 | int i, lightnum; | ||
718 | pspdef_t *psp; | ||
719 | |||
720 | // get light level | ||
721 | lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) | ||
722 | + extralight; | ||
723 | |||
724 | if (lightnum < 0) | ||
725 | spritelights = scalelight[0]; | ||
726 | else if (lightnum >= LIGHTLEVELS) | ||
727 | spritelights = scalelight[LIGHTLEVELS-1]; | ||
728 | else | ||
729 | spritelights = scalelight[lightnum]; | ||
730 | |||
731 | // clip to screen bounds | ||
732 | mfloorclip = screenheightarray; | ||
733 | mceilingclip = negonearray; | ||
734 | |||
735 | // add all active psprites | ||
736 | for (i=0, psp=viewplayer->psprites; i<NUMPSPRITES; i++,psp++) | ||
737 | if (psp->state) | ||
738 | R_DrawPSprite (psp); | ||
739 | } | ||
740 | |||
741 | // | ||
742 | // R_SortVisSprites | ||
743 | // | ||
744 | // Rewritten by Lee Killough to avoid using unnecessary | ||
745 | // linked lists, and to use faster sorting algorithm. | ||
746 | // | ||
747 | |||
748 | #define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *)) | ||
749 | |||
750 | // killough 9/2/98: merge sort | ||
751 | |||
752 | static void msort(vissprite_t **s, vissprite_t **t, int n) | ||
753 | { | ||
754 | if (n >= 16) | ||
755 | { | ||
756 | int n1 = n/2, n2 = n - n1; | ||
757 | vissprite_t **s1 = s, **s2 = s + n1, **d = t; | ||
758 | |||
759 | msort(s1, t, n1); | ||
760 | msort(s2, t, n2); | ||
761 | |||
762 | while ((*s1)->scale > (*s2)->scale ? | ||
763 | (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2)); | ||
764 | |||
765 | if (n2) | ||
766 | bcopyp(d, s2, n2); | ||
767 | else | ||
768 | bcopyp(d, s1, n1); | ||
769 | |||
770 | bcopyp(s, t, n); | ||
771 | } | ||
772 | else | ||
773 | { | ||
774 | int i; | ||
775 | for (i = 1; i < n; i++) | ||
776 | { | ||
777 | vissprite_t *temp = s[i]; | ||
778 | if (s[i-1]->scale < temp->scale) | ||
779 | { | ||
780 | int j = i; | ||
781 | while ((s[j] = s[j-1])->scale < temp->scale && --j); | ||
782 | s[j] = temp; | ||
783 | } | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | |||
788 | void R_SortVisSprites (void) | ||
789 | { | ||
790 | if (num_vissprite) | ||
791 | { | ||
792 | int i = num_vissprite; | ||
793 | |||
794 | // If we need to allocate more pointers for the vissprites, | ||
795 | // allocate as many as were allocated for sprites -- killough | ||
796 | // killough 9/22/98: allocate twice as many | ||
797 | |||
798 | if (num_vissprite_ptrs < num_vissprite*2) | ||
799 | { | ||
800 | free(vissprite_ptrs); // better than realloc -- no preserving needed | ||
801 | vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2) | ||
802 | * sizeof *vissprite_ptrs); | ||
803 | } | ||
804 | |||
805 | while (--i>=0) | ||
806 | vissprite_ptrs[i] = vissprites+i; | ||
807 | |||
808 | // killough 9/22/98: replace qsort with merge sort, since the keys | ||
809 | // are roughly in order to begin with, due to BSP rendering. | ||
810 | |||
811 | msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | // | ||
816 | // R_DrawSprite | ||
817 | // | ||
818 | |||
819 | void R_DrawSprite (vissprite_t* spr) | ||
820 | { | ||
821 | drawseg_t *ds; | ||
822 | short clipbot[SCREENWIDTH]; // killough 2/8/98: | ||
823 | short cliptop[SCREENWIDTH]; // change to MAX_* | ||
824 | int x; | ||
825 | int r1; | ||
826 | int r2; | ||
827 | fixed_t scale; | ||
828 | fixed_t lowscale; | ||
829 | |||
830 | for (x = spr->x1 ; x<=spr->x2 ; x++) | ||
831 | clipbot[x] = cliptop[x] = -2; | ||
832 | |||
833 | // Scan drawsegs from end to start for obscuring segs. | ||
834 | // The first drawseg that has a greater scale is the clip seg. | ||
835 | |||
836 | // Modified by Lee Killough: | ||
837 | // (pointer check was originally nonportable | ||
838 | // and buggy, by going past LEFT end of array): | ||
839 | |||
840 | // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code | ||
841 | |||
842 | for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough | ||
843 | { // determine if the drawseg obscures the sprite | ||
844 | if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || | ||
845 | (!ds->silhouette && !ds->maskedtexturecol)) | ||
846 | continue; // does not cover sprite | ||
847 | |||
848 | r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; | ||
849 | r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; | ||
850 | |||
851 | if (ds->scale1 > ds->scale2) | ||
852 | { | ||
853 | lowscale = ds->scale2; | ||
854 | scale = ds->scale1; | ||
855 | } | ||
856 | else | ||
857 | { | ||
858 | lowscale = ds->scale1; | ||
859 | scale = ds->scale2; | ||
860 | } | ||
861 | |||
862 | if (scale < spr->scale || (lowscale < spr->scale && | ||
863 | !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) | ||
864 | { | ||
865 | if (ds->maskedtexturecol) // masked mid texture? | ||
866 | R_RenderMaskedSegRange(ds, r1, r2); | ||
867 | continue; // seg is behind sprite | ||
868 | } | ||
869 | |||
870 | // clip this piece of the sprite | ||
871 | // killough 3/27/98: optimized and made much shorter | ||
872 | |||
873 | if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil | ||
874 | for (x=r1 ; x<=r2 ; x++) | ||
875 | if (clipbot[x] == -2) | ||
876 | clipbot[x] = ds->sprbottomclip[x]; | ||
877 | |||
878 | if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil | ||
879 | for (x=r1 ; x<=r2 ; x++) | ||
880 | if (cliptop[x] == -2) | ||
881 | cliptop[x] = ds->sprtopclip[x]; | ||
882 | } | ||
883 | |||
884 | // killough 3/27/98: | ||
885 | // Clip the sprite against deep water and/or fake ceilings. | ||
886 | // killough 4/9/98: optimize by adding mh | ||
887 | // killough 4/11/98: improve sprite clipping for underwater/fake ceilings | ||
888 | // killough 11/98: fix disappearing sprites | ||
889 | |||
890 | if (spr->heightsec != -1) // only things in specially marked sectors | ||
891 | { | ||
892 | fixed_t h,mh; | ||
893 | int phs = viewplayer->mo->subsector->sector->heightsec; | ||
894 | if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && | ||
895 | (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 && | ||
896 | (h >>= FRACBITS) < viewheight) { | ||
897 | if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) | ||
898 | { // clip bottom | ||
899 | for (x=spr->x1 ; x<=spr->x2 ; x++) | ||
900 | if (clipbot[x] == -2 || h < clipbot[x]) | ||
901 | clipbot[x] = h; | ||
902 | } | ||
903 | else // clip top | ||
904 | if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98 | ||
905 | for (x=spr->x1 ; x<=spr->x2 ; x++) | ||
906 | if (cliptop[x] == -2 || h > cliptop[x]) | ||
907 | cliptop[x] = h; | ||
908 | } | ||
909 | |||
910 | if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && | ||
911 | (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && | ||
912 | (h >>= FRACBITS) < viewheight) { | ||
913 | if (phs != -1 && viewz >= sectors[phs].ceilingheight) | ||
914 | { // clip bottom | ||
915 | for (x=spr->x1 ; x<=spr->x2 ; x++) | ||
916 | if (clipbot[x] == -2 || h < clipbot[x]) | ||
917 | clipbot[x] = h; | ||
918 | } | ||
919 | else // clip top | ||
920 | for (x=spr->x1 ; x<=spr->x2 ; x++) | ||
921 | if (cliptop[x] == -2 || h > cliptop[x]) | ||
922 | cliptop[x] = h; | ||
923 | } | ||
924 | } | ||
925 | // killough 3/27/98: end special clipping for deep water / fake ceilings | ||
926 | |||
927 | // all clipping has been performed, so draw the sprite | ||
928 | // check for unclipped columns | ||
929 | |||
930 | for (x = spr->x1 ; x<=spr->x2 ; x++) { | ||
931 | if (clipbot[x] == -2) | ||
932 | clipbot[x] = viewheight; | ||
933 | |||
934 | if (cliptop[x] == -2) | ||
935 | cliptop[x] = -1; | ||
936 | } | ||
937 | |||
938 | mfloorclip = clipbot; | ||
939 | mceilingclip = cliptop; | ||
940 | R_DrawVisSprite (spr, spr->x1, spr->x2); | ||
941 | } | ||
942 | |||
943 | // | ||
944 | // R_DrawMasked | ||
945 | // | ||
946 | |||
947 | void R_DrawMasked(void) | ||
948 | { | ||
949 | int i; | ||
950 | drawseg_t *ds; | ||
951 | |||
952 | R_SortVisSprites(); | ||
953 | |||
954 | // draw all vissprites back to front | ||
955 | |||
956 | // rendered_vissprites = num_vissprite; | ||
957 | for (i = num_vissprite ;--i>=0; ) | ||
958 | R_DrawSprite(vissprite_ptrs[i]); // killough | ||
959 | |||
960 | // render any remaining masked mid textures | ||
961 | |||
962 | // Modified by Lee Killough: | ||
963 | // (pointer check was originally nonportable | ||
964 | // and buggy, by going past LEFT end of array): | ||
965 | |||
966 | // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code | ||
967 | |||
968 | for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough | ||
969 | if (ds->maskedtexturecol) | ||
970 | R_RenderMaskedSegRange(ds, ds->x1, ds->x2); | ||
971 | |||
972 | // draw the psprites on top of everything | ||
973 | // but does not draw on side views | ||
974 | if (!viewangleoffset) | ||
975 | R_DrawPlayerSprites (); | ||
976 | } | ||