// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 1993-2008 Raven Software // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // HEADER FILES ------------------------------------------------------------ #include "h2def.h" #include "i_system.h" #include "r_local.h" // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- extern fixed_t Sky1ScrollDelta; extern fixed_t Sky2ScrollDelta; // PUBLIC DATA DEFINITIONS ------------------------------------------------- int Sky1Texture; int Sky2Texture; fixed_t Sky1ColumnOffset; fixed_t Sky2ColumnOffset; int skyflatnum; int skytexturemid; fixed_t skyiscale; boolean DoubleSky; planefunction_t floorfunc, ceilingfunc; // Opening visplane_t visplanes[MAXVISPLANES], *lastvisplane; visplane_t *floorplane, *ceilingplane; short openings[MAXOPENINGS], *lastopening; // Clip values are the solid pixel bounding the range. // floorclip start out SCREENHEIGHT // ceilingclip starts out -1 short floorclip[SCREENWIDTH]; short ceilingclip[SCREENWIDTH]; // spanstart holds the start of a plane span, initialized to 0 int spanstart[SCREENHEIGHT]; int spanstop[SCREENHEIGHT]; // Texture mapping lighttable_t **planezlight; fixed_t planeheight; fixed_t yslope[SCREENHEIGHT]; fixed_t distscale[SCREENWIDTH]; fixed_t basexscale, baseyscale; fixed_t cachedheight[SCREENHEIGHT]; fixed_t cacheddistance[SCREENHEIGHT]; fixed_t cachedxstep[SCREENHEIGHT]; fixed_t cachedystep[SCREENHEIGHT]; // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // R_InitSky // // Called at level load. // //========================================================================== void R_InitSky(int map) { Sky1Texture = P_GetMapSky1Texture(map); Sky2Texture = P_GetMapSky2Texture(map); Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map); Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map); Sky1ColumnOffset = 0; Sky2ColumnOffset = 0; DoubleSky = P_GetMapDoubleSky(map); } //========================================================================== // // R_InitSkyMap // // Called whenever the view size changes. // //========================================================================== void R_InitSkyMap(void) { skyflatnum = R_FlatNumForName("F_SKY"); skytexturemid = 200 * FRACUNIT; skyiscale = FRACUNIT; } //========================================================================== // // R_InitPlanes // // Called at game startup. // //========================================================================== void R_InitPlanes(void) { } //========================================================================== // // R_MapPlane // // Globals used: planeheight, ds_source, basexscale, baseyscale, // viewx, viewy. // //========================================================================== void R_MapPlane(int y, int x1, int x2) { angle_t angle; fixed_t distance, length; unsigned index; #ifdef RANGECHECK if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight) { I_Error("R_MapPlane: %i, %i at %i", x1, x2, y); } #endif if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); } else { distance = cacheddistance[y]; ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } length = FixedMul(distance, distscale[x1]); angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT; ds_xfrac = viewx + FixedMul(finecosine[angle], length); ds_yfrac = -viewy - FixedMul(finesine[angle], length); if (fixedcolormap) { ds_colormap = fixedcolormap; } else { index = distance >> LIGHTZSHIFT; if (index >= MAXLIGHTZ) { index = MAXLIGHTZ - 1; } ds_colormap = planezlight[index]; } ds_y = y; ds_x1 = x1; ds_x2 = x2; spanfunc(); // High or low detail } //========================================================================== // // R_ClearPlanes // // Called at the beginning of each frame. // //========================================================================== void R_ClearPlanes(void) { int i; angle_t angle; // Opening / clipping determination for (i = 0; i < viewwidth; i++) { floorclip[i] = viewheight; ceilingclip[i] = -1; } lastvisplane = visplanes; lastopening = openings; // Texture calculation memset(cachedheight, 0, sizeof(cachedheight)); angle = (viewangle - ANG90) >> ANGLETOFINESHIFT; // left to right mapping // Scale will be unit scale at SCREENWIDTH/2 distance basexscale = FixedDiv(finecosine[angle], centerxfrac); baseyscale = -FixedDiv(finesine[angle], centerxfrac); } //========================================================================== // // R_FindPlane // //========================================================================== visplane_t *R_FindPlane(fixed_t height, int picnum, int lightlevel, int special) { visplane_t *check; if (special < 150) { // Don't let low specials affect search special = 0; } if (picnum == skyflatnum) { // All skies map together height = 0; lightlevel = 0; } for (check = visplanes; check < lastvisplane; check++) { if (height == check->height && picnum == check->picnum && lightlevel == check->lightlevel && special == check->special) break; } if (check < lastvisplane) { return (check); } if (lastvisplane - visplanes == MAXVISPLANES) { I_Error("R_FindPlane: no more visplanes"); } lastvisplane++; check->height = height; check->picnum = picnum; check->lightlevel = lightlevel; check->special = special; check->minx = SCREENWIDTH; check->maxx = -1; memset(check->top, 0xff, sizeof(check->top)); return (check); } //========================================================================== // // R_CheckPlane // //========================================================================== visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop) { int intrl, intrh; int unionl, unionh; int x; if (start < pl->minx) { intrl = pl->minx; unionl = start; } else { unionl = pl->minx; intrl = start; } if (stop > pl->maxx) { intrh = pl->maxx; unionh = stop; } else { unionh = pl->maxx; intrh = stop; } for (x = intrl; x <= intrh; x++) { if (pl->top[x] != 0xff) { break; } } if (x > intrh) { pl->minx = unionl; pl->maxx = unionh; return pl; // use the same visplane } // Make a new visplane lastvisplane->height = pl->height; lastvisplane->picnum = pl->picnum; lastvisplane->lightlevel = pl->lightlevel; lastvisplane->special = pl->special; pl = lastvisplane++; pl->minx = start; pl->maxx = stop; memset(pl->top, 0xff, sizeof(pl->top)); return pl; } //========================================================================== // // R_MakeSpans // //========================================================================== void R_MakeSpans(int x, int t1, int b1, int t2, int b2) { while (t1 < t2 && t1 <= b1) { R_MapPlane(t1, spanstart[t1], x - 1); t1++; } while (b1 > b2 && b1 >= t1) { R_MapPlane(b1, spanstart[b1], x - 1); b1--; } while (t2 < t1 && t2 <= b2) { spanstart[t2] = x; t2++; } while (b2 > b1 && b2 >= t2) { spanstart[b2] = x; b2--; } } //========================================================================== // // R_DrawPlanes // //========================================================================== #define SKYTEXTUREMIDSHIFTED 200 void R_DrawPlanes(void) { visplane_t *pl; int light; int x, stop; int angle; byte *tempSource; byte *source; byte *source2; byte *dest; int count; int offset; int skyTexture; int offset2; int skyTexture2; int scrollOffset; extern byte *ylookup[MAXHEIGHT]; extern int columnofs[MAXWIDTH]; #ifdef RANGECHECK if (ds_p - drawsegs > MAXDRAWSEGS) { I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs); } if (lastvisplane - visplanes > MAXVISPLANES) { I_Error("R_DrawPlanes: visplane overflow (%i)", lastvisplane - visplanes); } if (lastopening - openings > MAXOPENINGS) { I_Error("R_DrawPlanes: opening overflow (%i)", lastopening - openings); } #endif for (pl = visplanes; pl < lastvisplane; pl++) { if (pl->minx > pl->maxx) { continue; } if (pl->picnum == skyflatnum) { // Sky flat if (DoubleSky) { // Render 2 layers, sky 1 in front offset = Sky1ColumnOffset >> 16; skyTexture = texturetranslation[Sky1Texture]; offset2 = Sky2ColumnOffset >> 16; skyTexture2 = texturetranslation[Sky2Texture]; for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { count = dc_yh - dc_yl; if (count < 0) { return; } angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT; source = R_GetColumn(skyTexture, angle + offset) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); source2 = R_GetColumn(skyTexture2, angle + offset2) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); dest = ylookup[dc_yl] + columnofs[x]; do { if (*source) { *dest = *source++; source2++; } else { *dest = *source2++; source++; } dest += SCREENWIDTH; } while (count--); } } continue; // Next visplane } else { // Render single layer if (pl->special == 200) { // Use sky 2 offset = Sky2ColumnOffset >> 16; skyTexture = texturetranslation[Sky2Texture]; } else { // Use sky 1 offset = Sky1ColumnOffset >> 16; skyTexture = texturetranslation[Sky1Texture]; } for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; if (dc_yl <= dc_yh) { count = dc_yh - dc_yl; if (count < 0) { return; } angle = (viewangle + xtoviewangle[x]) >> ANGLETOSKYSHIFT; source = R_GetColumn(skyTexture, angle + offset) + SKYTEXTUREMIDSHIFTED + (dc_yl - centery); dest = ylookup[dc_yl] + columnofs[x]; do { *dest = *source++; dest += SCREENWIDTH; } while (count--); } } continue; // Next visplane } } // Regular flat tempSource = W_CacheLumpNum(firstflat + flattranslation[pl->picnum], PU_STATIC); scrollOffset = leveltime >> 1 & 63; switch (pl->special) { // Handle scrolling flats case 201: case 202: case 203: // Scroll_North_xxx ds_source = tempSource + ((scrollOffset << (pl->special - 201) & 63) << 6); break; case 204: case 205: case 206: // Scroll_East_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 204) & 63); break; case 207: case 208: case 209: // Scroll_South_xxx ds_source = tempSource + (((63 - scrollOffset) << (pl->special - 207) & 63) << 6); break; case 210: case 211: case 212: // Scroll_West_xxx ds_source = tempSource + (scrollOffset << (pl->special - 210) & 63); break; case 213: case 214: case 215: // Scroll_NorthWest_xxx ds_source = tempSource + (scrollOffset << (pl->special - 213) & 63) + ((scrollOffset << (pl->special - 213) & 63) << 6); break; case 216: case 217: case 218: // Scroll_NorthEast_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 216) & 63) + ((scrollOffset << (pl->special - 216) & 63) << 6); break; case 219: case 220: case 221: // Scroll_SouthEast_xxx ds_source = tempSource + ((63 - scrollOffset) << (pl->special - 219) & 63) + (((63 - scrollOffset) << (pl->special - 219) & 63) << 6); break; case 222: case 223: case 224: // Scroll_SouthWest_xxx ds_source = tempSource + (scrollOffset << (pl->special - 222) & 63) + (((63 - scrollOffset) << (pl->special - 222) & 63) << 6); break; default: ds_source = tempSource; break; } planeheight = abs(pl->height - viewz); light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; if (light >= LIGHTLEVELS) { light = LIGHTLEVELS - 1; } if (light < 0) { light = 0; } planezlight = zlight[light]; pl->top[pl->maxx + 1] = 0xff; pl->top[pl->minx - 1] = 0xff; stop = pl->maxx + 1; for (x = pl->minx; x <= stop; x++) { R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1], pl->top[x], pl->bottom[x]); } W_ReleaseLumpNum(firstflat + flattranslation[pl->picnum]); } }