dvr/app/jni/prboom/v_video.c

1038 lines
31 KiB
C
Raw Normal View History

2016-03-03 22:28:59 +00:00
/* Emacs style mode select -*- C++ -*-
*-----------------------------------------------------------------------------
*
*
* PrBoom: a Doom port merged with LxDoom and LSDLDoom
* based on BOOM, a modified and improved DOOM engine
* Copyright (C) 1999 by
* id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
* Copyright (C) 1999-2000 by
* Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
* Copyright 2005, 2006 by
* Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* DESCRIPTION:
* Gamma correction LUT stuff.
* Color range translation support
* Functions to draw patches (by post) directly to screen.
* Functions to blit a block to the screen.
*
*-----------------------------------------------------------------------------
*/
#include "doomdef.h"
#include "r_main.h"
#include "r_draw.h"
#include "m_bbox.h"
#include "w_wad.h" /* needed for color translation lump lookup */
#include "v_video.h"
#include "i_video.h"
#include "r_filter.h"
#include "lprintf.h"
// Each screen is [SCREENWIDTH*SCREENHEIGHT];
screeninfo_t screens[NUM_SCREENS];
/* jff 4/24/98 initialize this at runtime */
const byte *colrngs[CR_LIMIT];
int usegamma;
/*
* V_InitColorTranslation
*
* Loads the color translation tables from predefined lumps at game start
* No return
*
* Used for translating text colors from the red palette range
* to other colors. The first nine entries can be used to dynamically
* switch the output of text color thru the HUlib_drawText routine
* by embedding ESCn in the text to obtain color n. Symbols for n are
* provided in v_video.h.
*
* cphipps - constness of crdef_t stuff fixed
*/
typedef struct {
const char *name;
const byte **map;
} crdef_t;
// killough 5/2/98: table-driven approach
static const crdef_t crdefs[] = {
{"CRBRICK", &colrngs[CR_BRICK ]},
{"CRTAN", &colrngs[CR_TAN ]},
{"CRGRAY", &colrngs[CR_GRAY ]},
{"CRGREEN", &colrngs[CR_GREEN ]},
{"CRBROWN", &colrngs[CR_BROWN ]},
{"CRGOLD", &colrngs[CR_GOLD ]},
{"CRRED", &colrngs[CR_RED ]},
{"CRBLUE", &colrngs[CR_BLUE ]},
{"CRORANGE", &colrngs[CR_ORANGE]},
{"CRYELLOW", &colrngs[CR_YELLOW]},
{"CRBLUE2", &colrngs[CR_BLUE2]},
{NULL}
};
// killough 5/2/98: tiny engine driven by table above
void V_InitColorTranslation(void)
{
register const crdef_t *p;
for (p=crdefs; p->name; p++)
*p->map = W_CacheLumpName(p->name);
}
//
// V_CopyRect
//
// Copies a source rectangle in a screen buffer to a destination
// rectangle in another screen buffer. Source origin in srcx,srcy,
// destination origin in destx,desty, common size in width and height.
// Source buffer specfified by srcscrn, destination buffer by destscrn.
//
// Marks the destination rectangle on the screen dirty.
//
// No return.
//
static void FUNC_V_CopyRect(int srcx, int srcy, int srcscrn, int width,
int height, int destx, int desty, int destscrn,
enum patch_translation_e flags)
{
byte *src;
byte *dest;
if (flags & VPT_STRETCH)
{
srcx=srcx*SCREENWIDTH/320;
srcy=srcy*SCREENHEIGHT/200;
width=width*SCREENWIDTH/320;
height=height*SCREENHEIGHT/200;
destx=destx*SCREENWIDTH/320;
desty=desty*SCREENHEIGHT/200;
}
#ifdef RANGECHECK
if (srcx<0
||srcx+width >SCREENWIDTH
|| srcy<0
|| srcy+height>SCREENHEIGHT
||destx<0||destx+width >SCREENWIDTH
|| desty<0
|| desty+height>SCREENHEIGHT)
I_Error ("V_CopyRect: Bad arguments");
#endif
src = screens[srcscrn].data+screens[srcscrn].byte_pitch*srcy+srcx*V_GetPixelDepth();
dest = screens[destscrn].data+screens[destscrn].byte_pitch*desty+destx*V_GetPixelDepth();
for ( ; height>0 ; height--)
{
memcpy (dest, src, width*V_GetPixelDepth());
src += screens[srcscrn].byte_pitch;
dest += screens[destscrn].byte_pitch;
}
}
/*
* V_DrawBackground tiles a 64x64 patch over the entire screen, providing the
* background for the Help and Setup screens, and plot text betwen levels.
* cphipps - used to have M_DrawBackground, but that was used the framebuffer
* directly, so this is my code from the equivalent function in f_finale.c
*/
static void FUNC_V_DrawBackground(const char* flatname, int scrn)
{
/* erase the entire screen to a tiled background */
const byte *src;
int x,y;
int width,height;
int lump;
// killough 4/17/98:
src = W_CacheLumpNum(lump = firstflat + R_FlatNumForName(flatname));
/* V_DrawBlock(0, 0, scrn, 64, 64, src, 0); */
width = height = 64;
if (V_GetMode() == VID_MODE8) {
byte *dest = screens[scrn].data;
while (height--) {
memcpy (dest, src, width);
src += width;
dest += screens[scrn].byte_pitch;
}
} else if (V_GetMode() == VID_MODE15) {
unsigned short *dest = (unsigned short *)screens[scrn].data;
while (height--) {
int i;
for (i=0; i<width; i++) {
dest[i] = VID_PAL15(src[i], VID_COLORWEIGHTMASK);
}
src += width;
dest += screens[scrn].short_pitch;
}
} else if (V_GetMode() == VID_MODE16) {
unsigned short *dest = (unsigned short *)screens[scrn].data;
while (height--) {
int i;
for (i=0; i<width; i++) {
dest[i] = VID_PAL16(src[i], VID_COLORWEIGHTMASK);
}
src += width;
dest += screens[scrn].short_pitch;
}
} else if (V_GetMode() == VID_MODE32) {
unsigned int *dest = (unsigned int *)screens[scrn].data;
while (height--) {
int i;
for (i=0; i<width; i++) {
dest[i] = VID_PAL32(src[i], VID_COLORWEIGHTMASK);
}
src += width;
dest += screens[scrn].int_pitch;
}
}
/* end V_DrawBlock */
for (y=0 ; y<SCREENHEIGHT ; y+=64)
for (x=y ? 0 : 64; x<SCREENWIDTH ; x+=64)
V_CopyRect(0, 0, scrn, ((SCREENWIDTH-x) < 64) ? (SCREENWIDTH-x) : 64,
((SCREENHEIGHT-y) < 64) ? (SCREENHEIGHT-y) : 64, x, y, scrn, VPT_NONE);
W_UnlockLumpNum(lump);
}
//
// V_Init
//
// Allocates the 4 full screen buffers in low DOS memory
// No return
//
void V_Init (void)
{
int i;
// reset the all
for (i = 0; i<NUM_SCREENS; i++) {
screens[i].data = NULL;
screens[i].not_on_heap = false;
screens[i].width = 0;
screens[i].height = 0;
screens[i].byte_pitch = 0;
screens[i].short_pitch = 0;
screens[i].int_pitch = 0;
}
}
//
// V_DrawMemPatch
//
// CPhipps - unifying patch drawing routine, handles all cases and combinations
// of stretching, flipping and translating
//
// This function is big, hopefully not too big that gcc can't optimise it well.
// In fact it packs pretty well, there is no big performance lose for all this merging;
// the inner loops themselves are just the same as they always were
// (indeed, laziness of the people who wrote the 'clones' of the original V_DrawPatch
// means that their inner loops weren't so well optimised, so merging code may even speed them).
//
static void V_DrawMemPatch(int x, int y, int scrn, const rpatch_t *patch,
int cm, enum patch_translation_e flags)
{
const byte *trans;
if (cm<CR_LIMIT)
trans=colrngs[cm];
else
trans=translationtables + 256*((cm-CR_LIMIT)-1);
y -= patch->topoffset;
x -= patch->leftoffset;
// CPhipps - auto-no-stretch if not high-res
if (flags & VPT_STRETCH)
if ((SCREENWIDTH==320) && (SCREENHEIGHT==200))
flags &= ~VPT_STRETCH;
// CPhipps - null translation pointer => no translation
if (!trans)
flags &= ~VPT_TRANS;
if (V_GetMode() == VID_MODE8 && !(flags & VPT_STRETCH)) {
int col;
byte *desttop = screens[scrn].data+y*screens[scrn].byte_pitch+x*V_GetPixelDepth();
unsigned int w = patch->width;
if (y<0 || y+patch->height > ((flags & VPT_STRETCH) ? 200 : SCREENHEIGHT)) {
// killough 1/19/98: improved error message:
lprintf(LO_WARN, "V_DrawMemPatch8: Patch (%d,%d)-(%d,%d) exceeds LFB in vertical direction (horizontal is clipped)\n"
"Bad V_DrawMemPatch8 (flags=%u)", x, y, x+patch->width, y+patch->height, flags);
return;
}
w--; // CPhipps - note: w = width-1 now, speeds up flipping
for (col=0 ; (unsigned int)col<=w ; desttop++, col++, x++) {
int i;
const int colindex = (flags & VPT_FLIP) ? (w - col) : (col);
const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
if (x < 0)
continue;
if (x >= SCREENWIDTH)
break;
// step through the posts in a column
for (i=0; i<column->numPosts; i++) {
const rpost_t *post = &column->posts[i];
// killough 2/21/98: Unrolled and performance-tuned
const byte *source = column->pixels + post->topdelta;
byte *dest = desttop + post->topdelta*screens[scrn].byte_pitch;
int count = post->length;
if (!(flags & VPT_TRANS)) {
if ((count-=4)>=0)
do {
register byte s0,s1;
s0 = source[0];
s1 = source[1];
dest[0] = s0;
dest[screens[scrn].byte_pitch] = s1;
dest += screens[scrn].byte_pitch*2;
s0 = source[2];
s1 = source[3];
source += 4;
dest[0] = s0;
dest[screens[scrn].byte_pitch] = s1;
dest += screens[scrn].byte_pitch*2;
} while ((count-=4)>=0);
if (count+=4)
do {
*dest = *source++;
dest += screens[scrn].byte_pitch;
} while (--count);
} else {
// CPhipps - merged translation code here
if ((count-=4)>=0)
do {
register byte s0,s1;
s0 = source[0];
s1 = source[1];
s0 = trans[s0];
s1 = trans[s1];
dest[0] = s0;
dest[screens[scrn].byte_pitch] = s1;
dest += screens[scrn].byte_pitch*2;
s0 = source[2];
s1 = source[3];
s0 = trans[s0];
s1 = trans[s1];
source += 4;
dest[0] = s0;
dest[screens[scrn].byte_pitch] = s1;
dest += screens[scrn].byte_pitch*2;
} while ((count-=4)>=0);
if (count+=4)
do {
*dest = trans[*source++];
dest += screens[scrn].byte_pitch;
} while (--count);
}
}
}
}
else {
// CPhipps - move stretched patch drawing code here
// - reformat initialisers, move variables into inner blocks
int col;
int w = (patch->width << 16) - 1; // CPhipps - -1 for faster flipping
int left, right, top, bottom;
int DX = (SCREENWIDTH<<16) / 320;
int DXI = (320<<16) / SCREENWIDTH;
int DY = (SCREENHEIGHT<<16) / 200;
int DYI = (200<<16) / SCREENHEIGHT;
R_DrawColumn_f colfunc;
draw_column_vars_t dcvars;
draw_vars_t olddrawvars = drawvars;
R_SetDefaultDrawColumnVars(&dcvars);
drawvars.byte_topleft = screens[scrn].data;
drawvars.short_topleft = (unsigned short *)screens[scrn].data;
drawvars.int_topleft = (unsigned int *)screens[scrn].data;
drawvars.byte_pitch = screens[scrn].byte_pitch;
drawvars.short_pitch = screens[scrn].short_pitch;
drawvars.int_pitch = screens[scrn].int_pitch;
if (!(flags & VPT_STRETCH)) {
DX = 1 << 16;
DXI = 1 << 16;
DY = 1 << 16;
DYI = 1 << 16;
}
if (flags & VPT_TRANS) {
colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, drawvars.filterpatch, RDRAW_FILTER_NONE);
dcvars.translation = trans;
} else {
colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, drawvars.filterpatch, RDRAW_FILTER_NONE);
}
left = ( x * DX ) >> FRACBITS;
top = ( y * DY ) >> FRACBITS;
right = ( (x + patch->width) * DX ) >> FRACBITS;
bottom = ( (y + patch->height) * DY ) >> FRACBITS;
dcvars.texheight = patch->height;
dcvars.iscale = DYI;
dcvars.drawingmasked = MAX(patch->width, patch->height) > 8;
dcvars.edgetype = drawvars.patch_edges;
if (drawvars.filterpatch == RDRAW_FILTER_LINEAR) {
// bias the texture u coordinate
if (patch->isNotTileable)
col = -(FRACUNIT>>1);
else
col = (patch->width<<FRACBITS)-(FRACUNIT>>1);
}
else {
col = 0;
}
for (dcvars.x=left; dcvars.x<right; dcvars.x++, col+=DXI) {
int i;
const int colindex = (flags & VPT_FLIP) ? ((w - col)>>16): (col>>16);
const rcolumn_t *column = R_GetPatchColumn(patch, colindex);
const rcolumn_t *prevcolumn = R_GetPatchColumn(patch, colindex-1);
const rcolumn_t *nextcolumn = R_GetPatchColumn(patch, colindex+1);
// ignore this column if it's to the left of our clampRect
if (dcvars.x < 0)
continue;
if (dcvars.x >= SCREENWIDTH)
break;
dcvars.texu = ((flags & VPT_FLIP) ? ((patch->width<<FRACBITS)-col) : col) % (patch->width<<FRACBITS);
// step through the posts in a column
for (i=0; i<column->numPosts; i++) {
const rpost_t *post = &column->posts[i];
int yoffset = 0;
dcvars.yl = (((y + post->topdelta) * DY)>>FRACBITS);
dcvars.yh = (((y + post->topdelta + post->length) * DY - (FRACUNIT>>1))>>FRACBITS);
dcvars.edgeslope = post->slope;
if ((dcvars.yh < 0) || (dcvars.yh < top))
continue;
if ((dcvars.yl >= SCREENHEIGHT) || (dcvars.yl >= bottom))
continue;
if (dcvars.yh >= bottom) {
dcvars.yh = bottom-1;
dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
}
if (dcvars.yh >= SCREENHEIGHT) {
dcvars.yh = SCREENHEIGHT-1;
dcvars.edgeslope &= ~RDRAW_EDGESLOPE_BOT_MASK;
}
if (dcvars.yl < 0) {
yoffset = 0-dcvars.yl;
dcvars.yl = 0;
dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
}
if (dcvars.yl < top) {
yoffset = top-dcvars.yl;
dcvars.yl = top;
dcvars.edgeslope &= ~RDRAW_EDGESLOPE_TOP_MASK;
}
dcvars.source = column->pixels + post->topdelta + yoffset;
dcvars.prevsource = prevcolumn ? prevcolumn->pixels + post->topdelta + yoffset: dcvars.source;
dcvars.nextsource = nextcolumn ? nextcolumn->pixels + post->topdelta + yoffset: dcvars.source;
dcvars.texturemid = -((dcvars.yl-centery)*dcvars.iscale);
colfunc(&dcvars);
}
}
R_ResetColumnBuffer();
drawvars = olddrawvars;
}
}
// CPhipps - some simple, useful wrappers for that function, for drawing patches from wads
// CPhipps - GNU C only suppresses generating a copy of a function if it is
// static inline; other compilers have different behaviour.
// This inline is _only_ for the function below
static void FUNC_V_DrawNumPatch(int x, int y, int scrn, int lump,
int cm, enum patch_translation_e flags)
{
V_DrawMemPatch(x, y, scrn, R_CachePatchNum(lump), cm, flags);
R_UnlockPatchNum(lump);
}
unsigned short *V_Palette15 = NULL;
unsigned short *V_Palette16 = NULL;
unsigned int *V_Palette32 = NULL;
static unsigned short *Palettes15 = NULL;
static unsigned short *Palettes16 = NULL;
static unsigned int *Palettes32 = NULL;
static int currentPaletteIndex = 0;
//
// V_UpdateTrueColorPalette
//
void V_UpdateTrueColorPalette(video_mode_t mode) {
int i, w, p;
byte r,g,b;
int nr,ng,nb;
float t;
int paletteNum = (V_GetMode() == VID_MODEGL ? 0 : currentPaletteIndex);
static int usegammaOnLastPaletteGeneration = -1;
int pplump = W_GetNumForName("PLAYPAL");
int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom);
const byte *pal = W_CacheLumpNum(pplump);
// opengl doesn't use the gamma
const byte *const gtable =
(const byte *)W_CacheLumpNum(gtlump) +
(V_GetMode() == VID_MODEGL ? 0 : 256*(usegamma))
;
int numPals = W_LumpLength(pplump) / (3*256);
const float dontRoundAbove = 220;
float roundUpR, roundUpG, roundUpB;
if (usegammaOnLastPaletteGeneration != usegamma) {
if (Palettes15) free(Palettes15);
if (Palettes16) free(Palettes16);
if (Palettes32) free(Palettes32);
Palettes15 = NULL;
Palettes16 = NULL;
Palettes32 = NULL;
usegammaOnLastPaletteGeneration = usegamma;
}
if (mode == VID_MODE32) {
if (!Palettes32) {
// set int palette
Palettes32 = (int*)malloc(numPals*256*sizeof(int)*VID_NUMCOLORWEIGHTS);
for (p=0; p<numPals; p++) {
for (i=0; i<256; i++) {
r = gtable[pal[(256*p+i)*3+0]];
g = gtable[pal[(256*p+i)*3+1]];
b = gtable[pal[(256*p+i)*3+2]];
// ideally, we should always round up, but very bright colors
// overflow the blending adds, so they don't get rounded.
roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
nr = (int)(r*t+roundUpR);
ng = (int)(g*t+roundUpG);
nb = (int)(b*t+roundUpB);
Palettes32[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
(nr<<16) | (ng<<8) | nb
2016-03-03 22:28:59 +00:00
);
}
}
}
}
V_Palette32 = Palettes32 + paletteNum*256*VID_NUMCOLORWEIGHTS;
}
else if (mode == VID_MODE16) {
if (!Palettes16) {
// set short palette
Palettes16 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
for (p=0; p<numPals; p++) {
for (i=0; i<256; i++) {
r = gtable[pal[(256*p+i)*3+0]];
g = gtable[pal[(256*p+i)*3+1]];
b = gtable[pal[(256*p+i)*3+2]];
// ideally, we should always round up, but very bright colors
// overflow the blending adds, so they don't get rounded.
roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
nr = (int)((r>>3)*t+roundUpR);
ng = (int)((g>>2)*t+roundUpG);
nb = (int)((b>>3)*t+roundUpB);
Palettes16[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
(nr<<11) | (ng<<5) | nb
);
}
}
}
}
V_Palette16 = Palettes16 + paletteNum*256*VID_NUMCOLORWEIGHTS;
}
else if (mode == VID_MODE15) {
if (!Palettes15) {
// set short palette
Palettes15 = (short*)malloc(numPals*256*sizeof(short)*VID_NUMCOLORWEIGHTS);
for (p=0; p<numPals; p++) {
for (i=0; i<256; i++) {
r = gtable[pal[(256*p+i)*3+0]];
g = gtable[pal[(256*p+i)*3+1]];
b = gtable[pal[(256*p+i)*3+2]];
// ideally, we should always round up, but very bright colors
// overflow the blending adds, so they don't get rounded.
roundUpR = (r > dontRoundAbove) ? 0 : 0.5f;
roundUpG = (g > dontRoundAbove) ? 0 : 0.5f;
roundUpB = (b > dontRoundAbove) ? 0 : 0.5f;
for (w=0; w<VID_NUMCOLORWEIGHTS; w++) {
t = (float)(w)/(float)(VID_NUMCOLORWEIGHTS-1);
nr = (int)((r>>3)*t+roundUpR);
ng = (int)((g>>3)*t+roundUpG);
nb = (int)((b>>3)*t+roundUpB);
Palettes15[((p*256+i)*VID_NUMCOLORWEIGHTS)+w] = (
(nr<<10) | (ng<<5) | nb
);
}
}
}
}
V_Palette15 = Palettes15 + paletteNum*256*VID_NUMCOLORWEIGHTS;
}
W_UnlockLumpNum(pplump);
W_UnlockLumpNum(gtlump);
}
//---------------------------------------------------------------------------
// V_DestroyTrueColorPalette
//---------------------------------------------------------------------------
static void V_DestroyTrueColorPalette(video_mode_t mode) {
if (mode == VID_MODE15) {
if (Palettes15) free(Palettes15);
Palettes15 = NULL;
V_Palette15 = NULL;
}
if (mode == VID_MODE16) {
if (Palettes16) free(Palettes16);
Palettes16 = NULL;
V_Palette16 = NULL;
}
if (mode == VID_MODE32) {
if (Palettes32) free(Palettes32);
Palettes32 = NULL;
V_Palette32 = NULL;
}
}
void V_DestroyUnusedTrueColorPalettes(void) {
if (V_GetMode() != VID_MODE15) V_DestroyTrueColorPalette(VID_MODE15);
if (V_GetMode() != VID_MODE16) V_DestroyTrueColorPalette(VID_MODE16);
if (V_GetMode() != VID_MODE32) V_DestroyTrueColorPalette(VID_MODE32);
}
//
// V_SetPalette
//
// CPhipps - New function to set the palette to palette number pal.
// Handles loading of PLAYPAL and calls I_SetPalette
void V_SetPalette(int pal)
{
currentPaletteIndex = pal;
if (V_GetMode() == VID_MODEGL) {
#ifdef GL_DOOM
gld_SetPalette(pal);
#endif
} else {
I_SetPalette(pal);
if (V_GetMode() == VID_MODE15 || V_GetMode() == VID_MODE16 || V_GetMode() == VID_MODE32) {
// V_SetPalette can be called as part of the gamma setting before
// we've loaded any wads, which prevents us from reading the palette - POPE
if (W_CheckNumForName("PLAYPAL") >= 0) {
V_UpdateTrueColorPalette(V_GetMode());
}
}
}
}
//
// V_FillRect
//
// CPhipps - New function to fill a rectangle with a given colour
static void V_FillRect8(int scrn, int x, int y, int width, int height, byte colour)
{
byte* dest = screens[scrn].data + x + y*screens[scrn].byte_pitch;
while (height--) {
memset(dest, colour, width);
dest += screens[scrn].byte_pitch;
}
}
static void V_FillRect15(int scrn, int x, int y, int width, int height, byte colour)
{
unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
int w;
short c = VID_PAL15(colour, VID_COLORWEIGHTMASK);
while (height--) {
for (w=0; w<width; w++) {
dest[w] = c;
}
dest += screens[scrn].short_pitch;
}
}
static void V_FillRect16(int scrn, int x, int y, int width, int height, byte colour)
{
unsigned short* dest = (unsigned short *)screens[scrn].data + x + y*screens[scrn].short_pitch;
int w;
short c = VID_PAL16(colour, VID_COLORWEIGHTMASK);
while (height--) {
for (w=0; w<width; w++) {
dest[w] = c;
}
dest += screens[scrn].short_pitch;
}
}
static void V_FillRect32(int scrn, int x, int y, int width, int height, byte colour)
{
unsigned int* dest = (unsigned int *)screens[scrn].data + x + y*screens[scrn].int_pitch;
int w;
int c = VID_PAL32(colour, VID_COLORWEIGHTMASK);
while (height--) {
for (w=0; w<width; w++) {
dest[w] = c;
}
dest += screens[scrn].int_pitch;
}
}
static void WRAP_V_DrawLine(fline_t* fl, int color);
static void V_PlotPixel8(int scrn, int x, int y, byte color);
static void V_PlotPixel15(int scrn, int x, int y, byte color);
static void V_PlotPixel16(int scrn, int x, int y, byte color);
static void V_PlotPixel32(int scrn, int x, int y, byte color);
#ifdef GL_DOOM
static void WRAP_gld_FillRect(int scrn, int x, int y, int width, int height, byte colour)
{
gld_FillBlock(x,y,width,height,colour);
}
static void WRAP_gld_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags)
{
}
static void WRAP_gld_DrawBackground(const char *flatname, int n)
{
gld_DrawBackground(flatname);
}
static void WRAP_gld_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags)
{
gld_DrawNumPatch(x,y,lump,cm,flags);
}
static void WRAP_gld_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags)
{
}
static void V_PlotPixelGL(int scrn, int x, int y, byte color) {
gld_DrawLine(x-1, y, x+1, y, color);
gld_DrawLine(x, y-1, x, y+1, color);
}
static void WRAP_gld_DrawLine(fline_t* fl, int color)
{
gld_DrawLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, color);
}
#endif
static void NULL_FillRect(int scrn, int x, int y, int width, int height, byte colour) {}
static void NULL_CopyRect(int srcx, int srcy, int srcscrn, int width, int height, int destx, int desty, int destscrn, enum patch_translation_e flags) {}
static void NULL_DrawBackground(const char *flatname, int n) {}
static void NULL_DrawNumPatch(int x, int y, int scrn, int lump, int cm, enum patch_translation_e flags) {}
static void NULL_DrawBlock(int x, int y, int scrn, int width, int height, const byte *src, enum patch_translation_e flags) {}
static void NULL_PlotPixel(int scrn, int x, int y, byte color) {}
static void NULL_DrawLine(fline_t* fl, int color) {}
const char *default_videomode;
static video_mode_t current_videomode = VID_MODE8;
V_CopyRect_f V_CopyRect = NULL_CopyRect;
V_FillRect_f V_FillRect = NULL_FillRect;
V_DrawNumPatch_f V_DrawNumPatch = NULL_DrawNumPatch;
V_DrawBackground_f V_DrawBackground = NULL_DrawBackground;
V_PlotPixel_f V_PlotPixel = NULL_PlotPixel;
V_DrawLine_f V_DrawLine = NULL_DrawLine;
//
// V_InitMode
//
void V_InitMode(video_mode_t mode) {
#ifndef GL_DOOM
if (mode == VID_MODEGL)
mode = VID_MODE8;
#endif
switch (mode) {
case VID_MODE8:
lprintf(LO_INFO, "V_InitMode: using 8 bit video mode\n");
V_CopyRect = FUNC_V_CopyRect;
V_FillRect = V_FillRect8;
V_DrawNumPatch = FUNC_V_DrawNumPatch;
V_DrawBackground = FUNC_V_DrawBackground;
V_PlotPixel = V_PlotPixel8;
V_DrawLine = WRAP_V_DrawLine;
current_videomode = VID_MODE8;
break;
case VID_MODE15:
lprintf(LO_INFO, "V_InitMode: using 15 bit video mode\n");
V_CopyRect = FUNC_V_CopyRect;
V_FillRect = V_FillRect15;
V_DrawNumPatch = FUNC_V_DrawNumPatch;
V_DrawBackground = FUNC_V_DrawBackground;
V_PlotPixel = V_PlotPixel15;
V_DrawLine = WRAP_V_DrawLine;
current_videomode = VID_MODE15;
break;
case VID_MODE16:
lprintf(LO_INFO, "V_InitMode: using 16 bit video mode\n");
V_CopyRect = FUNC_V_CopyRect;
V_FillRect = V_FillRect16;
V_DrawNumPatch = FUNC_V_DrawNumPatch;
V_DrawBackground = FUNC_V_DrawBackground;
V_PlotPixel = V_PlotPixel16;
V_DrawLine = WRAP_V_DrawLine;
current_videomode = VID_MODE16;
break;
case VID_MODE32:
lprintf(LO_INFO, "V_InitMode: using 32 bit video mode\n");
V_CopyRect = FUNC_V_CopyRect;
V_FillRect = V_FillRect32;
V_DrawNumPatch = FUNC_V_DrawNumPatch;
V_DrawBackground = FUNC_V_DrawBackground;
V_PlotPixel = V_PlotPixel32;
V_DrawLine = WRAP_V_DrawLine;
current_videomode = VID_MODE32;
break;
#ifdef GL_DOOM
case VID_MODEGL:
lprintf(LO_INFO, "V_InitMode: using OpenGL video mode\n");
V_CopyRect = WRAP_gld_CopyRect;
V_FillRect = WRAP_gld_FillRect;
V_DrawNumPatch = WRAP_gld_DrawNumPatch;
V_DrawBackground = WRAP_gld_DrawBackground;
V_PlotPixel = V_PlotPixelGL;
V_DrawLine = WRAP_gld_DrawLine;
current_videomode = VID_MODEGL;
break;
#endif
}
R_FilterInit();
}
//
// V_GetMode
//
video_mode_t V_GetMode(void) {
return current_videomode;
}
//
// V_GetModePixelDepth
//
int V_GetModePixelDepth(video_mode_t mode) {
switch (mode) {
case VID_MODE8: return 1;
case VID_MODE15: return 2;
case VID_MODE16: return 2;
case VID_MODE32: return 4;
default: return 0;
}
}
//
// V_GetNumPixelBits
//
int V_GetNumPixelBits(void) {
switch (current_videomode) {
case VID_MODE8: return 8;
case VID_MODE15: return 15;
case VID_MODE16: return 16;
case VID_MODE32: return 32;
default: return 0;
}
}
//
// V_GetPixelDepth
//
int V_GetPixelDepth(void) {
return V_GetModePixelDepth(current_videomode);
}
//
// V_AllocScreen
//
void V_AllocScreen(screeninfo_t *scrn) {
if (!scrn->not_on_heap)
if ((scrn->byte_pitch * scrn->height) > 0)
scrn->data = malloc(scrn->byte_pitch*scrn->height);
}
//
// V_AllocScreens
//
void V_AllocScreens(void) {
int i;
for (i=0; i<NUM_SCREENS; i++)
V_AllocScreen(&screens[i]);
}
//
// V_FreeScreen
//
void V_FreeScreen(screeninfo_t *scrn) {
if (!scrn->not_on_heap) {
free(scrn->data);
scrn->data = NULL;
}
}
//
// V_FreeScreens
//
void V_FreeScreens(void) {
int i;
for (i=0; i<NUM_SCREENS; i++)
V_FreeScreen(&screens[i]);
}
static void V_PlotPixel8(int scrn, int x, int y, byte color) {
screens[scrn].data[x+screens[scrn].byte_pitch*y] = color;
}
static void V_PlotPixel15(int scrn, int x, int y, byte color) {
((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL15(color, VID_COLORWEIGHTMASK);
}
static void V_PlotPixel16(int scrn, int x, int y, byte color) {
((unsigned short *)screens[scrn].data)[x+screens[scrn].short_pitch*y] = VID_PAL16(color, VID_COLORWEIGHTMASK);
}
static void V_PlotPixel32(int scrn, int x, int y, byte color) {
((unsigned int *)screens[scrn].data)[x+screens[scrn].int_pitch*y] = VID_PAL32(color, VID_COLORWEIGHTMASK);
}
//
// WRAP_V_DrawLine()
//
// Draw a line in the frame buffer.
// Classic Bresenham w/ whatever optimizations needed for speed
//
// Passed the frame coordinates of line, and the color to be drawn
// Returns nothing
//
static void WRAP_V_DrawLine(fline_t* fl, int color)
{
register int x;
register int y;
register int dx;
register int dy;
register int sx;
register int sy;
register int ax;
register int ay;
register int d;
#ifdef RANGECHECK // killough 2/22/98
static int fuck = 0;
// For debugging only
if
(
fl->a.x < 0 || fl->a.x >= SCREENWIDTH
|| fl->a.y < 0 || fl->a.y >= SCREENHEIGHT
|| fl->b.x < 0 || fl->b.x >= SCREENWIDTH
|| fl->b.y < 0 || fl->b.y >= SCREENHEIGHT
)
{
//jff 8/3/98 use logical output routine
lprintf(LO_DEBUG, "fuck %d \r", fuck++);
return;
}
#endif
#define PUTDOT(xx,yy,cc) V_PlotPixel(0,xx,yy,(byte)cc)
dx = fl->b.x - fl->a.x;
ax = 2 * (dx<0 ? -dx : dx);
sx = dx<0 ? -1 : 1;
dy = fl->b.y - fl->a.y;
ay = 2 * (dy<0 ? -dy : dy);
sy = dy<0 ? -1 : 1;
x = fl->a.x;
y = fl->a.y;
if (ax > ay)
{
d = ay - ax/2;
while (1)
{
PUTDOT(x,y,color);
if (x == fl->b.x) return;
if (d>=0)
{
y += sy;
d -= ax;
}
x += sx;
d += ay;
}
}
else
{
d = ax - ay/2;
while (1)
{
PUTDOT(x, y, color);
if (y == fl->b.y) return;
if (d >= 0)
{
x += sx;
d -= ay;
}
y += sy;
d += ax;
}
}
}