fteqw/engine/sw/d_trans.c
Spoike 6e3f69f504 d3d rendering is diabled (framestate, read later - merged will compile just sw+gl for now).
fte particle scripts are disabled (classic works).
I'll fix these in the new year.
Redid framestate stuff again. Slightly better now, but this is the bulk of the changes here.
Reworked the renderqueue to provide batches of items instead of individual items. This cleans up the particle rendering code significantly, and is a step towards multiple concurrent particle systems. fte's scripted particles are broken as I'm trying to find a way to rework them to batch types together, rather than having to restart each batch after each particle when you have two particles in a trail. I'll fix it some time.
Reworked some alias model code regarding skeletal models. Added some conceptual skeletal bone control builtins available to csqc. Currently it can query the bone names and save off animation states, but can't animate - its just not complete.
Added more info to glsl custom shaders.
Updated surface sorting on halflife maps to properly cope with alphaed entities, rather than just texture-based blends (q2-style).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3095 fc73d0e0-1445-4013-8a0c-d673dee63da5
2008-12-23 02:55:20 +00:00

765 lines
18 KiB
C

//contains routines for blending images (as well as blitting 32bit to 8bit type stuff)
#include "quakedef.h"
#include "d_local.h"
#include "r_local.h"
void MakeVideoPalette(void);
void MakeSwizzledPalette(void);
void MakePaletteRemaps(void);
int *srctable;
int *dsttable;
qbyte *pal555to8;
int swzpal[TRANS_LEVELS][256];
// menutint
palremap_t *mtpalremap;
// IB remap
palremap_t *ib_remap;
#define palette host_basepal
#define _abs(x) ((x)*(x))
void D_ShutdownTrans(void)
{
if (pal555to8)
{
BZ_Free(pal555to8);
pal555to8 = NULL;
}
if (palremaps)
{
BZ_Free(palremaps);
palremapsize = 0;
palremaps = NULL;
}
mtpalremap = NULL;
ib_remap = NULL;
}
void D_InitTrans(void)
{
// create pal555to8 and swizzled palette
MakeVideoPalette();
MakeSwizzledPalette();
MakePaletteRemaps();
srctable = swzpal[0];
dsttable = swzpal[TRANS_MAX];
ib_remap = D_IdentityRemap();
}
// TODO: INLINE THESE FUNCTIONS
qbyte Trans(qbyte p, qbyte p2)
{
int x;
x = (srctable[p] + dsttable[p2]) | 0x01F07C1F;
return pal555to8[x & (x >> 15)];
}
qbyte AddBlend(qbyte p, qbyte p2)
{
unsigned int x, y;
x = (srctable[p] + dsttable[p2]);
y = x & 0x40100400; // overflow bits
x = (x | 0x01F07C1F) & 0x3FFFFFFF;
y = y - (y >> 5);
x = x | y;
return pal555to8[x & (x >> 15)];
}
/*
void Set_TransLevelI(int level)
{
t_curtable = level/(100.0f/(t_numtables-1));
t_curlookupp = t_lookup[t_curtable];
}
*/
void D_SetTransLevel(float level, blendmode_t blend)
{
int ilvl;
// cap and set level
ilvl = (bound(0, level, 1) * (TRANS_MAX + 0.99));
// set blending tables
switch (blend)
{
case BM_ADD:
dsttable = swzpal[ilvl];
srctable = swzpal[TRANS_MAX];
break;
default:
dsttable = swzpal[ilvl];
srctable = swzpal[TRANS_MAX - ilvl];
}
}
#define _abs(x) ((x)*(x))
qbyte FindIndexFromRGB(int red, int green, int blue)
{
int i, best=15;
int bestdif=256*256*256, curdif;
extern qbyte *host_basepal;
qbyte *pa;
pa = host_basepal;
for (i = 0; i < 256; i++, pa+=3)
{
curdif = _abs(red - pa[0]) + _abs(green - pa[1]) + _abs(blue - pa[2]);
if (curdif < bestdif)
{
if (curdif<1)
return i;
bestdif = curdif;
best = i;
}
}
return best;
}
qbyte FindIndexFromRGBNoFB(int red, int green, int blue)
{
int i, best=15;
int bestdif=256*256*256, curdif;
extern qbyte *host_basepal;
qbyte *pa;
pa = host_basepal;
for (i = 0; i < 256 - vid.fullbright; i++, pa+=3)
{
curdif = _abs(red - pa[0]) + _abs(green - pa[1]) + _abs(blue - pa[2]);
if (curdif < bestdif)
{
if (curdif<1)
return i;
bestdif = curdif;
best = i;
}
}
return best;
}
#define FindPalette(r,g,b) pal555to8[((r&0xF8)>>3)|((g&0xF8)<<2)|((b&0xF8)<<7)]
qbyte GetPaletteIndex(int red, int green, int blue)
{
if (pal555to8) //fast precalculated method
return FindPalette(red,green,blue);
else //slow, horrible method.
return FindIndexFromRGB(red, green, blue);
}
qbyte GetPaletteNoFB(int red, int green, int blue)
{
if (pal555to8) //fast precalculated (but ugly) method
return fbremapidx(FindPalette(red,green,blue));
else //slow, horrible (but accurate) method.
return FindIndexFromRGBNoFB(red, green, blue);
}
void MakeVideoPalette(void)
{
vfsfile_t *f;
int r, g, b;
// allocate memory
if (!pal555to8)
pal555to8 = BZ_Malloc(PAL555_SIZE);
// pal555to8 = Hunk_AllocName(PAL555_SIZE, "RGB data");
// load in previously created table
if ((f = FS_OpenVFS("pal555.pal", "rb", FS_GAME)))
{
VFS_READ(f, pal555to8, PAL555_SIZE);
VFS_CLOSE(f);
return;
}
// create palette conversion table
for (b = 0; b < 32; b++)
for (g = 0; g < 32; g++)
for (r = 0; r < 32; r++)
pal555to8[r | (g << 5) | (b << 10)] =
FindIndexFromRGB(r<<3|r>>2, g<<3|g>>2, b<<3|b>>2);
// write palette conversion table
if (d_palconvwrite.value)
COM_WriteFile("pal555.pal", pal555to8, PAL555_SIZE);
}
void MakeSwizzledPalette(void)
{
int idx, lvl;
qbyte *pa;
// create swizzled palettes
for (lvl = 0; lvl < TRANS_LEVELS; lvl++)
{
pa = host_basepal;
for (idx = 0; idx < 256; idx++)
{
// create a b10r10g10 table for each alpha level
// may need some hacking due to the tendancy of
// identity merges becoming darker
swzpal[lvl][idx] = ( (pa[0] * lvl) >> 4 ) << 10; // red
swzpal[lvl][idx] |= ( (pa[1] * lvl) >> 4 ); // green
swzpal[lvl][idx] |= ( (pa[2] * lvl) >> 4 ) << 20; // blue
swzpal[lvl][idx] = swzpal[lvl][idx] & 0x3feffbff;
pa += 3;
}
}
}
// colormap functions
// REMAPKEY macro defines the palette remap key
// d = desaturate (0/1), f = fullbrights (0/1), t = top color, b = bottom color
#define REMAPKEY(d, f, t, b) (0x1 ^ (d<<1) ^ (f<<2) ^ (t<<3) ^ (b<<7))
#define DEREFDEFAULT -2147483647 // lowest negative 32-bit number (without MSVC being stupid)
void MakePaletteRemaps(void)
{
int i;
palremapsize = d_palremapsize.value;
if (palremapsize < 4)
{
Con_Printf("Invalid size for d_palremapsize, defaulting to 4.\n");
palremapsize = 4;
}
palremaps = BZ_Malloc(sizeof(palremap_t)*palremapsize);
// build identity remap
palremaps[0].r = palremaps[0].g = palremaps[0].b = 255;
palremaps[0].key = REMAPKEY(0, 1, TOP_DEFAULT, BOTTOM_DEFAULT);
palremaps[0].references = 999;
for (i = 0; i < 256; i++)
palremaps[0].pal[i] = i;
// build fullbright remap
palremaps[1].r = palremaps[1].g = palremaps[1].b = 255;
palremaps[1].key = REMAPKEY(0, 0, TOP_DEFAULT, BOTTOM_DEFAULT);
palremaps[1].references = 999;
for (i = 0; i < 256 - vid.fullbright; i++)
palremaps[1].pal[i] = i;
for (i = 256 - vid.fullbright; i < 256; i++)
palremaps[1].pal[i] = FindIndexFromRGBNoFB(host_basepal[i*3], host_basepal[i*3+1], host_basepal[i*3+2]);
for (i = 2; i < palremapsize; i++)
{
palremaps[i].key = 0;
palremaps[i].references = DEREFDEFAULT;
}
}
void BuildModulatedPalette(qbyte *indexes, int red, int green, int blue, qboolean desaturate, qboolean fullbrights, int topcolor, int bottomcolor)
{
qbyte *rgb = host_basepal;
unsigned int r, g, b, x, invmask = 0;
if (red < 0 || green < 0 || blue < 0)
invmask = 0xff;
// generate palette remap
if (desaturate)
{
int s;
for (x = 0; x < 256; x++)
{
s = rgb[0]*76 + rgb[1]*151 + rgb[2]*29 + 128;
r = abs((127*256 + s*red) >> 16);
g = abs((127*256 + s*green) >> 16);
b = abs((127*256 + s*blue) >> 16);
if (r > 255)
r = 255;
if (g > 255)
g = 255;
if (b > 255)
b = 255;
if (fullbrights) // relying on branch prediction here...
indexes[x] = GetPaletteIndex(r^invmask, g^invmask, b^invmask);
else
indexes[x] = GetPaletteNoFB(r^invmask, g^invmask, b^invmask);
rgb += 3;
}
}
else if (red == 255 && green == 255 && blue == 255)
{
// identity merge
if (fullbrights)
memcpy(indexes, identityremap.pal, sizeof(identityremap.pal));
else
memcpy(indexes, fullbrightremap.pal, sizeof(fullbrightremap.pal));
}
else
{
for (x = 0; x < 256; x++)
{
// modulus math
r = abs((127 + rgb[0]*red) >> 8);
g = abs((127 + rgb[1]*green) >> 8);
b = abs((127 + rgb[2]*blue) >> 8);
if (r > 255)
r = 255;
if (g > 255)
g = 255;
if (b > 255)
b = 255;
if (fullbrights) // relying on branch prediction here...
indexes[x] = GetPaletteIndex(r^invmask, g^invmask, b^invmask);
else
indexes[x] = GetPaletteNoFB(r^invmask, g^invmask, b^invmask);
rgb += 3;
}
}
// handle top/bottom remap
if (topcolor == TOP_DEFAULT && bottomcolor == BOTTOM_DEFAULT)
return;
{
qbyte topcolors[16];
qbyte bottomcolors[16];
topcolor = topcolor * 16;
bottomcolor = bottomcolor * 16;
for (x = 0; x < 16; x++)
{
if (topcolor < 128)
topcolors[x] = indexes[topcolor + x];
else
topcolors[x] = indexes[topcolor + 15 - x];
if (bottomcolor < 128)
bottomcolors[x] = indexes[bottomcolor + x];
else
bottomcolors[x] = indexes[bottomcolor + 15 - x];
}
for (x = 0; x < 16; x++)
{
indexes[TOP_RANGE + x] = topcolors[x];
indexes[BOTTOM_RANGE + x] = bottomcolors[x];
}
}
}
palremap_t *D_GetPaletteRemap(int red, int green, int blue, qboolean desaturate, qboolean fullbrights, int topcolor, int bottomcolor)
{
int i, key, deref = -1, dereflast = 1;
topcolor = topcolor & 0xf;
bottomcolor = bottomcolor & 0xf;
key = REMAPKEY(desaturate, fullbrights, topcolor, bottomcolor);
for (i = 0; i < palremapsize; i++)
{
if (palremaps[i].r == red &&
palremaps[i].g == green &&
palremaps[i].b == blue &&
palremaps[i].key == key)
{
if (palremaps[i].references < 1)
palremaps[i].references = 1;
else
palremaps[i].references++;
return palremaps + i;
}
else if (palremaps[i].references < dereflast)
{
deref = i;
dereflast = palremaps[i].references;
}
}
if (deref < 2) // no remaps found and all maps are referenced
return palremaps; // identity remap
// return non-referenced map
BuildModulatedPalette(palremaps[deref].pal, red, green, blue, desaturate, fullbrights, topcolor, bottomcolor);
if (palremaps[deref].references < 1)
palremaps[deref].references = 1;
else
palremaps[deref].references++;
palremaps[deref].r = red;
palremaps[deref].g = green;
palremaps[deref].b = blue;
palremaps[deref].key = key;
return palremaps + deref;
}
palremap_t *RebuildMenuTint(struct cvar_s *var)
{
vec3_t rgb;
if (var->string[0])
SCR_StringToRGB(var->string, rgb, 1);
else
return NULL;
return D_GetPaletteRemap(rgb[0]*255, rgb[1]*255, rgb[2]*255, true, true, TOP_DEFAULT, BOTTOM_DEFAULT);
}
void D_DereferenceRemap(palremap_t *palremap)
{
static int dereftime;
if (palremap && palremap >= palremaps+2)
{
if (palremap->references < 2)
{
if (dereftime >= 0)
dereftime = DEREFDEFAULT;
palremap->references = dereftime;
dereftime++;
}
else
palremap->references--;
}
}
void SWR_Menutint_Callback(struct cvar_s *var, char *oldvalue)
{
if (mtpalremap)
D_DereferenceRemap(mtpalremap);
mtpalremap = RebuildMenuTint(var);
}
qbyte *D_GetMenuTintPal(void)
{
if (mtpalremap && mtpalremap != palremaps)
return mtpalremap->pal;
else
return NULL;
}
struct palremap_s *D_IdentityRemap(void) // TODO: explicitly inline this
{
return palremaps;
}
#undef REMAPKEY
#undef DEREFDEFAULT
void MediaSW_ShowFrame8bit(qbyte *framedata, int inwidth, int inheight, qbyte *palette)
{
int y, x;
D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
if (r_pixbytes == 1)
{
qbyte *dest, *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth;
{
f = 0;
fstep = (inwidth<<16)/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest[x] = FindPalette(palette[src[(f>>16)]*3], palette[src[(f>>16)]*3+1], palette[src[(f>>16)]*3+2]);
f += fstep;
dest[x+1] = FindPalette(palette[src[(f>>16)]*3], palette[src[(f>>16)]*3+1], palette[src[(f>>16)]*3+2]);
f += fstep;
dest[x+2] = FindPalette(palette[src[(f>>16)]*3], palette[src[(f>>16)]*3+1], palette[src[(f>>16)]*3+2]);
f += fstep;
dest[x+3] = FindPalette(palette[src[(f>>16)]*3], palette[src[(f>>16)]*3+1], palette[src[(f>>16)]*3+2]);
f += fstep;
}
}
}
}
else if (r_pixbytes == 2)
{
/* this still expects 32bit input
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
unsigned short *dest;
qbyte *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = (unsigned short *)vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth*4;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth; x++) //sw 32 bit rendering is bgrx
{
dest[x] = (((src[(f>>16)*4]*(1<<redbits))/256)<<redshift) + (((src[(f>>16)*4+1]*(1<<greenbits))/256)<<greenshift) + (((src[(f>>16)*4+2]*(1<<bluebits))/256)<<blueshift);
f += fstep;
}
}
}
*/
}
else if (r_pixbytes == 4)
{
qbyte *dest, *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes*4)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth*4 ; x+=4) //sw 32 bit rendering is bgrx
{
dest[x] = palette[src[(f>>16)]*3+2];
dest[x+1] = palette[src[(f>>16)]*3+1];
dest[x+2] = palette[src[(f>>16)]*3];
f += fstep;
}
}
}
}
else
Sys_Error("24 bit rendering?");
D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
M_Draw(0);
}
void MediaSW_ShowFrameRGBA_32(qbyte *framedata, int inwidth, int inheight) //top down
{
int y, x;
D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
if (r_pixbytes == 1)
{
qbyte *dest, *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth*4;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest[x] = FindPalette(src[(f>>16)*4], src[(f>>16)*4+1], src[(f>>16)*4+2]);
f += fstep;
dest[x+1] = FindPalette(src[(f>>16)*4], src[(f>>16)*4+1], src[(f>>16)*4+2]);
f += fstep;
dest[x+2] = FindPalette(src[(f>>16)*4], src[(f>>16)*4+1], src[(f>>16)*4+2]);
f += fstep;
dest[x+3] = FindPalette(src[(f>>16)*4], src[(f>>16)*4+1], src[(f>>16)*4+2]);
f += fstep;
}
}
}
}
else if (r_pixbytes == 2)
{
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
unsigned short *dest;
qbyte *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = (unsigned short *)vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth*4;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth; x++) //sw 32 bit rendering is bgrx
{
dest[x] = (((src[(f>>16)*4]*(1<<redbits))/256)<<redshift) + (((src[(f>>16)*4+1]*(1<<greenbits))/256)<<greenshift) + (((src[(f>>16)*4+2]*(1<<bluebits))/256)<<blueshift);
f += fstep;
}
}
}
}
else if (r_pixbytes == 4)
{
qbyte *dest, *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes*4)
{
v = (vid.conheight - lines + y)*inheight/vid.conheight;
src = framedata + v*inwidth*4;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth*4 ; x+=4) //sw 32 bit rendering is bgrx
{
dest[x] = src[(f>>16)*4+2];
dest[x+1] = src[(f>>16)*4+1];
dest[x+2] = src[(f>>16)*4];
f += fstep;
}
}
}
}
else
Sys_Error("24 bit rendering?");
D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
}
void MediaSW_ShowFrameBGR_24_Flip(qbyte *framedata, int inwidth, int inheight) //input is bottom up...
{
int y, x;
D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
if (r_pixbytes == 1)
{
qbyte *dest, *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (lines - y)*inheight/vid.conheight;
src = framedata + v*inwidth*3;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x+=4)
{
dest[x] = FindPalette(src[(f>>16)*3+2], src[(f>>16)*3+1], src[(f>>16)*3]);
f += fstep;
dest[x+1] = FindPalette(src[(f>>16)*3+2], src[(f>>16)*3+1], src[(f>>16)*3]);
f += fstep;
dest[x+2] = FindPalette(src[(f>>16)*3+2], src[(f>>16)*3+1], src[(f>>16)*3]);
f += fstep;
dest[x+3] = FindPalette(src[(f>>16)*3+2], src[(f>>16)*3+1], src[(f>>16)*3]);
f += fstep;
}
}
}
}
else if (r_pixbytes == 2)
{
extern int redbits, redshift;
extern int greenbits, greenshift;
extern int bluebits, blueshift;
unsigned short *dest;
qbyte *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = (unsigned short *)vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (lines - y)*inheight/vid.conheight;
src = framedata + v*inwidth*3;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth; x++) //sw 32 bit rendering is bgrx
{
dest[x] = (((src[(f>>16)*3+2]*(1<<redbits))/256)<<redshift) + (((src[(f>>16)*3+1]*(1<<greenbits))/256)<<greenshift) + (((src[(f>>16)*3+0]*(1<<bluebits))/256)<<blueshift);
f += fstep;
}
}
}
}
else if (r_pixbytes == 4)
{
unsigned int *dest;
qbyte *src;
int lines=vid.conheight;
int v;
int f, fstep;
dest = (unsigned int *)vid.conbuffer;
for (y=0 ; y<lines ; y++, dest += vid.conrowbytes)
{
v = (lines - y)*inheight/vid.conheight;
src = framedata + v*inwidth*3;
{
f = 0;
fstep = ((inwidth)*0x10000)/vid.conwidth;
for (x=0 ; x<vid.conwidth ; x++) //sw 32 bit rendering is bgrx
{
*(dest+x) = *(int *)(src + (f>>16)*3);
f += fstep;
}
}
}
}
else
Sys_Error("24 bit rendering?");
D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
SCR_SetUpToDrawConsole();
if (scr_con_current)
SCR_DrawConsole (false);
}