fteqw/engine/sw/sw_draw.c
Spoike ce3c561cfe CSQC is standard now, and secure via the same md4 as a map currently has.
Particle system functions renamed a bit, a few other cleanups in that area.
Console handling tweeked. Better rules for subconsoles and plugins. Commands are coloured if it'll be execed, which should help reduce occurences of chat being commands. tab compleation tweeked, partial compleation no longer changes the suggestion.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@895 fc73d0e0-1445-4013-8a0c-d673dee63da5
2005-03-10 03:55:18 +00:00

2468 lines
51 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
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.
*/
// draw.c -- this is the only file outside the refresh that touches the
// vid buffer
#include "quakedef.h"
#ifdef RGLQUAKE
#include "glquake.h" //with sw refresh???
#endif
#include "d_local.h" //trans stuff
#include "sw_draw.h"
extern unsigned int *d_8to32table;
typedef struct {
vrect_t rect;
int width;
int height;
qbyte *ptexbytes;
int rowbytes;
} rectdesc_t;
static rectdesc_t r_rectdesc;
qbyte *draw_chars; // 8*8 graphic characters
mpic_t *draw_disc;
mpic_t *draw_backtile;
void SWDraw_TransPic (int x, int y, mpic_t *pic);
//=============================================================================
/* Support Routines */
typedef struct cachepic_s
{
char name[MAX_QPATH];
cache_user_t cache;
} swcachepic_t;
#define MAX_CACHED_PICS 1024
swcachepic_t swmenu_cachepics[MAX_CACHED_PICS];
int swmenu_numcachepics;
/*
================
Draw_CachePic
================
*/
mpic_t *SWDraw_SafeCachePic (char *extpath)
{
swcachepic_t *pic;
int i;
mpic_t *dat;
char alternatename[MAX_QPATH];
char path[MAX_QPATH];
Q_strncpyz(path, extpath, sizeof(path));
COM_StripExtension(path, path);
for (pic=swmenu_cachepics, i=0 ; i<swmenu_numcachepics ; pic++, i++)
if (!strcmp (path, pic->name))
break;
if (i == swmenu_numcachepics)
{
if (swmenu_numcachepics == MAX_CACHED_PICS)
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
swmenu_numcachepics++;
strcpy (pic->name, path);
}
dat = Cache_Check (&pic->cache);
if (dat)
return dat;
{
qbyte *file, *image;
int width;
int height;
_snprintf(alternatename, MAX_QPATH-1,"%s.pcx", path);
file = COM_LoadMallocFile(alternatename);
if (file)
{
image = ReadPCXFile(file, com_filesize, &width, &height);
BZ_Free(file);
if (image)
{
dat = Cache_Alloc(&pic->cache, sizeof(mpic_t) + width*height, path);
((mpic_t*)dat)->width = width;
((mpic_t*)dat)->height = height;
((mpic_t*)dat)->flags = 0;
for (i = 0; i < width*height; i++)
{
if (image[i*4+3] < 64) // 25% threshhold
{
((mpic_t*)dat)->flags |= MPIC_ALPHA;
dat->data[i] = 255;
}
else
dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]);
}
BZ_Free(image);
return dat;
}
}
}
#ifdef AVAIL_JPEGLIB
{
qbyte *file, *image;
int width;
int height;
_snprintf(alternatename, MAX_QPATH-1,"%s.jpg", path);
file = COM_LoadMallocFile(alternatename);
if (file)
{
image = ReadJPEGFile(file, com_filesize, &width, &height);
BZ_Free(file);
if (image)
{
dat = Cache_Alloc(&pic->cache, sizeof(mpic_t) + width*height, path);
((mpic_t*)dat)->width = width;
((mpic_t*)dat)->height = height;
((mpic_t*)dat)->flags = 0;
for (i = 0; i < width*height; i++)
{
if (image[i*4+3] < 64) // 25% threshhold
{
((mpic_t*)dat)->flags |= MPIC_ALPHA;
dat->data[i] = 255;
}
else
dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]);
}
BZ_Free(image);
return dat;
}
}
}
#endif
{
qbyte *file, *image;
int width;
int height;
_snprintf(alternatename, MAX_QPATH-1,"%s.tga", path);
file = COM_LoadMallocFile(alternatename);
if (file)
{
image = ReadTargaFile (file, com_filesize, &width, &height, 0);
BZ_Free(file);
if (image)
{
dat = Cache_Alloc(&pic->cache, sizeof(mpic_t) + width*height, path);
((mpic_t*)dat)->width = width;
((mpic_t*)dat)->height = height;
((mpic_t*)dat)->flags = 0;
for (i = 0; i < width*height; i++)
{
if (image[i*4+3] < 64) // 25% threshhold
{
((mpic_t*)dat)->flags |= MPIC_ALPHA;
dat->data[i] = 255;
}
else
dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]);
}
BZ_Free(image);
return dat;
}
}
}
//
// load the pic from disk
//
_snprintf(alternatename, MAX_QPATH-1,"%s.lmp", path);
COM_LoadCacheFile (alternatename, &pic->cache);
dat = pic->cache.data;
if (!dat)
{
char alternatename[MAX_QPATH];
sprintf(alternatename, "gfx/%s.lmp", path);
COM_LoadCacheFile(alternatename, &pic->cache);
dat = pic->cache.data;
if (!dat)
return NULL;
// Sys_Error ("Draw_CachePic: failed to load %s", path);
}
SwapPic ((qpic_t*)dat);
((mpic_t*)dat)->width = ((qpic_t*)dat)->width;
((mpic_t*)dat)->height = ((qpic_t*)dat)->height;
((mpic_t*)dat)->flags = 0;
return dat;
}
mpic_t *SWDraw_CachePic (char *path)
{
mpic_t *pic;
pic = SWDraw_SafeCachePic(path);
if (!pic)
Sys_Error ("Draw_CachePic: failed to load %s", path);
return pic;
}
mpic_t *SWDraw_ConcharsMalloc (char *name)
{
// stupid hack for conchars...
qpic_t *dat;
swcachepic_t *pic;
int i, j;
for (pic=swmenu_cachepics, i=0 ; i<swmenu_numcachepics ; pic++, i++)
if (!strcmp (name, pic->name))
break;
if (i == swmenu_numcachepics)
{
if (swmenu_numcachepics == MAX_CACHED_PICS)
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
swmenu_numcachepics++;
pic->cache.fake = true;
pic->cache.data = BZ_Malloc(sizeof(qpic_t) + 128*128);
dat = pic->cache.data;
// change 0 to 255 through conchars
for (j = 0; j < 128*128; j++)
dat->data[j] = (draw_chars[j] == 255 || !draw_chars[j]) ? draw_chars[j] ^ 255 : draw_chars[j];
// memcpy (dat->data, draw_chars, 128*128);
((mpic_t*)dat)->width = ((mpic_t*)dat)->height = 128;
((mpic_t*)dat)->flags = 1;
strcpy (pic->name, name);
}
return pic->cache.data;
}
mpic_t *SWDraw_MallocPic (char *path)
{
int i;
qpic_t *dat;
swcachepic_t *pic;
for (pic=swmenu_cachepics, i=0 ; i<swmenu_numcachepics ; pic++, i++)
if (!strcmp (path, pic->name))
break;
if (i == swmenu_numcachepics)
{
if (swmenu_numcachepics == MAX_CACHED_PICS)
Sys_Error ("menu_numcachepics == MAX_CACHED_PICS");
swmenu_numcachepics++;
pic->cache.fake = false;
pic->cache.data = NULL;
strcpy (pic->name, path);
}
dat = Cache_Check (&pic->cache);
if (dat)
return (mpic_t *)dat;
{
qbyte *file, *image;
int width;
int height;
file = COM_LoadMallocFile(path);
if (file)
{
image = ReadPCXFile(file, com_filesize, &width, &height);
BZ_Free(file);
if (image)
{
dat = BZ_Malloc(sizeof(qpic_t) + width*height);
if (dat)
{
pic->cache.data = dat;
pic->cache.fake = true;
((mpic_t*)dat)->width = width;
((mpic_t*)dat)->height = height;
((mpic_t*)dat)->flags = 0;
for (i = 0; i < width*height; i++)
dat->data[i] = GetPalette(image[i*4], image[i*4+1], image[i*4+2]);
BZ_Free(image);
return (mpic_t *)dat;
}
BZ_Free(image);
}
}
}
//
// load the pic from disk
//
dat = (qpic_t *)COM_LoadHunkFile (path);
pic->cache.data = dat;
pic->cache.fake = true;
if (!dat)
{
return NULL;
// Sys_Error ("Draw_CachePic: failed to load %s", path);
}
SwapPic (dat);
((mpic_t*)dat)->width = dat->width;
((mpic_t*)dat)->height = dat->height;
((mpic_t*)dat)->flags = 0;
return (mpic_t *)dat;
}
mpic_t *SWDraw_PicFromWad (char *name)
{
char q2name[MAX_QPATH];
qpic_t *qpic;
mpic_t *mpic;
if (!strcmp(name, "conchars")) // conchars hack
return SWDraw_ConcharsMalloc("conchars");
sprintf(q2name, "pics/%s.pcx", name);
mpic = SWDraw_MallocPic(q2name);
if (mpic)
return mpic;
qpic = W_SafeGetLumpName (name);
if (!qpic)
return NULL;
mpic = (mpic_t *)qpic;
mpic->width = qpic->width;
mpic->height = qpic->height;
mpic->flags = memchr (&qpic->data, 255, mpic->width * mpic->height)?MPIC_ALPHA:0;
return mpic;
}
/*
===============
Draw_Init
===============
*/
//FIXME: mallocs in place of wad references will not be freed
//we have a memory leak
void SWDraw_Init (void)
{
draw_chars = W_SafeGetLumpName ("conchars"); //q1
if (!draw_chars)
{
mpic_t *pic; //try q2
int i;
int s;
pic = (mpic_t *)SWDraw_MallocPic("pics/conchars.pcx"); //safe from host_hunkmarks...
if (pic)
{
draw_chars = pic->data;
s = pic->width*pic->height;
for (i = 0; i < s; i++) //convert 255s to 0, q1's transparent colour
if (draw_chars[i] == 162 || draw_chars[i] == 255)
draw_chars[i] = 0;
}
}
if (!draw_chars)
{ //now go for hexen2
int i, x;
char *tempchars = COM_LoadMallocFile("gfx/menu/conchars.lmp");
char *in, *out;
if (tempchars)
{
draw_chars = BZ_Malloc(256*256);
out = draw_chars;
for (i = 0; i < 8*8; i+=1)
{
if ((i/8)&1)
{
in = tempchars + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
else
{
in = tempchars + (i/8)*16*8*8+(i&7)*32*8;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
}
for (i = 0; i < 8*8; i+=1)
{
if ((i/8)&1)
{
in = tempchars+128*128 + ((i)/8)*16*8*8+(i&7)*32*8 - 256*4+128;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
else
{
in = tempchars+128*128 + (i/8)*16*8*8+(i&7)*32*8;
for (x = 0; x < 16*8; x++)
*out++ = *in++;
}
}
Z_Free(tempchars);
}
else
{ //nope, that failed too.
//use our built in fallback
{
int width;
int height;
qbyte *image;
qbyte *src, *dest;
extern qbyte default_conchar[11356];
image = ReadTargaFile(default_conchar, sizeof(default_conchar), &width, &height, false);
COM_WriteFile("test.dat", image, 256*256*4);
draw_chars = BZ_Malloc(128*128);
//downsample the 256 image to quake's 128 wide.
for (i = 0; i < 128;i++)
{
src = image+i*8*16*16;
dest = draw_chars + i*16*8;
for (x = 0; x < 128; x++)
dest[x] = src[(x*2)*4]?15:0;//GetPalette(image[i*4], image[i*4+1], image[i*4+2]);
}
COM_WriteFile("test2.dat", draw_chars, 128*128);
BZ_Free(image);
}
}
}
if (!draw_chars)
Sys_Error("Failed to find suitable console charactures\n");
draw_disc = W_SafeGetLumpName ("disc");
draw_backtile = W_SafeGetLumpName ("backtile");
if (!draw_backtile)
draw_backtile = (mpic_t *)COM_LoadMallocFile("gfx/menu/backtile.lmp");
if (draw_backtile)
{
{
((mpic_t*)draw_backtile)->width = ((qpic_t*)draw_backtile)->width;
((mpic_t*)draw_backtile)->height = ((qpic_t*)draw_backtile)->height;
((mpic_t*)draw_backtile)->flags = 0;
}
r_rectdesc.width = draw_backtile->width;
r_rectdesc.height = draw_backtile->height;
r_rectdesc.ptexbytes = draw_backtile->data;
r_rectdesc.rowbytes = draw_backtile->width;
}
#ifdef PLUGINS
Plug_DrawReloadImages();
#endif
}
void SWDraw_Shutdown(void)
{
int i;
swcachepic_t *pic;
for (pic=swmenu_cachepics, i=0 ; i<swmenu_numcachepics ; pic++, i++)
{
if (pic->cache.fake)
{
if (pic->cache.data)
BZ_Free(pic->cache.data);
pic->cache.fake = false;
pic->cache.data = NULL;
}
}
swmenu_numcachepics=0;
draw_disc = NULL;
}
/*
================
Draw_Character
Draws one 8*8 graphics character with 0 being transparent.
It can be clipped to the top of the screen to allow the console to be
smoothly scrolled off.
================
*/
void SWDraw_Character (int x, int y, unsigned int num)
{
qbyte *dest;
qbyte *source;
int drawline;
int row, col;
num &= 255;
if (y <= -8)
return; // totally off screen
if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
return;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
if (y < 0)
{ // clipped
drawline = 8 + y;
source -= 128*y;
y = 0;
}
else
drawline = 8;
if (r_pixbytes == 1)
{
dest = vid.conbuffer + y*vid.conrowbytes + x;
while (drawline--)
{
if (source[0])
dest[0] = source[0];
if (source[1])
dest[1] = source[1];
if (source[2])
dest[2] = source[2];
if (source[3])
dest[3] = source[3];
if (source[4])
dest[4] = source[4];
if (source[5])
dest[5] = source[5];
if (source[6])
dest[6] = source[6];
if (source[7])
dest[7] = source[7];
source += 128;
dest += vid.conrowbytes;
}
}
else if (r_pixbytes == 2)
{
unsigned short *dest16;
dest16 = (unsigned short*)vid.conbuffer + y*vid.conrowbytes + x;
while (drawline--)
{
if (source[0])
dest16[0] = d_8to16table[source[0]];
if (source[1])
dest16[1] = d_8to16table[source[1]];
if (source[2])
dest16[2] = d_8to16table[source[2]];
if (source[3])
dest16[3] = d_8to16table[source[3]];
if (source[4])
dest16[4] = d_8to16table[source[4]];
if (source[5])
dest16[5] = d_8to16table[source[5]];
if (source[6])
dest16[6] = d_8to16table[source[6]];
if (source[7])
dest16[7] = d_8to16table[source[7]];
source += 128;
dest16 += vid.conrowbytes;
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
p32dest = (unsigned int *)vid.conbuffer + y*vid.conrowbytes + x;
while (drawline--)
{
if (source[0])
p32dest[0] = d_8to32table[source[0]];
if (source[1])
p32dest[1] = d_8to32table[source[1]];
if (source[2])
p32dest[2] = d_8to32table[source[2]];
if (source[3])
p32dest[3] = d_8to32table[source[3]];
if (source[4])
p32dest[4] = d_8to32table[source[4]];
if (source[5])
p32dest[5] = d_8to32table[source[5]];
if (source[6])
p32dest[6] = d_8to32table[source[6]];
if (source[7])
p32dest[7] = d_8to32table[source[7]];
source += 128;
p32dest += vid.conrowbytes;
}
}
}
#define FindPallete(r,g,b) palxxxto8[((r&palmask[0])>>palshift[0]) | ((g&palmask[1])<<palshift[1]) | ((b&palmask[2])<<palshift[2])]
#define colourmask(p,r,g,b) FindPallete(host_basepal[p*3]*r, host_basepal[p*3+1]*g, host_basepal[p*3+2]*b)
#define draw(p) colourmask(p, (int)consolecolours[colour].r, (int)consolecolours[colour].g, (int)consolecolours[colour].b)
void SWDraw_ColouredCharacter (int x, int y, unsigned int num)
{
qbyte *source;
int drawline;
int row, col;
int colour;
if (y <= -8)
return; // totally off screen
if (y > vid.height - 8 || x < 0 || x > vid.width - 8)
return;
colour = (num&CON_COLOURMASK)/256;
if (num & CON_BLINKTEXT)
{
if ((int)(cl.time*2) & 1)
return;
}
if (colour == 0) //0 is white anyway (speedup)
{
Draw_Character(x, y, num);
return;
}
num &= 255;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
if (y < 0)
{ // clipped
drawline = 8 + y;
source -= 128*y;
y = 0;
}
else
drawline = 8;
if (r_pixbytes == 1)
{
qbyte *dest;
dest = vid.conbuffer + y*vid.conrowbytes + x;
while (drawline--)
{
if (source[0])
dest[0] = draw(source[0]);
if (source[1])
dest[1] = draw(source[1]);
if (source[2])
dest[2] = draw(source[2]);
if (source[3])
dest[3] = draw(source[3]);
if (source[4])
dest[4] = draw(source[4]);
if (source[5])
dest[5] = draw(source[5]);
if (source[6])
dest[6] = draw(source[6]);
if (source[7])
dest[7] = draw(source[7]);
source += 128;
dest += vid.conrowbytes;
}
}
else if (r_pixbytes == 2)
{
unsigned short *dest16;
unsigned char *pal = (unsigned char *)d_8to32table;
int i;
int rm, gm, bm;
dest16 = (unsigned short *)vid.conbuffer + y*vid.conrowbytes + x;
rm = consolecolours[colour].r*32;
gm = consolecolours[colour].g*32;
bm = consolecolours[colour].b*32;
while (drawline--)
{
for (i = 0; i < 8; i++)
{
if (source[i])
dest16[i] = ((pal[source[i]*4+0]*bm/256)<<10)+
((pal[source[i]*4+1]*gm/256)<<5)+
pal[source[i]*4+2]*rm/256;
}
/*
if (source[0])
dest16[0] = pal[draw(source[0])];
if (source[1])
dest16[1] = pal[draw(source[1])];
if (source[2])
dest16[2] = pal[draw(source[2])];
if (source[3])
dest16[3] = pal[draw(source[3])];
if (source[4])
dest16[4] = pal[draw(source[4])];
if (source[5])
dest16[5] = pal[draw(source[5])];
if (source[6])
dest16[6] = pal[draw(source[6])];
if (source[7])
dest16[7] = pal[draw(source[7])];
*/
source += 128;
dest16 += vid.conrowbytes;
}
}
else if (r_pixbytes == 4)
{
qbyte *dest;
int i;
unsigned char *pal = (unsigned char *)d_8to32table;
dest = vid.conbuffer + (y*vid.conrowbytes + x)*r_pixbytes;
while (drawline--)
{
for (i = 0; i < 8; i++)
{
if (source[i])
{
dest[0+i*4] = pal[source[i]*4+0]*consolecolours[colour].b;
dest[1+i*4] = pal[source[i]*4+1]*consolecolours[colour].g;
dest[2+i*4] = pal[source[i]*4+2]*consolecolours[colour].r;
}
}
source += 128;
dest += vid.conrowbytes*r_pixbytes;
}
}
}
#undef draw
/*
================
Draw_String
================
*/
void SWDraw_String (int x, int y, const qbyte *str)
{
while (*str)
{
Draw_Character (x, y, *str);
str++;
x += 8;
}
}
/*
================
Draw_Alt_String
================
*/
void SWDraw_Alt_String (int x, int y, const qbyte *str)
{
while (*str)
{
Draw_Character (x, y, (*str) | 0x80);
str++;
x += 8;
}
}
void SWDraw_Pixel(int x, int y, qbyte color)
{
qbyte *dest;
if (r_pixbytes == 1)
{
dest = vid.conbuffer + y*vid.conrowbytes + x;
*dest = color;
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
// FIXME: pre-expand to native format?
p32dest = ((unsigned int *)vid.conbuffer + y*vid.conrowbytes + x);
*p32dest = d_8to32table[color];
}
}
#include "crosshairs.dat"
qbyte *COM_LoadFile (char *path, int usehunk);
void SWDraw_Crosshair(void)
{
int x, y;
extern cvar_t crosshair, cl_crossx, cl_crossy, crosshaircolor;
extern vrect_t scr_vrect;
qbyte c = (qbyte)crosshaircolor.value;
qbyte c2 = (qbyte)crosshaircolor.value;
int sc;
for (sc = 0; sc < cl.splitclients; sc++)
{
SCR_CrosshairPosition(sc, &x, &y);
#define Pix(xp,yp,c) SWDraw_Pixel(x+xp, y+yp, c)
switch((int)crosshair.value)
{
case 0:
if (*crosshair.string>='a' && *crosshair.string<='z')
{
static qbyte *crosshairfile;
static int crosshairfilesize;
static char cachedcrosshairfile[64];
int fx, fy;
qbyte *f;
if (!strncmp(cachedcrosshairfile, crosshair.string, sizeof(cachedcrosshairfile)))
{
if (crosshairfile)
Z_Free(crosshairfile);
crosshairfile = COM_LoadFile(va("%s.csh", crosshair.string), 0);
crosshairfilesize = com_filesize;
Q_strncpyz(cachedcrosshairfile, crosshair.string, sizeof(cachedcrosshairfile));
}
f = crosshairfile;
if (!f)
return;
for (fy = 0; fy < 8; fy++)
{
for (fx = 0; fx < 8; )
{
if (f - crosshairfile > crosshairfilesize)
{
Con_Printf("Crosshair file has overrun");
fy=10;
break;
}
if (*f == 'x')
{
Pix(fx-3, fy-3, c);
fx++;
}
else if (*f == 'X')
{
Pix(fx-3, fy-3, c2);
fx++;
}
else if (*f == '0' || *f == 'o' || *f == 'O')
fx++;
f++;
}
}
}
break;
default:
case 1:
Draw_Character (
scr_vrect.x + scr_vrect.width/2-4 + cl_crossx.value,
scr_vrect.y + scr_vrect.height/2-4 + cl_crossy.value,
'+');
break;
#include "crosshairs.dat"
}
}
}
/*
================
Draw_DebugChar
Draws a single character directly to the upper right corner of the screen.
This is for debugging lockups by drawing different chars in different parts
of the code.
================
*/
void SWDraw_DebugChar (qbyte num)
{
qbyte *dest;
qbyte *source;
int drawline;
extern qbyte *draw_chars;
int row, col;
if (!vid.direct)
return; // don't have direct FB access, so no debugchars...
drawline = 8;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
dest = vid.direct + 312;
while (drawline--)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest[3] = source[3];
dest[4] = source[4];
dest[5] = source[5];
dest[6] = source[6];
dest[7] = source[7];
source += 128;
dest += 320;
}
}
/*
=============
Draw_Pic
=============
*/
void SWDraw_Pic (int x, int y, mpic_t *pic)
{
qbyte *dest, *source;
int v, u;
if (!pic)
return;
if (pic->flags & MPIC_ALPHA)
{
SWDraw_TransPic(x, y, pic);
return;
}
if ((x < 0) ||
(x + pic->width > vid.width) ||
(y < 0) ||
(y + pic->height > vid.height))
{
return;//Sys_Error ("Draw_Pic: bad coordinates");
}
source = pic->data;
if (r_pixbytes == 1)
{
dest = vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<pic->height ; v++)
{
Q_memcpy (dest, source, pic->width);
dest += vid.rowbytes;
source += pic->width;
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u++)
p32dest[u] = d_8to32table[source[u]];
p32dest += vid.rowbytes;
source += pic->width;
}
}
else if (r_pixbytes == 2)
{
unsigned short *p16dest;
p16dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u++)
p16dest[u] = d_8to16table[source[u]];
p16dest += vid.rowbytes;
source += pic->width;
}
}
}
/*
=============
Draw_SubPic
=============
*/
void SWDraw_TransSubPic(int x, int y, mpic_t *pic, int srcx, int srcy, int width, int height)
{
qbyte *dest, *source;
int v, u;
if ((x < 0) ||
(x + width > vid.width) ||
(y < 0) ||
(y + height > vid.height))
{
Sys_Error ("Draw_Pic: bad coordinates");
}
source = pic->data + srcy * pic->width + srcx;
if (r_pixbytes == 1)
{
qbyte tbyte;
dest = vid.buffer + y * vid.rowbytes + x;
if (pic->width & 7)
{ // general
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = tbyte;
dest += vid.rowbytes;
source += pic->width;
}
}
else
{ // unwound
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = tbyte;
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
dest[u+1] = tbyte;
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
dest[u+2] = tbyte;
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
dest[u+3] = tbyte;
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
dest[u+4] = tbyte;
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
dest[u+5] = tbyte;
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
dest[u+6] = tbyte;
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
dest[u+7] = tbyte;
}
dest += vid.rowbytes;
source += pic->width;
}
}
}
else if (r_pixbytes == 2)
{
unsigned short *p16dest;
p16dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<(width) ; u++)
p16dest[u] = d_8to16table[source[u]];
p16dest += vid.rowbytes;
source += pic->width;
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<(width) ; u++)
p32dest[u] = d_8to32table[source[u]];
p32dest += vid.rowbytes;
source += pic->width;
}
}
}
/*
=============
Draw_SubPic
=============
*/
void SWDraw_SubPic(int x, int y, mpic_t *pic, int srcx, int srcy, int width, int height)
{
qbyte *dest, *source;
int v, u;
if (pic->flags & MPIC_ALPHA)
{
SWDraw_TransSubPic(x, y, pic, srcx, srcy, width, height);
return;
}
if ((x < 0) ||
(x + width > vid.width) ||
(y < 0) ||
(y + height > vid.height))
{
Sys_Error ("Draw_Pic: bad coordinates");
}
source = pic->data + srcy * pic->width + srcx;
if (r_pixbytes == 1)
{
dest = vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<height ; v++)
{
Q_memcpy (dest, source, width);
dest += vid.rowbytes;
source += pic->width;
}
}
else if (r_pixbytes == 2)
{
unsigned short *p16dest;
p16dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<(width) ; u++)
p16dest[u] = d_8to16table[source[u]];
p16dest += vid.rowbytes;
source += pic->width;
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x;
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<(width) ; u++)
p32dest[u] = d_8to32table[source[u]];
p32dest += vid.rowbytes;
source += pic->width;
}
}
}
/*
=============
Draw_TransPic
=============
*/
void SWDraw_TransPic (int x, int y, mpic_t *pic)
{
qbyte *source, tbyte;
int v, u;
if (!pic)
return;
if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||
(unsigned)(y + pic->height) > vid.height)
{
return;
Sys_Error ("Draw_TransPic: bad coordinates");
}
source = pic->data;
if (r_pixbytes == 1)
{
qbyte *dest;
dest = vid.buffer + y * vid.rowbytes + x;
if (pic->width & 7)
{ // general
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = tbyte;
dest += vid.rowbytes;
source += pic->width;
}
}
else
{ // unwound
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = tbyte;
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
dest[u+1] = tbyte;
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
dest[u+2] = tbyte;
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
dest[u+3] = tbyte;
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
dest[u+4] = tbyte;
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
dest[u+5] = tbyte;
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
dest[u+6] = tbyte;
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
dest[u+7] = tbyte;
}
dest += vid.rowbytes;
source += pic->width;
}
}
}
else if (r_pixbytes == 2)
{
unsigned short *dest;
dest = (unsigned short *)vid.buffer + y * vid.rowbytes + x;
if (pic->width & 7)
{ // general
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = tbyte;
dest += vid.rowbytes;
source += pic->width;
}
}
else
{ // unwound
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = d_8to16table[tbyte];
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
dest[u+1] = d_8to16table[tbyte];
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
dest[u+2] = d_8to16table[tbyte];
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
dest[u+3] = d_8to16table[tbyte];
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
dest[u+4] = d_8to16table[tbyte];
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
dest[u+5] = d_8to16table[tbyte];
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
dest[u+6] = d_8to16table[tbyte];
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
dest[u+7] = d_8to16table[tbyte];
}
dest += vid.rowbytes;
source += pic->width;
}
}
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest = (unsigned int *)vid.buffer + y * vid.rowbytes + x;
if (pic->width & 7)
{ // general
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
p32dest[u] = d_8to32table[tbyte];
p32dest += vid.rowbytes;
source += pic->width;
}
}
else
{ // unwound
for (v=0 ; v<pic->height ; v++)
{
for (u=0 ; u<pic->width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
p32dest[u] = d_8to32table[tbyte];
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
p32dest[u+1] = d_8to32table[tbyte];
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
p32dest[u+2] = d_8to32table[tbyte];
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
p32dest[u+3] = d_8to32table[tbyte];
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
p32dest[u+4] = d_8to32table[tbyte];
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
p32dest[u+5] = d_8to32table[tbyte];
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
p32dest[u+6] = d_8to32table[tbyte];
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
p32dest[u+7] = d_8to32table[tbyte];
}
p32dest += vid.rowbytes;
source += pic->width;
}
}
}
}
/*
=============
Draw_TransPicTranslate
=============
*/
void SWDraw_TransPicTranslate (int x, int y, int width, int height, qbyte *source, qbyte *translation)
{
qbyte tbyte;
int v, u;
if (x < 0 || (unsigned)(x + width) > vid.width || y < 0 ||
(unsigned)(y + height) > vid.height)
{
Sys_Error ("Draw_TransPic: bad coordinates");
}
if (r_pixbytes == 1)
{
qbyte *dest;
dest = vid.buffer + y * vid.rowbytes + x;
if (width & 7)
{ // general
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = translation[tbyte];
dest += vid.rowbytes;
source += width;
}
}
else
{ // unwound
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
dest[u] = translation[tbyte];
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
dest[u+1] = translation[tbyte];
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
dest[u+2] = translation[tbyte];
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
dest[u+3] = translation[tbyte];
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
dest[u+4] = translation[tbyte];
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
dest[u+5] = translation[tbyte];
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
dest[u+6] = translation[tbyte];
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
dest[u+7] = translation[tbyte];
}
dest += vid.rowbytes;
source += width;
}
}
}
else if (r_pixbytes == 4)
{
unsigned int *puidest;
puidest = (unsigned int *)(vid.buffer + ((y * vid.rowbytes + x) << 2));
if (width & 7)
{ // general
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u++)
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
puidest[u] = d_8to32table[translation[tbyte]];
puidest += vid.rowbytes;
source += width;
}
}
else
{ // unwound
for (v=0 ; v<height ; v++)
{
for (u=0 ; u<width ; u+=8)
{
if ( (tbyte=source[u]) != TRANSPARENT_COLOR)
puidest[u] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR)
puidest[u+1] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR)
puidest[u+2] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR)
puidest[u+3] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR)
puidest[u+4] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR)
puidest[u+5] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR)
puidest[u+6] = d_8to32table[translation[tbyte]];
if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR)
puidest[u+7] = d_8to32table[translation[tbyte]];
}
puidest += vid.rowbytes;
source += width;
}
}
}
else
Sys_Error("draw_transpictranslate: r_pixbytes\n");
}
void SWDraw_CharToConback (int num, qbyte *dest)
{
int row, col;
qbyte *source;
int drawline;
int x;
row = num>>4;
col = num&15;
source = draw_chars + (row<<10) + (col<<3);
drawline = 8;
while (drawline--)
{
for (x=0 ; x<8 ; x++)
if (source[x])
dest[x] = 0x60 + source[x];
source += 128;
dest += 320;
}
}
void SWDraw_SubImage32(
int scx, int scy, int scwidth, int scheight, //screen
int six, int siy, int siwidth, int siheight, //sub image
int iwidth, int iheight, qbyte *in)
{
unsigned int *gamma = d_8to32table;
unsigned int *dest;
qbyte *src;
int v;
int f, fstep;
int x, y;
int outstride = vid.rowbytes;
dest = (unsigned int *)vid.buffer + scx + scy*outstride;
fstep = (siwidth<<16)/scwidth;
for (y=0 ; y<scheight ; y++, dest += outstride)
{
v = y*siheight/scheight;
src = in + (siy+v)*iwidth + six;
{
f = 0;
for (x=0; x < (scwidth&~3); x+=4) //cut down on loop stuff
{
if (src[(f>>16)] != 255)
{
dest[x] = gamma[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[1+x] = gamma[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[2+x] = gamma[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[3+x] = gamma[src[(f>>16)]];
}
f += fstep;
}
for (; x<scwidth; x+=1) //sw 32 bit rendering is bgrx
{
if (src[(f>>16)] != 255)
{
dest[x] = gamma[src[(f>>16)]];
}
f += fstep;
}
}
}
}
//blend in colour and alpha (still 8 bit source though)
void SWDraw_SubImageBlend32(
int scx, int scy, int scwidth, int scheight, //screen
int six, int siy, int siwidth, int siheight, //sub image
int iwidth, int iheight, qbyte *in, int red, int green, int blue, int alpha)
{
unsigned char *pal = (unsigned char *)d_8to32table;
unsigned char *dest;
qbyte *src;
int v;
int f, fstep;
int x, y;
int outstride = vid.rowbytes;
dest = (unsigned char *)vid.buffer + 4*(scx + scy*outstride);
fstep = (siwidth<<16)/scwidth;
for (y=0 ; y<scheight ; y++, dest += outstride*4)
{
v = y*siheight/scheight;
src = in + (siy+v)*iwidth + six;
{
f = 0;
for (x=0; x<scwidth<<2; x+=4) //sw 32 bit rendering is bgrx
{
if (src[(f>>16)] != 255)
{
dest[x + 0] = ((255-alpha)*dest[x + 0] + (blue*alpha*pal[(src[f>>16]<<2) + 0])/255)/255;
dest[x + 1] = ((255-alpha)*dest[x + 1] + (green*alpha*pal[(src[f>>16]<<2) + 1])/255)/255;
dest[x + 2] = ((255-alpha)*dest[x + 2] + (red*alpha*pal[(src[f>>16]<<2) + 2])/255)/255;
}
f += fstep;
}
}
}
}
void SWDraw_SubImage16(
int scx, int scy, int scwidth, int scheight, //screen
int six, int siy, int siwidth, int siheight, //sub image
int iwidth, int iheight, qbyte *in)
{
unsigned short *dest;
qbyte *src;
int v;
int f, fstep;
int x, y;
int outstride = vid.rowbytes;
dest = (unsigned short *)vid.buffer + scx + scy*outstride;
fstep = (siwidth<<16)/scwidth;
for (y=0 ; y<scheight ; y++, dest += outstride)
{
v = y*siheight/scheight;
src = in + (siy+v)*iwidth + six;
{
f = 0;
for (x=0; x < (scwidth&~3); x+=4) //cut down on loop stuff
{
if (src[(f>>16)] != 255)
{
dest[x] = d_8to16table[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[1+x] = d_8to16table[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[2+x] = d_8to16table[src[(f>>16)]];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[3+x] = d_8to16table[src[(f>>16)]];
}
f += fstep;
}
for (; x<scwidth; x+=1) //sw 32 bit rendering is bgrx
{
if (src[(f>>16)] != 255)
{
dest[x] = d_8to16table[src[(f>>16)]];
}
f += fstep;
}
}
}
}
void SWDraw_SubImage8(
int scx, int scy, int scwidth, int scheight, //screen
int six, int siy, int siwidth, int siheight, //sub image
int iwidth, int iheight, qbyte *in)
{
unsigned char *dest;
qbyte *src;
int v;
int f, fstep;
int x, y;
int outstride = vid.rowbytes;
dest = (unsigned char *)vid.buffer + scx + scy*outstride;
fstep = (siwidth<<16)/scwidth;
for (y=0 ; y<scheight ; y++, dest += outstride)
{
v = y*siheight/scheight;
src = in + (siy+v)*iwidth + six;
{
f = 0;
for (x=0; x < (scwidth&~3); x+=4) //cut down on loop stuff
{
if (src[(f>>16)] != 255)
{
dest[x] = src[(f>>16)];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[1+x] = src[(f>>16)];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[2+x] = src[(f>>16)];
}
f += fstep;
if (src[(f>>16)] != 255)
{
dest[3+x] = src[(f>>16)];
}
f += fstep;
}
for (; x<scwidth; x+=1) //sw 32 bit rendering is bgrx
{
if (src[(f>>16)] != 255)
{
dest[x] = src[(f>>16)];
}
f += fstep;
}
}
}
}
static qboolean SWDraw_Image_Blend;
static int SWDraw_Image_Red=1, SWDraw_Image_Green=1, SWDraw_Image_Blue=1, SWDraw_Image_Alpha=1;
void SWDraw_ImageColours (float r, float g, float b, float a) //like glcolour4f
{
SWDraw_Image_Red=r*255;
SWDraw_Image_Green=g*255;
SWDraw_Image_Blue=b*255;
SWDraw_Image_Alpha=a*255;
SWDraw_Image_Blend = r<1 || b<1 || g<1 || a<1;
}
void SWDraw_Image (float xp, float yp, float wp, float hp, float s1, float t1, float s2, float t2, mpic_t *pic)
{
float xend, yend, xratio, yratio;
if (!pic)
return;
xratio = pic->width / wp;
yratio = pic->height / hp;
// redefine borders
s2 = (s2-s1)*pic->width;
t2 = (t2-t1)*pic->height;
s1 = s1*pic->width;
t1 = t1*pic->height;
// clip left/top edge
if (xp < 0)
{
s1 -= xp * xratio;
s2 += xp * xratio;
wp += xp;
xp = 0;
}
if (yp < 0)
{
t1 -= yp * yratio;
t2 += yp * yratio;
hp += yp;
yp = 0;
}
// clip right/bottom edge
xend = xp+wp;
yend = yp+hp;
if (xend > vid.width)
{
xend -= vid.width;
s2 -= xend * xratio;
wp -= xend;
}
if (yend > vid.height)
{
yend -= vid.height;
t2 -= yend * yratio;
hp -= yend;
}
// bounds check...
if (s2 < 1)
s2 = 1;
if (t2 < 1)
t2 = 1;
if (wp < 1 || hp < 1 || s1 >= pic->width || t1 >= pic->height)
return;
// draw the pic
if (r_pixbytes == 1)
{
SWDraw_SubImage8(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data);
}
else if (r_pixbytes == 2)
{
SWDraw_SubImage16(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data);
}
else
{
if (SWDraw_Image_Blend) //blend it on
{
SWDraw_SubImageBlend32(xp, yp, wp, hp, s1, t1, s2, t2,
pic->width, pic->height, pic->data,
SWDraw_Image_Red, SWDraw_Image_Green, SWDraw_Image_Blue, SWDraw_Image_Alpha);
}
else //block colour (fast)
{
SWDraw_SubImage32(xp, yp, wp, hp, s1, t1, s2, t2, pic->width, pic->height, pic->data);
}
}
}
/*
================
Draw_ConsoleBackground
================
*/
void SWDraw_ConsoleBackground (int lines)
{
int x, y, v;
qbyte *src;
qbyte *dest;
int f, fstep;
mpic_t *conback;
char ver[100];
static char saveback[320*8];
conback = (mpic_t *)SWDraw_SafeCachePic ("gfx/conback.lmp");
if (!conback)
conback = (mpic_t *)SWDraw_SafeCachePic("pics/conback.pcx");
if (!conback)
conback = (mpic_t *)SWDraw_SafeCachePic ("gfx/menu/conback.lmp");
if (!conback)
{
swcachepic_t *cp;
for (cp=swmenu_cachepics, v=0 ; v<swmenu_numcachepics ; cp++, v++)
if (!strcmp ("gfx/conback", cp->name))
break;
conback = Cache_Alloc(&cp->cache, sizeof(mpic_t) + 320*200, cp->name);
conback->width = 320;
conback->height = 200;
conback->flags = 0;
}
if (lines > vid.conheight)
lines = vid.conheight;
// hack the version number directly into the pic
//sprintf (ver, "start commands with a \\ character %4.2f", VERSION);
sprintf (ver, "%4.2f", VERSION);
dest = conback->data + 320 + 320*186 - 11 - 8*strlen(ver);
memcpy(saveback, conback->data + 320*186, 320*8);
for (x=0 ; x<strlen(ver) ; x++)
SWDraw_CharToConback (ver[x], dest+(x<<3));
// draw the pic
if (r_pixbytes == 1)
{
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*200/vid.conheight;
src = conback->data + v*320;
if (vid.conwidth == 320)
memcpy (dest, src, vid.conwidth);
else
{
f = 0;
fstep = 320*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest[x] = src[f>>16];
f += fstep;
dest[x+1] = src[f>>16];
f += fstep;
dest[x+2] = src[f>>16];
f += fstep;
dest[x+3] = src[f>>16];
f += fstep;
}
}
}
}
else if (r_pixbytes == 2)
{
unsigned short *dest16 = (unsigned short *)vid.conbuffer;
unsigned short *pal = d_8to16table;
for (y=0 ; y<lines ; y++, dest16 += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*200/vid.conheight;
src = conback->data + v*320;
// if (vid.conwidth == 320)
// memcpy (dest16, src, vid.conwidth);
// else
{
f = 0;
fstep = 320*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest16[x] = pal[src[f>>16]];
f += fstep;
dest16[x+1] = pal[src[f>>16]];
f += fstep;
dest16[x+2] = pal[src[f>>16]];
f += fstep;
dest16[x+3] = pal[src[f>>16]];
f += fstep;
}
}
}
}
else
{
extern cvar_t d_smooth;
unsigned int *p24dest;
unsigned char *pal = (qbyte *)d_8to32table;
int alpha = ((float)(lines)/((vid.height * 3) >> 2))*255;
if (alpha > 255) alpha = 255;
p24dest = (unsigned int *)vid.conbuffer;
dest = (unsigned char *)vid.conbuffer;
if (d_smooth.value) //smoothed
{
qbyte *src2;
int f1, f2;
int vf, hf;
for (y=0 ; y<lines ; y++, dest += (vid.conrowbytes<<2))
{
v = (vid.conheight - lines + y)*199/vid.conheight;
src = conback->data + v*320;
v = (vid.conheight - lines + y)*199/vid.conheight+1;
src2 = conback->data + v*320;
v = (vid.conheight - lines + y)*199/vid.conheight;
vf = (((vid.conheight - lines + y)*199.0/vid.conheight) - v) * 255;
f = 0;
fstep = 319*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=1)
{
hf = (f - (f>>16)*65536) / 256;
f1 = ((255-hf) * pal[(src [f>>16]<<2) + 0] + hf * pal[(src [(f>>16)+1]<<2) + 0])/255;
f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 0] + hf * pal[(src2[(f>>16)+1]<<2) + 0])/255;
f1 = ((255-vf)*f1+vf*f2)/255;
dest[(x<<2) + 0] = ((255-alpha)*dest[(x<<2) + 0] + alpha*f1)/255;
f1 = ((255-hf) * pal[(src [f>>16]<<2) + 1] + hf * pal[(src [(f>>16)+1]<<2) + 1])/255;
f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 1] + hf * pal[(src2[(f>>16)+1]<<2) + 1])/255;
f1 = ((255-vf)*f1+vf*f2)/255;
dest[(x<<2) + 1] = ((255-alpha)*dest[(x<<2) + 1] + alpha*f1)/255;
f1 = ((255-hf) * pal[(src [f>>16]<<2) + 2] + hf * pal[(src [(f>>16)+1]<<2) + 2])/255;
f2 = ((255-hf) * pal[(src2[f>>16]<<2) + 2] + hf * pal[(src2[(f>>16)+1]<<2) + 2])/255;
f1 = ((255-vf)*f1+vf*f2)/255;
dest[(x<<2) + 2] = ((255-alpha)*dest[(x<<2) + 2] + alpha*f1)/255;
f += fstep;
}
}
}
else
if (alpha != 255) //blend it on
{
for (y=0 ; y<lines ; y++, dest += (vid.conrowbytes<<2))
{
v = (vid.conheight - lines + y)*200/vid.conheight;
src = conback->data + v*320;
f = 0;
fstep = 320*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=1)
{
dest[(x<<2) + 0] = ((255-alpha)*dest[(x<<2) + 0] + alpha*pal[(src[f>>16]<<2) + 0])/255;
dest[(x<<2) + 1] = ((255-alpha)*dest[(x<<2) + 1] + alpha*pal[(src[f>>16]<<2) + 1])/255;
dest[(x<<2) + 2] = ((255-alpha)*dest[(x<<2) + 2] + alpha*pal[(src[f>>16]<<2) + 2])/255;
f += fstep;
}
}
}
else //block colour (fast)
{
for (y=0 ; y<lines ; y++, p24dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*200/vid.conheight;
src = conback->data + v*320;
f = 0;
fstep = 320*0x10000/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
p24dest[x] = d_8to32table[src[f>>16]];
f += fstep;
p24dest[x+1] = d_8to32table[src[f>>16]];
f += fstep;
p24dest[x+2] = d_8to32table[src[f>>16]];
f += fstep;
p24dest[x+3] = d_8to32table[src[f>>16]];
f += fstep;
}
}
}
}
// put it back
memcpy(conback->data + 320*186, saveback, 320*8);
}
void SWDraw_EditorBackground (int lines)
{
SWDraw_ConsoleBackground (lines);
}
/*
==============
R_DrawRect8
==============
*/
void R_DrawRect8 (vrect_t *prect, int rowbytes, qbyte *psrc,
int transparent)
{
qbyte t;
int i, j, srcdelta, destdelta;
qbyte *pdest;
pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x;
srcdelta = rowbytes - prect->width;
destdelta = vid.rowbytes - prect->width;
if (transparent)
{
for (i=0 ; i<prect->height ; i++)
{
for (j=0 ; j<prect->width ; j++)
{
t = *psrc;
if (t != TRANSPARENT_COLOR)
{
*pdest = t;
}
psrc++;
pdest++;
}
psrc += srcdelta;
pdest += destdelta;
}
}
else
{
for (i=0 ; i<prect->height ; i++)
{
memcpy (pdest, psrc, prect->width);
psrc += rowbytes;
pdest += vid.rowbytes;
}
}
}
/*
==============
R_DrawRect16
==============
*/
void R_DrawRect16 (vrect_t *prect, int rowbytes, qbyte *psrc,
int transparent)
{
qbyte t;
int i, j, srcdelta, destdelta;
unsigned short *pdest;
// FIXME: would it be better to pre-expand native-format versions?
pdest = (unsigned short *)vid.buffer +
(prect->y * (vid.rowbytes)) + prect->x;
srcdelta = rowbytes - prect->width;
destdelta = (vid.rowbytes) - prect->width;
if (transparent)
{
for (i=0 ; i<prect->height ; i++)
{
for (j=0 ; j<prect->width ; j++)
{
t = *psrc;
if (t != TRANSPARENT_COLOR)
{
*pdest = d_8to16table[t];
}
psrc++;
pdest++;
}
psrc += srcdelta;
pdest += destdelta;
}
}
else
{
for (i=0 ; i<prect->height ; i++)
{
for (j=0 ; j<prect->width ; j++)
{
*pdest = d_8to16table[*psrc];
psrc++;
pdest++;
}
psrc += srcdelta;
pdest += destdelta;
}
}
}
void R_DrawRect32 (vrect_t *prect, int rowbytes, qbyte *psrc,
int transparent)
{
qbyte t;
int i, j, srcdelta, destdelta;
unsigned int *pdest;
// FIXME: would it be better to pre-expand native-format versions?
pdest = (unsigned int *)vid.buffer +
(prect->y * vid.rowbytes) + prect->x;
srcdelta = rowbytes - prect->width;
destdelta = vid.rowbytes - prect->width;
if (transparent)
{
for (i=0 ; i<prect->height ; i++)
{
for (j=0 ; j<prect->width ; j++)
{
t = *psrc;
if (t != TRANSPARENT_COLOR)
{
*pdest = d_8to32table[t];
}
psrc++;
pdest++;
}
psrc += srcdelta;
pdest += destdelta;
}
}
else
{
for (i=0 ; i<prect->height ; i++)
{
for (j=0 ; j<prect->width ; j++)
{
*pdest = d_8to32table[*psrc];
psrc++;
pdest++;
}
psrc += srcdelta;
pdest += destdelta;
}
}
}
/*
=============
Draw_TileClear
This repeats a 64*64 tile graphic to fill the screen around a sized down
refresh window.
=============
*/
void SWDraw_TileClear (int x, int y, int w, int h)
{
int width, height, tileoffsetx, tileoffsety;
qbyte *psrc;
vrect_t vr;
if (!r_rectdesc.height || !r_rectdesc.width)
return;
r_rectdesc.rect.x = x;
r_rectdesc.rect.y = y;
r_rectdesc.rect.width = w;
r_rectdesc.rect.height = h;
vr.y = r_rectdesc.rect.y;
height = r_rectdesc.rect.height;
tileoffsety = vr.y % r_rectdesc.height;
while (height > 0)
{
vr.x = r_rectdesc.rect.x;
width = r_rectdesc.rect.width;
if (tileoffsety != 0)
vr.height = r_rectdesc.height - tileoffsety;
else
vr.height = r_rectdesc.height;
if (vr.height > height)
vr.height = height;
tileoffsetx = vr.x % r_rectdesc.width;
while (width > 0)
{
if (tileoffsetx != 0)
vr.width = r_rectdesc.width - tileoffsetx;
else
vr.width = r_rectdesc.width;
if (vr.width > width)
vr.width = width;
psrc = r_rectdesc.ptexbytes +
(tileoffsety * r_rectdesc.rowbytes) + tileoffsetx;
if (r_pixbytes == 1)
{
R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0);
}
else if (r_pixbytes == 4)
{
R_DrawRect32 (&vr, r_rectdesc.rowbytes, psrc, 0);
}
else
{
R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0);
}
vr.x += vr.width;
width -= vr.width;
tileoffsetx = 0; // only the left tile can be left-clipped
}
vr.y += vr.height;
height -= vr.height;
tileoffsety = 0; // only the top tile can be top-clipped
}
}
/*
=============
Draw_Fill
Fills a box of pixels with a single color
=============
*/
void SWDraw_Fill (int x, int y, int w, int h, int c)
{
int u, v;
if (x < 0 || x + w > vid.width ||
y < 0 || y + h > vid.height) {
Con_Printf("Bad Draw_Fill(%d, %d, %d, %d, %c)\n",
x, y, w, h, c);
return;
}
if (r_pixbytes == 1)
{
qbyte *dest;
dest = vid.buffer + y*vid.rowbytes + x;
for (v=0 ; v<h ; v++, dest += vid.rowbytes)
for (u=0 ; u<w ; u++)
dest[u] = c;
}
else if (r_pixbytes == 4)
{
unsigned int *p32dest;
p32dest = (unsigned int*)vid.buffer + y*vid.rowbytes + x;
for (v=0 ; v<h ; v++, p32dest += vid.rowbytes)
for (u=0 ; u<w ; u++)
p32dest[u] = d_8to32table[c];
}
else if (r_pixbytes == 2)
{
unsigned short *p16dest;
p16dest = (unsigned short*)vid.buffer + y*vid.rowbytes + x;
for (v=0 ; v<h ; v++, p16dest += vid.rowbytes)
for (u=0 ; u<w ; u++)
p16dest[u] = d_8to16table[c];
}
}
//=============================================================================
/*
================
Draw_FadeScreen
================
*/
void SWDraw_FadeScreen (void)
{
int x,y;
VID_UnlockBuffer ();
S_ExtraUpdate ();
VID_LockBuffer ();
if (r_pixbytes == 4)
{
qbyte *pbuf;
for (y=0 ; y<vid.height ; y++)
{
pbuf = (qbyte *)((unsigned int *)vid.buffer + vid.rowbytes*y);
for (x=0 ; x<vid.width*4 ; x++)
{
pbuf[x] /= 1.7;
}
}
}
else if (r_pixbytes == 2)
{
unsigned short *pbuf;
for (y=0 ; y<vid.height ; y++)
{
int t;
pbuf = (unsigned short *)vid.buffer + vid.rowbytes*y;
t = (y & 1) << 1;
for (x=0 ; x<vid.width ; x++)
{
if ((x & 3) != t)
pbuf[x] = 0;
}
}
}
else
{
qbyte *pbuf;
for (y=0 ; y<vid.height ; y++)
{
int t;
pbuf = (qbyte *)(vid.buffer + vid.rowbytes*y);
t = (y & 1) << 1;
for (x=0 ; x<vid.width ; x++)
{
if ((x & 3) != t)
pbuf[x] = 0;
}
}
}
VID_UnlockBuffer ();
S_ExtraUpdate ();
VID_LockBuffer ();
}
void SWDraw_Box(int x1, int y1, int x2, int y2, int paletteindex, float alpha)
{
int x;
int y;
int w;
int h;
qbyte *dest;
unsigned int *puidest;
unsigned uc;
int u, v;
Set_TransLevelF(alpha);
if (t_state & TT_ZERO)
return;
if (x1 < x2)
{
x = x1;
w = x2-x1;
}
else
{
x = x2;
w = x1-x2;
}
if (y1 < y2)
{
y = y1;
h = y2-y1;
}
else
{
y = y2;
h = y1-y2;
}
if (x < 0 || x + w > vid.width ||
y < 0 || y + h > vid.height) {
Con_Printf("Bad SWDraw_Box(%d, %d, %d, %d, %i)\n",
x, y, w, h, paletteindex);
return;
}
if (r_pixbytes == 1)
{
if (t_state & TT_ONE)
{
dest = vid.buffer + y*vid.rowbytes + x;
for (v=0 ; v<h ; v++, dest += vid.rowbytes)
for (u=0 ; u<w ; u++)
dest[u] = paletteindex;
}
else
{
dest = vid.buffer + y*vid.rowbytes + x;
for (v=0 ; v<h ; v++, dest += vid.rowbytes)
for (u=0 ; u<w ; u++)
dest[u] = Trans(dest[u], paletteindex);
}
}
else if (r_pixbytes == 4)
{
uc = d_8to32table[paletteindex];
puidest = (unsigned int *)vid.buffer + y * (vid.rowbytes) + x;
for (v=0 ; v<h ; v++, puidest += vid.rowbytes)
for (u=0 ; u<w ; u++)
puidest[u] = uc;
}
}
//=============================================================================
/*
================
Draw_BeginDisc
Draws the little blue disc in the corner of the screen.
Call before beginning any disc IO.
================
*/
void SWDraw_BeginDisc (void)
{
if (draw_disc)
D_BeginDirectRect (vid.width - 24, 0, draw_disc->data, 24, 24);
}
/*
================
Draw_EndDisc
Erases the disc icon.
Call after completing any disc IO
================
*/
void SWDraw_EndDisc (void)
{
if (draw_disc)
D_EndDirectRect (vid.width - 24, 0, 24, 24);
}