doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

r_things.c (13830B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 #include "doomdef.h"
      5 #include "i_system.h"
      6 #include "z_zone.h"
      7 #include "w_wad.h"
      8 #include "m_swap.h"
      9 #include "r_local.h"
     10 #include "doomstat.h"
     11 
     12 #define MINZ (FRACUNIT*4)
     13 #define BASEYCENTER 100
     14 
     15 typedef struct {
     16 	int x1;
     17 	int x2;
     18 	int column;
     19 	int topclip;
     20 	int bottomclip;
     21 } maskdraw_t;
     22 
     23 fixed_t pspritescale;
     24 fixed_t pspriteiscale;
     25 lighttable_t** spritelights;
     26 short negonearray[SCREENWIDTH];
     27 short screenheightarray[SCREENWIDTH];
     28 spritedef_t* sprites;
     29 int numsprites;
     30 spriteframe_t sprtemp[29];
     31 int maxframe;
     32 char* spritename;
     33 
     34 void
     35 R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation, boolean flipped)
     36 {
     37 	int r;
     38 	
     39 	if (frame >= 29 || rotation > 8)
     40 		I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
     41 	if ((int)frame > maxframe)
     42 		maxframe = frame;
     43 	if (rotation == 0) {
     44 		if (sprtemp[frame].rotate == false)
     45 			I_Error ("R_InitSprites: Sprite %s frame %c has multip rot=0 lump", spritename, 'A'+frame);
     46 		if (sprtemp[frame].rotate == true)
     47 			I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A'+frame);
     48 		sprtemp[frame].rotate = false;
     49 		for (r = 0; r < 8; ++r) {
     50 			sprtemp[frame].lump[r] = lump - firstspritelump;
     51 			sprtemp[frame].flip[r] = (byte)flipped;
     52 		}
     53 		return;
     54 	}
     55 	if (sprtemp[frame].rotate == false)
     56 		I_Error ("R_InitSprites: Sprite %s frame %c has rotations and a rot=0 lump", spritename, 'A'+frame);
     57 	sprtemp[frame].rotate = true;
     58 	--rotation; 
     59 	if (sprtemp[frame].lump[rotation] != -1)
     60 	I_Error("R_InitSprites: Sprite %s : %c : %c has two lumps mapped to it", spritename, 'A'+frame, '1'+rotation);
     61 	sprtemp[frame].lump[rotation] = lump - firstspritelump;
     62 	sprtemp[frame].flip[rotation] = (byte)flipped;
     63 }
     64 
     65 void
     66 R_InitSpriteDefs(char** namelist) 
     67 { 
     68 	int i, l, intname, frame, rotation, start, end, patched;
     69 	
     70 	numsprites = LENGTH(sprnames);
     71 	if (!numsprites)
     72 		return;
     73 	sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL);
     74 	start = firstspritelump - 1;
     75 	end = lastspritelump + 1;
     76 	for (i = 0; i < numsprites; ++i) {
     77 		spritename = namelist[i];
     78 		memset(sprtemp, -1, sizeof(sprtemp));
     79 		maxframe = -1;
     80 		intname = *(int*)namelist[i];
     81 		for (l = start + 1; l < end; ++l) {
     82 			if (*(int*)lumpinfo_g[l].name == intname) {
     83 				frame = lumpinfo_g[l].name[4] - 'A';
     84 				rotation = lumpinfo_g[l].name[5] - '0';
     85 				if (modifiedgame)
     86 					patched = W_GetNumForName(lumpinfo_g[l].name);
     87 				else
     88 					patched = l;
     89 				R_InstallSpriteLump(patched, frame, rotation, false);
     90 				if (lumpinfo_g[l].name[6]) {
     91 					frame = lumpinfo_g[l].name[6] - 'A';
     92 					rotation = lumpinfo_g[l].name[7] - '0';
     93 					R_InstallSpriteLump(l, frame, rotation, true);
     94 				}
     95 			}
     96 		}
     97 		if (maxframe == -1) {
     98 			sprites[i].numframes = 0;
     99 			continue;
    100 		}
    101 		++maxframe;
    102 		
    103 		for (frame = 0; frame < maxframe; ++frame) {
    104 			switch ((int)sprtemp[frame].rotate) {
    105 				case -1:
    106 					I_Error ("R_InitSprites: No patches found for %s frame %c", namelist[i], frame+'A');
    107 					break;
    108 				case 0:
    109 					break;
    110 				case 1:
    111 					for (rotation = 0; rotation < 8; ++rotation)
    112 						if (sprtemp[frame].lump[rotation] == -1)
    113 							I_Error("R_InitSprites: Sprite %s frame %c is missing rotations", namelist[i], frame+'A');
    114 					break;
    115 			}
    116 		}
    117 		sprites[i].numframes = maxframe;
    118 		sprites[i].spriteframes = Z_Malloc(maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
    119 		memcpy(sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
    120 	}
    121 }
    122 
    123 vissprite_t vissprites[MAXVISSPRITES];
    124 vissprite_t* vissprite_p;
    125 int newvissprite;
    126 
    127 void
    128 R_InitSprites(char** namelist)
    129 {
    130 	int i;
    131 	
    132 	for (i = 0; i < SCREENWIDTH; ++i)
    133 		negonearray[i] = -1;
    134 	R_InitSpriteDefs(namelist);
    135 }
    136 
    137 void
    138 R_ClearSprites()
    139 {
    140 	vissprite_p = vissprites;
    141 }
    142 
    143 vissprite_t overflowsprite;
    144 
    145 vissprite_t*
    146 R_NewVisSprite()
    147 {
    148 	if (vissprite_p == &vissprites[MAXVISSPRITES])
    149 		return &overflowsprite;
    150 	++vissprite_p;
    151 	return vissprite_p - 1;
    152 }
    153 
    154 
    155 short* mfloorclip;
    156 short* mceilingclip;
    157 fixed_t spryscale;
    158 fixed_t sprtopscreen;
    159 
    160 void
    161 R_DrawMaskedColumn(column_t* column)
    162 {
    163 	fixed_t basetexturemid;
    164 	int topscreen, bottomscreen;
    165 	
    166 	basetexturemid = dc_texturemid;
    167 	for (; column->topdelta != 0xff;) {
    168 		topscreen = sprtopscreen + spryscale*column->topdelta;
    169 		bottomscreen = topscreen + spryscale*column->length;
    170 		dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
    171 		dc_yh = (bottomscreen-1)>>FRACBITS;
    172 		if (dc_yh >= mfloorclip[dc_x])
    173 			dc_yh = mfloorclip[dc_x]-1;
    174 		if (dc_yl <= mceilingclip[dc_x])
    175 			dc_yl = mceilingclip[dc_x]+1;
    176 		if (dc_yl <= dc_yh) {
    177 			dc_source = (byte *)column + 3;
    178 			dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
    179 			colfunc (); 
    180 		}
    181 		column = (column_t *)( (byte *)column + column->length + 4);
    182 	}
    183 	dc_texturemid = basetexturemid;
    184 }
    185 
    186 void
    187 R_DrawVisSprite(vissprite_t* vis, int x1, int x2)
    188 {
    189 	column_t* column;
    190 	patch_t* patch;
    191 	fixed_t frac;
    192 	int texturecolumn;
    193 	
    194 	patch = W_CacheLumpNum(vis->patch + firstspritelump, PU_CACHE);
    195 	dc_colormap = vis->colormap;
    196 	if (!dc_colormap)
    197 		colfunc = fuzzcolfunc;
    198 	if (vis->mobjflags & MF_TRANSLATION) {
    199 		colfunc = R_DrawTranslatedColumn;
    200 		dc_translation = translationtables - 256 + ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8));
    201 	}
    202 	dc_iscale = abs(vis->xiscale)>>detailshift;
    203 	dc_texturemid = vis->texturemid;
    204 	frac = vis->startfrac;
    205 	spryscale = vis->scale;
    206 	sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
    207 	for (dc_x = vis->x1; dc_x <= vis->x2; ++dc_x, frac += vis->xiscale) {
    208 		texturecolumn = frac>>FRACBITS;
    209 #ifdef RANGECHECK
    210 		if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
    211 			I_Error ("R_DrawSpriteRange: bad texturecolumn");
    212 #endif
    213 		column = (column_t*)((byte*)patch + LONG(patch->columnofs[texturecolumn]));
    214 		R_DrawMaskedColumn (column);
    215 	}
    216 	colfunc = basecolfunc;
    217 }
    218 
    219 void
    220 R_ProjectSprite(mobj_t* thing)
    221 {
    222 	spriteframe_t* sprframe;
    223 	spritedef_t* sprdef;
    224 	vissprite_t* vis;
    225 	angle_t ang;
    226 	fixed_t tr_x, tr_y, gxt, gyt, tx, tz, xscale, iscale;
    227 	int x1, x2, lump, index;
    228 	uint rot;
    229 	boolean flip;
    230 	
    231 	tr_x = thing->x - viewx;
    232 	tr_y = thing->y - viewy;
    233 	gxt = FixedMul(tr_x,viewcos); 
    234 	gyt = -FixedMul(tr_y,viewsin);
    235 	tz = gxt - gyt; 
    236 	if (tz < MINZ)
    237 		return;
    238 	xscale = FixedDiv(projection, tz);
    239 	gxt = -FixedMul(tr_x,viewsin); 
    240 	gyt = FixedMul(tr_y,viewcos); 
    241 	tx = -(gyt+gxt); 
    242 	if (abs(tx)>(tz<<2))
    243 		return;
    244 #ifdef RANGECHECK
    245 	if ((unsigned)thing->sprite >= numsprites)
    246 		I_Error ("R_ProjectSprite: invalid sprite number %i ", thing->sprite);
    247 #endif
    248 	sprdef = &sprites[thing->sprite];
    249 #ifdef RANGECHECK
    250 	if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
    251 		I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", thing->sprite, thing->frame);
    252 #endif
    253 	sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
    254 	if (sprframe->rotate) {
    255 		ang = R_PointToAngle (thing->x, thing->y);
    256 		rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
    257 		lump = sprframe->lump[rot];
    258 		flip = (boolean)sprframe->flip[rot];
    259 	} else {
    260 		lump = sprframe->lump[0];
    261 		flip = (boolean)sprframe->flip[0];
    262 	}
    263 	tx -= spriteoffset[lump]; 
    264 	x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
    265 	if (x1 > viewwidth)
    266 		return;
    267 	tx += spritewidth[lump];
    268 	x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
    269 	if (x2 < 0)
    270 		return;
    271 	vis = R_NewVisSprite();
    272 	vis->mobjflags = thing->flags;
    273 	vis->scale = xscale<<detailshift;
    274 	vis->gx = thing->x;
    275 	vis->gy = thing->y;
    276 	vis->gz = thing->z;
    277 	vis->gzt = thing->z + spritetopoffset[lump];
    278 	vis->texturemid = vis->gzt - viewz;
    279 	vis->x1 = x1 < 0 ? 0 : x1;
    280 	vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; 
    281 	iscale = FixedDiv(FRACUNIT, xscale);
    282 	if (flip) {
    283 		vis->startfrac = spritewidth[lump]-1;
    284 		vis->xiscale = -iscale;
    285 	} else {
    286 		vis->startfrac = 0;
    287 		vis->xiscale = iscale;
    288 	}
    289 	if (vis->x1 > x1)
    290 		vis->startfrac += vis->xiscale*(vis->x1-x1);
    291 	vis->patch = lump;
    292 	if (thing->flags & MF_SHADOW)
    293 		vis->colormap = NULL;
    294 	else if (fixedcolormap)
    295 		vis->colormap = fixedcolormap;
    296 	else if (thing->frame & FF_FULLBRIGHT)
    297 		vis->colormap = colormaps;
    298 	else {
    299 		index = xscale>>(LIGHTSCALESHIFT-detailshift);
    300 		if (index >= MAXLIGHTSCALE) 
    301 			index = MAXLIGHTSCALE-1;
    302 		vis->colormap = spritelights[index];
    303 	} 
    304 }
    305 
    306 void
    307 R_AddSprites(sector_t* sec)
    308 {
    309 	mobj_t* thing;
    310 	int lightnum;
    311 	
    312 	if (sec->validcount == validcount)
    313 		return; 
    314 	sec->validcount = validcount;
    315 	lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
    316 	if (lightnum < 0) 
    317 		spritelights = scalelight[0];
    318 	else if (lightnum >= LIGHTLEVELS)
    319 		spritelights = scalelight[LIGHTLEVELS-1];
    320 	else
    321 		spritelights = scalelight[lightnum];
    322 	for (thing = sec->thinglist; thing; thing = thing->snext)
    323 		R_ProjectSprite (thing);
    324 }
    325 
    326 void
    327 R_DrawPSprite(pspdef_t* psp)
    328 {
    329 	spriteframe_t* sprframe;
    330 	spritedef_t* sprdef;
    331 	vissprite_t avis, *vis;
    332 	fixed_t tx;
    333 	int x1, x2, lump;
    334 	boolean flip;
    335 #ifdef RANGECHECK
    336 	if ( (unsigned)psp->state->sprite >= numsprites)
    337 		I_Error ("R_ProjectSprite: invalid sprite number %i ", psp->state->sprite);
    338 #endif
    339 	sprdef = &sprites[psp->state->sprite];
    340 #ifdef RANGECHECK
    341 	if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
    342 		I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ", psp->state->sprite, psp->state->frame);
    343 #endif
    344 	sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
    345 	lump = sprframe->lump[0];
    346 	flip = (boolean)sprframe->flip[0];
    347 	tx = psp->sx-160*FRACUNIT;
    348 	tx -= spriteoffset[lump]; 
    349 	x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
    350 	if (x1 > viewwidth)
    351 		return; 
    352 	tx += spritewidth[lump];
    353 	x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
    354 	if (x2 < 0)
    355 		return;
    356 	vis = &avis;
    357 	vis->mobjflags = 0;
    358 	vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]);
    359 	vis->x1 = x1 < 0 ? 0 : x1;
    360 	vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; 
    361 	vis->scale = pspritescale<<detailshift;
    362 	if (flip) {
    363 		vis->xiscale = -pspriteiscale;
    364 		vis->startfrac = spritewidth[lump]-1;
    365 	} else {
    366 		vis->xiscale = pspriteiscale;
    367 		vis->startfrac = 0;
    368 	}
    369 	if (vis->x1 > x1)
    370 		vis->startfrac += vis->xiscale*(vis->x1-x1);
    371 	vis->patch = lump;
    372 	if (viewplayer->powers[pw_invisibility] > 4*32 || viewplayer->powers[pw_invisibility] & 8)
    373 		vis->colormap = NULL;
    374 	else if (fixedcolormap)
    375 		vis->colormap = fixedcolormap;
    376 	else if (psp->state->frame & FF_FULLBRIGHT)
    377 		vis->colormap = colormaps;
    378 	else
    379 		vis->colormap = spritelights[MAXLIGHTSCALE-1];
    380 	R_DrawVisSprite (vis, vis->x1, vis->x2);
    381 }
    382 
    383 void
    384 R_DrawPlayerSprites()
    385 {
    386 	int i, lightnum;
    387 	pspdef_t* psp;
    388 	
    389 	lightnum = (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) + extralight;
    390 	if (lightnum < 0) 
    391 		spritelights = scalelight[0];
    392 	else if (lightnum >= LIGHTLEVELS)
    393 		spritelights = scalelight[LIGHTLEVELS-1];
    394 	else
    395 		spritelights = scalelight[lightnum];
    396 	mfloorclip = screenheightarray;
    397 	mceilingclip = negonearray;
    398 	for (i = 0, psp = viewplayer->psprites; i < NUMPSPRITES; ++i, ++psp)
    399 		if (psp->state)
    400 			R_DrawPSprite(psp);
    401 }
    402 
    403 vissprite_t vsprsortedhead;
    404 
    405 void
    406 R_SortVisSprites()
    407 {
    408 	vissprite_t* best, *ds;
    409 	vissprite_t unsorted;
    410 	fixed_t bestscale;
    411 	int i, count;
    412 
    413 	count = vissprite_p - vissprites;
    414 	unsorted.next = unsorted.prev = &unsorted;
    415 	if (!count)
    416 		return;
    417 	for (ds = vissprites; ds < vissprite_p; ++ds) {
    418 		ds->next = ds+1;
    419 		ds->prev = ds-1;
    420 	}
    421 	vissprites[0].prev = &unsorted;
    422 	unsorted.next = &vissprites[0];
    423 	(vissprite_p-1)->next = &unsorted;
    424 	unsorted.prev = vissprite_p-1;
    425 	vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
    426 	for (i = 0; i < count; ++i) {
    427 		bestscale = INT_MAX;
    428 		for (best = ds = unsorted.next; ds != &unsorted; ds = ds->next) {
    429 			if (ds->scale < bestscale) {
    430 				bestscale = ds->scale;
    431 				best = ds;
    432 			}
    433 		}
    434 		best->next->prev = best->prev;
    435 		best->prev->next = best->next;
    436 		best->next = &vsprsortedhead;
    437 		best->prev = vsprsortedhead.prev;
    438 		vsprsortedhead.prev->next = best;
    439 		vsprsortedhead.prev = best;
    440 	}
    441 }
    442 
    443 void
    444 R_DrawSprite(vissprite_t* spr)
    445 {
    446 	drawseg_t* ds;
    447 	short clipbot[SCREENWIDTH], cliptop[SCREENWIDTH];
    448 	fixed_t scale, lowscale;
    449 	int x, r1, r2, silhouette;
    450 		
    451 	for (x = spr->x1; x <= spr->x2; ++x)
    452 		clipbot[x] = cliptop[x] = -2;
    453 	for (ds = ds_p-1; ds >= drawsegs; --ds) {
    454 		if (ds->x1 > spr->x2 || ds->x2 < spr->x1 || (!ds->silhouette && !ds->maskedtexturecol) )
    455 			continue;
    456 		r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
    457 		r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
    458 		if (ds->scale1 > ds->scale2) {
    459 			lowscale = ds->scale2;
    460 			scale = ds->scale1;
    461 		} else {
    462 			lowscale = ds->scale1;
    463 			scale = ds->scale2;
    464 		}
    465 		if (scale < spr->scale || ( lowscale < spr->scale && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) {
    466 			if (ds->maskedtexturecol) 
    467 				R_RenderMaskedSegRange (ds, r1, r2);
    468 			continue; 
    469 		}
    470 		silhouette = ds->silhouette;
    471 		if (spr->gz >= ds->bsilheight)
    472 			silhouette &= ~SIL_BOTTOM;
    473 		if (spr->gzt <= ds->tsilheight)
    474 			silhouette &= ~SIL_TOP;
    475 		if (silhouette == 1) {
    476 			for (x = r1; x <= r2; ++x)
    477 				if (clipbot[x] == -2)
    478 					clipbot[x] = ds->sprbottomclip[x];
    479 		}
    480 		if (silhouette == 2) {
    481 			for (x = r1; x <= r2; ++x)
    482 				if (cliptop[x] == -2)
    483 					cliptop[x] = ds->sprtopclip[x];
    484 		}
    485 		if (silhouette == 3) {
    486 			for (x = r1; x <= r2; ++x) {
    487 			if (clipbot[x] == -2)
    488 				clipbot[x] = ds->sprbottomclip[x];
    489 			if (cliptop[x] == -2)
    490 				cliptop[x] = ds->sprtopclip[x];
    491 			}
    492 		}
    493 	}
    494 	for (x = spr->x1; x <= spr->x2; ++x) {
    495 		if (clipbot[x] == -2) 
    496 			clipbot[x] = viewheight;
    497 		if (cliptop[x] == -2)
    498 			cliptop[x] = -1;
    499 	}
    500 	mfloorclip = clipbot;
    501 	mceilingclip = cliptop;
    502 	R_DrawVisSprite(spr, spr->x1, spr->x2);
    503 }
    504 
    505 void
    506 R_DrawMasked()
    507 {
    508 	vissprite_t* spr;
    509 	drawseg_t* ds;
    510 	
    511 	R_SortVisSprites();
    512 	if (vissprite_p > vissprites) {
    513 		for (spr = vsprsortedhead.next; spr != &vsprsortedhead; spr=spr->next)
    514 			R_DrawSprite(spr);
    515 	}
    516 	for (ds = ds_p-1; ds >= drawsegs; --ds)
    517 		if (ds->maskedtexturecol)
    518 			R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
    519 	if (!viewangleoffset) 
    520 		R_DrawPlayerSprites();
    521 }