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