gzdoom/code/R_draw.c

1297 lines
28 KiB
C
Raw Normal View History

1998-04-07 00:00:00 +00:00
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// The actual span/column drawing functions.
// Here find the main potential for optimization,
// e.g. inline assembly, different algorithms.
//
//-----------------------------------------------------------------------------
1998-04-07 00:00:00 +00:00
#include "m_alloc.h"
1998-04-07 00:00:00 +00:00
#include "doomdef.h"
#include "i_system.h"
#include "z_zone.h"
#include "w_wad.h"
#include "r_local.h"
// Needs access to LFB (guess what).
#include "v_video.h"
// State.
#include "doomstat.h"
1998-04-07 00:00:00 +00:00
#include "st_stuff.h"
1999-02-17 00:00:00 +00:00
#undef RANGECHECK
1998-04-07 00:00:00 +00:00
// status bar height at bottom of screen
1998-07-14 00:00:00 +00:00
// [RH] status bar position at bottom of screen
extern int ST_Y;
1998-04-07 00:00:00 +00:00
//
// All drawing to the view buffer is accomplished in this file.
// The other refresh files only know about ccordinates,
// not the architecture of the frame buffer.
// Conveniently, the frame buffer is a linear one,
// and we need only the base address,
// and the total size == width*height*depth/8.,
//
1998-07-14 00:00:00 +00:00
byte* viewimage;
1998-04-07 00:00:00 +00:00
int viewwidth;
int scaledviewwidth;
int viewheight;
int viewwindowx;
1998-07-14 00:00:00 +00:00
int viewwindowy;
1998-04-07 00:00:00 +00:00
byte** ylookup;
1998-07-14 00:00:00 +00:00
int* columnofs;
int realviewwidth; // [RH] Physical width of view window
int realviewheight; // [RH] Physical height of view window
int detailxshift; // [RH] X shift for horizontal detail level
int detailyshift; // [RH] Y shift for vertical detail level
1998-04-07 00:00:00 +00:00
1998-07-14 00:00:00 +00:00
// [RH] Pointers to the different column drawers.
// These get changed depending on the current
// screen depth.
1999-02-17 00:00:00 +00:00
void (*R_DrawColumnHoriz)(void);
1998-07-14 00:00:00 +00:00
void (*R_DrawColumn)(void);
void (*R_DrawFuzzColumn)(void);
void (*R_DrawTranslucentColumn)(void);
void (*R_DrawTranslatedColumn)(void);
1998-04-07 00:00:00 +00:00
//
// R_DrawColumn
// Source is the top of the column to scale.
//
1998-07-14 00:00:00 +00:00
int dc_pitch=0x12345678; // [RH] Distance between rows
1998-04-07 00:00:00 +00:00
lighttable_t* dc_colormap;
int dc_x;
int dc_yl;
int dc_yh;
fixed_t dc_iscale;
fixed_t dc_texturemid;
1999-02-17 00:00:00 +00:00
int dc_color; // [RH] Color for column filler
1998-04-07 00:00:00 +00:00
// first pixel in a column (possibly virtual)
byte* dc_source;
1998-07-14 00:00:00 +00:00
// [RH] Tutti-Frutti fix
unsigned int dc_mask;
1998-04-07 00:00:00 +00:00
// just for profiling
int dccount;
1998-07-14 00:00:00 +00:00
/************************************/
/* */
/* Palettized drawers (C versions) */
/* */
/************************************/
1998-04-07 00:00:00 +00:00
#ifndef USEASM
1998-04-07 00:00:00 +00:00
//
// A column is a vertical slice/span from a wall texture that,
// given the DOOM style restrictions on the view orientation,
// will always have constant z depth.
// Thus a special case loop for very fast rendering can
// be used. It has also been used with Wolfenstein 3D.
//
1999-02-17 00:00:00 +00:00
void R_DrawColumnP_C (void)
{
int count;
byte* dest;
1998-04-07 00:00:00 +00:00
fixed_t frac;
1999-02-17 00:00:00 +00:00
fixed_t fracstep;
count = dc_yh - dc_yl;
1998-04-07 00:00:00 +00:00
// Zero length, column does not exceed a pixel.
1999-02-17 00:00:00 +00:00
if (count < 0)
return;
count++;
1998-04-07 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-04-07 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height) {
1999-02-17 00:00:00 +00:00
Printf (PRINT_HIGH, "R_DrawColumnP_C: %i to %i at %i\n", dc_yl, dc_yh, dc_x);
1998-04-07 00:00:00 +00:00
return;
}
1999-02-17 00:00:00 +00:00
#endif
1998-04-07 00:00:00 +00:00
// Framebuffer destination address.
// Use ylookup LUT to avoid multiply with ScreenWidth.
1999-02-17 00:00:00 +00:00
// Use columnofs LUT for subwindows?
dest = ylookup[dc_yl] + columnofs[dc_x];
1998-04-07 00:00:00 +00:00
// Determine scaling,
// which is the only mapping to be done.
fracstep = dc_iscale;
1999-02-17 00:00:00 +00:00
frac = dc_texturemid + (dc_yl-centery)*fracstep;
1998-04-07 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
// [RH] Get local copies of these variables so that the compiler
// has a better chance of optimizing this well.
byte *colormap = dc_colormap;
int mask = dc_mask;
byte *source = dc_source;
int pitch = dc_pitch;
// Inner loop that does the actual texture mapping,
// e.g. a DDA-lile scaling.
// This is as fast as it gets.
do
{
// Re-map color indices from wall texture column
// using a lighting/special effects LUT.
*dest = colormap[source[(frac>>FRACBITS)&mask]];
dest += pitch;
frac += fracstep;
} while (--count);
}
1998-04-07 00:00:00 +00:00
}
1998-04-07 00:00:00 +00:00
#endif // USEASM
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
// [RH] Same as R_DrawColumnP_C except that it doesn't do any colormapping.
// Used by the sky drawer because the sky is always fullbright.
void R_StretchColumnP_C (void)
{
int count;
byte* dest;
fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
count++;
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1999-02-17 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height) {
1999-02-17 00:00:00 +00:00
Printf (PRINT_HIGH, "R_StretchColumnP_C: %i to %i at %i\n", dc_yl, dc_yh, dc_x);
return;
}
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
{
int mask = dc_mask;
byte *source = dc_source;
int pitch = dc_pitch;
do
{
*dest = source[(frac>>FRACBITS)&mask];
dest += pitch;
frac += fracstep;
} while (--count);
}
}
// [RH] Just fills a column with a color
void R_FillColumnP (void)
{
int count;
byte* dest;
count = dc_yh - dc_yl;
if (count < 0)
return;
count++;
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1999-02-17 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height) {
1999-02-17 00:00:00 +00:00
Printf (PRINT_HIGH, "R_StretchColumnP_C: %i to %i at %i\n", dc_yl, dc_yh, dc_x);
return;
}
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
{
int pitch = dc_pitch;
byte color = dc_color;
do
{
*dest = color;
dest += pitch;
} while (--count);
}
}
1998-04-07 00:00:00 +00:00
//
// Spectre/Invisibility.
//
1998-04-07 00:00:00 +00:00
// [RH] FUZZTABLE changed from 50 to 64
#define FUZZTABLE 64
1999-02-21 00:00:00 +00:00
#define FUZZOFF (screen.pitch)
1998-04-07 00:00:00 +00:00
int fuzzoffset[FUZZTABLE];
/*
FUZZOFF,-FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,
FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,
FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,
FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,
FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF,FUZZOFF,-FUZZOFF,FUZZOFF
*/
static const signed char fuzzinit[FUZZTABLE] = {
1998-04-07 00:00:00 +00:00
1,-1, 1,-1, 1, 1,-1, 1,
1,-1, 1, 1, 1,-1, 1, 1,
1,-1,-1,-1,-1, 1,-1,-1,
1, 1, 1, 1,-1, 1,-1, 1,
1,-1,-1, 1, 1,-1,-1,-1,
-1, 1, 1, 1, 1,-1, 1, 1,
-1, 1, 1, 1,-1, 1, 1, 1,
-1, 1, 1,-1, 1, 1,-1, 1
1998-04-07 00:00:00 +00:00
};
int fuzzpos = 0;
void R_InitFuzzTable (void)
{
int i;
1998-07-14 00:00:00 +00:00
int fuzzoff;
1999-02-21 00:00:00 +00:00
V_LockScreen (&screen);
1998-07-14 00:00:00 +00:00
fuzzoff = FUZZOFF << detailyshift;
1999-02-21 00:00:00 +00:00
V_UnlockScreen (&screen);
1998-04-07 00:00:00 +00:00
for (i = 0; i < FUZZTABLE; i++)
1998-07-14 00:00:00 +00:00
fuzzoffset[i] = fuzzinit[i] * fuzzoff;
1998-04-07 00:00:00 +00:00
}
1998-04-07 00:00:00 +00:00
#ifndef USEASM
1998-04-07 00:00:00 +00:00
//
// Framebuffer postprocessing.
// Creates a fuzzy image by copying pixels
// from adjacent ones to left and right.
// Used with an all black colormap, this
// could create the SHADOW effect,
// i.e. spectres and invisible players.
//
1999-02-17 00:00:00 +00:00
void R_DrawFuzzColumnP_C (void)
{
int count;
byte *dest;
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
// Adjust borders. Low...
if (!dc_yl)
1998-04-07 00:00:00 +00:00
dc_yl = 1;
// .. and high.
1999-02-17 00:00:00 +00:00
if (dc_yh == realviewheight-1)
dc_yh = realviewheight - 2;
count = dc_yh - dc_yl;
1998-04-07 00:00:00 +00:00
// Zero length.
1999-02-17 00:00:00 +00:00
if (count < 0)
return;
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
count++;
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
|| dc_yl < 0 || dc_yh >= screen.height)
1998-04-07 00:00:00 +00:00
{
1998-07-14 00:00:00 +00:00
I_Error ("R_DrawFuzzColumnP_C: %i to %i at %i",
1998-04-07 00:00:00 +00:00
dc_yl, dc_yh, dc_x);
}
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
// Looks like an attempt at dithering,
// using the colormap #6 (of 0-31, a bit
// brighter than average).
{
1999-02-17 00:00:00 +00:00
// [RH] Make local copies of global vars to try and improve
// the optimizations made by the compiler.
int pitch = dc_pitch;
int fuzz = fuzzpos;
byte *map = DefaultPalette->maps.colormaps + 6*256;
do
{
// Lookup framebuffer, and retrieve
// a pixel that is either one column
// left or right of the current one.
// Add index from colormap to index.
*dest = map[dest[fuzzoffset[fuzz]]];
// Clamp table lookup index.
fuzz = (fuzz + 1) & (FUZZTABLE - 1);
dest += pitch;
} while (--count);
fuzzpos = (fuzz + 3) & (FUZZTABLE - 1);
}
1998-04-07 00:00:00 +00:00
}
1998-04-07 00:00:00 +00:00
#endif // USEASM
1998-04-07 00:00:00 +00:00
//
// R_DrawTranlucentColumn
//
1998-04-07 00:00:00 +00:00
byte *dc_transmap;
#ifndef USEASM
1999-02-17 00:00:00 +00:00
void R_DrawTranslucentColumnP_C (void)
{
int count;
byte* dest;
1998-04-07 00:00:00 +00:00
fixed_t frac;
1999-02-17 00:00:00 +00:00
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
count++;
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-04-07 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height)
1998-04-07 00:00:00 +00:00
{
1998-07-14 00:00:00 +00:00
I_Error ( "R_DrawTranslucentColumnP_C: %i to %i at %i",
1998-04-07 00:00:00 +00:00
dc_yl, dc_yh, dc_x);
}
#endif
1999-02-17 00:00:00 +00:00
dest = ylookup[dc_yl] + columnofs[dc_x];
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
1998-04-07 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
byte *transmap = dc_transmap;
byte *colormap = dc_colormap;
byte *source = dc_source;
int mask = dc_mask;
int pitch = dc_pitch;
do
{
*dest = transmap[colormap[source[(frac>>FRACBITS)&mask]] | ((*dest)<<8)];
dest += pitch;
frac += fracstep;
} while (--count);
}
}
1998-04-07 00:00:00 +00:00
#endif // USEASM
1998-04-07 00:00:00 +00:00
//
// R_DrawTranslatedColumn
// Used to draw player sprites
// with the green colorramp mapped to others.
// Could be used with different translation
// tables, e.g. the lighter colored version
// of the BaronOfHell, the HellKnight, uses
// identical sprites, kinda brightened up.
//
byte* dc_translation;
byte* translationtables;
1999-02-17 00:00:00 +00:00
void R_DrawTranslatedColumnP_C (void)
1998-04-07 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
int count;
byte* dest;
1998-04-07 00:00:00 +00:00
fixed_t frac;
1999-02-17 00:00:00 +00:00
fixed_t fracstep;
count = dc_yh - dc_yl;
1998-04-07 00:00:00 +00:00
if (count < 0)
1999-02-17 00:00:00 +00:00
return;
count++;
1998-04-07 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-04-07 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height)
1998-04-07 00:00:00 +00:00
{
1998-07-14 00:00:00 +00:00
I_Error ( "R_DrawTranslatedColumnP_C: %i to %i at %i",
1998-04-07 00:00:00 +00:00
dc_yl, dc_yh, dc_x);
}
#endif
1999-02-17 00:00:00 +00:00
dest = ylookup[dc_yl] + columnofs[dc_x];
1998-04-07 00:00:00 +00:00
// Looks familiar.
1999-02-17 00:00:00 +00:00
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
1998-04-07 00:00:00 +00:00
// Here we do an additional index re-mapping.
{
1999-02-17 00:00:00 +00:00
// [RH] Local copies of global vars to improve compiler optimizations
byte *colormap = dc_colormap;
byte *translation = dc_translation;
byte *source = dc_source;
int pitch = dc_pitch;
int mask = dc_mask;
do
{
// Translation tables are used
// to map certain colorramps to other ones,
// used with PLAY sprites.
// Thus the "green" ramp of the player 0 sprite
// is mapped to gray, red, black/indigo.
*dest = colormap[translation[source[(frac>>FRACBITS) & mask]]];
dest += pitch;
frac += fracstep;
} while (--count);
}
}
// [RH] Draw a column that is both translated and translucent
void R_DrawTlatedLucentColumnP_C (void)
{
int count;
byte* dest;
fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
count++;
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1999-02-17 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height)
1999-02-17 00:00:00 +00:00
{
I_Error ( "R_DrawTlatedLucentColumnP_C: %i to %i at %i",
dc_yl, dc_yh, dc_x);
}
#endif
dest = ylookup[dc_yl] + columnofs[dc_x];
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
{
byte *translation = dc_translation;
byte *transmap = dc_transmap;
byte *colormap = dc_colormap;
byte *source = dc_source;
int mask = dc_mask;
int pitch = dc_pitch;
do
{
*dest = transmap[colormap[translation[source[(frac>>FRACBITS)&mask]]] | ((*dest)<<8)];
dest += pitch;
frac += fracstep;
} while (--count);
}
1998-04-07 00:00:00 +00:00
}
//
// R_DrawSpan
// With DOOM style restrictions on view orientation,
// the floors and ceilings consist of horizontal slices
// or spans with constant z depth.
// However, rotation around the world z axis is possible,
// thus this mapping, while simpler and faster than
// perspective correct texture mapping, has to traverse
// the texture at an angle in all but a few cases.
// In consequence, flats are not stored by column (like walls),
// and the inner loop has to step in texture space u and v.
//
1998-07-14 00:00:00 +00:00
int ds_colsize=0x12345678; // [RH] Distance between columns
int ds_colshift=1; // [RH] (1<<ds_colshift)=ds_colsize
1999-02-17 00:00:00 +00:00
int ds_color; // [RH] color for non-textured spans
1998-07-14 00:00:00 +00:00
1998-04-07 00:00:00 +00:00
int ds_y;
int ds_x1;
int ds_x2;
lighttable_t* ds_colormap;
fixed_t ds_xfrac;
fixed_t ds_yfrac;
fixed_t ds_xstep;
fixed_t ds_ystep;
// start of a 64*64 tile image
byte* ds_source;
// just for profiling
int dscount;
//
// Draws the actual span.
1998-07-14 00:00:00 +00:00
void R_DrawSpanP (void)
1998-04-07 00:00:00 +00:00
{
fixed_t xfrac;
fixed_t yfrac;
byte* dest;
int count;
int spot;
#ifdef RANGECHECK
if (ds_x2 < ds_x1
|| ds_x1<0
1999-02-21 00:00:00 +00:00
|| ds_x2>=screen.width
|| ds_y>screen.height)
1998-04-07 00:00:00 +00:00
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
// dscount++;
#endif
xfrac = ds_xfrac;
yfrac = ds_yfrac;
dest = ylookup[ds_y] + columnofs[ds_x1];
// We do not check for zero spans here?
1998-07-14 00:00:00 +00:00
count = ds_x2 - ds_x1 + 1;
1998-04-07 00:00:00 +00:00
/* [Petteri] Do optimized loop if enough to do: */
#ifdef USEASM
1998-07-14 00:00:00 +00:00
if ( count > 1 ) {
1998-04-07 00:00:00 +00:00
DrawSpan8Loop(xfrac, yfrac, count & (~1), dest);
1998-04-07 00:00:00 +00:00
if ( (count & 1) == 0 )
return;
xfrac += ds_xstep * (count & (~1));
yfrac += ds_ystep * (count & (~1));
1998-07-14 00:00:00 +00:00
dest += (count & (~1)) << ds_colshift;
// count = 1;
1998-04-07 00:00:00 +00:00
}
1998-07-14 00:00:00 +00:00
#else
1998-04-07 00:00:00 +00:00
do {
1998-07-14 00:00:00 +00:00
#endif
1998-04-07 00:00:00 +00:00
// Current texture index in u,v.
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
// Lookup pixel from flat texture tile,
// re-index using light/colormap.
1998-07-14 00:00:00 +00:00
*dest = ds_colormap[ds_source[spot]];
#ifndef USEASM
dest += ds_colsize;
1998-04-07 00:00:00 +00:00
// Next step in u,v.
xfrac += ds_xstep;
yfrac += ds_ystep;
1998-07-14 00:00:00 +00:00
} while (--count);
#endif
}
1999-02-17 00:00:00 +00:00
// [RH] Just fill a span with a color
void R_FillSpan (void)
{
byte *dest;
int count;
int color = ds_color;
int colsize = ds_colsize;
#ifdef RANGECHECK
if (ds_x2 < ds_x1
|| ds_x1<0
1999-02-21 00:00:00 +00:00
|| ds_x2>=screen.width
|| ds_y>screen.height)
1999-02-17 00:00:00 +00:00
{
I_Error( "R_FillSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
// dscount++;
#endif
dest = ylookup[ds_y] + columnofs[ds_x1];
count = ds_x2 - ds_x1 + 1;
do {
*dest = color;
dest += colsize;
} while (--count);
}
1998-07-14 00:00:00 +00:00
/****************************************/
/* */
/* [RH] ARGB8888 drawers (C versions) */
/* */
/****************************************/
1998-12-22 00:00:00 +00:00
#define dc_shademap ((unsigned int *)dc_colormap)
1998-07-14 00:00:00 +00:00
void R_DrawColumnD_C (void)
{
1999-02-17 00:00:00 +00:00
int count;
unsigned int* dest;
1998-07-14 00:00:00 +00:00
fixed_t frac;
1999-02-17 00:00:00 +00:00
fixed_t fracstep;
count = dc_yh - dc_yl;
1998-07-14 00:00:00 +00:00
// Zero length, column does not exceed a pixel.
1999-02-17 00:00:00 +00:00
if (count < 0)
return;
count++;
1998-07-14 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-07-14 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height) {
1999-02-17 00:00:00 +00:00
Printf (PRINT_HIGH, "R_DrawColumnD_C: %i to %i at %i\n", dc_yl, dc_yh, dc_x);
1998-07-14 00:00:00 +00:00
return;
}
1999-02-17 00:00:00 +00:00
#endif
1998-07-14 00:00:00 +00:00
dest = (unsigned int *)(ylookup[dc_yl] + columnofs[dc_x]);
1999-02-17 00:00:00 +00:00
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
1998-07-14 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
unsigned int *shademap = dc_shademap;
byte *source = dc_source;
int mask = dc_mask;
int pitch = dc_pitch >> 2;
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
do
{
*dest = shademap[source[(frac>>FRACBITS)&mask]];
dest += pitch;
frac += fracstep;
} while (--count);
}
}
void R_DrawFuzzColumnD_C (void)
{
1998-07-14 00:00:00 +00:00
int count;
unsigned int* dest;
// Adjust borders. Low...
if (!dc_yl)
dc_yl = 1;
// .. and high.
if (dc_yh == realviewheight-1)
dc_yh = realviewheight - 2;
count = dc_yh - dc_yl;
// Zero length.
if (count < 0)
return;
1999-02-17 00:00:00 +00:00
count++;
1998-07-14 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
|| dc_yl < 0 || dc_yh >= screen.height)
1998-07-14 00:00:00 +00:00
{
I_Error ("R_DrawFuzzColumnD_C: %i to %i at %i",
dc_yl, dc_yh, dc_x);
}
#endif
dest = (unsigned int *)(ylookup[dc_yl] + columnofs[dc_x]);
// [RH] This is actually slightly brighter than
// the indexed version, but it's close enough.
{
1999-02-17 00:00:00 +00:00
int fuzz = fuzzpos;
int pitch = dc_pitch >> 2;
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
do
{
unsigned int work = dest[fuzzoffset[fuzz]>>2];
*dest = work - ((work >> 2) & 0x3f3f3f);
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
// Clamp table lookup index.
fuzz = (fuzz + 1) & (FUZZTABLE - 1);
dest += pitch;
} while (--count);
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
fuzzpos = (fuzz + 3) & (FUZZTABLE - 1);
}
}
void R_DrawTranslucentColumnD_C (void)
1998-07-14 00:00:00 +00:00
{
int count;
unsigned int* dest;
fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
1999-02-17 00:00:00 +00:00
count++;
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-07-14 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height)
1998-07-14 00:00:00 +00:00
{
I_Error ( "R_DrawTranslucentColumnD_C: %i to %i at %i",
dc_yl, dc_yh, dc_x);
}
#endif
dest = (unsigned int *)(ylookup[dc_yl] + columnofs[dc_x]);
fracstep = dc_iscale;
1999-02-17 00:00:00 +00:00
frac = dc_texturemid + (dc_yl-centery)*fracstep;
1998-07-14 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
unsigned int *shademap = dc_shademap;
byte *source = dc_source;
int mask = dc_mask;
int pitch = dc_pitch >> 2;
do
{
*dest = ((*dest >> 1) & 0x7f7f7f) +
((shademap[source[(frac>>FRACBITS)&mask]] >> 1) & 0x7f7f7f);
dest += pitch;
frac += fracstep;
} while (--count);
}
1998-07-14 00:00:00 +00:00
}
void R_DrawTranslatedColumnD_C (void)
{
int count;
unsigned int* dest;
fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0)
return;
1999-02-17 00:00:00 +00:00
count++;
1998-07-14 00:00:00 +00:00
#ifdef RANGECHECK
1999-02-21 00:00:00 +00:00
if (dc_x >= screen.width
1998-07-14 00:00:00 +00:00
|| dc_yl < 0
1999-02-21 00:00:00 +00:00
|| dc_yh >= screen.height)
1998-07-14 00:00:00 +00:00
{
I_Error ( "R_DrawTranslatedColumnD_C: %i to %i at %i",
dc_yl, dc_yh, dc_x);
}
#endif
dest = (unsigned int *)(ylookup[dc_yl] + columnofs[dc_x]);
fracstep = dc_iscale;
frac = dc_texturemid + (dc_yl-centery)*fracstep;
// Here we do an additional index re-mapping.
{
1999-02-17 00:00:00 +00:00
byte *source = dc_source;
unsigned int *shademap = dc_shademap;
byte *translation = dc_translation;
int mask = dc_mask;
int pitch = dc_pitch >> 2;
do
{
*dest = shademap[translation[source[(frac>>FRACBITS) & mask]]];
dest += pitch;
frac += fracstep;
} while (--count);
}
1998-07-14 00:00:00 +00:00
}
1999-02-17 00:00:00 +00:00
void R_DrawSpanD (void)
1998-07-14 00:00:00 +00:00
{
fixed_t xfrac;
1999-02-17 00:00:00 +00:00
fixed_t yfrac;
unsigned int* dest;
1998-07-14 00:00:00 +00:00
int count;
1999-02-17 00:00:00 +00:00
int spot;
1998-07-14 00:00:00 +00:00
#ifdef RANGECHECK
if (ds_x2 < ds_x1
|| ds_x1<0
1999-02-21 00:00:00 +00:00
|| ds_x2>=screen.width
|| ds_y>screen.height)
1998-07-14 00:00:00 +00:00
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
1999-02-17 00:00:00 +00:00
// dscount++;
#endif
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
xfrac = ds_xfrac;
yfrac = ds_yfrac;
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
dest = (unsigned int *)(ylookup[ds_y] + columnofs[ds_x1]);
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
count = ds_x2 - ds_x1 + 1;
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
{
byte *source = ds_source;
unsigned int *shademap = (unsigned int *)ds_colormap;
int colsize = ds_colsize >> 2;
int xstep = ds_xstep;
int ystep = ds_ystep;
do {
spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
// Lookup pixel from flat texture tile,
// re-index using light/colormap.
*dest = shademap[source[spot]];
dest += colsize;
// Next step in u,v.
xfrac += xstep;
yfrac += ystep;
} while (--count);
}
}
1998-07-14 00:00:00 +00:00
/****************************************************/
/****************************************************/
//
// R_InitTranslationTables
// Creates the translation tables to map
// the green color ramp to gray, brown, red.
// Assumes a given structure of the PLAYPAL.
// Could be read from a lump instead.
//
extern byte *Ranges;
void R_InitTranslationTables (void)
{
static const char ranges[11][8] = {
"CRBRICK",
"CRTAN",
"CRGRAY",
"CRGREEN",
"CRBROWN",
"CRGOLD",
"CRRED",
1999-02-17 00:00:00 +00:00
"CRBLUE2",
1998-07-14 00:00:00 +00:00
"CRORANGE",
"CRYELLOW",
1999-02-17 00:00:00 +00:00
"CRBLUE"
1998-07-14 00:00:00 +00:00
};
int i;
1999-02-17 00:00:00 +00:00
translationtables = Z_Malloc (256*(MAXPLAYERS+3+11)+255, PU_STATIC, 0);
1998-07-14 00:00:00 +00:00
translationtables = (byte *)(( (int)translationtables + 255 )& ~255);
// [RH] Each player now gets their own translation table
// (soon to be palettes). These are set up during
// netgame arbitration and as-needed rather than
// in here. We do, however load some text translation
// tables from our PWAD (ala BOOM).
for (i = 0; i < 256; i++)
translationtables[i] = i;
1999-02-17 00:00:00 +00:00
for (i = 1; i < MAXPLAYERS+3; i++)
1998-07-14 00:00:00 +00:00
memcpy (translationtables + i*256, translationtables, 256);
1999-02-17 00:00:00 +00:00
// create translation tables for dehacked patches that expect them
for (i = 0x70; i < 0x80; i++) {
// map green ramp to gray, brown, red
translationtables[i+(MAXPLAYERS+0)*256] = 0x60 + (i&0xf);
translationtables[i+(MAXPLAYERS+1)*256] = 0x40 + (i&0xf);
translationtables[i+(MAXPLAYERS+2)*256] = 0x20 + (i&0xf);
}
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
Ranges = translationtables + (MAXPLAYERS+3)*256;
1998-07-14 00:00:00 +00:00
for (i = 0; i < 11; i++)
W_ReadLump (W_GetNumForName (ranges[i]), Ranges + 256 * i);
}
// [RH] Create a player's translation table based on
// a given mid-range color.
void R_BuildPlayerTranslation (int player, int color)
{
1999-02-17 00:00:00 +00:00
palette_t *pal = GetDefaultPalette();
byte *table = &translationtables[player * 256];
int i;
float r = (float)RPART(color) / 255.0f;
float g = (float)GPART(color) / 255.0f;
float b = (float)BPART(color) / 255.0f;
float h, s, v;
float sdelta, vdelta;
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
RGBtoHSV (r, g, b, &h, &s, &v);
s -= 0.23f;
if (s < 0.0f)
s = 0.0f;
sdelta = 0.014375f;
v += 0.1f;
if (v > 1.0f)
v = 1.0f;
vdelta = -0.05882f;
for (i = 0x70; i < 0x80; i++) {
HSVtoRGB (&r, &g, &b, h, s, v);
table[i] = BestColor (pal->basecolors,
(int)(r * 255.0f),
(int)(g * 255.0f),
(int)(b * 255.0f),
pal->numcolors);
s += sdelta;
if (s > 1.0f) {
s = 1.0f;
sdelta = 0.0f;
}
v += vdelta;
if (v < 0.0f) {
v = 0.0f;
vdelta = 0.0f;
1998-07-14 00:00:00 +00:00
}
}
}
1998-04-07 00:00:00 +00:00
//
// R_InitBuffer
// Creats lookup tables that avoid
1999-02-17 00:00:00 +00:00
// multiplies and other hassles
1998-04-07 00:00:00 +00:00
// for getting the framebuffer address
// of a pixel to draw.
//
1998-07-14 00:00:00 +00:00
void R_InitBuffer (int width, int height)
{
int i;
byte *buffer;
int pitch;
int xshift;
1998-04-07 00:00:00 +00:00
// Handle resize,
// e.g. smaller view windows
// with border and/or status bar.
1999-02-21 00:00:00 +00:00
viewwindowx = (screen.width-(width<<detailxshift))>>1;
1998-04-07 00:00:00 +00:00
1998-07-14 00:00:00 +00:00
// [RH] Adjust column offset according to bytes per pixel
// and detail mode
1999-02-21 00:00:00 +00:00
xshift = (screen.is8bit) ? 0 : 2;
1998-07-14 00:00:00 +00:00
xshift += detailxshift;
// Column offset. For windows
1999-02-17 00:00:00 +00:00
for (i = 0; i < width; i++)
columnofs[i] = viewwindowx + (i << xshift);
1998-04-07 00:00:00 +00:00
// Same with base row offset.
1999-02-21 00:00:00 +00:00
if ((width<<detailxshift) == screen.width)
1998-07-14 00:00:00 +00:00
viewwindowy = 0;
else
viewwindowy = (ST_Y-(height<<detailyshift)) >> 1;
1999-02-21 00:00:00 +00:00
V_LockScreen (&screen);
buffer = screen.buffer;
pitch = screen.pitch;
V_UnlockScreen (&screen);
1998-07-14 00:00:00 +00:00
// Precalculate all row offsets.
for (i=0 ; i<height ; i++)
ylookup[i] = buffer + ((i<<detailyshift)+viewwindowy)*pitch;
}
1999-02-17 00:00:00 +00:00
void R_DrawBorder (int x1, int y1, int x2, int y2)
1998-07-14 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
int lump;
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
lump = R_FlatNumForName ((gamemode == commercial) ? "GRNROCK" : "FLOOR7_2");
1999-02-21 00:00:00 +00:00
V_FlatFill (x1 & ~63, y1, x2, y2, &screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpNum (lump + firstflat, PU_CACHE));
1998-07-14 00:00:00 +00:00
}
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
/*
==================
=
= R_DrawViewBorder
=
= Draws the border around the view for different size windows
==================
*/
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
BOOL BorderNeedRefresh;
void V_MarkRect (int x, int y, int width, int height);
1998-07-14 00:00:00 +00:00
void R_DrawViewBorder (void)
{
1999-02-17 00:00:00 +00:00
int x, y;
1998-07-14 00:00:00 +00:00
1998-04-07 00:00:00 +00:00
// [RH] Redraw the status bar if SCREENWIDTH > status bar width.
// Will draw borders around itself, too.
1999-02-21 00:00:00 +00:00
if (screen.width > 320)
1999-02-17 00:00:00 +00:00
{
SB_state = -1;
1998-04-07 00:00:00 +00:00
}
1999-02-21 00:00:00 +00:00
if (realviewwidth == screen.width) {
1998-07-14 00:00:00 +00:00
return;
1998-04-07 00:00:00 +00:00
}
1998-07-14 00:00:00 +00:00
1999-02-21 00:00:00 +00:00
R_DrawBorder (0, 0, screen.width, viewwindowy);
1999-02-17 00:00:00 +00:00
R_DrawBorder (0, viewwindowy, viewwindowx, realviewheight + viewwindowy);
1999-02-21 00:00:00 +00:00
R_DrawBorder (viewwindowx + realviewwidth, viewwindowy, screen.width, realviewheight + viewwindowy);
R_DrawBorder (0, viewwindowy + realviewheight, screen.width, ST_Y);
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
for (x = viewwindowx; x < viewwindowx + realviewwidth; x += 8)
{
1999-02-21 00:00:00 +00:00
V_DrawPatch (x, viewwindowy - 8, &screen, W_CacheLumpName ("brdr_t", PU_CACHE));
V_DrawPatch (x, viewwindowy + realviewheight, &screen, W_CacheLumpName ("brdr_b", PU_CACHE));
1999-02-17 00:00:00 +00:00
}
for (y = viewwindowy; y < viewwindowy + realviewheight; y += 8)
{
1999-02-21 00:00:00 +00:00
V_DrawPatch (viewwindowx - 8, y, &screen, W_CacheLumpName ("brdr_l", PU_CACHE));
V_DrawPatch (viewwindowx + realviewwidth, y, &screen, W_CacheLumpName ("brdr_r", PU_CACHE));
1999-02-17 00:00:00 +00:00
}
// Draw beveled edge.
V_DrawPatch (viewwindowx-8,
viewwindowy-8,
1999-02-21 00:00:00 +00:00
&screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName ("brdr_tl",PU_CACHE));
V_DrawPatch (viewwindowx+realviewwidth,
viewwindowy-8,
1999-02-21 00:00:00 +00:00
&screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName ("brdr_tr",PU_CACHE));
V_DrawPatch (viewwindowx-8,
viewwindowy+realviewheight,
1999-02-21 00:00:00 +00:00
&screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName ("brdr_bl",PU_CACHE));
V_DrawPatch (viewwindowx+realviewwidth,
viewwindowy+realviewheight,
1999-02-21 00:00:00 +00:00
&screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName ("brdr_br",PU_CACHE));
1998-07-14 00:00:00 +00:00
1999-02-21 00:00:00 +00:00
V_MarkRect (0,0,screen.width, ST_Y);
1999-02-17 00:00:00 +00:00
}
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
/*
==================
=
= R_DrawTopBorder
=
= Draws the top border around the view for different size windows
==================
*/
BOOL BorderTopRefresh;
void R_DrawTopBorder (void)
{
int x, y;
1999-02-21 00:00:00 +00:00
if (realviewwidth == screen.width)
1999-02-17 00:00:00 +00:00
return;
1999-02-21 00:00:00 +00:00
R_DrawBorder (0, 0, screen.width, 34);
1998-07-14 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
if (viewwindowy < 35)
{
for (x = viewwindowx; x < viewwindowx + realviewwidth; x += 8)
{
1999-02-21 00:00:00 +00:00
V_DrawPatch (x, viewwindowy-8, &screen, W_CacheLumpName("brdr_t", PU_CACHE));
1999-02-17 00:00:00 +00:00
}
for (y = viewwindowy; y < 35; y += 8)
{
1999-02-21 00:00:00 +00:00
V_DrawPatch(viewwindowx-8, y, &screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName ("brdr_l", PU_CACHE));
1999-02-21 00:00:00 +00:00
V_DrawPatch(viewwindowx+realviewwidth, y, &screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName("brdr_r", PU_CACHE));
}
1998-04-07 00:00:00 +00:00
1999-02-21 00:00:00 +00:00
V_DrawPatch(viewwindowx-8, viewwindowy-8, &screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName("brdr_tl", PU_CACHE));
1999-02-21 00:00:00 +00:00
V_DrawPatch(viewwindowx+realviewwidth, viewwindowy-8, &screen,
1999-02-17 00:00:00 +00:00
W_CacheLumpName("brdr_tr", PU_CACHE));
}
1998-07-14 00:00:00 +00:00
}
// [RH] Double pixels in the view window horizontally
// and/or vertically (or not at all).
void R_DetailDouble (void)
{
1999-02-17 00:00:00 +00:00
switch ((detailxshift << 1) | detailyshift) {
case 1: // y-double
{
1999-02-21 00:00:00 +00:00
int rowsize = realviewwidth << ((screen.is8bit) ? 0 : 2);
int pitch = screen.pitch;
1999-02-17 00:00:00 +00:00
int y;
byte *line;
1999-02-21 00:00:00 +00:00
line = screen.buffer + viewwindowy*pitch + viewwindowx;
1999-02-17 00:00:00 +00:00
for (y = 0; y < viewheight; y++, line += pitch<<1) {
memcpy (line+pitch, line, rowsize);
1998-07-14 00:00:00 +00:00
}
}
1999-02-17 00:00:00 +00:00
break;
case 2: // x-double
{
int rowsize = realviewwidth >> 2;
1999-02-21 00:00:00 +00:00
int pitch = screen.pitch >> (2-detailyshift);
1999-02-17 00:00:00 +00:00
int y,x;
unsigned *line,a,b;
1999-02-21 00:00:00 +00:00
line = (unsigned *)(screen.buffer + viewwindowy*screen.pitch + viewwindowx);
1999-02-17 00:00:00 +00:00
for (y = 0; y < viewheight; y++, line += pitch) {
for (x = 0; x < rowsize; x += 2) {
a = line[x+0];
b = line[x+1];
a &= 0x00ff00ff;
b &= 0x00ff00ff;
line[x+0] = a | (a << 8);
line[x+1] = b | (b << 8);
}
}
}
break;
case 3: // x- and y-double
{
int rowsize = realviewwidth >> 2;
1999-02-21 00:00:00 +00:00
int pitch = screen.pitch >> (2-detailyshift);
int realpitch = screen.pitch >> 2;
1999-02-17 00:00:00 +00:00
int y,x;
unsigned *line,a,b;
1999-02-21 00:00:00 +00:00
line = (unsigned *)(screen.buffer + viewwindowy*screen.pitch + viewwindowx);
1999-02-17 00:00:00 +00:00
for (y = 0; y < viewheight; y++, line += pitch) {
for (x = 0; x < rowsize; x += 2) {
a = line[x+0];
b = line[x+1];
a &= 0x00ff00ff;
b &= 0x00ff00ff;
line[x+0] = a | (a << 8);
line[x+0+realpitch] = a | (a << 8);
line[x+1] = b | (b << 8);
line[x+1+realpitch] = b | (b << 8);
}
}
1998-07-14 00:00:00 +00:00
}
1999-02-17 00:00:00 +00:00
break;
1998-07-14 00:00:00 +00:00
}
}
// [RH] Initialize the column drawer pointers
void R_InitColumnDrawers (BOOL is8bit)
{
if (is8bit) {
#ifdef USEASM
1999-02-21 00:00:00 +00:00
if (screen.height <= 240)
1999-02-17 00:00:00 +00:00
R_DrawColumn = R_DrawColumnP_Unrolled;
else
R_DrawColumn = R_DrawColumnP_ASM;
R_DrawColumnHoriz = R_DrawColumnHorizP_ASM;
1998-07-14 00:00:00 +00:00
R_DrawFuzzColumn = R_DrawFuzzColumnP_ASM;
R_DrawTranslucentColumn = R_DrawTranslucentColumnP_ASM;
R_DrawTranslatedColumn = R_DrawTranslatedColumnP_C;
1999-02-21 00:00:00 +00:00
if (screen.width <= 320)
1999-02-17 00:00:00 +00:00
R_DrawSpan = R_DrawSpanP_Unrolled;
else
R_DrawSpan = R_DrawSpanP;
1998-07-14 00:00:00 +00:00
#else
1999-02-17 00:00:00 +00:00
R_DrawColumnHoriz = R_DrawColumnHorizP_C;
1998-07-14 00:00:00 +00:00
R_DrawColumn = R_DrawColumnP_C;
R_DrawFuzzColumn = R_DrawFuzzColumnP_C;
R_DrawTranslucentColumn = R_DrawTranslucentColumnP_C;
R_DrawTranslatedColumn = R_DrawTranslatedColumnP_C;
R_DrawSpan = R_DrawSpanP;
1999-02-17 00:00:00 +00:00
#endif
1998-07-14 00:00:00 +00:00
} else {
#ifdef USEASM
1999-02-17 00:00:00 +00:00
R_DrawColumnHoriz = R_DrawColumnHorizP_ASM;
1998-07-14 00:00:00 +00:00
R_DrawColumn = R_DrawColumnD_C;
R_DrawFuzzColumn = R_DrawFuzzColumnD_C;
R_DrawTranslucentColumn = R_DrawTranslucentColumnD_C;
R_DrawTranslatedColumn = R_DrawTranslatedColumnD_C;
#else
1999-02-17 00:00:00 +00:00
R_DrawColumnHoriz = R_DrawColumnHorizP_C;
1998-07-14 00:00:00 +00:00
R_DrawColumn = R_DrawColumnD_C;
R_DrawFuzzColumn = R_DrawFuzzColumnD_C;
R_DrawTranslucentColumn = R_DrawTranslucentColumnD_C;
R_DrawTranslatedColumn = R_DrawTranslatedColumnD_C;
#endif
R_DrawSpan = R_DrawSpanD;
}
}