fix some nq-server issues.

make trying to close the window shut down properly while debugging.
added r_softwarebanding cvar to approximate 8bit software rendering.
fix issue with invalid skeletal lerps.
external q3 lightmaps now uses IF_NOMIPMAP and respects gl_lightmap_nearest.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4838 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-02-07 22:34:22 +00:00
parent 052cba731d
commit 09196f3d14
26 changed files with 384 additions and 106 deletions

View file

@ -635,7 +635,7 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
news->u.q1.msec = 0; news->u.q1.msec = 0;
} }
if (!(predbits & UFP_VIEWANGLE) || (cls.fteprotocolextensions2 & PEXT2_PREDINFO)) if (!(predbits & UFP_VIEWANGLE) || !(cls.fteprotocolextensions2 & PEXT2_PREDINFO))
{ {
news->u.q1.vangle[0] = ANGLE2SHORT(news->angles[0]); news->u.q1.vangle[0] = ANGLE2SHORT(news->angles[0]);
news->u.q1.vangle[1] = ANGLE2SHORT(news->angles[1]); news->u.q1.vangle[1] = ANGLE2SHORT(news->angles[1]);

View file

@ -4028,7 +4028,9 @@ void CL_ParseStatic (int version)
// copy it to the current state // copy it to the current state
ent->model = cl.model_precache[es.modelindex]; ent->model = cl.model_precache[es.modelindex];
memset(&ent->framestate, 0, sizeof(ent->framestate));
ent->framestate.g[FS_REG].frame[0] = ent->framestate.g[FS_REG].frame[1] = es.frame; ent->framestate.g[FS_REG].frame[0] = ent->framestate.g[FS_REG].frame[1] = es.frame;
ent->framestate.g[FS_REG].lerpweight[0] = 1;
ent->skinnum = es.skinnum; ent->skinnum = es.skinnum;
ent->drawflags = es.hexen2flags; ent->drawflags = es.hexen2flags;

View file

@ -2813,6 +2813,8 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla
switch(mips->encoding) switch(mips->encoding)
{ {
case PTI_R8:
return;
case PTI_RGBA8: case PTI_RGBA8:
case PTI_RGBX8: case PTI_RGBX8:
case PTI_BGRA8: case PTI_BGRA8:
@ -3296,9 +3298,39 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, uploadfmt_t orig
return; //blurgh return; //blurgh
//if that format isn't supported/desired, try converting it. //if that format isn't supported/desired, try converting it.
if (sh_config.texfmt[PTI_RGBX8]) if (sh_config.texfmt[mips->encoding])
return; return;
if (mips->encoding == PTI_R8)
{
if (sh_config.texfmt[PTI_BGRX8]) //bgra8 is typically faster when supported.
mips->encoding = PTI_BGRX8;
else if (sh_config.texfmt[PTI_BGRX8])
mips->encoding = PTI_RGBX8;
else if (sh_config.texfmt[PTI_BGRA8])
mips->encoding = PTI_BGRA8;
else
mips->encoding = PTI_RGBA8;
for (mip = 0; mip < mips->mipcount; mip++)
{
unsigned int i;
unsigned int *out;
unsigned char *in;
in = mips->mip[mip].data;
out = BZ_Malloc(mips->mip[mip].width*mips->mip[mip].height*sizeof(*out));
for (i = 0; i < mips->mip[mip].width*mips->mip[mip].height; i++)
out[i] = in[i] * 0x01010101;
if (mips->mip[mip].needfree)
BZ_Free(in);
mips->mip[mip].data = out;
mips->mip[mip].needfree = true;
mips->mip[mip].datasize = mips->mip[mip].width*mips->mip[mip].height*sizeof(*out);
}
if (sh_config.texfmt[mips->encoding])
return;
}
//should we just use 5551 always? //should we just use 5551 always?
if (mips->encoding == PTI_RGBX8 || mips->encoding == PTI_BGRX8) if (mips->encoding == PTI_RGBX8 || mips->encoding == PTI_BGRX8)
{ {
@ -3318,6 +3350,7 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, uploadfmt_t orig
} }
} }
else*/ else*/
if (sh_config.texfmt[PTI_RGB565])
{ {
for (mip = 0; mip < mips->mipcount; mip++) for (mip = 0; mip < mips->mipcount; mip++)
Image_8888to565(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8); Image_8888to565(mips->mip[mip].data, mips->mip[mip].data, mips->mip[mip].width, mips->mip[mip].height, mips->encoding == PTI_BGRX8);
@ -3410,6 +3443,9 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_BGRA32: case TF_BGRA32:
mips->encoding = PTI_BGRA8; mips->encoding = PTI_BGRA8;
break; break;
case TF_LUM8:
mips->encoding = PTI_R8;
break;
case TF_SOLID8: case TF_SOLID8:
rgbadata = BZ_Malloc(imgwidth * imgheight*4); rgbadata = BZ_Malloc(imgwidth * imgheight*4);
if (sh_config.texfmt[PTI_BGRX8]) if (sh_config.texfmt[PTI_BGRX8])
@ -4184,6 +4220,7 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
pb = 4*256; pb = 4*256;
b = 1; b = 1;
break; break;
case TF_LUM8:
case TF_SOLID8: case TF_SOLID8:
case TF_TRANS8: case TF_TRANS8:
case TF_TRANS8_FULLBRIGHT: case TF_TRANS8_FULLBRIGHT:

View file

@ -2691,6 +2691,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_
ent.playerindex = -1; ent.playerindex = -1;
ent.skinnum = mods->skingroup; ent.skinnum = mods->skingroup;
ent.shaderTime = realtime; ent.shaderTime = realtime;
ent.framestate.g[FS_REG].lerpweight[0] = 1;
ent.framestate.g[FS_REG].frame[0] = mods->framegroup; ent.framestate.g[FS_REG].frame[0] = mods->framegroup;
ent.framestate.g[FS_REG].frametime[0] = realtime - mods->framechangetime; ent.framestate.g[FS_REG].frametime[0] = realtime - mods->framechangetime;
ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime; ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;

View file

@ -16,7 +16,8 @@ typedef enum
SKEL_RELATIVE, //relative to parent. SKEL_RELATIVE, //relative to parent.
SKEL_ABSOLUTE, //relative to model. doesn't blend very well. SKEL_ABSOLUTE, //relative to model. doesn't blend very well.
SKEL_INVERSE_RELATIVE, //pre-inverted. faster than regular relative but has weirdness with skeletal objects. blends okay. SKEL_INVERSE_RELATIVE, //pre-inverted. faster than regular relative but has weirdness with skeletal objects. blends okay.
SKEL_INVERSE_ABSOLUTE //final renderable type. SKEL_INVERSE_ABSOLUTE, //final renderable type.
SKEL_IDENTITY //PANIC
} skeltype_t; } skeltype_t;
#ifdef HALFLIFEMODELS #ifdef HALFLIFEMODELS
@ -274,6 +275,9 @@ struct pendingtextureinfo
//floating point formats //floating point formats
PTI_RGBA16F, PTI_RGBA16F,
PTI_RGBA32F, PTI_RGBA32F,
//small formats.
PTI_R8,
PTI_RG8,
//compressed formats //compressed formats
PTI_S3RGB1, PTI_S3RGB1,
PTI_S3RGBA1, PTI_S3RGBA1,
@ -341,11 +345,12 @@ typedef struct
} srect_t; } srect_t;
typedef struct texnums_s { typedef struct texnums_s {
texid_t base; texid_t base; //regular diffuse texture. may have alpha if surface is transparent
texid_t bump; texid_t bump; //normalmap. height values packed in alpha.
texid_t specular; texid_t specular; //specular lighting values.
texid_t upperoverlay; texid_t upperoverlay; //diffuse texture for the upper body(shirt colour). no alpha channel. added to base.rgb
texid_t loweroverlay; texid_t loweroverlay; //diffuse texture for the lower body(trouser colour). no alpha channel. added to base.rgb
texid_t paletted; //8bit paletted data, just because.
texid_t fullbright; texid_t fullbright;
} texnums_t; } texnums_t;

View file

@ -2712,6 +2712,11 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
csqc_deprecated("runplayerphysics with no ent"); csqc_deprecated("runplayerphysics with no ent");
return; return;
} }
if (ent->readonly)
{
csqc_deprecated("runplayerphysics called on read-only entity");
return;
}
if (!cl.worldmodel) if (!cl.worldmodel)
return; //urm.. return; //urm..

View file

@ -322,6 +322,7 @@ extern qboolean msg_suppress_1; // suppresses resolution and cache size consol
#if !defined(SERVERONLY) && !defined(CLIENTONLY) #if !defined(SERVERONLY) && !defined(CLIENTONLY)
extern qboolean isDedicated; extern qboolean isDedicated;
#endif #endif
extern qboolean wantquit; //flagged if we want to force a quit, safely breaking out of any modal stuff

View file

@ -50,6 +50,7 @@ extern cvar_t r_stains;
extern cvar_t r_loadlits; extern cvar_t r_loadlits;
extern cvar_t r_stainfadetime; extern cvar_t r_stainfadetime;
extern cvar_t r_stainfadeammount; extern cvar_t r_stainfadeammount;
extern cvar_t gl_lightmap_nearest;
static int lightmap_shift; static int lightmap_shift;
int Surf_LightmapShift (model_t *model) int Surf_LightmapShift (model_t *model)
@ -2607,7 +2608,7 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe)
Q_snprintfz(nname, sizeof(nname), filepattern, i - numlightmaps); Q_snprintfz(nname, sizeof(nname), filepattern, i - numlightmaps);
TEXASSIGN(lightmap[i]->lightmap_texture, R_LoadHiResTexture(nname, NULL, 0)); TEXASSIGN(lightmap[i]->lightmap_texture, R_LoadHiResTexture(nname, NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
if (lightmap[i]->lightmap_texture->status == TEX_LOADING) if (lightmap[i]->lightmap_texture->status == TEX_LOADING)
COM_WorkerPartialSync(lightmap[i]->lightmap_texture, &lightmap[i]->lightmap_texture->status, TEX_LOADING); COM_WorkerPartialSync(lightmap[i]->lightmap_texture, &lightmap[i]->lightmap_texture->status, TEX_LOADING);
lightmap[i]->width = lightmap[i]->lightmap_texture->width; lightmap[i]->width = lightmap[i]->lightmap_texture->width;

View file

@ -127,6 +127,7 @@ cvar_t r_part_rain = CVARFD ("r_part_rain", "0",
"Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects."); "Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects.");
cvar_t r_skyboxname = SCVARF ("r_skybox", "", cvar_t r_skyboxname = SCVARF ("r_skybox", "",
CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM); CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
cvar_t r_softwarebanding = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM | CVAR_RENDERERLATCH, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
cvar_t r_speeds = SCVAR ("r_speeds", "0"); cvar_t r_speeds = SCVAR ("r_speeds", "0");
cvar_t r_stainfadeammount = SCVAR ("r_stainfadeammount", "1"); cvar_t r_stainfadeammount = SCVAR ("r_stainfadeammount", "1");
cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1"); cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1");
@ -622,6 +623,7 @@ void Renderer_Init(void)
Cvar_Register (&r_mirroralpha, GLRENDEREROPTIONS); Cvar_Register (&r_mirroralpha, GLRENDEREROPTIONS);
Cvar_Register (&r_skyboxname, GRAPHICALNICETIES); Cvar_Register (&r_skyboxname, GRAPHICALNICETIES);
Cbuf_AddText("alias sky r_skybox\n", RESTRICT_LOCAL); /*alternative name for users*/ Cbuf_AddText("alias sky r_skybox\n", RESTRICT_LOCAL); /*alternative name for users*/
Cvar_Register (&r_softwarebanding, GRAPHICALNICETIES);
Cvar_Register(&r_dodgytgafiles, "Bug fixes"); Cvar_Register(&r_dodgytgafiles, "Bug fixes");
Cvar_Register(&r_dodgypcxfiles, "Bug fixes"); Cvar_Register(&r_dodgypcxfiles, "Bug fixes");

View file

@ -2037,6 +2037,7 @@ void Sys_SendKeyEvents (void)
HANDLE input = GetStdHandle(STD_INPUT_HANDLE); HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
if (!PeekNamedPipe(input, NULL, 0, NULL, &avail, NULL)) if (!PeekNamedPipe(input, NULL, 0, NULL, &avail, NULL))
{ {
wantquit = true;
Cmd_ExecuteString("quit force", RESTRICT_LOCAL); Cmd_ExecuteString("quit force", RESTRICT_LOCAL);
} }
else if (avail) else if (avail)

View file

@ -622,6 +622,20 @@ const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *sourcedat
sourcedata = dest; sourcedata = dest;
sourcetype = SKEL_INVERSE_ABSOLUTE; sourcetype = SKEL_INVERSE_ABSOLUTE;
} }
if (sourcetype == SKEL_IDENTITY)
{ //we can 'convert' identity matricies to anything. but we only want to do this when everything else is bad, because there really is no info here
float *dest = (sourcedata == destbuffer)?destbufferalt:destbuffer;
memset(dest, 0, bonecount*12*sizeof(float));
for (i = 0; i < bonecount; i++)
{ //is this right? does it matter?
dest[i*12+0] = 1;
dest[i*12+5] = 1;
dest[i*12+10] = 1;
}
sourcedata = dest;
sourcetype = desttype; //panic
}
if (sourcetype != desttype) if (sourcetype != desttype)
Sys_Error("Alias_ConvertBoneData: %i->%i not supported\n", (int)sourcetype, (int)desttype); Sys_Error("Alias_ConvertBoneData: %i->%i not supported\n", (int)sourcetype, (int)desttype);
@ -1137,6 +1151,9 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion
galiasgroup_t *g; galiasgroup_t *g;
unsigned int b; unsigned int b;
float totalweight = 0; float totalweight = 0;
lerps->skeltype = SKEL_IDENTITY; //sometimes nothing else is valid.
for (b = 0; b < FRAME_BLENDS; b++) for (b = 0; b < FRAME_BLENDS; b++)
{ {
if (fs->lerpweight[b]) if (fs->lerpweight[b])
@ -1165,7 +1182,7 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion
frame2=(frame2>g->numposes-1)?g->numposes-1:frame2; frame2=(frame2>g->numposes-1)?g->numposes-1:frame2;
} }
if (!l) if (lerps->skeltype == SKEL_IDENTITY)
lerps->skeltype = g->skeltype; lerps->skeltype = g->skeltype;
else if (lerps->skeltype != g->skeltype) else if (lerps->skeltype != g->skeltype)
continue; //oops, can't cope with mixed blend types continue; //oops, can't cope with mixed blend types
@ -1685,6 +1702,12 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
meshcache.ent = e; meshcache.ent = e;
#ifdef _DEBUG
if (!e->framestate.g[FS_REG].lerpweight[0] && !e->framestate.g[FS_REG].lerpweight[1] && !e->framestate.g[FS_REG].lerpweight[2] && !e->framestate.g[FS_REG].lerpweight[3])
Con_Printf("Entity with no lerp info\n");
#endif
#ifndef SERVERONLY #ifndef SERVERONLY
mesh->trneighbors = inf->ofs_trineighbours; mesh->trneighbors = inf->ofs_trineighbours;
mesh->normals_array = meshcache.norm; mesh->normals_array = meshcache.norm;

View file

@ -104,6 +104,7 @@ qboolean static_registered = true; // only for startup check, then set
qboolean msg_suppress_1 = false; qboolean msg_suppress_1 = false;
int isPlugin; //if 2, we qcdebug to external program int isPlugin; //if 2, we qcdebug to external program
qboolean wantquit;
void COM_Path_f (void); void COM_Path_f (void);
void COM_Dir_f (void); void COM_Dir_f (void);
@ -5018,6 +5019,8 @@ void COM_Init (void)
{ {
qbyte swaptest[2] = {1,0}; qbyte swaptest[2] = {1,0};
wantquit = false;
// set the qbyte swapping variables in a portable manner // set the qbyte swapping variables in a portable manner
if ( *(short *)swaptest == 1) if ( *(short *)swaptest == 1)
{ {

View file

@ -112,7 +112,7 @@ void QCLoadBreakpoints(const char *vmname, const char *progsname)
printf("qcreloaded \"%s\" \"%s\"\n", vmname, progsname); printf("qcreloaded \"%s\" \"%s\"\n", vmname, progsname);
fflush(stdout); fflush(stdout);
INS_UpdateGrabs(false, false); INS_UpdateGrabs(false, false);
while(debuggerresume == -1) while(debuggerresume == -1 && !wantquit)
{ {
Sleep(10); Sleep(10);
Sys_SendKeyEvents(); Sys_SendKeyEvents();
@ -236,6 +236,7 @@ qboolean QCExternalDebuggerCommand(char *text)
if (sv.state) if (sv.state)
Cbuf_AddText("restart\n", RESTRICT_LOCAL); Cbuf_AddText("restart\n", RESTRICT_LOCAL);
#endif #endif
Host_EndGame("Reloading QC");
} }
else if (!strncmp(text, "qcbreakpoint ", 13)) else if (!strncmp(text, "qcbreakpoint ", 13))
{ {
@ -273,6 +274,8 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
#if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL) #if defined(_WIN32) && !defined(SERVERONLY) && !defined(FTE_SDL)
if (isPlugin >= 2) if (isPlugin >= 2)
{ {
if (wantquit)
return DEBUG_TRACE_ABORT;
if (!*filename || !line || !*line) //don't try editing an empty line, it won't work if (!*filename || !line || !*line) //don't try editing an empty line, it won't work
return DEBUG_TRACE_OFF; return DEBUG_TRACE_OFF;
Sys_SendKeyEvents(); Sys_SendKeyEvents();
@ -295,7 +298,7 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
Con_Footerf(false, "^bDebugging: %s", reason); Con_Footerf(false, "^bDebugging: %s", reason);
else else
Con_Footerf(false, "^bDebugging"); Con_Footerf(false, "^bDebugging");
while(debuggerresume == -1) while(debuggerresume == -1 && !wantquit)
{ {
Sleep(10); Sleep(10);
Sys_SendKeyEvents(); Sys_SendKeyEvents();
@ -316,6 +319,8 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
*line = debuggerresumeline; *line = debuggerresumeline;
debuggerinstance = NULL; debuggerinstance = NULL;
debuggerfile = NULL; debuggerfile = NULL;
if (wantquit)
return DEBUG_TRACE_ABORT;
return debuggerresume; return debuggerresume;
} }
#endif #endif

View file

@ -1163,6 +1163,12 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
else else
t = missing_texture; t = missing_texture;
break; break;
case T_GEN_PALETTED:
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->paletted))
t = shaderstate.curtexnums->paletted;
else
t = missing_texture;
break;
case T_GEN_NORMALMAP: case T_GEN_NORMALMAP:
t = (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->bump))?shaderstate.curtexnums->bump:missing_texture_normal; t = (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->bump))?shaderstate.curtexnums->bump:missing_texture_normal;
break; break;
@ -5171,6 +5177,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
#endif #endif
shaderstate.identitylighting = 1; shaderstate.identitylighting = 1;
shaderstate.identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival); shaderstate.identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
shaderstate.identitylightmap =1;
#ifdef RTLIGHTS #ifdef RTLIGHTS
if (r_lightprepass.ival) if (r_lightprepass.ival)

View file

@ -233,16 +233,16 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
} }
else else
{ {
if ((filter[1] && !(flags & IF_NEAREST)) || (flags & IF_LINEAR)) if ((filter[1]))// && !(flags & IF_NEAREST)) || (flags & IF_LINEAR))
{ {
if (filter[0]) if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR))
min = GL_LINEAR_MIPMAP_LINEAR; min = GL_LINEAR_MIPMAP_LINEAR;
else else
min = GL_NEAREST_MIPMAP_LINEAR; min = GL_NEAREST_MIPMAP_LINEAR;
} }
else else
{ {
if (filter[0]) if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR))
min = GL_LINEAR_MIPMAP_NEAREST; min = GL_LINEAR_MIPMAP_NEAREST;
else else
min = GL_NEAREST_MIPMAP_NEAREST; min = GL_NEAREST_MIPMAP_NEAREST;
@ -448,7 +448,7 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips)
if (targ != GL_TEXTURE_CUBE_MAP_ARB && (tex->flags & IF_MIPCAP)) if (targ != GL_TEXTURE_CUBE_MAP_ARB && (tex->flags & IF_MIPCAP))
{ {
qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, min(mips->mipcount-1, gl_mipcap_min)); qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, min(mips->mipcount-1, gl_mipcap_min));
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, min(mips->mipcount, gl_mipcap_max)); qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, min(mips->mipcount-1, gl_mipcap_max));
} }
} }

View file

@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern cvar_t r_shadow_bumpscale_basetexture; extern cvar_t r_shadow_bumpscale_basetexture;
extern cvar_t r_replacemodels; extern cvar_t r_replacemodels;
extern cvar_t gl_lightmap_average; extern cvar_t gl_lightmap_average;
extern cvar_t r_softwarebanding;
cvar_t mod_loadentfiles = CVAR("sv_loadentfiles", "1"); cvar_t mod_loadentfiles = CVAR("sv_loadentfiles", "1");
cvar_t mod_external_vis = CVARD("mod_external_vis", "1", "Attempt to load .vis patches for quake maps, allowing transparent water to work properly."); cvar_t mod_external_vis = CVARD("mod_external_vis", "1", "Attempt to load .vis patches for quake maps, allowing transparent water to work properly.");
cvar_t mod_warnmodels = CVARD("mod_warnmodels", "1", "Warn if any models failed to load. Set to 0 if your mod is likely to lack optional models (like its in development)."); //set to 0 for hexen2 and its otherwise-spammy-as-heck demo. cvar_t mod_warnmodels = CVARD("mod_warnmodels", "1", "Warn if any models failed to load. Set to 0 if your mod is likely to lack optional models (like its in development)."); //set to 0 for hexen2 and its otherwise-spammy-as-heck demo.
@ -1397,6 +1398,7 @@ void Mod_FinishTexture(texture_t *tx)
#define LMT_FULLBRIGHT 2 #define LMT_FULLBRIGHT 2
#define LMT_BUMP 4 #define LMT_BUMP 4
#define LMT_SPEC 8 #define LMT_SPEC 8
#define LMT_PALETTED 16
static void Mod_LoadMiptex(model_t *loadmodel, char *loadname, texture_t *tx, miptex_t *mt, int maps) static void Mod_LoadMiptex(model_t *loadmodel, char *loadname, texture_t *tx, miptex_t *mt, int maps)
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
@ -1455,6 +1457,12 @@ static void Mod_LoadMiptex(model_t *loadmodel, char *loadname, texture_t *tx, mi
mipheight = tx->height; mipheight = tx->height;
} }
if (maps & LMT_PALETTED)
{
snprintf(altname, sizeof(altname)-1, "%s_pal", mt->name);
tx->texnums.paletted = R_LoadReplacementTexture(altname, loadname, ((*mt->name == '{')?0:IF_NOALPHA)|IF_MIPCAP|IF_NEAREST, mipbase, mipwidth, mipheight, TF_LUM8);
}
if (maps & LMT_DIFFUSE) if (maps & LMT_DIFFUSE)
{ {
tx->texnums.base = R_LoadReplacementTexture(mt->name, loadname, ((*mt->name == '{')?0:IF_NOALPHA)|IF_MIPCAP, mipbase, mipwidth, mipheight, (*mt->name == '{')?TF_TRANS8:TF_SOLID8); tx->texnums.base = R_LoadReplacementTexture(mt->name, loadname, ((*mt->name == '{')?0:IF_NOALPHA)|IF_MIPCAP, mipbase, mipwidth, mipheight, (*mt->name == '{')?TF_TRANS8:TF_SOLID8);
@ -1580,7 +1588,11 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
#ifndef SERVERONLY #ifndef SERVERONLY
if (qrenderer != QR_NONE) if (qrenderer != QR_NONE)
{ {
maps |= LMT_DIFFUSE; //FIXME: we really need to handle this stuff better, but the shader isn't known yet.
if (r_softwarebanding.ival)
maps |= LMT_PALETTED;
// else
maps |= LMT_DIFFUSE;
if (r_fb_bmodels.ival) if (r_fb_bmodels.ival)
maps |= LMT_FULLBRIGHT; maps |= LMT_FULLBRIGHT;
if (r_loadbumpmapping || (r_waterstyle.ival > 1 && *tx->name == '*')) if (r_loadbumpmapping || (r_waterstyle.ival > 1 && *tx->name == '*'))

View file

@ -48,7 +48,7 @@ sh_config_t sh_config;
cvar_t r_vertexlight = CVARFD("r_vertexlight", "0", CVAR_SHADERSYSTEM, "Hack loaded shaders to remove detail pass and lightmap sampling for faster rendering."); cvar_t r_vertexlight = CVARFD("r_vertexlight", "0", CVAR_SHADERSYSTEM, "Hack loaded shaders to remove detail pass and lightmap sampling for faster rendering.");
extern cvar_t r_glsl_offsetmapping_reliefmapping; extern cvar_t r_glsl_offsetmapping_reliefmapping;
extern cvar_t r_deluxemapping; extern cvar_t r_deluxemapping;
extern cvar_t r_fastturb, r_fastsky, r_skyboxname; extern cvar_t r_fastturb, r_fastsky, r_skyboxname, r_softwarebanding;
extern cvar_t r_drawflat; extern cvar_t r_drawflat;
extern cvar_t r_shaderblobs; extern cvar_t r_shaderblobs;
@ -652,6 +652,26 @@ static int Shader_SetImageFlags(shader_t *shader, shaderpass_t *pass, char **nam
return flags; return flags;
} }
texid_t R_LoadColourmapImage(void)
{
unsigned int w = 256, h = VID_GRADES-1;
unsigned int x;
unsigned int data[256*(VID_GRADES-1)];
qbyte *colourmappal = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", NULL);
if (colourmappal)
{
for (x = 0; x < sizeof(data)/sizeof(data[0]); x++)
data[x] = d_8to24rgbtable[colourmappal[x]];
}
else
{ //erk
for (x = 0; x < sizeof(data)/sizeof(data[0]); x++)
data[x] = d_8to24rgbtable[x & 0xff];
}
BZ_Free(colourmappal);
return R_LoadTexture("$colourmap", w, h, TF_RGBA32, data, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA|IF_CLAMP);
}
static texid_t Shader_FindImage ( char *name, int flags ) static texid_t Shader_FindImage ( char *name, int flags )
{ {
if (parsestate.mode == SPM_DOOM3) if (parsestate.mode == SPM_DOOM3)
@ -670,6 +690,8 @@ static texid_t Shader_FindImage ( char *name, int flags )
{ {
if (!Q_stricmp (name, "$whiteimage")) if (!Q_stricmp (name, "$whiteimage"))
return r_whiteimage; return r_whiteimage;
if (!Q_stricmp (name, "$colourmap"))
return R_LoadColourmapImage();
} }
if (flags & IF_RENDERTARGET) if (flags & IF_RENDERTARGET)
return R2D_RT_Configure(name, 0, 0, TF_INVALID); return R2D_RT_Configure(name, 0, 0, TF_INVALID);
@ -2068,6 +2090,11 @@ static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *t
pass->texgen = T_GEN_DIFFUSE; pass->texgen = T_GEN_DIFFUSE;
shader->flags |= SHADER_HASDIFFUSE; shader->flags |= SHADER_HASDIFFUSE;
} }
else if (!Q_stricmp (tname, "$paletted"))
{
pass->texgen = T_GEN_PALETTED;
shader->flags |= SHADER_HASPALETTED;
}
else if (!Q_stricmp (tname, "$normalmap")) else if (!Q_stricmp (tname, "$normalmap"))
{ {
pass->texgen = T_GEN_NORMALMAP; pass->texgen = T_GEN_NORMALMAP;
@ -3797,6 +3824,9 @@ done:;
if (pass->texgen != T_GEN_ANIMMAP && pass->texgen != T_GEN_SINGLEMAP && pass->texgen != T_GEN_VIDEOMAP) if (pass->texgen != T_GEN_ANIMMAP && pass->texgen != T_GEN_SINGLEMAP && pass->texgen != T_GEN_VIDEOMAP)
weight += 1000; weight += 1000;
if ((pass->texgen == T_GEN_ANIMMAP || pass->texgen == T_GEN_SINGLEMAP) && pass->anim_frames[0] && *pass->anim_frames[0]->ident == '$')
weight += 1500;
if (weight < bestweight) if (weight < bestweight)
{ {
@ -4042,6 +4072,17 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
TEXASSIGN(shader->defaulttextures.base, tn->base); TEXASSIGN(shader->defaulttextures.base, tn->base);
} }
if (!TEXVALID(shader->defaulttextures.paletted))
{
/*dlights/realtime lighting needs some stuff*/
// if (!TEXVALID(tn->paletted) && *shader->mapname)// && (shader->flags & SHADER_HASDIFFUSE))
// tn->paletted = R_LoadHiResTexture(shader->mapname, NULL, 0);
// if (!TEXVALID(tn->paletted))
// tn->paletted = R_LoadHiResTexture(imagename, subpath, (*imagename=='{')?0:IF_NOALPHA);
TEXASSIGN(shader->defaulttextures.paletted, tn->paletted);
}
COM_StripExtension(imagename, imagename, sizeof(imagename)); COM_StripExtension(imagename, imagename, sizeof(imagename));
if (!TEXVALID(shader->defaulttextures.bump)) if (!TEXVALID(shader->defaulttextures.bump))
@ -4667,6 +4708,34 @@ void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args)
); );
} }
if (!builtin && r_softwarebanding.ival)
{
/*alpha bended*/
builtin = (
"{\n"
"program defaultwall#EIGHTBIT\n"
"{\n"
"map $paletted\n"//$diffuse\n"
"}\n"
"{\n"
"map $lightmap\n"
"}\n"
"{\n"
"map $normalmap\n"
"}\n"
"{\n"
"map $deluxmap\n"
"}\n"
"{\n"
"map $colourmap\n"//$fullbright\n"
"}\n"
"{\n"
"map $specular\n"
"}\n"
"}\n"
);
}
if (builtin) if (builtin)
Shader_DefaultScript(shortname, s, builtin); Shader_DefaultScript(shortname, s, builtin);
else else

View file

@ -2255,6 +2255,7 @@ LONG WINAPI GLMainWndProc (
MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
{ {
Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); Cbuf_AddText("\nquit\n", RESTRICT_LOCAL);
wantquit = true;
} }
break; break;

View file

@ -1057,9 +1057,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef LIGHTSTYLED\n" "#ifdef LIGHTSTYLED\n"
//we could use an offset, but that would still need to be per-surface which would break batches //we could use an offset, but that would still need to be per-surface which would break batches
//fixme: merge attributes? //fixme: merge attributes?
"varying vec2 lm, lm2, lm3, lm4;\n" "varying vec2 lm0, lm1, lm2, lm3;\n"
"#else\n" "#else\n"
"varying vec2 lm;\n" "varying vec2 lm0;\n"
"#endif\n" "#endif\n"
"#ifdef VERTEX_SHADER\n" "#ifdef VERTEX_SHADER\n"
@ -1085,11 +1085,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n" "eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n"
"#endif\n" "#endif\n"
"tc = v_texcoord;\n" "tc = v_texcoord;\n"
"lm = v_lmcoord;\n" "lm0 = v_lmcoord;\n"
"#ifdef LIGHTSTYLED\n" "#ifdef LIGHTSTYLED\n"
"lm2 = v_lmcoord2;\n" "lm1 = v_lmcoord2;\n"
"lm3 = v_lmcoord3;\n" "lm2 = v_lmcoord3;\n"
"lm4 = v_lmcoord4;\n" "lm3 = v_lmcoord4;\n"
"#endif\n" "#endif\n"
"gl_Position = ftetransform();\n" "gl_Position = ftetransform();\n"
"}\n" "}\n"
@ -1097,28 +1097,44 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef FRAGMENT_SHADER\n" "#ifdef FRAGMENT_SHADER\n"
//samplers //samplers
"uniform sampler2D s_t0; //diffuse\n" "#define s_diffuse s_t0\n"
"uniform sampler2D s_t1; //lightmap0\n" "#define s_lightmap0 s_t1\n"
"#define s_normalmap s_t2\n"
"#define s_delux0 s_t3\n"
"#define s_fullbright s_t4\n"
"#define s_specular s_t5\n"
"#define s_lightmap1 s_t6\n"
"#define s_lightmap2 s_t7\n"
"#define s_lightmap3 s_t8\n"
"#define s_delux1 s_t9\n"
"#define s_delux2 s_t10\n"
"#define s_delux3 s_t11\n"
"#define s_paletted s_diffuse\n"
"#define s_colourmap s_fullbright\n"
"uniform sampler2D s_diffuse;\n"
"uniform sampler2D s_lightmap0;\n"
"#if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR))\n" "#if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR))\n"
"uniform sampler2D s_t2; //normal.rgb+height.a\n" "uniform sampler2D s_normalmap;\n"
"#endif\n" "#endif\n"
"#ifdef DELUXE\n" "#ifdef DELUXE\n"
"uniform sampler2D s_t3; //deluxe0\n" "uniform sampler2D s_delux0;\n"
"#endif\n" "#endif\n"
"#ifdef FULLBRIGHT\n" "#if defined(FULLBRIGHT) || defined(EIGHTBIT)\n"
"uniform sampler2D s_t4; //fullbright\n" "uniform sampler2D s_fullbright;\n"
"#endif\n" "#endif\n"
"#ifdef SPECULAR\n" "#ifdef SPECULAR\n"
"uniform sampler2D s_t5; //specular\n" "uniform sampler2D s_specular;\n"
"#endif\n" "#endif\n"
"#ifdef LIGHTSTYLED\n" "#ifdef LIGHTSTYLED\n"
"uniform sampler2D s_t6; //lightmap1\n" "uniform sampler2D s_lightmap1;\n"
"uniform sampler2D s_t7; //lightmap2\n" "uniform sampler2D s_lightmap2;\n"
"uniform sampler2D s_t8; //lightmap3\n" "uniform sampler2D s_lightmap3;\n"
"uniform sampler2D s_t9; //deluxe1\n" "uniform sampler2D s_delux1;\n"
"uniform sampler2D s_t10; //deluxe2\n" "uniform sampler2D s_delux2;\n"
"uniform sampler2D s_t11; //deluxe3\n" "uniform sampler2D s_delux3;\n"
"#endif\n" "#endif\n"
"#ifdef LIGHTSTYLED\n" "#ifdef LIGHTSTYLED\n"
@ -1137,15 +1153,24 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"{\n" "{\n"
//adjust texture coords for offsetmapping //adjust texture coords for offsetmapping
"#ifdef OFFSETMAPPING\n" "#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_t2, tc, eyevector);\n" "vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);\n"
"#define tc tcoffsetmap\n" "#define tc tcoffsetmap\n"
"#endif\n" "#endif\n"
"#if defined(EIGHTBIT) && !defined(LIGHTSTYLED)\n"
//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise.
//don't bother if its lightstyled, such cases will have unpredictable correlations anyway.
//FIXME: this rounding is likely not correct with respect to software rendering. oh well.
"vec2 lmcoord0 = floor(lm0 * 256.0*8.0)/(256.0*8.0);\n"
"#define lm0 lmcoord0\n"
"#endif\n"
//yay, regular texture! //yay, regular texture!
"gl_FragColor = texture2D(s_t0, tc);\n" "gl_FragColor = texture2D(s_diffuse, tc);\n"
"#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR))\n" "#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR))\n"
"vec3 norm = normalize(texture2D(s_t2, tc).rgb - 0.5);\n" "vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);\n"
"#elif defined(SPECULAR) || defined(DELUXE)\n" "#elif defined(SPECULAR) || defined(DELUXE)\n"
"vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n" "vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.\n"
"#endif\n" "#endif\n"
@ -1154,29 +1179,30 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#ifdef LIGHTSTYLED\n" "#ifdef LIGHTSTYLED\n"
"vec3 lightmaps;\n" "vec3 lightmaps;\n"
"#ifdef DELUXE\n" "#ifdef DELUXE\n"
"lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb * dot(norm, texture2D(s_t3, lm ).rgb);\n" "lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_delux0, lm0).rgb-0.5);\n"
"lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb * dot(norm, texture2D(s_t9, lm2).rgb);\n" "lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_delux1, lm1).rgb-0.5);\n"
"lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb * dot(norm, texture2D(s_t10, lm3).rgb);\n" "lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_delux2, lm2).rgb-0.5);\n"
"lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb * dot(norm, texture2D(s_t11,lm4).rgb);\n" "lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_delux3, lm3).rgb-0.5);\n"
"#else\n" "#else\n"
"lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb;\n" "lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb;\n"
"lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb;\n" "lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb;\n"
"lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb;\n" "lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb;\n"
"lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb;\n" "lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb;\n"
"#endif\n" "#endif\n"
"#else\n" "#else\n"
"vec3 lightmaps = (texture2D(s_t1, lm) * e_lmscale).rgb;\n" "vec3 lightmaps = (texture2D(s_lightmap0, lm0) * e_lmscale).rgb;\n"
//modulate by the bumpmap dot light //modulate by the bumpmap dot light
"#ifdef DELUXE\n" "#ifdef DELUXE\n"
"lightmaps *= dot(norm, 2.0*(texture2D(s_t3, lm).rgb-0.5));\n" "lightmaps *= dot(norm, 2.0*(texture2D(s_delux0, lm0).rgb-0.5));\n"
"#endif\n" "#endif\n"
"#endif\n" "#endif\n"
//add in specular, if applicable.
"#ifdef SPECULAR\n" "#ifdef SPECULAR\n"
"vec4 specs = texture2D(s_t5, tc);\n" "vec4 specs = texture2D(s_specular, tc);\n"
"#ifdef DELUXE\n" "#ifdef DELUXE\n"
//not lightstyled... //not lightstyled...
"vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_t3, lm).rgb-0.5)); //this norm should be the deluxemap info instead\n" "vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_delux0, lm).rgb-0.5)); //this norm should be the deluxemap info instead\n"
"#else\n" "#else\n"
"vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead\n" "vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead\n"
"#endif\n" "#endif\n"
@ -1189,13 +1215,23 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"gl_FragColor.rgb += spec * specs.rgb;\n" "gl_FragColor.rgb += spec * specs.rgb;\n"
"#endif\n" "#endif\n"
"#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.\n"
"lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.\n"
"float pal = texture2D(s_diffuse, tc).r; //the palette index. hopefully not interpolated.\n"
"lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest\n"
"gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n"
"gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.\n"
"gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.\n"
"#else\n"
//now we have our diffuse+specular terms, modulate by lightmap values. //now we have our diffuse+specular terms, modulate by lightmap values.
"gl_FragColor.rgb *= lightmaps.rgb;\n" "gl_FragColor.rgb *= lightmaps.rgb;\n"
//add on the fullbright //add on the fullbright
"#ifdef FULLBRIGHT\n" "#ifdef FULLBRIGHT\n"
"gl_FragColor.rgb += texture2D(s_t4, tc).rgb;\n" "gl_FragColor.rgb += texture2D(s_fullbright, tc).rgb;\n"
"#endif\n" "#endif\n"
"#endif\n"
//entity modifiers //entity modifiers
"gl_FragColor = gl_FragColor * e_colourident;\n" "gl_FragColor = gl_FragColor * e_colourident;\n"

View file

@ -255,6 +255,7 @@ typedef struct shaderpass_s {
T_GEN_UPPEROVERLAY, //texture's default personal colour T_GEN_UPPEROVERLAY, //texture's default personal colour
T_GEN_LOWEROVERLAY, //texture's default team colour T_GEN_LOWEROVERLAY, //texture's default team colour
T_GEN_FULLBRIGHT, //texture's default fullbright overlay T_GEN_FULLBRIGHT, //texture's default fullbright overlay
T_GEN_PALETTED, //texture's original paletted data (8bit)
T_GEN_CURRENTRENDER,//copy the current screen to a texture, and draw that T_GEN_CURRENTRENDER,//copy the current screen to a texture, and draw that
@ -544,6 +545,7 @@ struct shader_s
SHADER_NOSHADOWS = 1 << 25, //don't cast shadows SHADER_NOSHADOWS = 1 << 25, //don't cast shadows
SHADER_HASFULLBRIGHT = 1 << 26, //needs a fullbright texture, if possible. SHADER_HASFULLBRIGHT = 1 << 26, //needs a fullbright texture, if possible.
SHADER_HASDIFFUSE = 1 << 27, //has a T_GEN_DIFFUSE pass SHADER_HASDIFFUSE = 1 << 27, //has a T_GEN_DIFFUSE pass
SHADER_HASPALETTED = 1 << 28, //has a T_GEN_PALETTED pass
} flags; } flags;
program_t *prog; program_t *prog;

View file

@ -8614,6 +8614,19 @@ static void QCBUILTIN PF_globalstat(pubprogfuncs_t *prinst, struct globalvars_s
#endif #endif
} }
//void(float num, float type, void *ptr) pointerstat
static void QCBUILTIN PF_pointerstat(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int num = G_FLOAT(OFS_PARM0);
int type = G_FLOAT(OFS_PARM1);
int addr = G_INT(OFS_PARM2);
int size = (type == ev_vector)?sizeof(vec3_t):sizeof(float);
if (addr < 0 || addr+size >= prinst->stringtablesize)
prinst->RunError(prinst, "QCVM address %#x is not valid.", addr);
else
SV_QCStatPtr(type, prinst->stringtable+addr, num);
}
//EXT_CSQC_1 //EXT_CSQC_1
static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
@ -8624,6 +8637,13 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
extern cvar_t sv_gravity; extern cvar_t sv_gravity;
edict_t *ent = G_EDICT(prinst, OFS_PARM0); edict_t *ent = G_EDICT(prinst, OFS_PARM0);
edict_t *touched; edict_t *touched;
if (ent->readonly)
{
Con_Printf("runplayerphysics called on read-only entity");
return;
}
if (pr_global_ptrs->clientcommandframe) if (pr_global_ptrs->clientcommandframe)
pmove.sequence = *pr_global_ptrs->clientcommandframe; pmove.sequence = *pr_global_ptrs->clientcommandframe;
else else
@ -9443,7 +9463,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
//EXT_CSQC //EXT_CSQC
{"clientstat", PF_clientstat, 0, 0, 0, 232, D("void(float num, float type, .__variant fld)", "Specifies what data to use in order to send various stats, in a client-specific way.\n'num' should be a value between 32 and 127, other values are reserved.\n'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY.\nfld must be a reference to the field used, each player will be sent only their own copy of these fields.")}, //EXT_CSQC {"clientstat", PF_clientstat, 0, 0, 0, 232, D("void(float num, float type, .__variant fld)", "Specifies what data to use in order to send various stats, in a client-specific way.\n'num' should be a value between 32 and 127, other values are reserved.\n'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY.\nfld must be a reference to the field used, each player will be sent only their own copy of these fields.")}, //EXT_CSQC
{"globalstat", PF_globalstat, 0, 0, 0, 233, D("void(float num, float type, string name)", "Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, name however, is the name of the global to read in the form of a string.")}, //EXT_CSQC_1 actually {"globalstat", PF_globalstat, 0, 0, 0, 233, D("void(float num, float type, string name)", "Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, name however, is the name of the global to read in the form of a string (pass \"foo\").")}, //EXT_CSQC_1 actually
{"pointerstat", PF_pointerstat, 0, 0, 0, 0, D("void(float num, float type, __variant *address)", "Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, address however, is the address of the variable you would like to use (pass &foo).")},
//END EXT_CSQC //END EXT_CSQC
{"isbackbuffered", PF_isbackbuffered, 0, 0, 0, 234, D("float(entity player)", "Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client.")}, {"isbackbuffered", PF_isbackbuffered, 0, 0, 0, 234, D("float(entity player)", "Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client.")},
{"rotatevectorsbyangle",PF_rotatevectorsbyangles,0,0, 0, 235, "void(vector angle)"}, // #235 {"rotatevectorsbyangle",PF_rotatevectorsbyangles,0,0, 0, 235, "void(vector angle)"}, // #235

View file

@ -581,6 +581,7 @@ typedef struct client_s
//note, nq is nq+ //note, nq is nq+
} protocol; } protocol;
unsigned int lastruncmd; //for non-qw physics. timestamp they were last run, so switching between physics modes isn't a (significant) cheat
//speed cheat testing //speed cheat testing
#define NEWSPEEDCHEATPROT #define NEWSPEEDCHEATPROT
int msecs; int msecs;

View file

@ -2316,16 +2316,15 @@ void World_Physics_Frame(world_t *w)
} }
else else
{ {
float newt; unsigned int newt;
float delt; unsigned int delt;
newt = sv.time*1000; newt = sv.time*1000;
delt = newt - svs.clients[i-1].msecs; delt = newt - svs.clients[i-1].lastruncmd;
if (delt > 1000/77.0 || delt < -10) if (delt > (int)(1000/77.0) || delt < -10)
{ {
float ft = host_frametime; float ft = host_frametime;
host_client = &svs.clients[i-1]; host_client = &svs.clients[i-1];
sv_player = svs.clients[i-1].edict; sv_player = svs.clients[i-1].edict;
svs.clients[i-1].msecs = newt;
SV_PreRunCmd(); SV_PreRunCmd();
#ifndef NEWSPEEDCHEATPROT #ifndef NEWSPEEDCHEATPROT
svs.clients[i-1].last_check = 0; svs.clients[i-1].last_check = 0;

View file

@ -1559,15 +1559,15 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
if (nqjunk) if (nqjunk)
{ {
MSG_WriteShort (msg, ent->v->health); MSG_WriteShort (msg, ent->v->health);
MSG_WriteByte (msg, ent->v->currentammo); MSG_WriteByte (msg, min(ent->v->currentammo, 255));
MSG_WriteByte (msg, ent->v->ammo_shells); MSG_WriteByte (msg, min(ent->v->ammo_shells, 255));
MSG_WriteByte (msg, ent->v->ammo_nails); MSG_WriteByte (msg, min(ent->v->ammo_nails, 255));
MSG_WriteByte (msg, ent->v->ammo_rockets); MSG_WriteByte (msg, min(ent->v->ammo_rockets, 255));
MSG_WriteByte (msg, ent->v->ammo_cells); MSG_WriteByte (msg, min(ent->v->ammo_cells, 255));
if (standard_quake) if (standard_quake)
{ {
MSG_WriteByte (msg, ent->v->weapon); MSG_WriteByte (msg, (unsigned int)ent->v->weapon & 0xff);
} }
else else
{ {
@ -1618,7 +1618,8 @@ void SV_QCStatEval(int type, char *name, evalc_t *field, eval_t *global, int sta
for (i = 0; i < numqcstats; i++) for (i = 0; i < numqcstats; i++)
{ {
if (qcstats[i].statnum == statnum) //strings use a different namespace.
if (qcstats[i].statnum == statnum && ((qcstats[i].type == ev_string||qcstats[i].type == -ev_string) == (type == ev_string||type == -ev_string)))
break; break;
} }
if (i == numqcstats) if (i == numqcstats)
@ -2756,6 +2757,7 @@ void SV_SendClientMessages (void)
if (c->nextservertimeupdate > pt + 6) if (c->nextservertimeupdate > pt + 6)
c->nextservertimeupdate = 0; c->nextservertimeupdate = 0;
c->netchan.cleartime = realtime - 100;
c->netchan.nqunreliableonly = !c->send_message; c->netchan.nqunreliableonly = !c->send_message;
c->datagram.cursize = 0; c->datagram.cursize = 0;
if (!c->send_message && c->nextservertimeupdate < pt) if (!c->send_message && c->nextservertimeupdate < pt)

View file

@ -4642,7 +4642,11 @@ void Cmd_Observe_f (void)
PR_ExecuteProgram (svprogfuncs, SpectatorConnect); PR_ExecuteProgram (svprogfuncs, SpectatorConnect);
} }
else else
{
sv_player->v->movetype = MOVETYPE_NOCLIP; sv_player->v->movetype = MOVETYPE_NOCLIP;
sv_player->v->model = 0;
sv_player->v->modelindex = 0;
}
sv.spawned_observer_slots++; sv.spawned_observer_slots++;
// send notification to all clients // send notification to all clients
@ -4854,12 +4858,10 @@ void SVNQ_Spawn_f (void)
ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters); ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters);
} }
MSG_WriteByte (&host_client->netchan.message, svc_signonnum); ClientReliableWrite_Begin (host_client, svc_signonnum, 2);
MSG_WriteByte (&host_client->netchan.message, 3); ClientReliableWrite_Byte (host_client, 3);
host_client->send_message = true; host_client->send_message = true;
} }
void SVNQ_Begin_f (void) void SVNQ_Begin_f (void)
{ {
@ -4984,7 +4986,7 @@ void SVNQ_PreSpawn_f (void)
host_client->prespawn_idx = 0; host_client->prespawn_idx = 0;
if (sv_mapcheck.value) if (sv_mapcheck.value)
Con_Printf("Warning: %s does cannot be applied to NQ clients.\n", sv_mapcheck.name); //as you can fake it in a client anyway, this is hardly a significant issue. Con_Printf("Warning: %s cannot be enforced on NQ clients.\n", sv_mapcheck.name); //as you can fake it in a client anyway, this is hardly a significant issue.
} }
host_client->send_message = true; host_client->send_message = true;
@ -5852,6 +5854,10 @@ void SV_PreRunCmd(void)
playertouch = BZ_Malloc((playertouchmax>>3)+1); playertouch = BZ_Malloc((playertouchmax>>3)+1);
} }
memset(playertouch, 0, playertouchmax>>3); memset(playertouch, 0, playertouchmax>>3);
//timestamp it, so things can't go weird
if (host_client)
host_client->lastruncmd = sv.time * 1000;
} }
void SV_RunCmdCleanup(void) void SV_RunCmdCleanup(void)
{ {

View file

@ -19,9 +19,9 @@ varying vec2 tc;
#ifdef LIGHTSTYLED #ifdef LIGHTSTYLED
//we could use an offset, but that would still need to be per-surface which would break batches //we could use an offset, but that would still need to be per-surface which would break batches
//fixme: merge attributes? //fixme: merge attributes?
varying vec2 lm, lm2, lm3, lm4; varying vec2 lm0, lm1, lm2, lm3;
#else #else
varying vec2 lm; varying vec2 lm0;
#endif #endif
#ifdef VERTEX_SHADER #ifdef VERTEX_SHADER
@ -47,11 +47,11 @@ void main ()
eyevector.z = dot(eyeminusvertex, v_normal.xyz); eyevector.z = dot(eyeminusvertex, v_normal.xyz);
#endif #endif
tc = v_texcoord; tc = v_texcoord;
lm = v_lmcoord; lm0 = v_lmcoord;
#ifdef LIGHTSTYLED #ifdef LIGHTSTYLED
lm2 = v_lmcoord2; lm1 = v_lmcoord2;
lm3 = v_lmcoord3; lm2 = v_lmcoord3;
lm4 = v_lmcoord4; lm3 = v_lmcoord4;
#endif #endif
gl_Position = ftetransform(); gl_Position = ftetransform();
} }
@ -59,28 +59,44 @@ void main ()
#ifdef FRAGMENT_SHADER #ifdef FRAGMENT_SHADER
//samplers //samplers
uniform sampler2D s_t0; //diffuse #define s_diffuse s_t0
uniform sampler2D s_t1; //lightmap0 #define s_lightmap0 s_t1
#define s_normalmap s_t2
#define s_delux0 s_t3
#define s_fullbright s_t4
#define s_specular s_t5
#define s_lightmap1 s_t6
#define s_lightmap2 s_t7
#define s_lightmap3 s_t8
#define s_delux1 s_t9
#define s_delux2 s_t10
#define s_delux3 s_t11
#define s_paletted s_diffuse
#define s_colourmap s_fullbright
uniform sampler2D s_diffuse;
uniform sampler2D s_lightmap0;
#if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR)) #if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR))
uniform sampler2D s_t2; //normal.rgb+height.a uniform sampler2D s_normalmap;
#endif #endif
#ifdef DELUXE #ifdef DELUXE
uniform sampler2D s_t3; //deluxe0 uniform sampler2D s_delux0;
#endif #endif
#ifdef FULLBRIGHT #if defined(FULLBRIGHT) || defined(EIGHTBIT)
uniform sampler2D s_t4; //fullbright uniform sampler2D s_fullbright;
#endif #endif
#ifdef SPECULAR #ifdef SPECULAR
uniform sampler2D s_t5; //specular uniform sampler2D s_specular;
#endif #endif
#ifdef LIGHTSTYLED #ifdef LIGHTSTYLED
uniform sampler2D s_t6; //lightmap1 uniform sampler2D s_lightmap1;
uniform sampler2D s_t7; //lightmap2 uniform sampler2D s_lightmap2;
uniform sampler2D s_t8; //lightmap3 uniform sampler2D s_lightmap3;
uniform sampler2D s_t9; //deluxe1 uniform sampler2D s_delux1;
uniform sampler2D s_t10; //deluxe2 uniform sampler2D s_delux2;
uniform sampler2D s_t11; //deluxe3 uniform sampler2D s_delux3;
#endif #endif
#ifdef LIGHTSTYLED #ifdef LIGHTSTYLED
@ -99,15 +115,24 @@ void main ()
{ {
//adjust texture coords for offsetmapping //adjust texture coords for offsetmapping
#ifdef OFFSETMAPPING #ifdef OFFSETMAPPING
vec2 tcoffsetmap = offsetmap(s_t2, tc, eyevector); vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);
#define tc tcoffsetmap #define tc tcoffsetmap
#endif #endif
#if defined(EIGHTBIT) && !defined(LIGHTSTYLED)
//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise.
//don't bother if its lightstyled, such cases will have unpredictable correlations anyway.
//FIXME: this rounding is likely not correct with respect to software rendering. oh well.
vec2 lmcoord0 = floor(lm0 * 256.0*8.0)/(256.0*8.0);
#define lm0 lmcoord0
#endif
//yay, regular texture! //yay, regular texture!
gl_FragColor = texture2D(s_t0, tc); gl_FragColor = texture2D(s_diffuse, tc);
#if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR)) #if defined(BUMP) && (defined(DELUXE) || defined(SPECULAR))
vec3 norm = normalize(texture2D(s_t2, tc).rgb - 0.5); vec3 norm = normalize(texture2D(s_normalmap, tc).rgb - 0.5);
#elif defined(SPECULAR) || defined(DELUXE) #elif defined(SPECULAR) || defined(DELUXE)
vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist. vec3 norm = vec3(0, 0, 1); //specular lighting expects this to exist.
#endif #endif
@ -116,29 +141,30 @@ void main ()
#ifdef LIGHTSTYLED #ifdef LIGHTSTYLED
vec3 lightmaps; vec3 lightmaps;
#ifdef DELUXE #ifdef DELUXE
lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb * dot(norm, texture2D(s_t3, lm ).rgb); lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb * dot(norm, 2.0*texture2D(s_delux0, lm0).rgb-0.5);
lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb * dot(norm, texture2D(s_t9, lm2).rgb); lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb * dot(norm, 2.0*texture2D(s_delux1, lm1).rgb-0.5);
lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb * dot(norm, texture2D(s_t10, lm3).rgb); lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb * dot(norm, 2.0*texture2D(s_delux2, lm2).rgb-0.5);
lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb * dot(norm, texture2D(s_t11,lm4).rgb); lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb * dot(norm, 2.0*texture2D(s_delux3, lm3).rgb-0.5);
#else #else
lightmaps = texture2D(s_t1, lm ).rgb * e_lmscale[0].rgb; lightmaps = texture2D(s_lightmap0, lm0).rgb * e_lmscale[0].rgb;
lightmaps += texture2D(s_t6, lm2).rgb * e_lmscale[1].rgb; lightmaps += texture2D(s_lightmap1, lm1).rgb * e_lmscale[1].rgb;
lightmaps += texture2D(s_t7, lm3).rgb * e_lmscale[2].rgb; lightmaps += texture2D(s_lightmap2, lm2).rgb * e_lmscale[2].rgb;
lightmaps += texture2D(s_t8, lm4).rgb * e_lmscale[3].rgb; lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb;
#endif #endif
#else #else
vec3 lightmaps = (texture2D(s_t1, lm) * e_lmscale).rgb; vec3 lightmaps = (texture2D(s_lightmap0, lm0) * e_lmscale).rgb;
//modulate by the bumpmap dot light //modulate by the bumpmap dot light
#ifdef DELUXE #ifdef DELUXE
lightmaps *= dot(norm, 2.0*(texture2D(s_t3, lm).rgb-0.5)); lightmaps *= dot(norm, 2.0*(texture2D(s_delux0, lm0).rgb-0.5));
#endif #endif
#endif #endif
//add in specular, if applicable.
#ifdef SPECULAR #ifdef SPECULAR
vec4 specs = texture2D(s_t5, tc); vec4 specs = texture2D(s_specular, tc);
#ifdef DELUXE #ifdef DELUXE
//not lightstyled... //not lightstyled...
vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_t3, lm).rgb-0.5)); //this norm should be the deluxemap info instead vec3 halfdir = normalize(normalize(eyevector) + 2.0*(texture2D(s_delux0, lm).rgb-0.5)); //this norm should be the deluxemap info instead
#else #else
vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead vec3 halfdir = normalize(normalize(eyevector) + vec3(0.0, 0.0, 1.0)); //this norm should be the deluxemap info instead
#endif #endif
@ -151,13 +177,23 @@ void main ()
gl_FragColor.rgb += spec * specs.rgb; gl_FragColor.rgb += spec * specs.rgb;
#endif #endif
#ifdef EIGHTBIT //FIXME: with this extra flag, half the permutations are redundant.
lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.
float pal = texture2D(s_diffuse, tc).r; //the palette index. hopefully not interpolated.
lightmaps -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest
gl_FragColor.r = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.
gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.
gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.
#else
//now we have our diffuse+specular terms, modulate by lightmap values. //now we have our diffuse+specular terms, modulate by lightmap values.
gl_FragColor.rgb *= lightmaps.rgb; gl_FragColor.rgb *= lightmaps.rgb;
//add on the fullbright //add on the fullbright
#ifdef FULLBRIGHT #ifdef FULLBRIGHT
gl_FragColor.rgb += texture2D(s_t4, tc).rgb; gl_FragColor.rgb += texture2D(s_fullbright, tc).rgb;
#endif #endif
#endif
//entity modifiers //entity modifiers
gl_FragColor = gl_FragColor * e_colourident; gl_FragColor = gl_FragColor * e_colourident;