try to fix common-symbol conflicts in windows builds.

attempt to provide some better gettext support for engine strings (especially cvar/command descriptions). still no translations available though.
try to optimise hldml rendering a little.
fix issue with menuqc models rendering as black when fog is active.
use threads to try to reduce stalls from player-skin switches.
add sys_clocktype cvar to linux builds too, with CLOCK_MONOTONIC by default.
enable dtls certificate pinning log stuff.
fix r_viewmodel_fov being used instead of fov cvar.
fix possible segfault when egl driver fails.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5742 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-08-13 08:39:48 +00:00
parent f7d46b7878
commit 744b9a25db
57 changed files with 1680 additions and 1011 deletions

View File

@ -5696,7 +5696,7 @@ void CL_SetSolidEntities (void)
if (state->modelindex <= 0) if (state->modelindex <= 0)
continue; continue;
mod = cl.model_precache[state->modelindex]; mod = cl.model_precache[state->modelindex];
if (!mod) if (!mod || mod->loadstate != MLS_LOADED)
continue; continue;
/*vanilla protocols have no 'solid' information. all entities get assigned ES_SOLID_BSP, even if its not actually solid. /*vanilla protocols have no 'solid' information. all entities get assigned ES_SOLID_BSP, even if its not actually solid.
so we need to make sure that item pickups are not erroneously considered solid, but doors etc are. so we need to make sure that item pickups are not erroneously considered solid, but doors etc are.
@ -5709,8 +5709,6 @@ void CL_SetSolidEntities (void)
pent = &pmove.physents[pmove.numphysent]; pent = &pmove.physents[pmove.numphysent];
memset(pent, 0, sizeof(physent_t)); memset(pent, 0, sizeof(physent_t));
pent->model = mod; pent->model = mod;
if (pent->model->loadstate != MLS_LOADED)
continue;
VectorCopy (state->angles, pent->angles); VectorCopy (state->angles, pent->angles);
pent->angles[0]*=r_meshpitch.value; pent->angles[0]*=r_meshpitch.value;
} }

View File

@ -2365,6 +2365,7 @@ void CL_CheckServerInfo(void)
// Initialize cl.maxpitch & cl.minpitch // Initialize cl.maxpitch & cl.minpitch
if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE) if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE)
{ {
#ifdef NQPROT
s = InfoBuf_ValueForKey(&cl.serverinfo, "maxpitch"); s = InfoBuf_ValueForKey(&cl.serverinfo, "maxpitch");
cl.maxpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?90.0f:80.0f); cl.maxpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?90.0f:80.0f);
s = InfoBuf_ValueForKey(&cl.serverinfo, "minpitch"); s = InfoBuf_ValueForKey(&cl.serverinfo, "minpitch");
@ -2375,6 +2376,12 @@ void CL_CheckServerInfo(void)
//should be about 0.5/65536, but there's some precision issues with such small numbers around 80, so we need to bias it more than we ought //should be about 0.5/65536, but there's some precision issues with such small numbers around 80, so we need to bias it more than we ought
cl.maxpitch -= 1.0/2048; cl.maxpitch -= 1.0/2048;
} }
#else
s = InfoBuf_ValueForKey(&cl.serverinfo, "maxpitch");
cl.maxpitch = *s ? Q_atof(s) : 80.0f;
s = InfoBuf_ValueForKey(&cl.serverinfo, "minpitch");
cl.minpitch = *s ? Q_atof(s) : -70.0f;
#endif
} }
else else
{ {

View File

@ -154,7 +154,7 @@ typedef struct serverinfo_s
char gamedir[8+1]; char gamedir[8+1];
char map[16]; char map[16];
unsigned short gameversion; // unsigned short gameversion;
unsigned short ping; unsigned short ping;
short tl; short tl;

View File

@ -1597,7 +1597,7 @@ qbyte *ReadPCXData(qbyte *buf, int length, int width, int height, qbyte *result)
qwskin_t *Skin_Lookup (char *fullname); qwskin_t *Skin_Lookup (char *fullname);
char *Skin_FindName (player_info_t *sc); char *Skin_FindName (player_info_t *sc);
void Skin_Find (player_info_t *sc); void Skin_Find (player_info_t *sc);
qbyte *Skin_Cache8 (qwskin_t *skin); qbyte *Skin_TryCache8 (qwskin_t *skin);
void Skin_Skins_f (void); void Skin_Skins_f (void);
void Skin_FlushSkin(char *name); void Skin_FlushSkin(char *name);
void Skin_AllSkins_f (void); void Skin_AllSkins_f (void);

View File

@ -103,8 +103,8 @@ static cvar_t in_builtinkeymap = CVARF("in_builtinkeymap", "0", CVAR_ARCHIVE);
static cvar_t in_simulatemultitouch = CVAR("in_simulatemultitouch", "0"); static cvar_t in_simulatemultitouch = CVAR("in_simulatemultitouch", "0");
static cvar_t in_nonstandarddeadkeys = CVARD("in_nonstandarddeadkeys", "1", "Discard input events that result in multiple keys. Only the last key will be used. This results in behaviour that differs from eg notepad. To use a dead key, press it twice instead of the dead key followed by space."); static cvar_t in_nonstandarddeadkeys = CVARD("in_nonstandarddeadkeys", "1", "Discard input events that result in multiple keys. Only the last key will be used. This results in behaviour that differs from eg notepad. To use a dead key, press it twice instead of the dead key followed by space.");
static cvar_t xinput_leftvibrator = CVARFD("xinput_leftvibrator","0", CVAR_ARCHIVE, ""); static cvar_t xinput_leftvibrator = CVARF("xinput_leftvibrator","0", CVAR_ARCHIVE);
static cvar_t xinput_rightvibrator = CVARFD("xinput_rightvibrator","0", CVAR_ARCHIVE, ""); static cvar_t xinput_rightvibrator = CVARF("xinput_rightvibrator","0", CVAR_ARCHIVE);
static cvar_t m_accel_noforce = CVAR("m_accel_noforce", "0"); static cvar_t m_accel_noforce = CVAR("m_accel_noforce", "0");
static cvar_t m_threshold_noforce = CVAR("m_threshold_noforce", "0"); static cvar_t m_threshold_noforce = CVAR("m_threshold_noforce", "0");
@ -116,6 +116,12 @@ extern qboolean multicursor_active[8];
POINT current_mouse_pos; POINT current_mouse_pos;
HWND mainwindow;
int window_center_x, window_center_y;
RECT window_rect;
typedef struct { typedef struct {
union { union {
HANDLE rawinputhandle; HANDLE rawinputhandle;
@ -1569,10 +1575,9 @@ void INS_Accumulate (void)
if (!mouseactive) if (!mouseactive)
{ {
extern int window_x, window_y;
GetCursorPos (&current_mouse_pos); GetCursorPos (&current_mouse_pos);
IN_MouseMove(sysmouse.qdeviceid, true, current_mouse_pos.x-window_x, current_mouse_pos.y-window_y, 0, 0); IN_MouseMove(sysmouse.qdeviceid, true, current_mouse_pos.x-window_rect.left, current_mouse_pos.y-window_rect.top, 0, 0);
return; return;
} }
} }

View File

@ -432,14 +432,14 @@ void Key_UpdateCompletionDesc(void)
if (var) if (var)
{ {
if (desc) if (desc)
Con_Footerf(NULL, false, "%s %s\n%s", cmd, var->string, desc); Con_Footerf(NULL, false, "%s %s\n%s", cmd, var->string, localtext(desc));
else else
Con_Footerf(NULL, false, "%s %s", cmd, var->string); Con_Footerf(NULL, false, "%s %s", cmd, var->string);
} }
else else
{ {
if (desc) if (desc)
Con_Footerf(NULL, false, "%s: %s", cmd, desc); Con_Footerf(NULL, false, "%s: %s", cmd, localtext(desc));
else else
Con_Footerf(NULL, false, ""); Con_Footerf(NULL, false, "");
} }
@ -508,7 +508,7 @@ void CompleteCommand (qboolean force, int direction)
con_commandmatch = 1; con_commandmatch = 1;
if (desc) if (desc)
Con_Footerf(NULL, false, "%s: %s", cmd, desc); Con_Footerf(NULL, false, "%s: %s", cmd, localtext(desc));
else else
Con_Footerf(NULL, false, ""); Con_Footerf(NULL, false, "");
return; return;

View File

@ -175,6 +175,7 @@ typedef struct package_s {
// DEP_MIRROR, // DEP_MIRROR,
// DEP_FAILEDMIRROR, // DEP_FAILEDMIRROR,
DEP_SOURCE, //which source url we found this package from
DEP_EXTRACTNAME, //a file that will be installed DEP_EXTRACTNAME, //a file that will be installed
DEP_FILE //a file that will be installed DEP_FILE //a file that will be installed
} dtype; } dtype;
@ -286,6 +287,37 @@ static void PM_FreePackage(package_t *p)
Z_Free(p); Z_Free(p);
} }
static void PM_AddDep(package_t *p, int deptype, const char *depname)
{
struct packagedep_s *nd, **link;
//no dupes.
for (link = &p->deps; (nd=*link) ; link = &nd->next)
{
if (nd->dtype == deptype && !strcmp(nd->name, depname))
return;
}
//add it on the end, preserving order.
nd = Z_Malloc(sizeof(*nd) + strlen(depname));
nd->dtype = deptype;
strcpy(nd->name, depname);
nd->next = *link;
*link = nd;
}
static qboolean PM_HasDep(package_t *p, int deptype, const char *depname)
{
struct packagedep_s *d;
//no dupes.
for (d = p->deps; d ; d = d->next)
{
if (d->dtype == deptype && !strcmp(d->name, depname))
return true;
}
return false;
}
static qboolean PM_PurgeOnDisable(package_t *p) static qboolean PM_PurgeOnDisable(package_t *p)
{ {
//corrupt packages must be purged //corrupt packages must be purged
@ -310,7 +342,7 @@ void PM_ValidateAuthenticity(package_t *p)
int r; int r;
char authority[MAX_QPATH], *sig; char authority[MAX_QPATH], *sig;
#if 1//ndef _DEBUG #ifndef _DEBUG
#pragma message("Temporary code.") #pragma message("Temporary code.")
//this is temporary code and should be removed once everything else has been fixed. //this is temporary code and should be removed once everything else has been fixed.
//ignore the signature (flag as accepted) for any packages with all mirrors on our own update site. //ignore the signature (flag as accepted) for any packages with all mirrors on our own update site.
@ -381,6 +413,7 @@ void PM_ValidateAuthenticity(package_t *p)
r = OSSL_VerifyHash(hashdata, hashsize, authority, signdata, signsize); r = OSSL_VerifyHash(hashdata, hashsize, authority, signdata, signsize);
#endif #endif
p->flags &= ~(DPF_SIGNATUREACCEPTED|DPF_SIGNATUREREJECTED|DPF_SIGNATUREUNKNOWN);
if (r == VH_CORRECT) if (r == VH_CORRECT)
p->flags |= DPF_SIGNATUREACCEPTED; p->flags |= DPF_SIGNATUREACCEPTED;
else if (r == VH_INCORRECT) else if (r == VH_INCORRECT)
@ -570,18 +603,15 @@ static qboolean PM_MergePackage(package_t *oldp, package_t *newp)
{ {
//if its a zip then the 'remote' file list will be blank while the local list is not (we can just keep the local list). //if its a zip then the 'remote' file list will be blank while the local list is not (we can just keep the local list).
//if the file list DOES change, then bump the version. //if the file list DOES change, then bump the version.
if (ignorefiles) if ((od->dtype == DEP_FILE && ignorefiles) || od->dtype == DEP_SOURCE)
{ {
if (od->dtype == DEP_FILE) od = od->next;
{ continue;
od = od->next; }
continue; if ((nd->dtype == DEP_FILE && ignorefiles) || nd->dtype == DEP_SOURCE)
} {
if (nd->dtype == DEP_FILE) nd = nd->next;
{ continue;
nd = nd->next;
continue;
}
} }
if (od->dtype != nd->dtype) if (od->dtype != nd->dtype)
@ -600,6 +630,12 @@ static qboolean PM_MergePackage(package_t *oldp, package_t *newp)
if (newp->author){Z_Free(oldp->author); oldp->author = Z_StrDup(newp->author);} if (newp->author){Z_Free(oldp->author); oldp->author = Z_StrDup(newp->author);}
if (newp->website){Z_Free(oldp->website); oldp->website = Z_StrDup(newp->website);} if (newp->website){Z_Free(oldp->website); oldp->website = Z_StrDup(newp->website);}
if (newp->previewimage){Z_Free(oldp->previewimage); oldp->previewimage = Z_StrDup(newp->previewimage);} if (newp->previewimage){Z_Free(oldp->previewimage); oldp->previewimage = Z_StrDup(newp->previewimage);}
if (newp->signature){Z_Free(oldp->signature); oldp->signature = Z_StrDup(newp->signature);}
if (newp->filesha1){Z_Free(oldp->filesha1); oldp->previewimage = Z_StrDup(newp->filesha1);}
if (newp->filesha512){Z_Free(oldp->filesha512); oldp->filesha512 = Z_StrDup(newp->filesha512);}
if (newp->filesize){oldp->filesize = newp->filesize;}
oldp->priority = newp->priority; oldp->priority = newp->priority;
if (nm) if (nm)
@ -625,6 +661,15 @@ static qboolean PM_MergePackage(package_t *oldp, package_t *newp)
//these flags should only remain set if set in both. //these flags should only remain set if set in both.
oldp->flags &= ~(DPF_FORGETONUNINSTALL|DPF_TESTING|DPF_MANIFEST) | (newp->flags & (DPF_FORGETONUNINSTALL|DPF_TESTING|DPF_MANIFEST)); oldp->flags &= ~(DPF_FORGETONUNINSTALL|DPF_TESTING|DPF_MANIFEST) | (newp->flags & (DPF_FORGETONUNINSTALL|DPF_TESTING|DPF_MANIFEST));
for (nd = newp->deps; nd ; nd = nd->next)
{
if (nd->dtype == DEP_SOURCE)
{
if (!PM_HasDep(oldp, DEP_SOURCE, nd->name))
PM_AddDep(oldp, DEP_SOURCE, nd->name);
}
}
PM_FreePackage(newp); PM_FreePackage(newp);
return true; return true;
} }
@ -786,24 +831,6 @@ static qboolean PM_CheckFile(const char *filename, enum fs_relative base)
} }
return false; return false;
} }
static void PM_AddDep(package_t *p, int deptype, const char *depname)
{
struct packagedep_s *nd, **link;
//no dupes.
for (link = &p->deps; (nd=*link) ; link = &nd->next)
{
if (nd->dtype == deptype && !strcmp(nd->name, depname))
return;
}
//add it on the end, preserving order.
nd = Z_Malloc(sizeof(*nd) + strlen(depname));
nd->dtype = deptype;
strcpy(nd->name, depname);
nd->next = *link;
*link = nd;
}
static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean trustworthy) static void PM_AddSubList(const char *url, const char *prefix, qboolean save, qboolean trustworthy)
{ {
@ -845,6 +872,8 @@ static void PM_RemSubList(const char *url)
{ {
if (!strcmp(downloadablelist[i].url, url)) if (!strcmp(downloadablelist[i].url, url))
{ {
//FIXME: forget all packages which have only this url as a source. remove this source from other packages.
if (downloadablelist[i].curdl) if (downloadablelist[i].curdl)
DL_Close(downloadablelist[i].curdl); DL_Close(downloadablelist[i].curdl);
Z_Free(downloadablelist[i].url); Z_Free(downloadablelist[i].url);
@ -1318,6 +1347,9 @@ static qboolean PM_ParsePackageList(const char *f, int parseflags, const char *u
p->flags |= DPF_USERMARKED; //FIXME: we don't know if this was manual or auto p->flags |= DPF_USERMARKED; //FIXME: we don't know if this was manual or auto
} }
if (url)
PM_AddDep(p, DEP_SOURCE, url);
PM_InsertPackage(p); PM_InsertPackage(p);
} }
} }
@ -3450,7 +3482,7 @@ static void PM_PromptApplyChanges(void)
pkg_updating = true; pkg_updating = true;
#endif #endif
strcpy(text, "Really decline the following\nrecommendedpackages?\n\n"); strcpy(text, "Really decline the following\nrecommended packages?\n\n");
if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text))) if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text)))
Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel"); Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel");
else else
@ -3585,6 +3617,7 @@ void PM_Command_f(void)
int i, count; int i, count;
package_t **sorted; package_t **sorted;
const char *category = "", *newcat; const char *category = "", *newcat;
struct packagedep_s *dep;
for (count = 0, p = availablepackages; p; p=p->next) for (count = 0, p = availablepackages; p; p=p->next)
count++; count++;
sorted = Z_Malloc(sizeof(*sorted)*count); sorted = Z_Malloc(sizeof(*sorted)*count);
@ -3659,6 +3692,12 @@ void PM_Command_f(void)
//show the package details. //show the package details.
Con_Printf("\t^["S_COLOR_GRAY"%s%s%s%s^] %s"S_COLOR_GRAY" %s (%s%s)", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":""); Con_Printf("\t^["S_COLOR_GRAY"%s%s%s%s^] %s"S_COLOR_GRAY" %s (%s%s)", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":"");
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_SOURCE)
Con_Printf(S_COLOR_MAGENTA" %s", dep->name);
}
if (!(p->flags&DPF_MARKED) && p == PM_FindPackage(p->name)) if (!(p->flags&DPF_MARKED) && p == PM_FindPackage(p->name))
Con_Printf(" ^[[Add]\\type\\pkg add %s;pkg apply^]", COM_QuotedString(p->name, quoted, sizeof(quoted), false)); Con_Printf(" ^[[Add]\\type\\pkg add %s;pkg apply^]", COM_QuotedString(p->name, quoted, sizeof(quoted), false));
if ((p->flags&DPF_MARKED) && p == PM_MarkedPackage(p->name, DPF_MARKED)) if ((p->flags&DPF_MARKED) && p == PM_MarkedPackage(p->name, DPF_MARKED))
@ -3670,22 +3709,31 @@ void PM_Command_f(void)
} }
else if (!strcmp(act, "show")) else if (!strcmp(act, "show"))
{ {
struct packagedep_s *dep;
int found = 0;
key = Cmd_Argv(2); key = Cmd_Argv(2);
p = PM_FindPackage(key); for (p = availablepackages; p; p=p->next)
if (p)
{ {
if (Q_strcasecmp(p->name, key))
continue;
if (p->previewimage) if (p->previewimage)
Con_Printf("^[%s (%s)\\tipimg\\%s\\tip\\%s^]\n", p->name, p->version, p->previewimage, ""); Con_Printf("^[%s (%s)\\tipimg\\%s\\tip\\%s^]\n", p->name, p->version, p->previewimage, "");
else else
Con_Printf("%s (%s)\n", p->name, p->version); Con_Printf("%s (%s)\n", p->name, p->version);
if (p->title) if (p->title)
Con_Printf(" title: %s\n", p->title); Con_Printf(" ^mtitle: ^m%s\n", p->title);
if (p->license) if (p->license)
Con_Printf(" license: %s\n", p->license); Con_Printf(" ^mlicense: ^m%s\n", p->license);
if (p->author) if (p->author)
Con_Printf(" author: %s\n", p->author); Con_Printf(" ^mauthor: ^m%s\n", p->author);
if (p->website) if (p->website)
Con_Printf(" website: %s\n", p->website); Con_Printf(" ^mwebsite: ^m%s\n", p->website);
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_SOURCE)
Con_Printf(" ^msource: ^m%s\n", dep->name);
}
if (p->description) if (p->description)
Con_Printf("%s\n", p->description); Con_Printf("%s\n", p->description);
@ -3728,10 +3776,22 @@ void PM_Command_f(void)
if (p->flags & DPF_ENGINE) if (p->flags & DPF_ENGINE)
Con_Printf(" package is an engine update\n"); Con_Printf(" package is an engine update\n");
if (p->flags & DPF_TESTING) if (p->flags & DPF_TESTING)
Con_Printf(" package is untested\n"); Con_Printf(S_COLOR_YELLOW" package is untested\n");
return; if (!PM_SignatureOkay(p))
{
if (!p->signature)
Con_Printf(CON_ERROR" Signature missing"CON_DEFAULT"\n"); //some idiot forgot to include a signature
else if (p->flags & DPF_SIGNATUREREJECTED)
Con_Printf(CON_ERROR" Signature invalid"CON_DEFAULT"\n"); //some idiot got the wrong auth/sig/hash
else if (p->flags & DPF_SIGNATUREUNKNOWN)
Con_Printf(S_COLOR_RED" Signature is not trusted"CON_DEFAULT"\n"); //clientside permission.
else
Con_Printf(CON_ERROR" Unable to verify signature"CON_DEFAULT"\n"); //clientside problem.
}
found++;
} }
Con_Printf("<package not found>\n"); if (!found)
Con_Printf("<package not found>\n");
} }
else if (!strcmp(act, "search") || !strcmp(act, "find")) else if (!strcmp(act, "search") || !strcmp(act, "find"))
{ {

View File

@ -3590,7 +3590,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
{ {
case MV_NONE: case MV_NONE:
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va("arrows: pitch/rotate\n" va("Help:\narrows: pitch/rotate\n"
"w: zoom in\n" "w: zoom in\n"
"s: zoom out\n" "s: zoom out\n"
"m: mode\n" "m: mode\n"
@ -3644,7 +3644,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
if (!*contents) if (!*contents)
Q_strncatz(contents, "non-solid", sizeof(contents)); Q_strncatz(contents, "non-solid", sizeof(contents));
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va( "mins: %g %g %g, maxs: %g %g %g\n" va( "Collision:\n"
"mins: %g %g %g, maxs: %g %g %g\n"
"contents: %s\n" "contents: %s\n"
"surfflags: %#x\n" "surfflags: %#x\n"
"body: %i\n" "body: %i\n"
@ -3675,11 +3676,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
else else
{ {
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y, R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+y, r_refdef.grect.width, r_refdef.grect.height-y,
va("mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2]) va( "Collision info not available\n"
"mins: %g %g %g, maxs: %g %g %g\n", ent.model->mins[0], ent.model->mins[1], ent.model->mins[2], ent.model->maxs[0], ent.model->maxs[1], ent.model->maxs[2])
, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs); , CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
} }
break; break;
case MV_NORMALS: case MV_NORMALS:
Draw_FunString(0, y, va("Normals"));
break; break;
case MV_BONES: case MV_BONES:
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
@ -3717,7 +3720,10 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
{ {
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup), mods->shaderfile, sizeof(mods->shaderfile)); char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup), mods->shaderfile, sizeof(mods->shaderfile));
if (!body) if (!body)
{
Draw_FunString(0, y, "Shader info not available");
break; break;
}
if (*mods->shaderfile) if (*mods->shaderfile)
mods->shadertext = Z_StrDup(va("\n\nPress space to view+edit the shader\n\n%s", body)); mods->shadertext = Z_StrDup(va("\n\nPress space to view+edit the shader\n\n%s", body));
else else
@ -3790,8 +3796,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
else else
Draw_FunString(0, y, va("%s: <NO TEXTURE>", t)); Draw_FunString(0, y, va("%s: <NO TEXTURE>", t));
} }
else
Draw_FunString(0, y, "Texture info not available");
} }
break; break;
default:
Draw_FunString(0, y, "Unknown display mode");
break;
} }
} }
static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode)

View File

@ -572,7 +572,7 @@ static void Prompt_Release(struct menu_s *gm)
callback(ctx, PROMPT_CANCEL); callback(ctx, PROMPT_CANCEL);
Z_Free(m); Z_Free(m);
} }
void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, char *optionyes, char *optionno, char *optioncancel) void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel)
{ {
promptmenu_t *m; promptmenu_t *m;
char *t; char *t;

View File

@ -127,7 +127,7 @@ typedef enum
PROMPT_NO = 1, PROMPT_NO = 1,
PROMPT_CANCEL = -1, PROMPT_CANCEL = -1,
} promptbutton_t; } promptbutton_t;
void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, char *optionyes, char *optionno, char *optioncancel); void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel);
#ifndef NOBUILTINMENUS #ifndef NOBUILTINMENUS

View File

@ -3236,7 +3236,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
Q_strncpyz(info->qcstatus, Info_ValueForKey(msg, "qcstatus"), sizeof(info->qcstatus)); Q_strncpyz(info->qcstatus, Info_ValueForKey(msg, "qcstatus"), sizeof(info->qcstatus));
Q_strncpyz(info->modname, Info_ValueForKey(msg, "modname"), sizeof(info->modname)); Q_strncpyz(info->modname, Info_ValueForKey(msg, "modname"), sizeof(info->modname));
info->gameversion = atoi(Info_ValueForKey(msg, "gameversion")); // info->gameversion = atoi(Info_ValueForKey(msg, "gameversion"));
info->numbots = 0;//atoi(Info_ValueForKey(msg, "bots")); info->numbots = 0;//atoi(Info_ValueForKey(msg, "bots"));
info->numhumans = info->players - info->numbots; info->numhumans = info->players - info->numbots;

View File

@ -1381,6 +1381,8 @@ void P_ParticleEffect_f(void)
ptype->count = 1/atof(value); ptype->count = 1/atof(value);
if (Cmd_Argc()>2) if (Cmd_Argc()>2)
ptype->countrand = 1/atof(Cmd_Argv(2)); ptype->countrand = 1/atof(Cmd_Argv(2));
if (Cmd_Argc()>3)
ptype->countextra = atof(Cmd_Argv(3));
} }
else if (!strcmp(var, "count")) else if (!strcmp(var, "count"))
{ {

View File

@ -2797,6 +2797,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
if (csqc_worldchanged) if (csqc_worldchanged)
{ {
csqc_worldchanged = false; csqc_worldchanged = false;
cl.worldmodel = r_worldentity.model = csqc_world.worldmodel;
Surf_NewMap(); Surf_NewMap();
CL_UpdateWindowTitle(); CL_UpdateWindowTitle();
@ -3144,7 +3145,7 @@ static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalv
v = G_VECTOR(OFS_PARM0); v = G_VECTOR(OFS_PARM0);
cont = cl.worldmodel?World_PointContentsWorldOnly(w, v):FTECONTENTS_EMPTY; cont = w->worldmodel?World_PointContentsWorldOnly(w, v):FTECONTENTS_EMPTY;
if (cont & FTECONTENTS_SOLID) if (cont & FTECONTENTS_SOLID)
G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID; G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID;
else if (cont & FTECONTENTS_SKY) else if (cont & FTECONTENTS_SKY)
@ -3197,12 +3198,16 @@ static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int mode
VectorSubtract (model->maxs, model->mins, ent->v->size); VectorSubtract (model->maxs, model->mins, ent->v->size);
if (!ent->entnum) if (!ent->entnum)
{ { //setmodel(world, "maps/foo.bsp"); may be used to switch the csqc's worldmodel.
cl.worldmodel = r_worldentity.model = csqc_world.worldmodel = model; csqc_world.worldmodel = model;
csqc_worldchanged = true; csqc_worldchanged = true;
VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin); VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin);
VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax); VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax);
World_ClearWorld (&csqc_world, true); //make sure any pvs stuff is rebuilt.
cl.num_statics = 0; //has pvs indexes that can cause crashes.
return model;
} }
} }
else else
@ -4028,7 +4033,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
return; return;
} }
if (!cl.worldmodel) if (!csqc_world.worldmodel)
return; //urm.. return; //urm..
VALGRIND_MAKE_MEM_UNDEFINED(&pmove, sizeof(pmove)); VALGRIND_MAKE_MEM_UNDEFINED(&pmove, sizeof(pmove));
@ -4122,11 +4127,11 @@ static void QCBUILTIN PF_cs_getentitytoken (pubprogfuncs_t *prinst, struct globa
if (prinst->callargc) if (prinst->callargc)
{ {
const char *s = PR_GetStringOfs(prinst, OFS_PARM0); const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
if (*s == 0 && cl.worldmodel) if (*s == 0 && csqc_world.worldmodel)
{ {
if (cl.worldmodel->loadstate == MLS_LOADING) if (csqc_world.worldmodel->loadstate == MLS_LOADING)
COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); COM_WorkerPartialSync(csqc_world.worldmodel, &csqc_world.worldmodel->loadstate, MLS_LOADING);
s = Mod_GetEntitiesString(cl.worldmodel); s = Mod_GetEntitiesString(csqc_world.worldmodel);
} }
csqcmapentitydata = s; csqcmapentitydata = s;
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
@ -4796,11 +4801,6 @@ static void QCBUILTIN PF_cs_lightstyle (pubprogfuncs_t *prinst, struct globalvar
if (prinst->callargc >= 3) //fte is a quakeworld engine if (prinst->callargc >= 3) //fte is a quakeworld engine
VectorCopy(G_VECTOR(OFS_PARM2), rgb); VectorCopy(G_VECTOR(OFS_PARM2), rgb);
if ((unsigned)stnum >= cl_max_lightstyles)
{
Con_Printf ("PF_cs_lightstyle: stnum > MAX_LIGHTSTYLES");
return;
}
R_UpdateLightStyle(stnum, str, rgb[0],rgb[1],rgb[2]); R_UpdateLightStyle(stnum, str, rgb[0],rgb[1],rgb[2]);
} }
@ -5268,7 +5268,7 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar
{ {
/* /*
#ifdef Q2BSPS #ifdef Q2BSPS
if (cl.worldmodel->fromgame == fg_quake2) if (csqc_world.worldmodel->fromgame == fg_quake2)
{ {
int portal; int portal;
int state = G_FLOAT(OFS_PARM1)!=0; int state = G_FLOAT(OFS_PARM1)!=0;
@ -5276,19 +5276,19 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar
portal = G_FLOAT(OFS_PARM0); //old legacy crap. portal = G_FLOAT(OFS_PARM0); //old legacy crap.
else else
portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field. portal = G_WEDICT(prinst, OFS_PARM0)->xv->style; //read the func_areaportal's style field.
CMQ2_SetAreaPortalState(cl.worldmodel, portal, state); CMQ2_SetAreaPortalState(csqc_world.worldmodel, portal, state);
} }
#endif #endif
*/ */
#ifdef Q3BSPS #ifdef Q3BSPS
if (cl.worldmodel->fromgame == fg_quake3) if (csqc_world.worldmodel->fromgame == fg_quake3)
{ {
int state = G_FLOAT(OFS_PARM1)!=0; int state = G_FLOAT(OFS_PARM1)!=0;
wedict_t *portal = G_WEDICT(prinst, OFS_PARM0); wedict_t *portal = G_WEDICT(prinst, OFS_PARM0);
int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2; int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2;
if (area1 == area2 || area1<0 || area2<0) if (area1 == area2 || area1<0 || area2<0)
return; return;
CMQ3_SetAreaPortalState(cl.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state); CMQ3_SetAreaPortalState(csqc_world.worldmodel, portal->pvsinfo.areanum, portal->pvsinfo.areanum2, state);
} }
#endif #endif
} }
@ -5323,11 +5323,11 @@ static void QCBUILTIN PF_cs_droptofloor (pubprogfuncs_t *prinst, struct globalva
static void QCBUILTIN PF_cl_getlight (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_cl_getlight (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
vec3_t ambient, diffuse, dir; vec3_t ambient, diffuse, dir;
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED || !cl.worldmodel->funcs.LightPointValues) if (!csqc_world.worldmodel || csqc_world.worldmodel->loadstate != MLS_LOADED || !csqc_world.worldmodel->funcs.LightPointValues)
VectorSet(G_VECTOR(OFS_RETURN), 0, 0, 0); VectorSet(G_VECTOR(OFS_RETURN), 0, 0, 0);
else else
{ {
cl.worldmodel->funcs.LightPointValues(cl.worldmodel, G_VECTOR(OFS_PARM0), ambient, diffuse, dir); csqc_world.worldmodel->funcs.LightPointValues(csqc_world.worldmodel, G_VECTOR(OFS_PARM0), ambient, diffuse, dir);
VectorMA(ambient, 0.5, diffuse, G_VECTOR(OFS_RETURN)); VectorMA(ambient, 0.5, diffuse, G_VECTOR(OFS_RETURN));
} }
} }
@ -8291,15 +8291,16 @@ void CSQC_WorldLoaded(void)
if (csqc_isdarkplaces) if (csqc_isdarkplaces)
CSQC_FindGlobals(false); CSQC_FindGlobals(false);
csqcmapentitydataloaded = true;
csqcmapentitydata = Mod_GetEntitiesString(cl.worldmodel);
csqc_world.worldmodel = cl.worldmodel; csqc_world.worldmodel = cl.worldmodel;
csqcmapentitydataloaded = true;
csqcmapentitydata = Mod_GetEntitiesString(csqc_world.worldmodel);
World_RBE_Start(&csqc_world); World_RBE_Start(&csqc_world);
worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0); worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0);
worldent->v->solid = SOLID_BSP; worldent->v->solid = SOLID_BSP;
wmodelindex = CS_FindModel(cl.worldmodel?cl.worldmodel->name:"", &tmp); wmodelindex = CS_FindModel(csqc_world.worldmodel?csqc_world.worldmodel->name:"", &tmp);
tmp = csqc_worldchanged; tmp = csqc_worldchanged;
csqc_setmodel(csqcprogs, worldent, wmodelindex); csqc_setmodel(csqcprogs, worldent, wmodelindex);
csqc_worldchanged = tmp; csqc_worldchanged = tmp;

View File

@ -1359,6 +1359,8 @@ static struct
evalc_t frame2time; evalc_t frame2time;
evalc_t renderflags; evalc_t renderflags;
evalc_t skinobject; evalc_t skinobject;
evalc_t colourmod;
evalc_t alpha;
} menuc_eval; } menuc_eval;
static playerview_t menuview; static playerview_t menuview;
@ -2117,6 +2119,8 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap); eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap);
eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags); eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags);
eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject); eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject);
eval_t *colourmodval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormod", ev_vector, &menuc_eval.colourmod);
eval_t *alphaval = prinst->GetEdictFieldValue(prinst, (void*)in, "alpha", ev_float, &menuc_eval.alpha);
int ival; int ival;
int rflags; int rflags;
@ -2163,6 +2167,22 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
out->bottomcolour = BOTTOM_DEFAULT; out->bottomcolour = BOTTOM_DEFAULT;
} }
VectorSet(out->glowmod, 1,1,1);
if (!colourmodval || (!colourmodval->_vector[0] && !colourmodval->_vector[1] && !colourmodval->_vector[2]))
VectorSet(out->shaderRGBAf, 1, 1, 1);
else
{
out->flags |= RF_FORCECOLOURMOD;
VectorCopy(colourmodval->_vector, out->shaderRGBAf);
}
if (!alphaval || !alphaval->_float || alphaval->_float == 1)
out->shaderRGBAf[3] = 1.0f;
else
{
out->flags |= RF_TRANSLUCENT;
out->shaderRGBAf[3] = alphaval->_float;
}
if (rflags & CSQCRF_ADDITIVE) if (rflags & CSQCRF_ADDITIVE)
out->flags |= RF_ADDITIVE; out->flags |= RF_ADDITIVE;
if (rflags & CSQCRF_DEPTHHACK) if (rflags & CSQCRF_DEPTHHACK)

View File

@ -2958,12 +2958,12 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
*b = *ob; *b = *ob;
if (b->vbo && b->maxmeshes) if (b->vbo && b->maxmeshes)
{ {
b->meshbuf = *b->mesh[0]; b->user.meshbuf = *b->mesh[0];
b->meshbuf.numindexes = b->mesh[b->maxmeshes-1]->indexes+b->mesh[b->maxmeshes-1]->numindexes-b->mesh[0]->indexes; b->user.meshbuf.numindexes = b->mesh[b->maxmeshes-1]->indexes+b->mesh[b->maxmeshes-1]->numindexes-b->mesh[0]->indexes;
b->meshbuf.numvertexes = b->mesh[b->maxmeshes-1]->xyz_array+b->mesh[b->maxmeshes-1]->numvertexes-b->mesh[0]->xyz_array; b->user.meshbuf.numvertexes = b->mesh[b->maxmeshes-1]->xyz_array+b->mesh[b->maxmeshes-1]->numvertexes-b->mesh[0]->xyz_array;
b->mesh = &b->meshptr; b->mesh = &b->user.meshptr;
b->meshptr = &b->meshbuf; b->user.meshptr = &b->user.meshbuf;
b->meshes = b->maxmeshes = 1; b->meshes = b->maxmeshes = 1;
} }
else else
@ -3182,7 +3182,7 @@ static void Surf_SimpleWorld_Q1BSP(struct webostate_s *es, qbyte *pvs)
Surf_RenderDynamicLightmaps_Worker (wmodel, surf, es->lightstylevalues); Surf_RenderDynamicLightmaps_Worker (wmodel, surf, es->lightstylevalues);
mesh = surf->mesh; mesh = surf->mesh;
eb = &es->batches[surf->sbatch->ebobatch]; eb = &es->batches[surf->sbatch->user.bmodel.ebobatch];
if (eb->maxidx < eb->numidx + mesh->numindexes) if (eb->maxidx < eb->numidx + mesh->numindexes)
{ {
//FIXME: pre-allocate //FIXME: pre-allocate
@ -3253,7 +3253,7 @@ static void Surf_SimpleWorld_Q3BSP(struct webostate_s *es, qbyte *pvs)
surf->visframe = fc; surf->visframe = fc;
mesh = surf->mesh; mesh = surf->mesh;
eb = &es->batches[surf->sbatch->ebobatch]; eb = &es->batches[surf->sbatch->user.bmodel.ebobatch];
if (eb->maxidx < eb->numidx + mesh->numindexes) if (eb->maxidx < eb->numidx + mesh->numindexes)
{ {
//FIXME: pre-allocate //FIXME: pre-allocate
@ -3431,7 +3431,7 @@ void Surf_DrawWorld (void)
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next)
{ {
batch->ebobatch = currentmodel->numbatches; batch->user.bmodel.ebobatch = currentmodel->numbatches;
currentmodel->numbatches++; currentmodel->numbatches++;
} }
/*TODO submodels too*/ /*TODO submodels too*/
@ -3469,7 +3469,7 @@ void Surf_DrawWorld (void)
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next)
{ {
batch->ebobatch = currentmodel->numbatches; batch->user.bmodel.ebobatch = currentmodel->numbatches;
currentmodel->numbatches++; currentmodel->numbatches++;
} }
} }

View File

@ -411,6 +411,19 @@ void GLVID_Console_Resize(void);
int R_LightPoint (vec3_t p); int R_LightPoint (vec3_t p);
void R_RenderDlights (void); void R_RenderDlights (void);
typedef struct
{
int allocated[LMBLOCK_SIZE_MAX];
int firstlm;
int lmnum;
unsigned int width;
unsigned int height;
qboolean deluxe;
} lmalloc_t;
void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height, int firstlm); //firstlm is for debugging stray lightmap indexes
//void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod);
void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short *x, unsigned short *y, int *tnum);
enum imageflags enum imageflags
{ {
/*warning: many of these flags only apply the first time it is requested*/ /*warning: many of these flags only apply the first time it is requested*/
@ -449,7 +462,7 @@ enum imageflags
IF_NOPURGE = 1<<22, //texture is not flushed when no more shaders refer to it (for C code that holds a permanant reference to it - still purged on vid_reloads though) IF_NOPURGE = 1<<22, //texture is not flushed when no more shaders refer to it (for C code that holds a permanant reference to it - still purged on vid_reloads though)
IF_HIGHPRIORITY = 1<<23, //pushed to start of worker queue instead of end... IF_HIGHPRIORITY = 1<<23, //pushed to start of worker queue instead of end...
IF_LOWPRIORITY = 1<<24, // IF_LOWPRIORITY = 1<<24, //
IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance*/ IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance. valid on worker threads.*/
IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/ IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/
IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/ IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/
IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/ IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/

View File

@ -408,15 +408,15 @@ cvar_t gl_conback = CVARFCD ("gl_conback", "",
// CVAR_ARCHIVE); // CVAR_ARCHIVE);
//cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); //cvar_t gl_detailscale = CVAR ("gl_detailscale", "5");
cvar_t gl_font = CVARFD ("gl_font", "", cvar_t gl_font = CVARFD ("gl_font", "",
CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n" CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, "Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n"
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n" "When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n"
"TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints." "TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints."
)); );
cvar_t con_textfont = CVARAFD ("con_textfont", "", "gl_consolefont", cvar_t con_textfont = CVARAFD ("con_textfont", "", "gl_consolefont",
CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n" CVAR_RENDERERCALLBACK|CVAR_ARCHIVE, "Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n"
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n" "When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n"
"TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints." "TTF fonts may be loaded from your windows directory. \'gl_font cour?col=1,1,1:couri?col=0,1,0\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text, with specific colour tints."
)); );
cvar_t gl_lateswap = CVAR ("gl_lateswap", "0"); cvar_t gl_lateswap = CVAR ("gl_lateswap", "0");
cvar_t gl_lerpimages = CVARFD ("gl_lerpimages", "1", CVAR_ARCHIVE, "Enables smoother resampling for images which are not power-of-two, when the drivers do not support non-power-of-two textures."); cvar_t gl_lerpimages = CVARFD ("gl_lerpimages", "1", CVAR_ARCHIVE, "Enables smoother resampling for images which are not power-of-two, when the drivers do not support non-power-of-two textures.");
//cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "", //cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "",

View File

@ -120,7 +120,7 @@ qwskin_t *Skin_Lookup (char *fullname)
if (!strcmp (cleanname, skins[i].name)) if (!strcmp (cleanname, skins[i].name))
{ {
skin = &skins[i]; skin = &skins[i];
Skin_Cache8 (skin); Skin_TryCache8 (skin);
return skin; return skin;
} }
} }
@ -136,7 +136,7 @@ qwskin_t *Skin_Lookup (char *fullname)
memset (skin, 0, sizeof(*skin)); memset (skin, 0, sizeof(*skin));
Q_strncpyz(skin->name, cleanname, sizeof(skin->name)); Q_strncpyz(skin->name, cleanname, sizeof(skin->name));
Skin_Cache8 (skin); Skin_TryCache8 (skin);
return skin; return skin;
} }
/* /*
@ -187,6 +187,126 @@ void Skin_Find (player_info_t *sc)
Q_strncpyz(skin->name, name, sizeof(skin->name)); Q_strncpyz(skin->name, name, sizeof(skin->name));
} }
qbyte *Skin_ParsePCX(const char *name, const pcx_t *pcx, size_t pcxsize, int *pcxheight, int *pcxwidth)
{
const qbyte *raw;
qbyte *out, *pix;
int x, y, srcw, srch;
int dataByte;
int runLength;
int fbremap[256];
unsigned short xmax, ymax, xmin, ymin;
*pcxheight = *pcxwidth = 0;
//
// parse the PCX file
//
raw = (const qbyte *)(pcx+1);
//check format (sizes are checked later)
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
|| pcx->bits_per_pixel != 8)
{
Con_Printf ("Bad skin %s (unsupported format)\n", name);
return NULL;
}
xmax = (unsigned short)LittleShort(pcx->xmax);
ymax = (unsigned short)LittleShort(pcx->ymax);
xmin = (unsigned short)LittleShort(pcx->xmin);
ymin = (unsigned short)LittleShort(pcx->ymin);
srcw = xmax-xmin+1;
srch = ymax-ymin+1;
if (srcw < 1 || srch < 1 || srcw > 320 || srch > 200)
{
Con_Printf ("Bad skin %s (unsupported size)\n", name);
return NULL;
}
*pcxheight = srcw;
*pcxwidth = srch;
out = BZ_Malloc(srcw*srch);
if (!out)
Sys_Error ("Skin_Cache: couldn't allocate");
// TODO: we build a fullbright remap.. can we get rid of this?
for (x = 0; x < vid.fullbright; x++)
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
pix = out;
// memset (out, 0, skin->width*skin->height);
dataByte = 0; //typically black (this is in case a 0*0 file is loaded... which won't happen anyway)
for (y=0 ; y < srch ; y++, pix += srcw)
{
for (x=0 ; x < srcw ; )
{
if (raw - (const qbyte*)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
return NULL;
}
dataByte = *raw++;
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
if (raw - (const qbyte*)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
return NULL;
}
dataByte = *raw++;
}
else
runLength = 1;
// skin sanity check
if (runLength + x > xmax + 2)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
return NULL;
}
if (dataByte >= 256-vid.fullbright) //kill the fb componant
if (!r_fb_models.ival)
dataByte = fbremap[dataByte + vid.fullbright-256];
while(runLength-- > 0)
pix[x++] = dataByte;
}
//pad the end of the scan line with the trailing pixel
for ( ; x < srcw ; )
pix[x++] = dataByte;
}
//pad the bottom of the skin with that final pixel
for ( ; y < srch; y++, pix += srcw)
for (x = 0; x < srcw; )
pix[x++] = dataByte;
if ( raw - (const qbyte *)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
return NULL;
}
return out;
}
void Skin_WorkerDone(void *skinptr, void *skindata, size_t width, size_t height) void Skin_WorkerDone(void *skinptr, void *skindata, size_t width, size_t height)
{ {
qwskin_t *skin = skinptr; qwskin_t *skin = skinptr;
@ -202,18 +322,15 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
{ {
qwskin_t *skin = skinptr; qwskin_t *skin = skinptr;
char name[MAX_QPATH]; char name[MAX_QPATH];
qbyte *raw; qbyte *out;
qbyte *out, *pix; int srcw, srch;
pcx_t *pcx;
int x, y, srcw, srch;
int dataByte;
int runLength;
int fbremap[256];
size_t pcxsize; size_t pcxsize;
void *pcxfiledata;
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", skin->name); Q_snprintfz (name, sizeof(name), "skins/%s.pcx", skin->name);
raw = COM_LoadTempFile (name, FSLF_IGNOREPURE, &pcxsize); pcxfiledata = FS_LoadMallocFileFlags (name, FSLF_IGNOREPURE, &pcxsize);
if (!raw) if (!pcxfiledata)
{ {
//use 24bit skins even if gl_load24bit is failed //use 24bit skins even if gl_load24bit is failed
if (strcmp(skin->name, baseskin.string)) if (strcmp(skin->name, baseskin.string))
@ -223,126 +340,30 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
if (*baseskin.string) if (*baseskin.string)
{ {
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", baseskin.string); Q_snprintfz (name, sizeof(name), "skins/%s.pcx", baseskin.string);
raw = COM_LoadTempFile (name, FSLF_IGNOREPURE, &pcxsize); pcxfiledata = FS_LoadMallocFileFlags (name, FSLF_IGNOREPURE, &pcxsize);
} }
} }
if (!raw) if (!pcxfiledata)
{ {
Skin_WorkerDone(skin, NULL, 0, 0); Skin_WorkerDone(skin, NULL, 0, 0);
return; return;
} }
} }
// if (pcxfiledata)
// parse the PCX file
//
pcx = (pcx_t *)raw;
raw = (qbyte *)(pcx+1);
//check format (sizes are checked later)
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
|| pcx->bits_per_pixel != 8)
{ {
Con_Printf ("Bad skin %s (unsupported format)\n", name); out = Skin_ParsePCX(name, pcxfiledata, pcxsize, &srcw, &srch);
Skin_WorkerDone(skin, NULL, 0, 0); FS_FreeFile(pcxfiledata);
return;
} }
else
pcx->xmax = (unsigned short)LittleShort(pcx->xmax);
pcx->ymax = (unsigned short)LittleShort(pcx->ymax);
pcx->xmin = (unsigned short)LittleShort(pcx->xmin);
pcx->ymin = (unsigned short)LittleShort(pcx->ymin);
srcw = pcx->xmax-pcx->xmin+1;
srch = pcx->ymax-pcx->ymin+1;
if (srcw < 1 || srch < 1 || srcw > 320 || srch > 200)
{ {
Con_Printf ("Bad skin %s (unsupported size)\n", name); out = NULL;
Skin_WorkerDone(skin, NULL, 0, 0); srcw = srch = 0;
return;
} }
skin->width = srcw;
skin->height = srch;
out = BZ_Malloc(skin->width*skin->height);
if (!out) if (!out)
Sys_Error ("Skin_Cache: couldn't allocate"); COM_AddWork(WG_MAIN, Skin_WorkerDone, skin, NULL, 0, 0);
else
// TODO: we build a fullbright remap.. can we get rid of this? COM_AddWork(WG_MAIN, Skin_WorkerDone, skin, out, srcw, srch);
for (x = 0; x < vid.fullbright; x++)
fbremap[x] = x + (256-vid.fullbright); //fullbrights don't exist, so don't loose palette info.
pix = out;
// memset (out, 0, skin->width*skin->height);
dataByte = 0; //typically black (this is in case a 0*0 file is loaded... which won't happen anyway)
for (y=0 ; y < srch ; y++, pix += skin->width)
{
for (x=0 ; x < srcw ; )
{
if (raw - (qbyte*)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
Skin_WorkerDone(skin, NULL, 0, 0);
return;
}
dataByte = *raw++;
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
if (raw - (qbyte*)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
Skin_WorkerDone(skin, NULL, 0, 0);
return;
}
dataByte = *raw++;
}
else
runLength = 1;
// skin sanity check
if (runLength + x > pcx->xmax + 2)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
Skin_WorkerDone(skin, NULL, 0, 0);
return;
}
if (dataByte >= 256-vid.fullbright) //kill the fb componant
if (!r_fb_models.ival)
dataByte = fbremap[dataByte + vid.fullbright-256];
while(runLength-- > 0)
pix[x++] = dataByte;
}
//pad the end of the scan line with the trailing pixel
for ( ; x < skin->width ; )
pix[x++] = dataByte;
}
//pad the bottom of the skin with that final pixel
for ( ; y < skin->height; y++, pix += skin->width)
for (x = 0; x < skin->width; )
pix[x++] = dataByte;
if ( raw - (qbyte *)pcx > pcxsize)
{
BZ_Free(out);
Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
Skin_WorkerDone(skin, NULL, 0, 0);
return;
}
Skin_WorkerDone(skin, out, srcw, srch);
} }
/* /*
@ -352,7 +373,7 @@ Skin_Cache
Returns a pointer to the skin bitmap, or NULL to use the default Returns a pointer to the skin bitmap, or NULL to use the default
========== ==========
*/ */
qbyte *Skin_Cache8 (qwskin_t *skin) qbyte *Skin_TryCache8 (qwskin_t *skin)
{ {
char name[1024]; char name[1024];
char *skinpath; char *skinpath;
@ -436,10 +457,8 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
if (skin->loadstate == SKIN_FAILED) if (skin->loadstate == SKIN_FAILED)
return NULL; return NULL;
skin->loadstate = SKIN_LOADING; skin->loadstate = SKIN_LOADING;
COM_AddWork(WG_LOADER, Skin_WorkerLoad, skin, NULL,0,0);
Skin_WorkerLoad(skin, NULL, 0, 0); return NULL;
return skin->skindata;
} }
/* /*
@ -512,7 +531,7 @@ void Skin_NextDownload (void)
sc = &cl.players[i]; sc = &cl.players[i];
if (!sc->name[0] || !sc->qwskin) if (!sc->name[0] || !sc->qwskin)
continue; continue;
Skin_Cache8 (sc->qwskin); Skin_TryCache8 (sc->qwskin);
//sc->qwskin = NULL; //sc->qwskin = NULL;
} }
} }
@ -561,7 +580,7 @@ void Skin_Skins_f (void)
if (cls.state == ca_disconnected) if (cls.state == ca_disconnected)
{ {
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); Con_TPrintf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return; return;
} }
@ -627,7 +646,7 @@ void Skin_Skins_f (void)
{ {
if (cls.state == ca_disconnected) if (cls.state == ca_disconnected)
{ {
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); Con_TPrintf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return; return;
} }

View File

@ -1180,7 +1180,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname)
devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
} }
Q_snprintfz(sc->name, sizeof(sc->name), "%s", devname); Q_snprintfz(sc->name, sizeof(sc->name), "%s", devname);
Con_Printf("Initiating "SDRVNAME": %s.\n", devname); Con_TPrintf("Initiating "SDRVNAME": %s.\n", devname);
oali = Z_Malloc(sizeof(oalinfo_t)); oali = Z_Malloc(sizeof(oalinfo_t));
sc->handle = oali; sc->handle = oali;
@ -1489,11 +1489,11 @@ static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname)
return false; return false;
oali = sc->handle; oali = sc->handle;
Con_Printf( SDRVNAME" AL_VERSION: %s\n",palGetString(AL_VERSION)); Con_Printf( "AL_VERSION: %s\n",palGetString(AL_VERSION));
Con_Printf( SDRVNAME" AL_RENDERER: %s\n",palGetString(AL_RENDERER)); Con_Printf( "AL_RENDERER: %s\n",palGetString(AL_RENDERER));
Con_Printf( SDRVNAME" AL_VENDOR: %s\n",palGetString(AL_VENDOR)); Con_Printf( "AL_VENDOR: %s\n",palGetString(AL_VENDOR));
Con_DPrintf(SDRVNAME" AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS)); Con_DPrintf("AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS));
Con_DPrintf(SDRVNAME" ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); Con_DPrintf("ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS));
sc->Shutdown = OpenAL_Shutdown; sc->Shutdown = OpenAL_Shutdown;
#ifdef USEEFX #ifdef USEEFX

View File

@ -78,6 +78,7 @@ long sys_parentwindow;
qboolean sys_gracefulexit; qboolean sys_gracefulexit;
qboolean X11_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate); qboolean X11_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate);
static void Sys_InitClock(void);
qboolean Sys_InitTerminal (void) //we either have one or we don't. qboolean Sys_InitTerminal (void) //we either have one or we don't.
{ {
@ -424,6 +425,7 @@ static void Sys_Register_File_Associations_f(void)
void Sys_Init(void) void Sys_Init(void)
{ {
Sys_InitClock();
Cmd_AddCommandD("sys_register_file_associations", Sys_Register_File_Associations_f, "Register FTE as the default handler for various file+protocol types, using FreeDesktop standards.\n"); Cmd_AddCommandD("sys_register_file_associations", Sys_Register_File_Associations_f, "Register FTE as the default handler for various file+protocol types, using FreeDesktop standards.\n");
} }
void Sys_Shutdown(void) void Sys_Shutdown(void)
@ -682,29 +684,111 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
return Sys_EnumerateFiles2(truepath, suboffset, match, func, parm, spath); return Sys_EnumerateFiles2(truepath, suboffset, match, func, parm, spath);
} }
int secbase; static quint64_t timer_basetime; //used by all clocks to bias them to starting at 0
static void Sys_ClockType_Changed(cvar_t *var, char *oldval);
static cvar_t sys_clocktype = CVARFCD("sys_clocktype", "", CVAR_NOTFROMSERVER, Sys_ClockType_Changed, "Controls which system clock to base timings from.\n0: auto\n"
"1: gettimeofday (may be discontinuous).\n"
"2: monotonic.");
static enum
{
QCLOCK_AUTO = 0,
QCLOCK_GTOD,
QCLOCK_MONOTONIC,
QCLOCK_REALTIME,
QCLOCK_INVALID
} timer_clocktype;
static quint64_t Sys_GetClock(quint64_t *freq)
{
quint64_t t;
if (timer_clocktype == QCLOCK_MONOTONIC)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
*freq = 1000000000;
t = (ts.tv_sec*(quint64_t)1000000000) + ts.tv_nsec;
}
else if (timer_clocktype == QCLOCK_REALTIME)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
*freq = 1000000000;
t = (ts.tv_sec*(quint64_t)1000000000) + ts.tv_nsec;
//WARNING t can go backwards
}
else //if (timer_clocktype == QCLOCK_GTOD)
{
struct timeval tp;
gettimeofday(&tp, NULL);
*freq = 1000000;
t = tp.tv_sec*(quint64_t)1000000 + tp.tv_usec;
//WARNING t can go backwards
}
return t - timer_basetime;
}
static void Sys_ClockType_Changed(cvar_t *var, char *oldval)
{
int newtype = var?var->ival:0;
if (newtype >= QCLOCK_INVALID)
newtype = QCLOCK_AUTO;
if (newtype <= QCLOCK_AUTO)
newtype = QCLOCK_MONOTONIC;
if (newtype != timer_clocktype)
{
quint64_t oldtime, oldfreq;
quint64_t newtime, newfreq;
oldtime = Sys_GetClock(&oldfreq);
timer_clocktype = newtype;
timer_basetime = 0;
newtime = Sys_GetClock(&newfreq);
timer_basetime = newtime - (newfreq * (oldtime) / oldfreq);
/*if (host_initialized)
{
const char *clockname = "unknown";
switch(timer_clocktype)
{
case QCLOCK_GTOD: clockname = "gettimeofday"; break;
case QCLOCK_MONOTONIC: clockname = "monotonic"; break;
case QCLOCK_REALTIME: clockname = "realtime"; break;
case QCLOCK_AUTO:
case QCLOCK_INVALID: break;
}
Con_Printf("Clock %s, wraps after %"PRIu64" days, %"PRIu64" years\n", clockname, (((quint64_t)-1)/newfreq)/(24*60*60), (((quint64_t)-1)/newfreq)/(24*60*60*365));
}*/
}
}
static void Sys_InitClock(void)
{
quint64_t freq;
Cvar_Register(&sys_clocktype, "System vars");
//calibrate it, and apply.
Sys_ClockType_Changed(NULL, NULL);
timer_basetime = 0;
timer_basetime = Sys_GetClock(&freq);
}
double Sys_DoubleTime (void) double Sys_DoubleTime (void)
{ {
struct timeval tp; quint64_t denum, num = Sys_GetClock(&denum);
struct timezone tzp; return num / (long double)denum;
gettimeofday(&tp, &tzp);
if (!secbase)
{
secbase = tp.tv_sec;
return tp.tv_usec/1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
} }
unsigned int Sys_Milliseconds (void) unsigned int Sys_Milliseconds (void)
{ {
return Sys_DoubleTime() * 1000; quint64_t denum, num = Sys_GetClock(&denum);
num *= 1000;
return num / denum;
} }
#ifdef USE_LIBTOOL #ifdef USE_LIBTOOL
void Sys_CloseLibrary(dllhandle_t *lib) void Sys_CloseLibrary(dllhandle_t *lib)
{ {

View File

@ -3798,7 +3798,7 @@ void CL_Say (qboolean team, char *extra)
if (cls.state == ca_disconnected) if (cls.state == ca_disconnected)
{ {
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); Con_TPrintf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return; return;
} }

View File

@ -2521,15 +2521,17 @@ static void Cmd_Apropos_f (void)
char escapedvalue[1024]; char escapedvalue[1024];
char latchedvalue[1024]; char latchedvalue[1024];
char *query = Cmd_Argv(1); char *query = Cmd_Argv(1);
const char *d;
for (grp=cvar_groups ; grp ; grp=grp->next) for (grp=cvar_groups ; grp ; grp=grp->next)
for (var=grp->cvars ; var ; var=var->next) for (var=grp->cvars ; var ; var=var->next)
{ {
d = var->description?localtext(var->description):NULL;
if (var->name && Q_strcasestr(var->name, query)) if (var->name && Q_strcasestr(var->name, query))
name = var->name; name = var->name;
else if (var->name2 && Q_strcasestr(var->name2, query)) else if (var->name2 && Q_strcasestr(var->name2, query))
name = var->name2; name = var->name2;
else if (var->description && Q_strcasestr(var->description, query)) else if (d && Q_strcasestr(d, query))
name = var->name; name = var->name;
else else
continue; continue;
@ -2539,21 +2541,34 @@ static void Cmd_Apropos_f (void)
if (var->latched_string) if (var->latched_string)
{ {
COM_QuotedString(var->latched_string, latchedvalue, sizeof(latchedvalue), false); COM_QuotedString(var->latched_string, latchedvalue, sizeof(latchedvalue), false);
Con_Printf("cvar ^2%s^7: %s (effective %s): %s\n", name, latchedvalue, escapedvalue, var->description?var->description:"no description"); if (d)
Con_TPrintf("cvar ^2%s^7: %s (effective %s): ^3%s\n", name, latchedvalue, escapedvalue, d);
else
Con_TPrintf("cvar ^2%s^7: %s (effective %s): ^3no description\n", name, latchedvalue, escapedvalue);
} }
else else
Con_Printf("cvar ^2%s^7: %s : %s\n", name, escapedvalue, var->description?var->description:"no description"); {
if (d)
Con_TPrintf("cvar ^2%s^7: %s : ^3%s\n", name, escapedvalue, d);
else
Con_TPrintf("cvar ^2%s^7: %s : ^3no description\n", name, escapedvalue);
}
} }
for (cmd=cmd_functions ; cmd ; cmd=cmd->next) for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
{ {
d = cmd->description?localtext(cmd->description):NULL;
if (cmd->name && Q_strcasestr(cmd->name, query)) if (cmd->name && Q_strcasestr(cmd->name, query))
; ;
else if (cmd->description && strstr(cmd->description, query)) else if (d && strstr(d, query))
; ;
else else
continue; continue;
Con_Printf("command ^2%s^7: %s\n", cmd->name, cmd->description?cmd->description:"no description");
if (d)
Con_TPrintf("command ^2%s^7: ^3%s\n", cmd->name, d);
else
Con_TPrintf("command ^2%s^7: ^3no description\n", cmd->name);
} }
//FIXME: add aliases. //FIXME: add aliases.
} }

View File

@ -1427,22 +1427,6 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali
); );
} }
#if !defined(SERVERONLY)
static void Alias_BuildSkeletalVerts(float *xyzout, float *normout, framestate_t *framestate, galiasinfo_t *inf)
{
float buffer[MAX_BONES*12];
float bufferalt[MAX_BONES*12];
boneidx_t *fte_restrict bidx = inf->ofs_skel_idx[0];
float *fte_restrict weight = inf->ofs_skel_weight[0];
const float *bonepose = Alias_GetBoneInformation(inf, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES);
if (normout)
Alias_TransformVerticies_VN(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout, inf->ofs_skel_norm[0], normout);
else
Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout);
}
#endif
#if defined(MD5MODELS) || defined(ZYMOTICMODELS) || defined(DPMMODELS) #if defined(MD5MODELS) || defined(ZYMOTICMODELS) || defined(DPMMODELS)
static int QDECL sortweights(const void *v1, const void *v2) //helper for Alias_BuildGPUWeights static int QDECL sortweights(const void *v1, const void *v2) //helper for Alias_BuildGPUWeights
{ {
@ -1941,7 +1925,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
//float fg2time; //float fg2time;
static float printtimer; static float printtimer;
#if FRAME_BLENDS != 2 #if defined(_DEBUG) && FRAME_BLENDS != 2
if (e->framestate.g[FS_REG].lerpweight[2] || e->framestate.g[FS_REG].lerpweight[3]) if (e->framestate.g[FS_REG].lerpweight[2] || e->framestate.g[FS_REG].lerpweight[3])
Con_ThrottlePrintf(&printtimer, 1, "Alias_GAliasBuildMesh(%s): non-skeletal animation only supports two animations\n", e->model->name); Con_ThrottlePrintf(&printtimer, 1, "Alias_GAliasBuildMesh(%s): non-skeletal animation only supports two animations\n", e->model->name);
#endif #endif
@ -2128,174 +2112,190 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
//used by the modelviewer. //used by the modelviewer.
void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qboolean normals) void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qboolean normals)
{ {
galiasinfo_t *mod;
scenetris_t *t; scenetris_t *t;
vecV_t *posedata = NULL; vecV_t *posedata = NULL;
vec3_t *normdata = NULL, tmp; vec3_t *normdata = NULL, tmp;
int surfnum = 0, i; int i, j;
#ifdef SKELETALMODELS
int cursurfnum = -1;
#endif
if (!ent->model || ent->model->loadstate != MLS_LOADED || ent->model->type != mod_alias) batch_t *batches[SHADER_SORT_COUNT], *b;
int s;
mesh_t *m;
unsigned int meshidx;
if (!ent->model || ent->model->loadstate != MLS_LOADED)
return; return;
mod = Mod_Extradata(ent->model);
for(; mod; mod = mod->nextsurf, surfnum++) memset(batches, 0, sizeof(batches));
r_refdef.frustum_numplanes = 0;
switch(ent->model->type)
{ {
if (surfaceidx < 0) case mod_alias:
{ R_GAlias_GenerateBatches(ent, batches);
if (!mod->contents) break;
continue;
} #ifdef HALFLIFEMODELS
else if (surfnum != surfaceidx) case mod_halflife:
R_HalfLife_GenerateBatches(ent, batches);
break;
#endif
default:
return;
}
for (s = 0; s < countof(batches); s++)
{
if (!batches[s])
continue; continue;
for (b = batches[s]; b; b = b->next)
normdata = NULL;
#ifdef SKELETALMODELS
if (mod->numbones)
{ {
if (!mod->ofs_skel_idx) if (b->buildmeshes)
posedata = mod->ofs_skel_xyz; //if there's no weights, don't try animating anything. b->buildmeshes(b);
else if (mod->shares_verts != cursurfnum || !posedata)
for (meshidx = b->firstmesh; meshidx < b->meshes; meshidx++)
{ {
cursurfnum = mod->shares_verts; if (surfaceidx < 0)
{ //only draw meshes that have an actual contents value (collision data)
//FIXME: implement.
}
else
{ //only draw the mesh that's actually selected.
if (b->user.alias.surfrefs[meshidx] != surfaceidx)
continue;
}
posedata = alloca(mod->numverts*sizeof(vecV_t)); m = b->mesh[meshidx];
normdata = normals?alloca(mod->numverts*sizeof(vec3_t)):NULL;
Alias_BuildSkeletalVerts((float*)posedata, (float*)normdata, &ent->framestate, mod);
}
//else posedata = posedata;
}
else
#endif
#ifndef NONSKELETALMODELS
continue;
#else
if (!mod->numanimations)
{
#ifdef SKELETALMODELS
normdata = mod->ofs_skel_norm;
if (mod->ofs_skel_xyz)
posedata = mod->ofs_skel_xyz;
else
#endif
continue;
}
else
{
galiaspose_t *pose;
galiasanimation_t *group = mod->ofsanimations;
group += ent->framestate.g[FS_REG].frame[0] % mod->numanimations;
//FIXME: no support for frame blending.
if (!group->numposes || !group->poseofs)
continue;
pose = group->poseofs;
pose += (int)(ent->framestate.g[FS_REG].frametime[0] * group->rate)%group->numposes;
posedata = pose->ofsverts;
normdata = pose->ofsnormals;
}
#endif
posedata = m->xyz_array;
if (normals && normdata) normdata = normals?m->normals_array:NULL;
{ //pegs, one on each vertex. if (m->numbones)
if (cl_numstris == cl_maxstris) { //intended shader might have caused it to use skeletal stuff.
{ //we're too lame for that though.
cl_maxstris+=8; posedata = alloca(m->numvertexes*sizeof(vecV_t));
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); if (normdata)
} {
t = &cl_stris[cl_numstris++]; normdata = alloca(m->numvertexes*sizeof(vec3_t));
t->shader = shader; Alias_TransformVerticies_VN(m->bones, m->numvertexes, m->bonenums[0], m->boneweights[0], m->xyz_array[0], posedata[0], m->normals_array[0], normdata[0]);
t->flags = BEF_LINES; }
t->firstidx = cl_numstrisidx; else
t->firstvert = cl_numstrisvert; Alias_TransformVerticies_V(m->bones, m->numvertexes, m->bonenums[0], m->boneweights[0], m->xyz_array[0], posedata[0]);
t->numidx = t->numvert = mod->numverts*2; }
else
if (cl_numstrisidx+t->numidx > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+t->numidx;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+t->numvert > cl_maxstrisvert)
cl_stris_ExpandVerts(cl_numstrisvert+t->numvert);
for (i = 0; i < mod->numverts; i++)
{
VectorMA(vec3_origin, posedata[i][0], ent->axis[0], tmp);
VectorMA(tmp, posedata[i][1], ent->axis[1], tmp);
VectorMA(tmp, posedata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+0]);
VectorMA(tmp, normdata[i][0], ent->axis[0], tmp);
VectorMA(tmp, normdata[i][1], ent->axis[1], tmp);
VectorMA(tmp, normdata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+1]);
Vector2Set(cl_strisvertt[t->firstvert+i*2+0], 0.0, 0.0);
Vector2Set(cl_strisvertt[t->firstvert+i*2+1], 1.0, 1.0);
Vector4Set(cl_strisvertc[t->firstvert+i*2+0], 0, 0, 1, 1);
Vector4Set(cl_strisvertc[t->firstvert+i*2+1], 0, 0, 1, 1);
cl_strisidx[cl_numstrisidx+i*2+0] = i*2+0;
cl_strisidx[cl_numstrisidx+i*2+1] = i*2+1;
}
cl_numstrisidx += i*2;
cl_numstrisvert += i*2;
}
else
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris+=8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = shader;
t->flags = 0;//BEF_LINES;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
if (t->flags&BEF_LINES)
t->numidx = mod->numindexes*2;
else
t->numidx = mod->numindexes;
t->numvert = mod->numverts;
if (cl_numstrisidx+t->numidx > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+t->numidx;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+mod->numverts > cl_maxstrisvert)
cl_stris_ExpandVerts(cl_numstrisvert+mod->numverts);
for (i = 0; i < mod->numverts; i++)
{
VectorMA(vec3_origin, posedata[i][0], ent->axis[0], tmp);
VectorMA(tmp, posedata[i][1], ent->axis[1], tmp);
VectorMA(tmp, posedata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i]);
Vector2Set(cl_strisvertt[t->firstvert+i], 0.5, 0.5);
Vector4Set(cl_strisvertc[t->firstvert+i], (mod->contents?1:0), 1, 1, 0.1);
}
if (t->flags&BEF_LINES)
{
for (i = 0; i < mod->numindexes; i+=3)
{ {
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+0]; if (m->xyz_blendw[1] == 1 && m->xyz2_array)
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+1]; posedata = m->xyz2_array;
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+1]; else if (m->xyz_blendw[0] != 1 && m->xyz2_array)
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+2]; {
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+2]; posedata = alloca(m->numvertexes*sizeof(vecV_t));
cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+0]; for (i = 0; i < m->numvertexes; i++)
{
for (j = 0; j < 3; j++)
posedata[i][j] = m->xyz_array[i][j] * m->xyz_blendw[0] +
m->xyz2_array[i][j] * m->xyz_blendw[1];
}
}
else
posedata = m->xyz_array;
}
if (normdata)
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris+=8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = shader;
t->flags = BEF_LINES;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
t->numidx = t->numvert = m->numvertexes*2;
if (cl_numstrisidx+t->numidx > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+t->numidx;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+t->numvert > cl_maxstrisvert)
cl_stris_ExpandVerts(cl_numstrisvert+t->numvert);
for (i = 0; i < m->numvertexes; i++)
{
VectorMA(vec3_origin, posedata[i][0], ent->axis[0], tmp);
VectorMA(tmp, posedata[i][1], ent->axis[1], tmp);
VectorMA(tmp, posedata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+0]);
VectorMA(tmp, normdata[i][0], ent->axis[0], tmp);
VectorMA(tmp, normdata[i][1], ent->axis[1], tmp);
VectorMA(tmp, normdata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+1]);
Vector2Set(cl_strisvertt[t->firstvert+i*2+0], 0.0, 0.0);
Vector2Set(cl_strisvertt[t->firstvert+i*2+1], 1.0, 1.0);
Vector4Set(cl_strisvertc[t->firstvert+i*2+0], 0, 0, 1, 1);
Vector4Set(cl_strisvertc[t->firstvert+i*2+1], 0, 0, 1, 1);
cl_strisidx[cl_numstrisidx+i*2+0] = i*2+0;
cl_strisidx[cl_numstrisidx+i*2+1] = i*2+1;
}
cl_numstrisidx += i*2;
cl_numstrisvert += i*2;
}
if (!normals)
{
if (cl_numstris == cl_maxstris)
{
cl_maxstris+=8;
cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris);
}
t = &cl_stris[cl_numstris++];
t->shader = shader;
t->flags = 0;//BEF_LINES;
t->firstidx = cl_numstrisidx;
t->firstvert = cl_numstrisvert;
if (t->flags&BEF_LINES)
t->numidx = m->numindexes*2;
else
t->numidx = m->numindexes;
t->numvert = m->numvertexes;
if (cl_numstrisidx+t->numidx > cl_maxstrisidx)
{
cl_maxstrisidx=cl_numstrisidx+t->numidx;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
if (cl_numstrisvert+m->numvertexes > cl_maxstrisvert)
cl_stris_ExpandVerts(cl_numstrisvert+m->numvertexes);
for (i = 0; i < m->numvertexes; i++)
{
VectorMA(vec3_origin, posedata[i][0], ent->axis[0], tmp);
VectorMA(tmp, posedata[i][1], ent->axis[1], tmp);
VectorMA(tmp, posedata[i][2], ent->axis[2], tmp);
VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i]);
Vector2Set(cl_strisvertt[t->firstvert+i], 0.5, 0.5);
Vector4Set(cl_strisvertc[t->firstvert+i], 1, 1, 1, 0.1);
}
if (t->flags&BEF_LINES)
{
for (i = 0; i < m->numindexes; i+=3)
{
cl_strisidx[cl_numstrisidx++] = m->indexes[i+0];
cl_strisidx[cl_numstrisidx++] = m->indexes[i+1];
cl_strisidx[cl_numstrisidx++] = m->indexes[i+1];
cl_strisidx[cl_numstrisidx++] = m->indexes[i+2];
cl_strisidx[cl_numstrisidx++] = m->indexes[i+2];
cl_strisidx[cl_numstrisidx++] = m->indexes[i+0];
}
}
else
{
for (i = 0; i < m->numindexes; i++)
cl_strisidx[cl_numstrisidx+i] = m->indexes[i];
cl_numstrisidx += m->numindexes;
}
cl_numstrisvert += m->numvertexes;
} }
} }
else
{
for (i = 0; i < mod->numindexes; i++)
cl_strisidx[cl_numstrisidx+i] = mod->ofs_indexes[i];
cl_numstrisidx += mod->numindexes;
}
cl_numstrisvert += mod->numverts;
} }
} }
} }
@ -5487,8 +5487,14 @@ shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num)
return NULL; return NULL;
} }
if (model->type == mod_alias) switch(model->type)
{ {
case mod_brush:
if (surfaceidx < model->numtextures && !num)
return model->textures[surfaceidx]->shader;
return NULL;
case mod_alias:
inf = Mod_Extradata(model); inf = Mod_Extradata(model);
while(surfaceidx-->0 && inf) while(surfaceidx-->0 && inf)
@ -5498,11 +5504,9 @@ shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num)
return NULL; return NULL;
skin = inf->ofsskins; skin = inf->ofsskins;
return skin[num].frame[0].shader; return skin[num].frame[0].shader;
} default:
else if (model->type == mod_brush && surfaceidx < model->numtextures && !num)
return model->textures[surfaceidx]->shader;
else
return NULL; return NULL;
}
} }
#endif #endif
const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num) const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num)
@ -5523,23 +5527,27 @@ const char *Mod_SkinNameForNum(model_t *model, int surfaceidx, int num)
return NULL; return NULL;
} }
if (!model || model->type != mod_alias) switch(model->type)
{ {
if (model->type == mod_brush && surfaceidx < model->numtextures && !num) case mod_brush:
if (surfaceidx < model->numtextures && !num)
return ""; return "";
return NULL; return NULL;
} case mod_alias:
inf = Mod_Extradata(model); inf = Mod_Extradata(model);
while(surfaceidx-->0 && inf) while(surfaceidx-->0 && inf)
inf = inf->nextsurf; inf = inf->nextsurf;
if (!inf || num >= inf->numskins) if (!inf || num >= inf->numskins)
return NULL;
skin = inf->ofsskins;
// if (!*skin[num].name)
// return skin[num].frame[0].shadername;
// else
return skin[num].name;
default:
return NULL; return NULL;
skin = inf->ofsskins; }
// if (!*skin[num].name)
// return skin[num].frame[0].shadername;
// else
return skin[num].name;
#endif #endif
} }
@ -5550,20 +5558,39 @@ const char *Mod_SurfaceNameForNum(model_t *model, int num)
#else #else
galiasinfo_t *inf; galiasinfo_t *inf;
if (!model || model->type != mod_alias) if (!model || model->loadstate != MLS_LOADED)
{ {
if (model && model->loadstate == MLS_NOTLOADED)
Mod_LoadModel(model, MLV_SILENT);
if (model && model->loadstate == MLS_LOADING)
COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING);
if (!model || model->loadstate != MLS_LOADED)
return NULL;
}
switch(model->type)
{
case mod_brush:
if (model->type == mod_brush && num < model->numtextures) if (model->type == mod_brush && num < model->numtextures)
return model->textures[num]->name; return model->textures[num]->name;
return NULL; return NULL;
} case mod_halflife:
inf = Mod_Extradata(model);
while(num-->0 && inf)
inf = inf->nextsurf;
if (inf)
return inf->surfacename;
else
return NULL; return NULL;
case mod_alias:
inf = Mod_Extradata(model);
while(num-->0 && inf)
inf = inf->nextsurf;
if (inf)
return inf->surfacename;
else
return NULL;
case mod_sprite:
case mod_dummy:
case mod_heightmap:
default:
return NULL;
}
#endif #endif
} }

View File

@ -1022,7 +1022,7 @@ coorddata MSG_ToAngle(float f, int bytes) //return value is NOT byteswapped.
void MSG_WriteCoord (sizebuf_t *sb, float f) void MSG_WriteCoord (sizebuf_t *sb, float f)
{ {
coorddata i = MSG_ToCoord(f, sb->prim.coordtype); coorddata i = MSG_ToCoord(f, sb->prim.coordtype);
SZ_Write (sb, (void*)&i, sb->prim.coordtype&0xf); SZ_Write (sb, (void*)&i, sb->prim.coordtype&COORDTYPE_SIZE_MASK);
} }
void MSG_WriteAngle16 (sizebuf_t *sb, float f) void MSG_WriteAngle16 (sizebuf_t *sb, float f)
@ -1684,13 +1684,13 @@ float MSG_ReadCoord (void)
coorddata c = {{0}}; coorddata c = {{0}};
if (net_message.prim.coordtype == COORDTYPE_UNDEFINED) if (net_message.prim.coordtype == COORDTYPE_UNDEFINED)
net_message.prim.coordtype = COORDTYPE_FIXED_13_3; net_message.prim.coordtype = COORDTYPE_FIXED_13_3;
MSG_ReadData(&c, net_message.prim.coordtype&0xf); MSG_ReadData(c.b, net_message.prim.coordtype&COORDTYPE_SIZE_MASK);
return MSG_FromCoord(c, net_message.prim.coordtype); return MSG_FromCoord(c, net_message.prim.coordtype);
} }
float MSG_ReadCoordFloat (void) float MSG_ReadCoordFloat (void)
{ {
coorddata c = {{0}}; coorddata c = {{0}};
MSG_ReadData(&c, COORDTYPE_FLOAT_32&0xf); MSG_ReadData(c.b, COORDTYPE_FLOAT_32&COORDTYPE_SIZE_MASK);
return MSG_FromCoord(c, COORDTYPE_FLOAT_32); return MSG_FromCoord(c, COORDTYPE_FLOAT_32);
} }
@ -7775,7 +7775,7 @@ void Con_TPrintf (translation_t stringnum, ...)
if (!Sys_IsMainThread()) if (!Sys_IsMainThread())
{ //shouldn't be redirected anyway... { //shouldn't be redirected anyway...
fmt = langtext(stringnum,com_language); fmt = localtext(stringnum);
va_start (argptr,stringnum); va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr); vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr); va_end (argptr);
@ -7799,7 +7799,7 @@ void Con_TPrintf (translation_t stringnum, ...)
} }
#endif #endif
fmt = langtext(stringnum,com_language); fmt = localtext(stringnum);
va_start (argptr,stringnum); va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr); vsnprintf (msg,sizeof(msg)-1, fmt,argptr);

View File

@ -160,6 +160,7 @@ struct netprim_s
#define COORDTYPE_FIXED_16_8 3 //rmq #define COORDTYPE_FIXED_16_8 3 //rmq
#define COORDTYPE_FIXED_28_4 4 //rmq, pointless #define COORDTYPE_FIXED_28_4 4 //rmq, pointless
#define COORDTYPE_FLOAT_32 (4|0x80) //fte/dp/rmq #define COORDTYPE_FLOAT_32 (4|0x80) //fte/dp/rmq
#define COORDTYPE_SIZE_MASK 0xf //coordtype&mask == number of bytes.
qbyte anglesize; qbyte anglesize;
qbyte flags; qbyte flags;
#define NPQ2_ANG16 (1u<<0) #define NPQ2_ANG16 (1u<<0)
@ -756,6 +757,7 @@ int FS_GetManifestArgv(char **argv, int maxargs);
struct zonegroup_s; struct zonegroup_s;
void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize, qboolean filters); void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize, qboolean filters);
qbyte *FS_LoadMallocFile (const char *path, size_t *fsize); qbyte *FS_LoadMallocFile (const char *path, size_t *fsize);
qbyte *FS_LoadMallocFileFlags (const char *path, unsigned int locateflags, size_t *fsize);
qofs_t FS_LoadFile(const char *name, void **file); qofs_t FS_LoadFile(const char *name, void **file);
void FS_FreeFile(void *file); void FS_FreeFile(void *file);
@ -918,7 +920,15 @@ void Log_ShutDown(void);
void IPLog_Add(const char *ip, const char *name); //for associating player ip addresses with names. void IPLog_Add(const char *ip, const char *name); //for associating player ip addresses with names.
qboolean IPLog_Merge_File(const char *fname); qboolean IPLog_Merge_File(const char *fname);
#endif #endif
qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize); enum certlog_problem_e
{
CERTLOG_WRONGHOST,
CERTLOG_EXPIRED,
CERTLOG_MISSINGCA,
CERTLOG_UNKNOWN,
};
qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize, unsigned int certlogproblems);
#if defined(HAVE_SERVER) && defined(HAVE_CLIENT) #if defined(HAVE_SERVER) && defined(HAVE_CLIENT)
qboolean Log_CheckMapCompletion(const char *packagename, const char *mapname, float *besttime, float *fulltime, float *bestkills, float *bestsecrets); qboolean Log_CheckMapCompletion(const char *packagename, const char *mapname, float *besttime, float *fulltime, float *bestkills, float *bestsecrets);

View File

@ -1239,8 +1239,8 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c
if (var) if (var)
return var; return var;
if (!description) if (!description || !*description)
description = ""; description = NULL;
//don't allow cvars with certain funny chars in their name. ever. such things get really messy when saved in configs or whatever. //don't allow cvars with certain funny chars in their name. ever. such things get really messy when saved in configs or whatever.
if (!*name || strchr(name, '\"') || strchr(name, '^') || strchr(name, '$') || strchr(name, ' ') || strchr(name, '\t') || strchr(name, '\r') || strchr(name, '\n') || strchr(name, ';')) if (!*name || strchr(name, '\"') || strchr(name, '^') || strchr(name, '$') || strchr(name, ' ') || strchr(name, '\t') || strchr(name, '\r') || strchr(name, '\n') || strchr(name, ';'))
@ -1313,13 +1313,13 @@ qboolean Cvar_Command (int level)
if (!level || (v->restriction?v->restriction:rcon_level.ival) > level) if (!level || (v->restriction?v->restriction:rcon_level.ival) > level)
{ {
Con_Printf ("You do not have the priveledges for %s\n", v->name); Con_TPrintf ("You do not have the priveledges for %s\n", v->name);
return true; return true;
} }
if (v->flags & CVAR_NOTFROMSERVER && Cmd_IsInsecure()) if (v->flags & CVAR_NOTFROMSERVER && Cmd_IsInsecure())
{ {
Con_Printf ("Server tried setting %s cvar\n", v->name); Con_TPrintf ("Server tried setting %s cvar\n", v->name);
return true; return true;
} }
@ -1330,36 +1330,36 @@ qboolean Cvar_Command (int level)
{ {
if (v->flags & CVAR_LATCH) if (v->flags & CVAR_LATCH)
{ {
Con_Printf ("\"%s\" is currently \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is currently \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); Con_TPrintf ("Will be changed to \"%s\" on the next map\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
} }
else if (v->flags & CVAR_VIDEOLATCH) else if (v->flags & CVAR_VIDEOLATCH)
{ {
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); Con_TPrintf ("Will be changed to \"%s\" on vid_restart\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
} }
else if (v->flags & CVAR_RENDERERLATCH) else if (v->flags & CVAR_RENDERERLATCH)
{ {
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
Con_Printf ("Will be changed to \"%s\" on vid_reload\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); Con_TPrintf ("Will be changed to \"%s\" on vid_reload\n", COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
} }
else else
{ {
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true));
Con_Printf ("Effective value is \"%s\"\n", COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("Effective value is \"%s\"\n", COM_QuotedString(v->string, buffer, sizeof(buffer), true));
} }
if (v->defaultstr) if (v->defaultstr)
Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true)); Con_TPrintf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true));
} }
else else
{ {
if (v->defaultstr && !strcmp(v->string, v->defaultstr)) if (v->defaultstr && !strcmp(v->string, v->defaultstr))
Con_Printf ("\"%s\" is \"%s\" (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is \"%s\" (default)\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
else else
{ {
Con_Printf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true)); Con_TPrintf ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->string, buffer, sizeof(buffer), true));
if (v->defaultstr) if (v->defaultstr)
Con_Printf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true)); Con_TPrintf("Default: \"%s\"\n", COM_QuotedString(v->defaultstr, buffer, sizeof(buffer), true));
} }
} }
return true; return true;
@ -1373,7 +1373,7 @@ qboolean Cvar_Command (int level)
if (v->flags & CVAR_NOSET) if (v->flags & CVAR_NOSET)
{ {
if (cl_warncmd.value || developer.value) if (cl_warncmd.value || developer.value)
Con_Printf ("Cvar %s may not be set via the console\n", v->name); Con_TPrintf ("Cvar %s may not be set via the console\n", v->name);
return true; return true;
} }

View File

@ -103,8 +103,6 @@ typedef struct cvar_s
#define CVARD(ConsoleName,Value,Description) CVARAFCD(ConsoleName, Value, NULL, 0, NULL, Description) #define CVARD(ConsoleName,Value,Description) CVARAFCD(ConsoleName, Value, NULL, 0, NULL, Description)
#define CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL) #define CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL)
#define CVARDP4(Flags,ConsoleName,Value,Description) CVARFD(ConsoleName, Value, Flags,Description)
typedef struct cvar_group_s typedef struct cvar_group_s
{ {
const char *name; const char *name;

View File

@ -2601,6 +2601,10 @@ qbyte *FS_LoadMallocFile (const char *path, size_t *fsize)
{ {
return COM_LoadFile (path, 0, 5, fsize); return COM_LoadFile (path, 0, 5, fsize);
} }
qbyte *FS_LoadMallocFileFlags (const char *path, unsigned int locateflags, size_t *fsize)
{
return COM_LoadFile (path, locateflags, 5, fsize);
}
void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize, qboolean filters) void *FS_LoadMallocGroupFile(zonegroup_t *ctx, char *path, size_t *fsize, qboolean filters)
{ {
@ -5206,7 +5210,7 @@ static ftemanifest_t *FS_GenerateLegacyManifest(int game, const char *basedir)
{ {
man = FS_Manifest_Create(NULL, basedir); man = FS_Manifest_Create(NULL, basedir);
for (cexec = gamemode_info[game].customexec; cexec[0] == '/' && cexec[1] == '/'; ) for (cexec = gamemode_info[game].customexec; cexec && cexec[0] == '/' && cexec[1] == '/'; )
{ {
char line[256]; char line[256];
char *e = strchr(cexec, '\n'); char *e = strchr(cexec, '\n');

View File

@ -1670,6 +1670,19 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce
//access and creation do NOT exist in the central header. //access and creation do NOT exist in the central header.
extra += extrachunk_len; extra += extrachunk_len;
break; break;
case 0x7075: //unicode (utf-8) filename replacements.
if (extra[0] == 1) //version
{
//if (LittleU4FromPtr(extra+1) == qcrc32(?,entry->fname, entry->fnane_len))
{
entry->fname = extra+5;
entry->fnane_len = extrachunk_len-5;
extra += extrachunk_len;
entry->gflags |= (1u<<11); //just set that flag. we don't support comments anyway.
}
}
break;
default: default:
/* Con_Printf("Unknown chunk %x\n", extrachunk_tag); /* Con_Printf("Unknown chunk %x\n", extrachunk_tag);
case 0x5455: //extended timestamp case 0x5455: //extended timestamp

View File

@ -640,7 +640,10 @@ struct certlog_s
size_t certsize; size_t certsize;
qbyte cert[1]; qbyte cert[1];
}; };
#define CERTLOG_FILENAME "knowncerts.txt"
static link_t certlog; static link_t certlog;
static qboolean certlog_inited = false;
static void CertLog_Import(const char *filename);
static struct certlog_s *CertLog_Find(const char *hostname) static struct certlog_s *CertLog_Find(const char *hostname)
{ {
struct certlog_s *l; struct certlog_s *l;
@ -669,7 +672,7 @@ static void CertLog_Update(const char *hostname, const void *cert, size_t certsi
static void CertLog_Write(void) static void CertLog_Write(void)
{ {
struct certlog_s *l; struct certlog_s *l;
vfsfile_t *f = NULL;//FS_OpenVFS("knowncerts.txt", "wb", FS_ROOT); vfsfile_t *f = FS_OpenVFS(CERTLOG_FILENAME, "wb", FS_ROOT);
if (f) if (f)
{ {
VFS_PRINTF(f, "version 1.0\n"); VFS_PRINTF(f, "version 1.0\n");
@ -685,7 +688,9 @@ static void CertLog_Write(void)
certhex[i*2+1] = hex[l->cert[i]&0xf]; certhex[i*2+1] = hex[l->cert[i]&0xf];
} }
certhex[i*2] = 0; certhex[i*2] = 0;
VFS_PRINTF(f, "%s \"%s\"\n", l->hostname, certhex); VFS_PRINTF(f, "%s \"", l->hostname);
VFS_PUTS(f, certhex);
VFS_PRINTF(f, "\"\n");
} }
} }
} }
@ -697,6 +702,8 @@ static void CertLog_Purge(void)
RemoveLink(&l->l); RemoveLink(&l->l);
Z_Free(l); Z_Free(l);
} }
certlog_inited = false;
} }
static int hexdecode(char c) static int hexdecode(char c)
{ {
@ -715,7 +722,13 @@ static void CertLog_Import(const char *filename)
char certdata[16384]; char certdata[16384];
char line[65536], *l; char line[65536], *l;
size_t i, certsize; size_t i, certsize;
vfsfile_t *f = FS_OpenVFS(filename, "rb", FS_ROOT); vfsfile_t *f;
if (!certlog_inited && filename)
CertLog_Import(NULL);
certlog_inited |= !filename;
f = FS_OpenVFS(filename?filename:CERTLOG_FILENAME, "rb", FS_ROOT);
if (!f)
return;
//CertLog_Purge(); //CertLog_Purge();
VFS_GETS(f, line, sizeof(line)); VFS_GETS(f, line, sizeof(line));
if (strncmp(line, "version 1.", 10)) if (strncmp(line, "version 1.", 10))
@ -743,8 +756,10 @@ static void CertLog_UntrustAll_f(void)
static void CertLog_Import_f(void) static void CertLog_Import_f(void)
{ {
const char *fname = Cmd_Argv(1); const char *fname = Cmd_Argv(1);
if (Cmd_IsInsecure())
return;
if (!*fname) if (!*fname)
fname = "knowncerts.txt"; fname = NULL;
CertLog_Import(fname); CertLog_Import(fname);
} }
struct certprompt_s struct certprompt_s
@ -762,34 +777,64 @@ static void CertLog_Add_Prompted(void *vctx, promptbutton_t button)
{ {
CertLog_Update(ctx->hostname, ctx->cert, ctx->certsize); CertLog_Update(ctx->hostname, ctx->cert, ctx->certsize);
CertLog_Write(); CertLog_Write();
CL_BeginServerReconnect();
} }
else else
CL_Disconnect("Server certificate rejected"); CL_Disconnect("Server certificate rejected");
certlog_curprompt = NULL; certlog_curprompt = NULL;
} }
qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize) qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize, unsigned int certlogproblems)
{ {
struct certlog_s *l = CertLog_Find(hostname); struct certlog_s *l;
if (certlog_curprompt) if (certlog_curprompt)
return false; return false;
if (!certlog_inited)
CertLog_Import(NULL);
l = CertLog_Find(hostname);
if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize)) if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize))
{ { //new or different
if (qrenderer) if (qrenderer)
{ {
unsigned int i;
size_t len;
char *text;
const char *accepttext;
const char *lines[] = {
va(localtext("Certificate for %s\n"), hostname),
(certlogproblems&CERTLOG_WRONGHOST)?localtext("^1Certificate does not match host\n"):"",
((certlogproblems&(CERTLOG_MISSINGCA|CERTLOG_WRONGHOST))==CERTLOG_MISSINGCA)?localtext("^1Certificate authority is untrusted.\n"):"",
(certlogproblems&CERTLOG_EXPIRED)?localtext("^1Expired Certificate\n"):"",
l?localtext("\n^1WARNING: Certificate has changed since previously trusted."):""};
struct certprompt_s *ctx = certlog_curprompt = Z_Malloc(sizeof(*ctx)+certsize + strlen(hostname)); struct certprompt_s *ctx = certlog_curprompt = Z_Malloc(sizeof(*ctx)+certsize + strlen(hostname));
ctx->hostname = ctx->cert + certsize; ctx->hostname = ctx->cert + certsize;
ctx->certsize = certsize; ctx->certsize = certsize;
memcpy(ctx->cert, cert, certsize); memcpy(ctx->cert, cert, certsize);
strcpy(ctx->hostname, hostname); strcpy(ctx->hostname, hostname);
//FIXME: display some sort of fingerprint if (l) //FIXME: show expiry info for the old cert, warn if more than a month?
if (!l) accepttext = localtext("Replace Trust");
Menu_Prompt(CertLog_Add_Prompted, ctx, va("%s\nServer certificate is\nself-signed", hostname), "Trust", NULL, "Disconnect"); else if (!certlogproblems)
accepttext = localtext("Pin Trust");
else else
Menu_Prompt(CertLog_Add_Prompted, ctx, va("%s\n^1Server certificate HAS CHANGED\nZomg\n^bFlee in Terror", hostname), "ReTrust", NULL, "Disconnect"); accepttext = localtext("Trust Anyway");
for (i = 0, len = 0; i < countof(lines); i++)
len += strlen(lines[i]);
text = alloca(len+1);
for (i = 0, len = 0; i < countof(lines); i++)
{
strcpy(text+len, lines[i]);
len += strlen(lines[i]);
}
text[len] = 0;
//FIXME: display some sort of fingerprint
Menu_Prompt(CertLog_Add_Prompted, ctx, text, accepttext, NULL, localtext("Disconnect"));
} }
return false; //can't connect yet... return false; //can't connect yet...
} }

View File

@ -469,9 +469,11 @@ static qboolean QDECL SSL_CloseFile(vfsfile_t *vfs)
return true; return true;
} }
static qboolean SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int *errorcode) static int SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int gcertcode)
{ {
int ret = gcertcode?GNUTLS_E_CERTIFICATE_ERROR:GNUTLS_E_SUCCESS;
#ifdef HAVE_CLIENT #ifdef HAVE_CLIENT
unsigned int ferrcode;
//when using dtls, we expect self-signed certs and persistent trust. //when using dtls, we expect self-signed certs and persistent trust.
if (file->datagram) if (file->datagram)
{ {
@ -487,16 +489,27 @@ static qboolean SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file,
memcpy(certdata+certsize, certlist[j].data, certlist[j].size); memcpy(certdata+certsize, certlist[j].data, certlist[j].size);
certsize += certlist[j].size; certsize += certlist[j].size;
} }
if (CertLog_ConnectOkay(file->certname, certdata, certsize))
*errorcode = 0; //user has previously authorised it. //if gcertcode is 0 then we can still pin it.
ferrcode = 0;
if (gcertcode & GNUTLS_CERT_SIGNER_NOT_FOUND)
ferrcode |= CERTLOG_MISSINGCA;
if (gcertcode & GNUTLS_CERT_UNEXPECTED_OWNER)
ferrcode |= CERTLOG_WRONGHOST;
if (gcertcode & GNUTLS_CERT_EXPIRED)
ferrcode |= CERTLOG_EXPIRED;
if (gcertcode & ~(GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND|GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_EXPIRED))
ferrcode |= CERTLOG_UNKNOWN;
if (CertLog_ConnectOkay(file->certname, certdata, certsize, ferrcode))
ret = GNUTLS_E_SUCCESS; //user has previously authorised it.
else else
*errorcode = GNUTLS_E_CERTIFICATE_ERROR; //user didn't trust it yet ret = GNUTLS_E_CERTIFICATE_ERROR; //user didn't trust it yet
free(certdata); free(certdata);
return true;
} }
#endif #endif
return false; return ret;
} }
static int QDECL SSL_CheckCert(gnutls_session_t session) static int QDECL SSL_CheckCert(gnutls_session_t session)
@ -566,16 +579,13 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
{ {
gnutls_datum_t out; gnutls_datum_t out;
gnutls_certificate_type_t type; gnutls_certificate_type_t type;
int ret;
if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND)) if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND))
return 0; return 0;
if (certstatus == 0) ret = SSL_CheckUserTrust(session, file, certstatus);
return SSL_CheckUserTrust(session, file, 0); if (!ret)
if (certstatus == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND)) return ret;
{
if (SSL_CheckUserTrust(session, file, &errcode))
return errcode;
}
type = qgnutls_certificate_type_get (session); type = qgnutls_certificate_type_get (session);
if (qgnutls_certificate_verification_status_print(certstatus, type, &out, 0) >= 0) if (qgnutls_certificate_verification_status_print(certstatus, type, &out, 0) >= 0)
@ -592,6 +602,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
if (certlist && certslen) if (certlist && certslen)
{ {
//and make sure the hostname on it actually makes sense. //and make sure the hostname on it actually makes sense.
int ret;
gnutls_x509_crt_t cert; gnutls_x509_crt_t cert;
qgnutls_x509_crt_init(&cert); qgnutls_x509_crt_init(&cert);
qgnutls_x509_crt_import(cert, certlist, GNUTLS_X509_FMT_DER); qgnutls_x509_crt_import(cert, certlist, GNUTLS_X509_FMT_DER);
@ -599,10 +610,10 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
{ {
if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND)) if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND))
return 0; return 0;
if (certstatus == 0)
return SSL_CheckUserTrust(session, file, 0); ret = SSL_CheckUserTrust(session, file, certstatus); //looks okay... pin it by default...
if (certstatus == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND) && SSL_CheckUserTrust(session, file, GNUTLS_E_CERTIFICATE_ERROR)) if (!ret)
return 0; return ret;
if (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND) if (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND)
Con_Printf(CON_ERROR "%s: Certificate authority is not recognised\n", file->certname); Con_Printf(CON_ERROR "%s: Certificate authority is not recognised\n", file->certname);
@ -1233,7 +1244,7 @@ int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize)
} }
} }
//generates a signed blob //crypto: generates a signed blob
int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax) int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax)
{ {
gnutls_datum_t hash = {hashdata, hashsize}; gnutls_datum_t hash = {hashdata, hashsize};
@ -1264,7 +1275,7 @@ int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata,
return sign.size; return sign.size;
} }
//windows equivelent https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-hash-and-verifying-the-hash-signature //crypto: verifies a signed blob matches an authority's public cert. windows equivelent https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-hash-and-verifying-the-hash-signature
enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize) enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize)
{ {
gnutls_datum_t hash = {hashdata, hashsize}; gnutls_datum_t hash = {hashdata, hashsize};

View File

@ -7733,19 +7733,19 @@ int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_gener
static enum addressscope_e NET_ClassifyAddressipv4(int ip, const char **outdesc) static enum addressscope_e NET_ClassifyAddressipv4(int ip, const char **outdesc)
{ {
int scope = ASCOPE_NET; int scope = ASCOPE_NET;
char *desc = NULL; const char *desc = NULL;
if ((ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16 if ((ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16
scope = ASCOPE_LINK, desc = "link-local"; scope = ASCOPE_LINK, desc = localtext("link-local");
else if ((ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8 else if ((ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8
scope = ASCOPE_LAN, desc = "private"; scope = ASCOPE_LAN, desc = localtext("private");
else if ((ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8 else if ((ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8
scope = ASCOPE_HOST, desc = "localhost"; scope = ASCOPE_HOST, desc = "localhost";
else if ((ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12 else if ((ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12
scope = ASCOPE_LAN, desc = "private"; scope = ASCOPE_LAN, desc = localtext("private");
else if ((ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16 else if ((ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16
scope = ASCOPE_LAN, desc = "private"; scope = ASCOPE_LAN, desc = localtext("private");
else if ((ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10 else if ((ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10
scope = ASCOPE_LAN, desc = "CGNAT"; scope = ASCOPE_LAN, desc = localtext("CGNAT");
else if (ip == BigLong(0x00000000)) //0.0.0.0/32 else if (ip == BigLong(0x00000000)) //0.0.0.0/32
scope = ASCOPE_LAN, desc = "any"; scope = ASCOPE_LAN, desc = "any";
@ -7760,14 +7760,14 @@ enum addressscope_e NET_ClassifyAddress(netadr_t *adr, const char **outdesc)
if (adr->type == NA_LOOPBACK) if (adr->type == NA_LOOPBACK)
{ {
//we don't list 127.0.0.1 or ::1, so don't bother with this either. its not interesting. //we don't list 127.0.0.1 or ::1, so don't bother with this either. its not interesting.
scope = ASCOPE_PROCESS, desc = "internal"; scope = ASCOPE_PROCESS, desc = localtext("internal");
} }
else if (adr->type == NA_IPV6) else if (adr->type == NA_IPV6)
{ {
if ((*(int*)adr->address.ip6&BigLong(0xffc00000)) == BigLong(0xfe800000)) //fe80::/10 if ((*(int*)adr->address.ip6&BigLong(0xffc00000)) == BigLong(0xfe800000)) //fe80::/10
scope = ASCOPE_LINK, desc = "link-local"; scope = ASCOPE_LINK, desc = localtext("link-local");
else if ((*(int*)adr->address.ip6&BigLong(0xfe000000)) == BigLong(0xfc00000)) //fc::/7 else if ((*(int*)adr->address.ip6&BigLong(0xfe000000)) == BigLong(0xfc00000)) //fc::/7
scope = ASCOPE_LAN, desc = "ULA/private"; scope = ASCOPE_LAN, desc = localtext("ULA/private");
else if (*(int*)adr->address.ip6 == BigLong(0x20010000)) //2001::/32 else if (*(int*)adr->address.ip6 == BigLong(0x20010000)) //2001::/32
scope = ASCOPE_NET, desc = "toredo"; scope = ASCOPE_NET, desc = "toredo";
else if ((*(int*)adr->address.ip6&BigLong(0xffff0000)) == BigLong(0x20020000)) //2002::/16 else if ((*(int*)adr->address.ip6&BigLong(0xffff0000)) == BigLong(0x20020000)) //2002::/16
@ -7780,7 +7780,7 @@ enum addressscope_e NET_ClassifyAddress(netadr_t *adr, const char **outdesc)
{ {
scope = NET_ClassifyAddressipv4(*(int*)(adr->address.ip6+12), &desc); scope = NET_ClassifyAddressipv4(*(int*)(adr->address.ip6+12), &desc);
if (!desc) if (!desc)
desc = "vp-mapped"; desc = localtext("v4-mapped");
} }
} }
#ifdef UNIXSOCKETS #ifdef UNIXSOCKETS
@ -7826,20 +7826,20 @@ void NET_PrintAddresses(ftenet_connections_t *collection)
if ((addr[i].prot == NP_RTC_TCP || addr[i].prot == NP_RTC_TLS) && params[i]) if ((addr[i].prot == NP_RTC_TCP || addr[i].prot == NP_RTC_TLS) && params[i])
{ {
if (addr[i].type == NA_INVALID) if (addr[i].type == NA_INVALID)
Con_Printf("%s address (%s): /%s\n", scopes[scope], con[i]->name, params[i]); Con_TPrintf("%s address (%s): /%s\n", scopes[scope], con[i]->name, params[i]);
else else
Con_Printf("%s address (%s): %s/%s\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i]), params[i]); Con_TPrintf("%s address (%s): %s/%s\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i]), params[i]);
} }
else if (desc) else if (desc)
Con_Printf("%s address (%s): %s (%s)\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i]), desc); Con_TPrintf("%s address (%s): %s (%s)\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i]), desc);
else else
Con_Printf("%s address (%s): %s\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i])); Con_TPrintf("%s address (%s): %s\n", scopes[scope], con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i]));
} }
} }
} }
if (warn) if (warn)
Con_Printf("net address: no public addresses\n"); Con_TPrintf("net address: no public addresses\n");
} }
void NET_PrintConnectionsStatus(ftenet_connections_t *collection) void NET_PrintConnectionsStatus(ftenet_connections_t *collection)

View File

@ -344,6 +344,7 @@ enum hashvalidation_e
VH_INCORRECT, //signature is wrong for that authority (bad, probably maliciously so) VH_INCORRECT, //signature is wrong for that authority (bad, probably maliciously so)
VH_CORRECT //all is well. VH_CORRECT //all is well.
}; };
struct dtlsfuncs_s;
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
typedef struct dtlsfuncs_s typedef struct dtlsfuncs_s
{ {
@ -360,23 +361,23 @@ const dtlsfuncs_t *DTLS_InitClient(void);
#ifdef HAVE_WINSSPI #ifdef HAVE_WINSSPI
vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available. const struct dtlsfuncs_s *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *SSPI_DTLS_InitClient(void); //should always return something, if implemented. const struct dtlsfuncs_s *SSPI_DTLS_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); enum hashvalidation_e SSPI_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
#endif #endif
#ifdef HAVE_GNUTLS #ifdef HAVE_GNUTLS
vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *GNUDTLS_InitServer(void); //returns NULL if there's no cert available. const struct dtlsfuncs_s *GNUDTLS_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *GNUDTLS_InitClient(void); //should always return something, if implemented. const struct dtlsfuncs_s *GNUDTLS_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); enum hashvalidation_e GNUTLS_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax); int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax);
#endif #endif
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver);
int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize);
const dtlsfuncs_t *OSSL_InitServer(void); //returns NULL if there's no cert available. const struct dtlsfuncs_s *OSSL_InitServer(void); //returns NULL if there's no cert available.
const dtlsfuncs_t *OSSL_InitClient(void); //should always return something, if implemented. const struct dtlsfuncs_s *OSSL_InitClient(void); //should always return something, if implemented.
enum hashvalidation_e OSSL_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize); enum hashvalidation_e OSSL_VerifyHash(qbyte *hashdata, size_t hashsize, const char *authority, qbyte *signdata, size_t signsize);
#endif #endif

View File

@ -1572,7 +1572,12 @@ void QCBUILTIN PF_cvar_description (pubprogfuncs_t *prinst, struct globalvars_s
const char *str = PR_GetStringOfs(prinst, OFS_PARM0); const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
cvar_t *cv = PF_Cvar_FindOrGet(str); cvar_t *cv = PF_Cvar_FindOrGet(str);
if (cv && !(cv->flags & CVAR_NOUNSAFEEXPAND)) if (cv && !(cv->flags & CVAR_NOUNSAFEEXPAND))
RETURN_CSTRING(cv->description); {
if (cv->description)
RETURN_CSTRING(localtext(cv->description));
else
G_INT(OFS_RETURN) = 0;
}
else else
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
} }

View File

@ -1,5 +1,8 @@
#include "quakedef.h" #include "quakedef.h"
//#define COLOURMISSINGSTRINGS //for english people to more easily see what's not translatable (text still white)
//#define COLOURUNTRANSLATEDSTRINGS //show empty translations as alt-text versions of the original string
//client may remap messages from the server to a regional bit of text. //client may remap messages from the server to a regional bit of text.
//server may remap progs messages //server may remap progs messages
@ -74,7 +77,9 @@ static int TL_LoadLanguage(char *lang)
languages[j].name = strdup(lang); languages[j].name = strdup(lang);
languages[j].po = NULL; languages[j].po = NULL;
#ifndef COLOURUNTRANSLATEDSTRINGS
if (f) if (f)
#endif
{ {
languages[j].po = PO_Create(); languages[j].po = PO_Create();
PO_Merge(languages[j].po, f); PO_Merge(languages[j].po, f);
@ -299,17 +304,7 @@ struct po_s
struct poline_s *lines; struct poline_s *lines;
}; };
const char *PO_GetText(struct po_s *po, const char *msg) static struct poline_s *PO_AddText(struct po_s *po, const char *orig, const char *trans)
{
struct poline_s *line;
if (!po)
return msg;
line = Hash_Get(&po->hash, msg);
if (line)
return line->translated;
return msg;
}
static void PO_AddText(struct po_s *po, const char *orig, const char *trans)
{ {
size_t olen = strlen(orig)+1; size_t olen = strlen(orig)+1;
size_t tlen = strlen(trans)+1; size_t tlen = strlen(trans)+1;
@ -323,6 +318,7 @@ static void PO_AddText(struct po_s *po, const char *orig, const char *trans)
line->next = po->lines; line->next = po->lines;
po->lines = line; po->lines = line;
return line;
} }
void PO_Merge(struct po_s *po, vfsfile_t *file) void PO_Merge(struct po_s *po, vfsfile_t *file)
{ {
@ -330,6 +326,15 @@ void PO_Merge(struct po_s *po, vfsfile_t *file)
int inlen; int inlen;
char msgid[32768]; char msgid[32768];
char msgstr[32768]; char msgstr[32768];
struct {
quint32_t magic;
quint32_t revision;
quint32_t numstrings;
quint32_t offset_orig;
quint32_t offset_trans;
// quint32_t hashsize;
// quint32_t offset_hash;
} *moheader;
qboolean allowblanks = !!COM_CheckParm("-translatetoblank"); qboolean allowblanks = !!COM_CheckParm("-translatetoblank");
if (!file) if (!file)
@ -343,61 +348,95 @@ void PO_Merge(struct po_s *po, vfsfile_t *file)
if (file) if (file)
VFS_CLOSE(file); VFS_CLOSE(file);
end = in + inlen; moheader = (void*)in;
while(in < end) if (inlen >= sizeof(*moheader) && moheader->magic == 0x950412de)
{ {
while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') struct
in++;
if (*in == '#')
{ {
while (*in && *in != '\n') quint32_t length;
quint32_t offset;
} *src = (void*)(in+moheader->offset_orig), *dst = (void*)(in+moheader->offset_trans);
quint32_t i;
for (i = moheader->numstrings; i-- > 0; src++, dst++)
PO_AddText(po, in+src->offset, in+dst->offset);
}
else
{
end = in + inlen;
while(in < end)
{
while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t')
in++; in++;
} if (*in == '#')
else if (!strncmp(in, "msgid", 5) && (in[5] == ' ' || in[5] == '\t' || in[5] == '\r' || in[5] == '\n'))
{
size_t start = 0;
size_t ofs = 0;
in += 5;
while(1)
{ {
while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') while (*in && *in != '\n')
in++; in++;
if (*in == '\"')
{
in = COM_ParseCString(in, msgid+start, sizeof(msgid) - start, &ofs);
start += ofs;
}
else
break;
} }
} else if (!strncmp(in, "msgid", 5) && (in[5] == ' ' || in[5] == '\t' || in[5] == '\r' || in[5] == '\n'))
else if (!strncmp(in, "msgstr", 6) && (in[6] == ' ' || in[6] == '\t' || in[6] == '\r' || in[6] == '\n'))
{
size_t start = 0;
size_t ofs = 0;
in += 6;
while(1)
{ {
while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') size_t start = 0;
in++; size_t ofs = 0;
if (*in == '\"') in += 5;
while(1)
{ {
in = COM_ParseCString(in, msgstr+start, sizeof(msgstr) - start, &ofs); while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t')
start += ofs; in++;
if (*in == '\"')
{
in = COM_ParseCString(in, msgid+start, sizeof(msgid) - start, &ofs);
start += ofs;
}
else
break;
} }
else
break;
} }
else if (!strncmp(in, "msgstr", 6) && (in[6] == ' ' || in[6] == '\t' || in[6] == '\r' || in[6] == '\n'))
{
size_t start = 0;
size_t ofs = 0;
in += 6;
while(1)
{
while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t')
in++;
if (*in == '\"')
{
in = COM_ParseCString(in, msgstr+start, sizeof(msgstr) - start, &ofs);
start += ofs;
}
else
break;
}
if ((*msgid && start) || allowblanks) if ((*msgid && start) || allowblanks)
PO_AddText(po, msgid, msgstr); PO_AddText(po, msgid, msgstr);
} #ifdef COLOURUNTRANSLATEDSTRINGS
else else if (!start)
{ {
//some sort of junk? char temp[1024];
in++; int i;
while (*in && *in != '\n') Q_snprintfz(temp, sizeof(temp), "%s", *msgstr?msgstr:msgid);
for (i = 0; temp[i]; i++)
{
if (temp[i] == '%')
{
while (temp[i] > ' ')
i++;
}
else if (temp[i] >= ' ')
temp[i] |= 0x80;
}
PO_AddText(po, msgid, temp);
}
#endif
}
else
{
//some sort of junk?
in++; in++;
while (*in && *in != '\n')
in++;
}
} }
} }
@ -424,3 +463,35 @@ void PO_Close(struct po_s *po)
} }
Z_Free(po); Z_Free(po);
} }
const char *PO_GetText(struct po_s *po, const char *msg)
{
struct poline_s *line;
if (!po)
return msg;
line = Hash_Get(&po->hash, msg);
#ifdef COLOURMISSINGSTRINGS
if (!line)
{
char temp[1024];
int i;
Q_snprintfz(temp, sizeof(temp), "%s", msg);
for (i = 0; temp[i]; i++)
{
if (temp[i] == '%')
{
while (temp[i] > ' ')
i++;
}
else if (temp[i] >= ' ')
temp[i] |= 0x80;
}
line = PO_AddText(po, msg, temp);
}
#endif
if (line)
return line->translated;
return msg;
}

View File

@ -17,6 +17,7 @@ extern struct language_s languages[MAX_LANGUAGES];
extern int com_language; extern int com_language;
extern cvar_t language; extern cvar_t language;
#define langtext(t,l) PO_GetText(languages[l].po, t) #define langtext(t,l) PO_GetText(languages[l].po, t)
#define localtext(t) PO_GetText(languages[com_language].po, t)
int TL_FindLanguage(const char *lang); int TL_FindLanguage(const char *lang);
#endif #endif

View File

@ -62,7 +62,7 @@ static D3DPRESENT_PARAMETERS d3dpp;
float d3d_trueprojection_std[16]; float d3d_trueprojection_std[16];
float d3d_trueprojection_view[16]; float d3d_trueprojection_view[16];
qboolean vid_initializing; static qboolean vid_initializing;
extern qboolean scr_initialized; // ready to draw extern qboolean scr_initialized; // ready to draw
extern qboolean scr_drawloading; extern qboolean scr_drawloading;
@ -73,15 +73,6 @@ extern cvar_t vid_hardwaregamma;
extern cvar_t vid_srgb; extern cvar_t vid_srgb;
//sound/error code needs this
HWND mainwindow;
//input code needs these
int window_center_x, window_center_y;
RECT window_rect;
int window_x, window_y;
/*void BuildGammaTable (float g, float c); /*void BuildGammaTable (float g, float c);
static void D3D9_VID_GenPaletteTables (unsigned char *palette) static void D3D9_VID_GenPaletteTables (unsigned char *palette)
{ {
@ -161,6 +152,7 @@ static void D3DVID_UpdateWindowStatus (HWND hWnd)
{ {
POINT p; POINT p;
RECT nr; RECT nr;
int window_x, window_y;
int window_width, window_height; int window_width, window_height;
GetClientRect(hWnd, &nr); GetClientRect(hWnd, &nr);

View File

@ -78,22 +78,13 @@ static DXGI_FORMAT depthformat;
void *d3d11mod; void *d3d11mod;
static unsigned int d3d11multisample_count, d3d11multisample_quality; static unsigned int d3d11multisample_count, d3d11multisample_quality;
qboolean vid_initializing; static qboolean vid_initializing;
extern qboolean scr_initialized; // ready to draw extern qboolean scr_initialized; // ready to draw
extern qboolean scr_drawloading; extern qboolean scr_drawloading;
extern qboolean scr_con_forcedraw; extern qboolean scr_con_forcedraw;
static qboolean d3d_resized; static qboolean d3d_resized;
//sound/error code needs this
HWND mainwindow;
//input code needs these
int window_center_x, window_center_y;
RECT window_rect;
int window_x, window_y;
static void released3dbackbuffer(void); static void released3dbackbuffer(void);
static qboolean resetd3dbackbuffer(int width, int height); static qboolean resetd3dbackbuffer(int width, int height);
@ -218,6 +209,7 @@ static void D3DVID_UpdateWindowStatus (HWND hWnd)
{ {
POINT p; POINT p;
RECT nr; RECT nr;
int window_x, window_y;
int window_width, window_height; int window_width, window_height;
GetClientRect(hWnd, &nr); GetClientRect(hWnd, &nr);

View File

@ -63,7 +63,7 @@ LPDIRECT3DDEVICE8 pD3DDev8;
static D3DPRESENT_PARAMETERS d3dpp; static D3DPRESENT_PARAMETERS d3dpp;
float d3d_trueprojection[16]; float d3d_trueprojection[16];
qboolean vid_initializing; static qboolean vid_initializing;
extern qboolean scr_initialized; // ready to draw extern qboolean scr_initialized; // ready to draw
extern qboolean scr_drawloading; extern qboolean scr_drawloading;
@ -72,16 +72,6 @@ static qboolean d3d_resized;
extern cvar_t vid_hardwaregamma; extern cvar_t vid_hardwaregamma;
//sound/error code needs this
HWND mainwindow;
//input code needs these
int window_center_x, window_center_y;
RECT window_rect;
int window_x, window_y;
/*void BuildGammaTable (float g, float c); /*void BuildGammaTable (float g, float c);
static void D3D8_VID_GenPaletteTables (unsigned char *palette) static void D3D8_VID_GenPaletteTables (unsigned char *palette)
{ {

View File

@ -693,7 +693,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
if (plskin && plskin->loadstate < SKIN_LOADED) if (plskin && plskin->loadstate < SKIN_LOADED)
{ {
Skin_Cache8(plskin); //we're not going to use it, but make sure its status is updated when it is finally loaded.. Skin_TryCache8(plskin); //we're not going to use it, but make sure its status is updated when it is finally loaded..
plskin = cl.players[e->playerindex].lastskin; plskin = cl.players[e->playerindex].lastskin;
} }
else else
@ -806,6 +806,21 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
} }
} }
if (plskin)
{
original = Skin_TryCache8(plskin); //will start it loading if not already loaded.
if (plskin->loadstate == SKIN_LOADING)
return shader;
inwidth = plskin->width;
inheight = plskin->height;
}
else
{
original = NULL;
inwidth = 0;
inheight = 0;
}
//colourmap isn't present yet. //colourmap isn't present yet.
cm = Z_Malloc(sizeof(*cm)); cm = Z_Malloc(sizeof(*cm));
*forcedtex = &cm->texnum; *forcedtex = &cm->texnum;
@ -823,13 +838,8 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
shader = R_RegisterSkin(skinname, NULL); shader = R_RegisterSkin(skinname, NULL);
cm->texnum.bump = shader->defaulttextures->bump; //can't colour bumpmapping cm->texnum.bump = shader->defaulttextures->bump; //can't colour bumpmapping
if (plskin) if (original)
{ {
/*q1 only reskins the player model, not gibbed heads (which have the same colourmap)*/
original = Skin_Cache8(plskin);
inwidth = plskin->width;
inheight = plskin->height;
if (!original && TEXLOADED(plskin->textures.base)) if (!original && TEXLOADED(plskin->textures.base))
{ {
cm->texnum.loweroverlay = plskin->textures.loweroverlay; cm->texnum.loweroverlay = plskin->textures.loweroverlay;
@ -844,12 +854,6 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
return shader; return shader;
} }
} }
else
{
original = NULL;
inwidth = 0;
inheight = 0;
}
if (!original) if (!original)
{ {
if (skins && skins->numframes && skins->frame[subframe].texels) if (skins && skins->numframes && skins->frame[subframe].texels)
@ -1653,7 +1657,7 @@ void R_GAlias_DrawBatch(batch_t *batch)
galiasinfo_t *inf; galiasinfo_t *inf;
model_t *clmodel; model_t *clmodel;
int surfnum; unsigned int surfnum;
static mesh_t mesh; static mesh_t mesh;
static mesh_t *meshl = &mesh; static mesh_t *meshl = &mesh;
@ -1673,7 +1677,7 @@ void R_GAlias_DrawBatch(batch_t *batch)
memset(&mesh, 0, sizeof(mesh)); memset(&mesh, 0, sizeof(mesh));
for(surfnum=0; inf; inf=inf->nextsurf, surfnum++) for(surfnum=0; inf; inf=inf->nextsurf, surfnum++)
{ {
if (batch->surf_first == surfnum) if (batch->user.alias.surfrefs[0] == surfnum)
{ {
/*needrecolour =*/ Alias_GAliasBuildMesh(&mesh, &batch->vbo, inf, surfnum, e, batch->shader->prog && (batch->shader->prog->supportedpermutations & PERMUTATION_SKELETAL)); /*needrecolour =*/ Alias_GAliasBuildMesh(&mesh, &batch->vbo, inf, surfnum, e, batch->shader->prog && (batch->shader->prog->supportedpermutations & PERMUTATION_SKELETAL));
batch->mesh = &meshl; batch->mesh = &meshl;
@ -1806,8 +1810,11 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
b->texture = NULL; b->texture = NULL;
b->shader = shader; b->shader = shader;
for (j = 0; j < MAXRLIGHTMAPS; j++) for (j = 0; j < MAXRLIGHTMAPS; j++)
{
b->lightmap[j] = -1; b->lightmap[j] = -1;
b->surf_first = surfnum; b->lmlightstyle[j] = INVALID_LIGHTSTYLE;
}
b->user.alias.surfrefs[0] = surfnum;
b->flags = 0; b->flags = 0;
sort = shader->sort; sort = shader->sort;
if (e->flags & RF_FORCECOLOURMOD) if (e->flags & RF_FORCECOLOURMOD)
@ -2732,7 +2739,7 @@ static void R_DB_Poly(batch_t *batch)
{ {
static mesh_t mesh; static mesh_t mesh;
static mesh_t *meshptr = &mesh; static mesh_t *meshptr = &mesh;
unsigned int i = batch->surf_first; unsigned int i = batch->user.poly.surface;
batch->mesh = &meshptr; batch->mesh = &meshptr;
@ -2776,7 +2783,7 @@ static void BE_GenPolyBatches(batch_t **batches)
b->shader = shader; b->shader = shader;
for (j = 0; j < MAXRLIGHTMAPS; j++) for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1; b->lightmap[j] = -1;
b->surf_first = i; b->user.poly.surface = i;
b->flags = cl_stris[i].flags; b->flags = cl_stris[i].flags;
b->vbo = 0; b->vbo = 0;
@ -2792,7 +2799,6 @@ static void BE_GenPolyBatches(batch_t **batches)
batches[sort] = b; batches[sort] = b;
} }
} }
void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches);
void PR_Route_Visualise(void); void PR_Route_Visualise(void);
void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, const qbyte *worldpvs, const int *worldareas) void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, const qbyte *worldpvs, const int *worldareas)
{ {

View File

@ -4150,6 +4150,8 @@ void GLBE_SelectEntity(entity_t *ent)
nd = 1; nd = 1;
if (shaderstate.depthrange != nd) if (shaderstate.depthrange != nd)
{ {
shaderstate.depthrange = nd;
if (nd < 1) if (nd < 1)
memcpy(shaderstate.projectionmatrix, r_refdef.m_projection_view, sizeof(shaderstate.projectionmatrix)); memcpy(shaderstate.projectionmatrix, r_refdef.m_projection_view, sizeof(shaderstate.projectionmatrix));
else else
@ -4160,12 +4162,6 @@ void GLBE_SelectEntity(entity_t *ent)
qglLoadMatrixf(shaderstate.projectionmatrix); qglLoadMatrixf(shaderstate.projectionmatrix);
qglMatrixMode(GL_MODELVIEW); qglMatrixMode(GL_MODELVIEW);
} }
shaderstate.depthrange = nd;
// if (qglDepthRange)
// qglDepthRange (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
// else if (qglDepthRangef)
// qglDepthRangef (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
} }
shaderstate.lastuniform = 0; shaderstate.lastuniform = 0;

View File

@ -78,10 +78,10 @@ struct hlvremaps
unsigned short scoord; unsigned short scoord;
unsigned short tcoord; unsigned short tcoord;
}; };
static index_t HLMDL_DeDupe(unsigned short *order, struct hlvremaps *rem, size_t *count, size_t max) static index_t HLMDL_DeDupe(unsigned short *order, struct hlvremaps *rem, size_t *count, size_t first, size_t max)
{ {
size_t i; size_t i;
for (i = *count; i-- > 0;) for (i = *count; i-- > first;)
{ {
if (rem[i].vertidx == order[0] && rem[i].normalidx == order[1] && rem[i].scoord == order[2] && rem[i].tcoord == order[3]) if (rem[i].vertidx == order[0] && rem[i].normalidx == order[1] && rem[i].scoord == order[2] && rem[i].tcoord == order[3])
return i; return i;
@ -99,133 +99,189 @@ static index_t HLMDL_DeDupe(unsigned short *order, struct hlvremaps *rem, size_t
} }
//parse the vertex info, pull out what we can //parse the vertex info, pull out what we can
static void HLMDL_PrepareVerticies (hlmodel_t *model, hlmdl_submodel_t *amodel, struct hlalternative_s *submodel) static void HLMDL_PrepareVerticies (model_t *mod, hlmodel_t *model)
{ {
struct hlvremaps *uvert; struct hlvremaps *uvert;
size_t uvertcount, uvertstart; size_t uvertcount=0, uvertstart;
unsigned short count; unsigned short count;
int i; int i;
size_t idx = 0, v, m, maxidx=65536*3; size_t idx = 0, m, maxidx=65536*3;
size_t maxverts = 65536; size_t maxverts = 65536;
mesh_t *mesh = &submodel->mesh;
index_t *index; index_t *index;
mesh_t *mesh, *submesh;
vec3_t *verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex); int body;
qbyte *bone = ((qbyte *) model->header + amodel->vertinfoindex);
vec3_t *norms = (vec3_t *) ((qbyte *) model->header + amodel->normindex);
uvertcount = 0;
uvert = malloc(sizeof(*uvert)*maxverts); uvert = malloc(sizeof(*uvert)*maxverts);
index = malloc(sizeof(*mesh->colors4b_array)*maxidx); index = malloc(sizeof(byte_vec4_t)*maxidx);
for(m = 0; m < amodel->nummesh; m++) model->numgeomsets = model->header->numbodyparts;
model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets);
for (body = 0; body < model->numgeomsets; body++)
{ {
hlmdl_mesh_t *inmesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m; hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
unsigned short *order = (unsigned short *) ((qbyte *) model->header + inmesh->index); int bodyindex;
model->geomset[body].numalternatives = bodypart->nummodels;
uvertstart = uvertcount; model->geomset[body].alternatives = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives) * bodypart->nummodels);
submodel->submesh[m].firstindex = mesh->numindexes; for (bodyindex = 0; bodyindex < bodypart->nummodels; bodyindex++)
submodel->submesh[m].numindexes = 0;
for(;;)
{ {
count = *order++; /* get the vertex count and primitive type */ hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
if(!count) break; /* done */ struct hlalternative_s *submodel;
if(count & 0x8000) model->geomset[body].alternatives[bodyindex].numsubmeshes = amodel->nummesh;
{ //fan model->geomset[body].alternatives[bodyindex].submesh = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives[bodyindex].submesh) * amodel->nummesh);
int first = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, maxverts);
int prev = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, maxverts); submodel = &model->geomset[body].alternatives[bodyindex];
count = (unsigned short)-(short)count;
if (idx + (count-2)*3 > maxidx) for(m = 0; m < amodel->nummesh; m++)
break; //would overflow. fixme: extend
for (i = min(2,count); i < count; i++)
{
index[idx++] = first;
index[idx++] = prev;
index[idx++] = prev = HLMDL_DeDupe(order+i*4, uvert, &uvertcount, maxverts);
}
}
else
{ {
int v0 = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, maxverts); hlmdl_mesh_t *inmesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m;
int v1 = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, maxverts); unsigned short *order = (unsigned short *) ((qbyte *) model->header + inmesh->index);
//emit (count-2)*3 indicies as a strip
//012 213, etc uvertstart = uvertcount;
if (idx + (count-2)*3 > maxidx) submodel->submesh[m].vbofirstvert = uvertstart;
break; //would overflow. fixme: extend submodel->submesh[m].vbofirstelement = idx;
for (i = min(2,count); i < count; i++) submodel->submesh[m].numvertexes = 0;
submodel->submesh[m].numindexes = 0;
for(;;)
{ {
if (i & 1) count = *order++; /* get the vertex count and primitive type */
{ if(!count) break; /* done */
index[idx++] = v1;
index[idx++] = v0; if(count & 0x8000)
{ //fan
int first = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, uvertstart, maxverts);
int prev = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, uvertstart, maxverts);
count = (unsigned short)-(short)count;
if (idx + (count-2)*3 > maxidx)
break; //would overflow. fixme: extend
for (i = min(2,count); i < count; i++)
{
index[idx++] = first;
index[idx++] = prev;
index[idx++] = prev = HLMDL_DeDupe(order+i*4, uvert, &uvertcount, uvertstart, maxverts);
}
} }
else else
{ {
index[idx++] = v0; int v0 = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, uvertstart, maxverts);
index[idx++] = v1; int v1 = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, uvertstart, maxverts);
//emit (count-2)*3 indicies as a strip
//012 213, etc
if (idx + (count-2)*3 > maxidx)
break; //would overflow. fixme: extend
for (i = min(2,count); i < count; i++)
{
if (i & 1)
{
index[idx++] = v1;
index[idx++] = v0;
}
else
{
index[idx++] = v0;
index[idx++] = v1;
}
v0 = v1;
index[idx++] = v1 = HLMDL_DeDupe(order+i*4, uvert, &uvertcount, uvertstart, maxverts);
}
} }
v0 = v1; order += i*4;
index[idx++] = v1 = HLMDL_DeDupe(order+i*4, uvert, &uvertcount, maxverts);
} }
if (uvertcount >= maxverts)
{
//if we're overflowing our verts, rewind, as we cannot generate this mesh. we'll just end up with a 0-index mesh, with no extra verts either
uvertcount = uvertstart;
idx = submodel->submesh[m].vbofirstelement;
}
submodel->submesh[m].numindexes = idx - submodel->submesh[m].vbofirstelement;
submodel->submesh[m].numvertexes = uvertcount - uvertstart;
} }
order += i*4;
} }
if (uvertcount >= maxverts)
{
//if we're overflowing our verts, rewind, as we cannot generate this mesh. we'll just end up with a 0-index mesh, with no extra verts either
uvertcount = uvertstart;
idx = submodel->submesh[m].firstindex;
}
submodel->submesh[m].numindexes = idx - submodel->submesh[m].firstindex;
} }
mesh->numindexes = idx; mesh = &model->mesh;
mesh->numvertexes = uvertcount;
mesh->indexes = ZG_Malloc(model->memgroup, sizeof(*mesh->indexes)*idx); mesh->indexes = ZG_Malloc(model->memgroup, sizeof(*mesh->indexes)*idx);
memcpy(mesh->indexes, index, sizeof(*mesh->indexes)*idx); memcpy(mesh->indexes, index, sizeof(*index)*idx);
mesh->colors4b_array = ZG_Malloc(model->memgroup, sizeof(*mesh->colors4b_array)*uvertcount); mesh->colors4b_array = ZG_Malloc(model->memgroup, sizeof(*mesh->colors4b_array)*uvertcount);
mesh->st_array = ZG_Malloc(model->memgroup, sizeof(*mesh->st_array)*uvertcount); mesh->st_array = ZG_Malloc(model->memgroup, sizeof(*mesh->st_array)*uvertcount);
mesh->lmst_array[0] = ZG_Malloc(model->memgroup, sizeof(*mesh->lmst_array[0])*uvertcount); mesh->lmst_array[0] = ZG_Malloc(model->memgroup, sizeof(*mesh->lmst_array[0])*uvertcount);
mesh->xyz_array = ZG_Malloc(model->memgroup, sizeof(*mesh->xyz_array)*uvertcount); mesh->xyz_array = ZG_Malloc(model->memgroup, sizeof(*mesh->xyz_array)*uvertcount);
mesh->normals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->normals_array)*uvertcount); mesh->normals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->normals_array)*uvertcount);
mesh->bonenums = ZG_Malloc(model->memgroup, sizeof(*mesh->bonenums)*uvertcount);
mesh->boneweights = ZG_Malloc(model->memgroup, sizeof(*mesh->boneweights)*uvertcount);
#if defined(RTLIGHTS) #if defined(RTLIGHTS)
mesh->snormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->snormals_array)*uvertcount); mesh->snormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->snormals_array)*uvertcount);
mesh->tnormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->tnormals_array)*uvertcount); mesh->tnormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->tnormals_array)*uvertcount);
#endif #endif
mesh->bonenums = ZG_Malloc(model->memgroup, sizeof(*mesh->bonenums)*uvertcount);
mesh->boneweights = ZG_Malloc(model->memgroup, sizeof(*mesh->boneweights)*uvertcount);
//prepare the verticies now that we have the mappings mesh->numindexes = idx;
for(v = 0; v < uvertcount; v++) mesh->numvertexes = uvertcount;
for (body = 0; body < model->numgeomsets; body++)
{ {
mesh->bonenums[v][0] = mesh->bonenums[v][1] = mesh->bonenums[v][2] = mesh->bonenums[v][3] = bone[uvert[v].vertidx]; hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
Vector4Set(mesh->boneweights[v], 1, 0, 0, 0); int bodyindex;
Vector4Set(mesh->colors4b_array[v], 255, 255, 255, 255); //why bytes? why not? for (bodyindex = 0; bodyindex < bodypart->nummodels; bodyindex++)
{
hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
mesh->lmst_array[0][v][0] = uvert[v].scoord; vec3_t *verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex);
mesh->lmst_array[0][v][1] = uvert[v].tcoord; qbyte *bone = ((qbyte *) model->header + amodel->vertinfoindex);
VectorCopy(verts[uvert[v].vertidx], mesh->xyz_array[v]); vec3_t *norms = (vec3_t *) ((qbyte *) model->header + amodel->normindex);
size_t iv, ov;
//Warning: these models use different tables for vertex and normals. struct hlalternative_s *submodel = &model->geomset[body].alternatives[bodyindex];
//this means they might be transformed by different bones. we ignore that and just assume that the normals will want the same bone. for(m = 0; m < amodel->nummesh; m++)
VectorCopy(norms[uvert[v].normalidx], mesh->normals_array[v]); {
submesh = &submodel->submesh[m];
submesh->indexes = mesh->indexes + submesh->vbofirstelement;
submesh->colors4b_array = mesh->colors4b_array + submesh->vbofirstvert;
submesh->st_array = mesh->st_array + submesh->vbofirstvert;
submesh->lmst_array[0] = mesh->lmst_array[0] + submesh->vbofirstvert;
submesh->xyz_array = mesh->xyz_array + submesh->vbofirstvert;
submesh->normals_array = mesh->normals_array + submesh->vbofirstvert;
submesh->bonenums = mesh->bonenums + submesh->vbofirstvert;
submesh->boneweights = mesh->boneweights + submesh->vbofirstvert;
//prepare the verticies now that we have the mappings
for(ov = 0, iv = submesh->vbofirstvert; ov < submesh->numvertexes; ov++, iv++)
{
submesh->bonenums[ov][0] = submesh->bonenums[ov][1] = submesh->bonenums[ov][2] = submesh->bonenums[ov][3] = bone[uvert[iv].vertidx];
Vector4Set(submesh->boneweights[ov], 1, 0, 0, 0);
Vector4Set(submesh->colors4b_array[ov], 255, 255, 255, 255); //why bytes? why not?
submesh->lmst_array[0][ov][0] = uvert[iv].scoord;
submesh->lmst_array[0][ov][1] = uvert[iv].tcoord;
VectorCopy(verts[uvert[iv].vertidx], submesh->xyz_array[ov]);
//Warning: these models use different tables for vertex and normals.
//this means they might be transformed by different bones. we ignore that and just assume that the normals will want the same bone.
VectorCopy(norms[uvert[iv].normalidx], submesh->normals_array[ov]);
}
#if defined(RTLIGHTS)
//treat this as the base pose, and calculate the sdir+tdir for bumpmaps.
submesh->snormals_array = mesh->snormals_array + submesh->vbofirstvert;
submesh->tnormals_array = mesh->tnormals_array + submesh->vbofirstvert;
// R_Generate_Mesh_ST_Vectors(submesh);
#endif
}
}
} }
//scratch space...
mesh->indexes = ZG_Malloc(model->memgroup, sizeof(*mesh->indexes)*idx);
//don't need that mapping any more //don't need that mapping any more
free(uvert); free(uvert);
free(index); free(index);
#if defined(RTLIGHTS)
//treat this as the base pose, and calculate the sdir+tdir for bumpmaps.
R_Generate_Mesh_ST_Vectors(mesh);
#endif
} }
#endif #endif
@ -237,10 +293,11 @@ static void HLMDL_PrepareVerticies (hlmodel_t *model, hlmdl_submodel_t *amodel,
qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize) qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
int i; int i, j;
int body;
struct hlmodelshaders_s *shaders; struct hlmodelshaders_s *shaders;
hlmdl_tex_t *tex; hlmdl_tex_t *tex;
lmalloc_t atlas;
#endif #endif
hlmodel_t *model; hlmodel_t *model;
@ -317,6 +374,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t)); shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
model->shaders = shaders; model->shaders = shaders;
for(i = 0; i < texheader->numtextures; i++) for(i = 0; i < texheader->numtextures; i++)
{ {
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "%s/%s", mod->name, COM_SkipPath(tex[i].name)); Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "%s/%s", mod->name, COM_SkipPath(tex[i].name));
@ -328,23 +386,128 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
if (tex[i].flags & HLMDLFL_FULLBRIGHT) if (tex[i].flags & HLMDLFL_FULLBRIGHT)
{ {
if (tex[i].flags & HLMDLFL_CHROME) if (tex[i].flags & HLMDLFL_CHROME)
{
shader = HLSHADER_FULLBRIGHTCHROME; shader = HLSHADER_FULLBRIGHTCHROME;
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_fullbrightchrome");
}
else else
{
shader = HLSHADER_FULLBRIGHT; shader = HLSHADER_FULLBRIGHT;
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_fullbright");
}
} }
else if (tex[i].flags & HLMDLFL_CHROME) else if (tex[i].flags & HLMDLFL_CHROME)
{
shader = HLSHADER_CHROME; shader = HLSHADER_CHROME;
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_chrome");
}
else else
{
shader = ""; shader = "";
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_other");
}
shaders[i].defaultshadertext = shader; shaders[i].defaultshadertext = shader;
} }
else else
{
shaders[i].defaultshadertext = NULL; shaders[i].defaultshadertext = NULL;
Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel");
}
memset(&shaders[i].defaulttex, 0, sizeof(shaders[i].defaulttex)); memset(&shaders[i].defaulttex, 0, sizeof(shaders[i].defaulttex));
shaders[i].defaulttex.base = Image_GetTexture(shaders[i].name, "", IF_NOALPHA, (qbyte *) texheader + tex[i].offset, (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset, tex[i].w, tex[i].h, TF_8PAL24); }
//figure out the preferred atlas size. hopefully it'll fit well enough...
if (texheader->numtextures == 1)
Mod_LightmapAllocInit(&atlas, false, tex[0].w, tex[0].h, 0);
else
{
int sz = 1;
for(i = 0; i < texheader->numtextures; i++)
while (sz < tex[i].w || sz < tex[i].h)
sz <<= 1;
for (; sz < sh_config.texture2d_maxsize; sz<<=1)
{
unsigned short x,y;
int atlasid;
Mod_LightmapAllocInit(&atlas, false, sz, sz, 0);
for(i = 0; i < texheader->numtextures; i++)
{
if (tex[i].flags & HLMDLFL_CHROME)
continue;
Mod_LightmapAllocBlock(&atlas, tex[i].w, tex[i].h, &x, &y, &atlasid);
}
if (i == texheader->numtextures && atlas.lmnum <= 0)
break; //okay, just go with it.
}
Mod_LightmapAllocInit(&atlas, false, sz, sz, 0);
}
for(i = 0; i < texheader->numtextures; i++)
{
if (tex[i].flags & HLMDLFL_CHROME)
{
shaders[i].x =
shaders[i].y = 0;
shaders[i].w = tex[i].w;
shaders[i].h = tex[i].h;
shaders[i].atlasid = -1;
continue;
}
shaders[i].w = tex[i].w; shaders[i].w = tex[i].w;
shaders[i].h = tex[i].h; shaders[i].h = tex[i].h;
Mod_LightmapAllocBlock(&atlas, shaders[i].w, shaders[i].h, &shaders[i].x, &shaders[i].y, &shaders[i].atlasid);
} }
if (atlas.allocated[0])
atlas.lmnum++;
//now we know where the various textures will be, generate the atlas images.
for (j = 0; j < atlas.lmnum; j++)
{
char texname[MAX_QPATH];
texid_t basetex;
int y, x;
unsigned int *basepix = Z_Malloc(atlas.width * atlas.height * sizeof(*basepix));
for(i = 0; i < texheader->numtextures; i++)
{
if (shaders[i].atlasid == j)
{
unsigned *out = basepix + atlas.width*shaders[i].y + shaders[i].x;
qbyte *in = (qbyte *) texheader + tex[i].offset;
qbyte *pal = (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset;
qbyte *rgb;
for(y = 0; y < tex[i].h; y++, out += atlas.width-shaders[i].w)
for(x = 0; x < tex[i].w; x++, in++)
{
rgb = pal + *in*3;
*out++ = 0xff000000 | (rgb[0]<<0) | (rgb[1]<<8) | (rgb[2]<<16);
}
}
}
Q_snprintfz(texname, sizeof(texname), "%s*%i", mod->name, j);
basetex = Image_GetTexture(texname, "", IF_NOALPHA|IF_NOREPLACE, basepix, NULL, atlas.width, atlas.height, PTI_RGBX8);
Z_Free(basepix);
for(i = 0; i < texheader->numtextures; i++)
{
if (shaders[i].atlasid == j)
shaders[i].defaulttex.base = basetex;
}
}
//and chrome textures need to preserve their texture coords to avoid weirdness.
for(i = 0; i < texheader->numtextures; i++)
{
if (tex[i].flags & HLMDLFL_CHROME)
{
qbyte *in = (qbyte *) texheader + tex[i].offset;
qbyte *pal = (qbyte *) texheader + tex[i].w * tex[i].h + tex[i].offset;
char texname[MAX_QPATH];
shaders[i].atlasid = j++;
Q_snprintfz(texname, sizeof(texname), "%s*%i", mod->name, shaders[i].atlasid);
shaders[i].defaulttex.base = Image_GetTexture(texname, "", IF_NOALPHA|IF_NOREPLACE, in, pal, tex[i].w, tex[i].h, TF_8PAL24);
}
}
model->numskinrefs = texheader->skinrefs; model->numskinrefs = texheader->skinrefs;
model->numskingroups = texheader->skingroups; model->numskingroups = texheader->skingroups;
@ -364,20 +527,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
#ifndef SERVERONLY #ifndef SERVERONLY
model->numgeomsets = model->header->numbodyparts; model->numgeomsets = model->header->numbodyparts;
model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets); model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets);
for (body = 0; body < model->numgeomsets; body++) HLMDL_PrepareVerticies(mod, model);
{
hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
int bodyindex;
model->geomset[body].numalternatives = bodypart->nummodels;
model->geomset[body].alternatives = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives) * bodypart->nummodels);
for (bodyindex = 0; bodyindex < bodypart->nummodels; bodyindex++)
{
hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
model->geomset[body].alternatives[bodyindex].numsubmeshes = amodel->nummesh;
model->geomset[body].alternatives[bodyindex].submesh = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset[body].alternatives[bodyindex].submesh) * amodel->nummesh);
HLMDL_PrepareVerticies(model, amodel, &model->geomset[body].alternatives[bodyindex]);
}
}
//FIXME: No VBOs used. //FIXME: No VBOs used.
#endif #endif
return true; return true;
@ -1149,63 +1299,127 @@ unsigned int HLMDL_Contents (model_t *model, int hulloverride, const framestate_
#ifndef SERVERONLY #ifndef SERVERONLY
void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curent, int bodypart, int bodyidx, int meshidx, float tex_s, float tex_t, mesh_t *mesh, qboolean gpubones) void R_HL_BuildFrame(hlmodel_t *model, int bodypart, int bodyidx, int meshidx, struct hlmodelshaders_s *texinfo, mesh_t *outmesh)
{ {
int b;
int cbone;
// int bgroup;
// int lastbone;
int v; int v;
int w = texinfo->defaulttex.base->width;
int h = texinfo->defaulttex.base->height;
vec2_t texbase = {texinfo->x/(float)w, texinfo->y/(float)h};
vec2_t texscale = {1.0/w, 1.0/h};
*mesh = model->geomset[bodypart].alternatives[bodyidx].mesh; mesh_t *srcmesh = &model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx];
//copy out the indexes into the final mesh.
memcpy(outmesh->indexes+outmesh->numindexes, srcmesh->indexes, sizeof(index_t)*srcmesh->numindexes);
outmesh->numindexes += srcmesh->numindexes;
if (outmesh == &model->mesh)
{ //get the backend to do the skeletal stuff (read: glsl)
for(v = 0; v < srcmesh->numvertexes; v++)
{ //should really come up with a better way to deal with this, like rect textures.
srcmesh->st_array[v][0] = texbase[0] + srcmesh->lmst_array[0][v][0] * texscale[0];
srcmesh->st_array[v][1] = texbase[1] + srcmesh->lmst_array[0][v][1] * texscale[1];
}
}
else
{ //backend can't handle it, apparently. do it in software.
int fvert = srcmesh->vbofirstvert;
vecV_t *nxyz = outmesh->xyz_array+fvert;
vec3_t *nnorm = outmesh->normals_array+fvert;
for(v = 0; v < srcmesh->numvertexes; v++)
{ //should really come up with a better way to deal with this, like rect textures.
srcmesh->st_array[v][0] = texbase[0] + srcmesh->lmst_array[0][v][0] * texscale[0];
srcmesh->st_array[v][1] = texbase[1] + srcmesh->lmst_array[0][v][1] * texscale[1];
//transform to nxyz (a separate buffer from the srcmesh data)
VectorTransform(srcmesh->xyz_array[v], (void *)transform_matrix[srcmesh->bonenums[v][0]], nxyz[v]);
//transform to nnorm (a separate buffer from the srcmesh data)
nnorm[v][0] = DotProduct(srcmesh->normals_array[v], transform_matrix[srcmesh->bonenums[v][0]][0]);
nnorm[v][1] = DotProduct(srcmesh->normals_array[v], transform_matrix[srcmesh->bonenums[v][0]][1]);
nnorm[v][2] = DotProduct(srcmesh->normals_array[v], transform_matrix[srcmesh->bonenums[v][0]][2]);
//FIXME: svector, tvector!
}
}
}
static void R_HL_BuildMeshes(batch_t *b)
{
entity_t *rent = b->ent;
hlmodel_t *model = Mod_Extradata(rent->model);
int body, m;
static mesh_t *mptr[1], softbonemesh;
skinfile_t *sk = rent->customskin?Mod_LookupSkin(rent->customskin):NULL;
const unsigned int entity_body = 0/*rent->body*/;
int surf;
float *bones;
int numbones;
if (b->shader->prog && (b->shader->prog->supportedpermutations & PERMUTATION_SKELETAL) && model->header->numbones < sh_config.max_gpu_bones)
{ //okay, we can use gpu gones. yay.
b->mesh = mptr;
*b->mesh = &model->mesh;
}
else
{
static vecV_t nxyz_buffer[65536];
static vec3_t nnorm_buffer[65536];
//no gpu bone support. :(
softbonemesh = model->mesh;
b->mesh = mptr;
*b->mesh = &softbonemesh;
//this stuff will get recalculated
softbonemesh.xyz_array = nxyz_buffer;
softbonemesh.normals_array = nnorm_buffer;
//don't get confused.
softbonemesh.bonenums = NULL;
softbonemesh.boneweights = NULL;
softbonemesh.bones = NULL;
softbonemesh.numbones = 0;
}
(*b->mesh)->numindexes = 0;
//FIXME: cache this! //FIXME: cache this!
if (curent->framestate.bonecount >= model->header->numbones) if (rent->framestate.bonecount >= model->header->numbones)
{ { //skeletal object...
if (curent->framestate.skeltype == SKEL_RELATIVE) int b;
if (rent->framestate.skeltype == SKEL_RELATIVE)
{ {
mesh->numbones = model->header->numbones; numbones = model->header->numbones;
for (b = 0; b < mesh->numbones; b++) for (b = 0; b < numbones; b++)
{ {
/* If we have a parent, take the addition. Otherwise just copy the values */ /* If we have a parent, take the addition. Otherwise just copy the values */
if(model->bones[b].parent>=0) if(model->bones[b].parent>=0)
{ {
R_ConcatTransforms((void*)transform_matrix[model->bones[b].parent], (void*)(curent->framestate.bonestate+b*12), transform_matrix[b]); R_ConcatTransforms((void*)transform_matrix[model->bones[b].parent], (void*)(rent->framestate.bonestate+b*12), transform_matrix[b]);
} }
else else
{ {
memcpy(transform_matrix[b], curent->framestate.bonestate+b*12, 12 * sizeof(float)); memcpy(transform_matrix[b], rent->framestate.bonestate+b*12, 12 * sizeof(float));
} }
} }
mesh->bones = transform_matrix[0][0]; bones = transform_matrix[0][0];
} }
else else
{ {
mesh->bones = curent->framestate.bonestate; bones = rent->framestate.bonestate;
mesh->numbones = curent->framestate.bonecount; numbones = rent->framestate.bonecount;
} }
} }
else else
{ { //lerp the bone data ourselves.
float relatives[12*MAX_BONES]; float relatives[12*MAX_BONES];
mesh->bones = transform_matrix[0][0]; int cbone, b;
mesh->numbones = model->header->numbones; bones = transform_matrix[0][0];
numbones = model->header->numbones;
/* //FIXME: needs caching. cbone = HLMDL_GetBoneData_Internal(model, 0, model->header->numbones, &rent->framestate, relatives);
for (b = 0; b < MAX_BONE_CONTROLLERS; b++)
model->controller[b] = curent->framestate.bonecontrols[b];
for (cbone = 0, bgroup = 0; bgroup < FS_COUNT; bgroup++)
{
lastbone = curent->framestate.g[bgroup].endbone;
if (bgroup == FS_COUNT-1)
lastbone = model->header->numbones;
if (cbone >= lastbone)
continue;
HL_SetupBones(model, curent->framestate.g[bgroup].frame[0], cbone, lastbone, curent->framestate.g[bgroup].subblendfrac, curent->framestate.g[bgroup].frametime[0], relatives); // Setup the bones
cbone = lastbone;
}
*/
cbone = HLMDL_GetBoneData_Internal(model, 0, model->header->numbones, &curent->framestate, relatives);
//convert relative to absolutes //convert relative to absolutes
for (b = 0; b < cbone; b++) for (b = 0; b < cbone; b++)
@ -1222,62 +1436,83 @@ void R_HL_BuildFrame(hlmodel_t *model, hlmdl_submodel_t *amodel, entity_t *curen
} }
} }
mesh->indexes += model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx].firstindex; model->mesh.bones = bones;
mesh->numindexes = model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx].numindexes; model->mesh.numbones = numbones;
if (gpubones && model->header->numbones < sh_config.max_gpu_bones) for (surf = 0; surf < b->meshes; surf++)
{ //get the backend to do the skeletal stuff (read: glsl) {
for(v = 0; v < mesh->numvertexes; v++) body = b->user.alias.surfrefs[surf] >> 8;
{ //should really come up with a better way to deal with this, like rect textures. {
mesh->st_array[v][0] = mesh->lmst_array[0][v][0] * tex_s; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
mesh->st_array[v][1] = mesh->lmst_array[0][v][1] * tex_t; hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body;
int bodyindex = ((sk && body < MAX_GEOMSETS && sk->geomset[body] >= 1)?sk->geomset[body]-1:(entity_body / bodypart->base)) % bodypart->nummodels;
hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Draw each mesh */
m = b->user.alias.surfrefs[surf] & 0xff;
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m;
struct hlmodelshaders_s *texinfo;
int skinidx = mesh->skinindex;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (rent->skinnum < model->numskingroups)
skinidx += rent->skinnum * model->numskinrefs;
texinfo = &model->shaders[model->skinref[skinidx]];
R_HL_BuildFrame(model, body, bodyindex, m, texinfo, *b->mesh);
}
} }
} }
else b->meshes = 1;
{ //backend can't handle it, apparently. do it in software.
static vecV_t nxyz[2048];
static vec3_t nnorm[2048];
for(v = 0; v < mesh->numvertexes; v++)
{ //should really come up with a better way to deal with this, like rect textures.
mesh->st_array[v][0] = mesh->lmst_array[0][v][0] * tex_s;
mesh->st_array[v][1] = mesh->lmst_array[0][v][1] * tex_t;
VectorTransform(mesh->xyz_array[v], (void *)transform_matrix[mesh->bonenums[v][0]], nxyz[v]);
nnorm[v][0] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][0]);
nnorm[v][1] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][1]);
nnorm[v][2] = DotProduct(mesh->normals_array[v], transform_matrix[mesh->bonenums[v][0]][2]);
//FIXME: svector, tvector!
}
mesh->xyz_array = nxyz;
mesh->normals_array = nnorm;
mesh->bonenums = NULL;
mesh->boneweights = NULL;
mesh->bones = NULL;
mesh->numbones = 0;
}
} }
qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel);
static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches); void R_HalfLife_GenerateBatches(entity_t *rent, batch_t **batches)
static void R_HL_BuildMesh(struct batch_s *b)
{
R_HalfLife_WalkMeshes(b->ent, b, NULL);
}
static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
{ {
hlmodel_t *model = Mod_Extradata(rent->model); hlmodel_t *model = Mod_Extradata(rent->model);
int body, m; int body, m;
int batchid = 0; skinfile_t *sk = rent->customskin?Mod_LookupSkin(rent->customskin):NULL;
static mesh_t bmesh, *mptr = &bmesh;
skinfile_t *sk = NULL;
unsigned int entity_body = 0; const unsigned int entity_body = 0/*rent->body*/;
batch_t *b = NULL;
if (rent->customskin) unsigned int surfidx = 0;
sk = Mod_LookupSkin(rent->customskin);
//entity_body = rent->body; //hey, if its there, lets use it. R_CalcModelLighting(rent, rent->model); //make sure the ent's lighting is right.
/*if (!model->vbobuilt)
{
mesh_t *mesh = &model->mesh;
vbo_t *vbo = &model->vbo;
vbobctx_t ctx;
model->vbobuilt = true;
BE_VBO_Begin(&ctx, (sizeof(*mesh->xyz_array)+
sizeof(*mesh->colors4b_array)+
sizeof(*mesh->st_array)+
sizeof(*mesh->lmst_array[0])+
sizeof(*mesh->normals_array)+
sizeof(*mesh->bonenums)+
sizeof(*mesh->boneweights)+
sizeof(*mesh->snormals_array)+
sizeof(*mesh->tnormals_array))*mesh->numvertexes);
BE_VBO_Data(&ctx, mesh->xyz_array, sizeof(*mesh->xyz_array)*mesh->numvertexes, &vbo->coord);
BE_VBO_Data(&ctx, mesh->colors4b_array, sizeof(*mesh->colors4b_array)*mesh->numvertexes, &vbo->colours[0]);vbo->colours_bytes = true;
BE_VBO_Data(&ctx, mesh->st_array, sizeof(*mesh->st_array)*mesh->numvertexes, &vbo->texcoord);
BE_VBO_Data(&ctx, mesh->lmst_array[0], sizeof(*mesh->lmst_array[0])*mesh->numvertexes, &vbo->lmcoord[0]);
BE_VBO_Data(&ctx, mesh->normals_array, sizeof(*mesh->normals_array)*mesh->numvertexes, &vbo->normals);
BE_VBO_Data(&ctx, mesh->bonenums, sizeof(*mesh->bonenums)*mesh->numvertexes, &vbo->bonenums);
BE_VBO_Data(&ctx, mesh->boneweights, sizeof(*mesh->boneweights)*mesh->numvertexes, &vbo->boneweights);
#if defined(RTLIGHTS)
BE_VBO_Data(&ctx, mesh->snormals_array, sizeof(*mesh->snormals_array)*mesh->numvertexes, &vbo->tvector);
BE_VBO_Data(&ctx, mesh->tnormals_array, sizeof(*mesh->tnormals_array)*mesh->numvertexes, &vbo->svector);
#endif
BE_VBO_Finish(&ctx, mesh->indexes, mesh->numindexes, &vbo->indicies, &vbo->vbomem, &vbo->ebomem);
}*/
for (body = 0; body < model->numgeomsets; body++) for (body = 0; body < model->numgeomsets; body++)
{ {
@ -1289,14 +1524,15 @@ static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
/* Draw each mesh */ /* Draw each mesh */
for(m = 0; m < amodel->nummesh; m++) for(m = 0; m < amodel->nummesh; m++, surfidx++)
{ {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m; hlmdl_mesh_t *mesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m;
float tex_w;
float tex_h;
struct hlmodelshaders_s *s; struct hlmodelshaders_s *s;
int skinidx = mesh->skinindex; int skinidx = mesh->skinindex;
texnums_t *skin;
shader_t *shader;
int sort, j;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (skinidx >= model->numskinrefs) if (skinidx >= model->numskinrefs)
@ -1305,54 +1541,59 @@ static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
skinidx += rent->skinnum * model->numskinrefs; skinidx += rent->skinnum * model->numskinrefs;
s = &model->shaders[model->skinref[skinidx]]; s = &model->shaders[model->skinref[skinidx]];
if (batches)
{
int sort, j;
if (!s->shader)
{
if (s->defaultshadertext)
s->shader = R_RegisterShader(s->name, SUF_NONE, s->defaultshadertext);
else
s->shader = R_RegisterSkin(s->name, rent->model->name);
// R_BuildDefaultTexnums(&s->defaulttex, s->shader, 0);
}
skin = &s->defaulttex;
shader = s->shader;
if (sk)
{
int i;
for (i = 0; i < sk->nummappings; i++)
{
if (!strcmp(sk->mappings[i].surface, s->name))
{
skin = &sk->mappings[i].texnums;
shader = sk->mappings[i].shader;
break;
}
}
}
if ( rent->forcedshader ) {
shader = rent->forcedshader;
}
if (b && b->skin->base == skin->base && b->shader == shader && b->meshes < countof(b->user.alias.surfrefs))
; //merging it.
else
{
b = BE_GetTempBatch(); b = BE_GetTempBatch();
if (!b) if (!b)
return; return;
b->skin = skin;
b->shader = shader;
b->buildmeshes = R_HL_BuildMeshes;
if (!s->shader)
{
if (s->defaultshadertext)
s->shader = R_RegisterShader(s->name, SUF_NONE, s->defaultshadertext);
else
s->shader = R_RegisterSkin(s->name, rent->model->name);
R_BuildDefaultTexnums(&s->defaulttex, s->shader, 0);
}
b->skin = NULL;
b->shader = s->shader;
if (sk)
{
int i;
for (i = 0; i < sk->nummappings; i++)
{
if (!strcmp(sk->mappings[i].surface, s->name))
{
b->skin = &sk->mappings[i].texnums;
b->shader = sk->mappings[i].shader;
break;
}
}
}
if ( rent->forcedshader ) {
b->shader = rent->forcedshader;
}
b->buildmeshes = R_HL_BuildMesh;
b->ent = rent; b->ent = rent;
b->mesh = NULL; b->mesh = NULL;
b->firstmesh = 0; b->firstmesh = 0;
b->meshes = 1; b->meshes = 0;
b->texture = NULL; b->texture = NULL;
for (j = 0; j < MAXRLIGHTMAPS; j++) for (j = 0; j < MAXRLIGHTMAPS; j++)
{
b->lightmap[j] = -1; b->lightmap[j] = -1;
b->surf_first = batchid; b->lmlightstyle[j] = INVALID_LIGHTSTYLE;
}
b->flags = 0; b->flags = 0;
sort = b->shader->sort; sort = shader->sort;
//fixme: we probably need to force some blend modes based on the surface flags. //fixme: we probably need to force some blend modes based on the surface flags.
if (rent->flags & RF_FORCECOLOURMOD) if (rent->flags & RF_FORCECOLOURMOD)
b->flags |= BEF_FORCECOLOURMOD; b->flags |= BEF_FORCECOLOURMOD;
@ -1376,36 +1617,16 @@ static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches)
} }
if (rent->flags & RF_NOSHADOW) if (rent->flags & RF_NOSHADOW)
b->flags |= BEF_NOSHADOWS; b->flags |= BEF_NOSHADOWS;
b->vbo = NULL; b->vbo = NULL;//&model->vbo;
b->next = batches[sort]; b->next = batches[sort];
batches[sort] = b; batches[sort] = b;
} }
else
{
if (batchid == b->surf_first)
{
tex_w = 1.0f / s->w;
tex_h = 1.0f / s->h;
b->mesh = &mptr; b->user.alias.surfrefs[b->meshes++] = (body<<8)|(m&0xff);
R_HL_BuildFrame(model, amodel, b->ent, body, bodyindex, m, tex_w, tex_h, b->mesh[0], b->shader->prog && (b->shader->prog->supportedpermutations & PERMUTATION_SKELETAL));
return;
}
}
batchid++;
} }
} }
} }
qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel);
void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches)
{
R_CalcModelLighting(e, e->model);
R_HalfLife_WalkMeshes(e, NULL, batches);
}
void HLMDL_DrawHitBoxes(entity_t *rent) void HLMDL_DrawHitBoxes(entity_t *rent)
{ {
hlmodel_t *model = Mod_Extradata(rent->model); hlmodel_t *model = Mod_Extradata(rent->model);

View File

@ -2730,7 +2730,7 @@ static int Mod_Batches_Generate(model_t *mod)
lbatch->texture == surf->texinfo->texture && lbatch->texture == surf->texinfo->texture &&
lbatch->shader == shader && lbatch->shader == shader &&
lbatch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && lbatch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) &&
Vector4Compare(plane, lbatch->plane) && Vector4Compare(plane, lbatch->user.bmodel.plane) &&
lbatch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && lbatch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES &&
#if MAXRLIGHTMAPS > 1 #if MAXRLIGHTMAPS > 1
lbatch->lightmap[1] == lmmerge(surf->lightmaptexturenums[1]) && lbatch->lightmap[1] == lmmerge(surf->lightmaptexturenums[1]) &&
@ -2748,7 +2748,7 @@ static int Mod_Batches_Generate(model_t *mod)
batch->texture == surf->texinfo->texture && batch->texture == surf->texinfo->texture &&
batch->shader == shader && batch->shader == shader &&
batch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && batch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) &&
Vector4Compare(plane, batch->plane) && Vector4Compare(plane, batch->user.bmodel.plane) &&
batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES &&
#if MAXRLIGHTMAPS > 1 #if MAXRLIGHTMAPS > 1
batch->lightmap[1] == lmmerge(surf->lightmaptexturenums[1]) && batch->lightmap[1] == lmmerge(surf->lightmaptexturenums[1]) &&
@ -2794,7 +2794,7 @@ static int Mod_Batches_Generate(model_t *mod)
batch->ent = &r_worldentity; batch->ent = &r_worldentity;
batch->fog = surf->fog; batch->fog = surf->fog;
batch->envmap = envmap; batch->envmap = envmap;
Vector4Copy(plane, batch->plane); Vector4Copy(plane, batch->user.bmodel.plane);
mod->batches[sortid] = batch; mod->batches[sortid] = batch;
} }

View File

@ -160,21 +160,36 @@ typedef struct batch_s
struct struct
{ {
unsigned int shadowbatch; //a unique index to accelerate shadowmesh generation (dlights, yay!) unsigned int shadowbatch; //a unique index to accelerate shadowmesh generation (dlights, yay!)
unsigned int ebobatch; // unsigned int ebobatch; //temporal scene cache stuff, basically just a simple index so we don't have to deal with shader sort values when generating new index lists.
unsigned int webobatch; //su // } bmodel;
}; // struct
// {
vec4_t plane; /*used only at load (for portal surfaces, so multiple planes are not part of the same batch)*/
} bmodel; //bmodel surfaces.
struct struct
{ {
unsigned int surf_first; unsigned int lightidx;
unsigned int surf_count; unsigned int lightmode;
}; } dlight; //deferred light batches
vec4_t plane; /*used only at load (for portal surfaces, so multiple planes are not part of the same batch)*/ struct
{
unsigned short surfrefs[sizeof(mesh_t)/sizeof(unsigned short)]; //for hlmdl batching...
} alias;
struct
{
unsigned int surface;
} poly;
/* struct
{
unsigned int first;
unsigned int count;
} surf;*/
struct struct
{ {
mesh_t meshbuf; mesh_t meshbuf;
mesh_t *meshptr; mesh_t *meshptr;
}; };
}; } user;
} batch_t; } batch_t;
/* /*

View File

@ -551,10 +551,10 @@ qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis);
void R_GenDlightMesh(struct batch_s *batch) void R_GenDlightMesh(struct batch_s *batch)
{ {
static mesh_t *meshptr; static mesh_t *meshptr;
dlight_t *l = cl_dlights + batch->surf_first; dlight_t *l = cl_dlights + batch->user.dlight.lightidx;
vec3_t colour; vec3_t colour;
int lightflags = batch->surf_count; int lightflags = batch->user.dlight.lightmode;
VectorCopy(l->color, colour); VectorCopy(l->color, colour);
if (l->style>=0 && l->style < cl_max_lightstyles) if (l->style>=0 && l->style < cl_max_lightstyles)
@ -698,8 +698,8 @@ void R_GenDlightBatches(batch_t *batches[])
b->texture = NULL; b->texture = NULL;
for (j = 0; j < MAXRLIGHTMAPS; j++) for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1; b->lightmap[j] = -1;
b->surf_first = i; b->user.dlight.lightidx = i;
b->surf_count = lmode; b->user.dlight.lightmode = lmode;
b->flags |= BEF_NOSHADOWS|BEF_NODLIGHT; //that would be weeird b->flags |= BEF_NOSHADOWS|BEF_NODLIGHT; //that would be weeird
b->vbo = NULL; b->vbo = NULL;
b->next = batches[sort]; b->next = batches[sort];

View File

@ -270,12 +270,12 @@ void GL_SetupSceneProcessingTextures (void)
void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const model_t *mod) void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const model_t *mod)
{ {
if ((e->flags & RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0) if (e->flags & RF_WEAPONMODEL)
{ {
float em[16]; float em[16];
float vm[16]; float vm[16];
if (e->flags & RF_WEAPONMODELNOBOB) if ((e->flags & RF_WEAPONMODELNOBOB) || r_refdef.playerview->viewentity <= 0)
{ {
vm[0] = vpn[0]; vm[0] = vpn[0];
vm[1] = vpn[1]; vm[1] = vpn[1];
@ -625,7 +625,7 @@ static void R_SetupGL (vec3_t axisorigin[4], vec4_t fovoverrides, float projmatr
} }
else else
{ {
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fovv_x, fovv_y, r_refdef.mindist, false); Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false);
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false); Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false);
} }

View File

@ -355,7 +355,7 @@ static void SHM_Shadow_Cache_Surface(msurface_t *surf)
{ {
int i; int i;
i = surf->sbatch->shadowbatch; i = surf->sbatch->user.bmodel.shadowbatch;
if (i < 0) if (i < 0)
return; return;
@ -451,11 +451,11 @@ static void SH_CalcShadowBatches(model_t *mod)
{ {
if (!l || l->vbo != b->vbo || l->texture != b->texture) if (!l || l->vbo != b->vbo || l->texture != b->texture)
{ {
b->shadowbatch = mod->numshadowbatches++; b->user.bmodel.shadowbatch = mod->numshadowbatches++;
l = b; l = b;
} }
else else
b->shadowbatch = l->shadowbatch; b->user.bmodel.shadowbatch = l->user.bmodel.shadowbatch;
} }
} }

View File

@ -3387,7 +3387,6 @@ static void GLVID_Shutdown(void)
#ifdef USE_EGL #ifdef USE_EGL
case PSL_EGL: case PSL_EGL:
EGL_Shutdown(); EGL_Shutdown();
EGL_UnloadLibrary();
GL_ForgetPointers(); GL_ForgetPointers();
break; break;
#endif #endif
@ -3431,10 +3430,24 @@ static void GLVID_Shutdown(void)
vm.modes = NULL; vm.modes = NULL;
vm.num_modes = 0; vm.num_modes = 0;
#endif #endif
x11.pXCloseDisplay(vid_dpy);
} }
x11.pXCloseDisplay(vid_dpy);
vid_dpy = NULL; vid_dpy = NULL;
vid_window = (Window)NULL; vid_window = (Window)NULL;
switch(currentpsl)
{
#ifdef GLQUAKE
#ifdef USE_EGL
case PSL_EGL:
EGL_UnloadLibrary();
break;
#endif
#endif
default:
break;
}
currentpsl = PSL_NONE; currentpsl = PSL_NONE;
} }

View File

@ -141,21 +141,18 @@ extern qboolean vid_isfullscreen;
static unsigned short originalgammaramps[3][256]; static unsigned short originalgammaramps[3][256];
qboolean vid_initializing; static qboolean vid_initializing;
static int DIBWidth, DIBHeight; static int DIBWidth, DIBHeight;
static RECT WindowRect; static RECT WindowRect;
static DWORD WindowStyle, ExWindowStyle; static DWORD WindowStyle, ExWindowStyle;
HWND mainwindow;
static HWND dibwindow; static HWND dibwindow;
static HDC maindc; static HDC maindc;
HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
viddef_t vid; // global video state
//unsigned short d_8to16rgbtable[256]; //unsigned short d_8to16rgbtable[256];
//unsigned d_8to24rgbtable[256]; //unsigned d_8to24rgbtable[256];
//unsigned short d_8to16bgrtable[256]; //unsigned short d_8to16bgrtable[256];
@ -176,10 +173,8 @@ extern cvar_t vid_desktopgamma;
extern cvar_t gl_lateswap; extern cvar_t gl_lateswap;
extern cvar_t vid_preservegamma; extern cvar_t vid_preservegamma;
int window_x, window_y; static int window_x, window_y;
static int window_width, window_height; static int window_width, window_height;
int window_center_x, window_center_y;
RECT window_rect;
static LONG WINAPI GLMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LONG WINAPI GLMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

View File

@ -39,22 +39,6 @@ struct builddata_s
}; };
void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b); //data === builddata_t
typedef struct
{
int allocated[LMBLOCK_SIZE_MAX];
int firstlm;
int lmnum;
unsigned int width;
unsigned int height;
qboolean deluxe;
} lmalloc_t;
void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height, int firstlm); //firstlm is for debugging stray lightmap indexes
void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod);
void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short *x, unsigned short *y, int *tnum);
#ifdef GLQUAKE #ifdef GLQUAKE
#if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/
#ifndef GLSLONLY #ifndef GLSLONLY

View File

@ -295,6 +295,8 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra
texnums_t defaulttex; texnums_t defaulttex;
shader_t *shader; shader_t *shader;
int w, h; int w, h;
int atlasid;
unsigned short x,y;
} *shaders; } *shaders;
short *skinref; short *skinref;
int numskinrefs; int numskinrefs;
@ -306,15 +308,13 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra
int numalternatives; int numalternatives;
struct hlalternative_s struct hlalternative_s
{ {
mesh_t mesh;
int numsubmeshes; int numsubmeshes;
struct mesh_t *submesh;
{
int firstindex;
int numindexes;
} *submesh;
} *alternatives; } *alternatives;
} *geomset; } *geomset;
mesh_t mesh;
vbo_t vbo;
qboolean vbobuilt;
} hlmodel_t; } hlmodel_t;
/* HL mathlib prototypes: */ /* HL mathlib prototypes: */
@ -343,4 +343,5 @@ int HLMDL_GetAttachment(model_t *model, int tagnum, float *resultmatrix);
//stuff only useful for clients that need to draw stuff //stuff only useful for clients that need to draw stuff
void R_DrawHLModel(entity_t *curent); void R_DrawHLModel(entity_t *curent);
void HLMDL_DrawHitBoxes(entity_t *ent); void HLMDL_DrawHitBoxes(entity_t *ent);
void R_HalfLife_GenerateBatches(entity_t *rent, batch_t **batches);
#endif #endif

View File

@ -447,9 +447,6 @@ reeval:
break; break;
} }
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
errorif (!ed || ed->readonly) errorif (!ed || ed->readonly)
{ //boot it over to the debugger { //boot it over to the debugger
#if INTSIZE == 16 #if INTSIZE == 16
@ -492,9 +489,6 @@ reeval:
break; break;
} }
ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict); ed = PROG_TO_EDICT_PB(progfuncs, OPA->edict);
#ifdef PARANOID
NUM_FOR_EDICT(ed); // make sure it's in range
#endif
errorif (!ed || ed->readonly) errorif (!ed || ed->readonly)
{ //boot it over to the debugger { //boot it over to the debugger
#if INTSIZE == 16 #if INTSIZE == 16
@ -790,7 +784,6 @@ reeval:
PR_SwitchProgsParms(progfuncs, 0); PR_SwitchProgsParms(progfuncs, 0);
} }
i = -newf->first_statement; i = -newf->first_statement;
// p = pr_typecurrent;
if (i < externs->numglobalbuiltins) if (i < externs->numglobalbuiltins)
{ {
#ifndef QCGC #ifndef QCGC
@ -802,26 +795,18 @@ reeval:
num_edicts = sv_num_edicts; num_edicts = sv_num_edicts;
} }
else else
{ PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement);
// if (newf->first_statement == -0x7fffffff)
// ((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
// else
PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement);
}
// memcpy(&pr_progstate[p].globals[OFS_RETURN], &current_progstate->globals[OFS_RETURN], sizeof(vec3_t));
PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs); PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs);
//decide weather non debugger wants to start debugging. //decide weather non debugger wants to start debugging.
return prinst.pr_xstatement; return prinst.pr_xstatement;
} }
// PR_SwitchProgsParms((OPA->function & 0xff000000)>>24);
s = PR_EnterFunction (progfuncs, newf, callerprogs); s = PR_EnterFunction (progfuncs, newf, callerprogs);
st = &pr_statements[s]; st = &pr_statements[s];
} }
//resume at the new statement, which might be in a different progs //resume at the new statement, which might be in a different progs
return s; return s;
// break;
case OP_DONE: case OP_DONE:
case OP_RETURN: case OP_RETURN:
@ -831,13 +816,7 @@ reeval:
glob[OFS_RETURN] = glob[st->a]; glob[OFS_RETURN] = glob[st->a];
glob[OFS_RETURN+1] = glob[st->a+1]; glob[OFS_RETURN+1] = glob[st->a+1];
glob[OFS_RETURN+2] = glob[st->a+2]; glob[OFS_RETURN+2] = glob[st->a+2];
/*
{
static char buffer[1024*1024*8];
int size = sizeof buffer;
progfuncs->save_ents(progfuncs, buffer, &size, 0);
}
*/
s = PR_LeaveFunction (progfuncs); s = PR_LeaveFunction (progfuncs);
st = &pr_statements[s]; st = &pr_statements[s];
if (prinst.pr_depth == prinst.exitdepth) if (prinst.pr_depth == prinst.exitdepth)

View File

@ -3370,7 +3370,7 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_
if (eval_b && eval_b->_int == 4) if (eval_b && eval_b->_int == 4)
{ {
if (opt_assignments && var_a.cast && var_a.sym == statements[numstatements-1].c.sym && var_a.ofs == statements[numstatements-1].c.ofs) if (var_a.cast && var_a.sym == statements[numstatements-1].c.sym && var_a.ofs == statements[numstatements-1].c.ofs)
if (var_a.sym && var_b.sym && var_a.sym->temp && var_a.sym->refcount==1) if (var_a.sym && var_b.sym && var_a.sym->temp && var_a.sym->refcount==1)
{ {
op = &pr_opcodes[OP_ADD_PIW]; op = &pr_opcodes[OP_ADD_PIW];

View File

@ -12281,6 +12281,7 @@ void PR_DumpPlatform_f(void)
{"startspot", "string", QW|NQ, "Receives the value of the second argument to changelevel from the previous map."}, {"startspot", "string", QW|NQ, "Receives the value of the second argument to changelevel from the previous map."},
{"dimension_send", "var float", QW|NQ, "Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero."}, {"dimension_send", "var float", QW|NQ, "Used by multicast functionality. Multicasts (and related builtins that multicast internally) will only be sent to players where (player.dimension_see & dimension_send) is non-zero."},
{"dimension_default", "//var float", QW|NQ, "Default dimension bitmask", 255}, {"dimension_default", "//var float", QW|NQ, "Default dimension bitmask", 255},
{"__fullspawndata", "__unused var string", QW|NQ|H2, "Set by the engine before calls to spawn functions, and is most easily parsed with the tokenize builtin. This allows you to handle halflife's multiple-fields-with-the-same-name (or target-specific fields)."},
{"physics_mode", "__used var float", QW|NQ|CS, "0: original csqc - physics are not run\n1: DP-compat. Thinks occur, but not true movetypes.\n2: movetypes occur just as they do in ssqc.", 2}, {"physics_mode", "__used var float", QW|NQ|CS, "0: original csqc - physics are not run\n1: DP-compat. Thinks occur, but not true movetypes.\n2: movetypes occur just as they do in ssqc.", 2},
{"gamespeed", "float", CS, "Set by the engine, this is the value of the sv_gamespeed cvar"}, {"gamespeed", "float", CS, "Set by the engine, this is the value of the sv_gamespeed cvar"},
{"numclientseats", "float", CS, "This is the number of splitscreen clients currently running on this client."}, {"numclientseats", "float", CS, "This is the number of splitscreen clients currently running on this client."},

View File

@ -2010,7 +2010,7 @@ static void SV_Status_f (void)
if (!sv.state) if (!sv.state)
{ {
Con_Printf("Server is not running\n"); Con_TPrintf("Server is not running\n");
return; return;
} }
@ -2021,30 +2021,30 @@ static void SV_Status_f (void)
if (cpu) if (cpu)
cpu = 100*svs.stats.latched_active/cpu; cpu = 100*svs.stats.latched_active/cpu;
Con_Printf("cpu utilization : %3i%%\n",(int)cpu); Con_TPrintf("cpu utilization : %3i%%\n",(int)cpu);
Con_Printf("avg response time: %i ms (%i max)\n",(int)(1000*svs.stats.latched_active/svs.stats.latched_count), (int)(1000*svs.stats.latched_maxresponse)); Con_TPrintf("avg response time: %i ms (%i max)\n",(int)(1000*svs.stats.latched_active/svs.stats.latched_count), (int)(1000*svs.stats.latched_maxresponse));
Con_Printf("packets/frame : %5.2f (%i max)\n", (float)svs.stats.latched_packets/svs.stats.latched_count, svs.stats.latched_maxpackets); //not relevent as a limit. Con_TPrintf("packets/frame : %5.2f (%i max)\n", (float)svs.stats.latched_packets/svs.stats.latched_count, svs.stats.latched_maxpackets); //not relevent as a limit.
if (NET_GetRates(svs.sockets, &pi, &po, &bi, &bo)) if (NET_GetRates(svs.sockets, &pi, &po, &bi, &bo))
Con_Printf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit. Con_TPrintf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit.
Con_Printf("server uptime : %s\n", ShowTime(realtime)); Con_TPrintf("server uptime : %s\n", ShowTime(realtime));
Con_Printf("public : %s\n", sv_public.value?"yes":"no"); Con_TPrintf("public : %s\n", sv_public.value?"yes":"no");
switch(svs.gametype) switch(svs.gametype)
{ {
#ifdef Q3SERVER #ifdef Q3SERVER
case GT_QUAKE3: case GT_QUAKE3:
Con_Printf("client types :%s\n", sv_listen_qw.ival?" Q3":""); Con_TPrintf("client types :%s\n", sv_listen_qw.ival?" Q3":"");
break; break;
#endif #endif
#ifdef Q2SERVER #ifdef Q2SERVER
case GT_QUAKE2: case GT_QUAKE2:
Con_Printf("client types :%s\n", sv_listen_qw.ival?" Q2":""); Con_TPrintf("client types :%s\n", sv_listen_qw.ival?" Q2":"");
break; break;
#endif #endif
default: default:
Con_Printf("client types :%s", sv_listen_qw.ival?" QW":""); Con_TPrintf("client types :%s", sv_listen_qw.ival?" QW":"");
#ifdef NQPROT #ifdef NQPROT
Con_Printf("%s%s", (sv_listen_nq.ival==2)?" -NQ":(sv_listen_nq.ival?" NQ":""), sv_listen_dp.ival?" DP":""); Con_TPrintf("%s%s", (sv_listen_nq.ival==2)?" -NQ":(sv_listen_nq.ival?" NQ":""), sv_listen_dp.ival?" DP":"");
#endif #endif
#ifdef QWOVERQ3 #ifdef QWOVERQ3
if (sv_listen_q3.ival) Con_Printf(" Q3"); if (sv_listen_q3.ival) Con_Printf(" Q3");
@ -2057,7 +2057,7 @@ static void SV_Status_f (void)
#endif #endif
Con_Printf("\n"); Con_Printf("\n");
#if defined(TCPCONNECT) && !defined(CLIENTONLY) #if defined(TCPCONNECT) && !defined(CLIENTONLY)
Con_Printf("tcp services :"); Con_TPrintf("tcp services :");
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
if (net_enable_tls.ival) if (net_enable_tls.ival)
Con_Printf(" TLS"); Con_Printf(" TLS");
@ -2085,12 +2085,12 @@ static void SV_Status_f (void)
return; return;
} }
#endif #endif
Con_Printf("map uptime : %s\n", ShowTime(sv.world.physicstime)); Con_TPrintf("map uptime : %s\n", ShowTime(sv.world.physicstime));
//show the current map+name (but hide name if its too long or would be ugly) //show the current map+name (but hide name if its too long or would be ugly)
if (columns >= 80 && *sv.mapname && strlen(sv.mapname) < 45 && !strchr(sv.mapname, '\n')) if (columns >= 80 && *sv.mapname && strlen(sv.mapname) < 45 && !strchr(sv.mapname, '\n'))
Con_Printf ("current map : %s (%s)\n", svs.name, sv.mapname); Con_TPrintf ("current map : %s (%s)\n", svs.name, sv.mapname);
else else
Con_Printf ("current map : %s\n", svs.name); Con_TPrintf ("current map : %s\n", svs.name);
if (svs.gametype == GT_PROGS) if (svs.gametype == GT_PROGS)
{ {
@ -2103,25 +2103,25 @@ static void SV_Status_f (void)
continue; //free, and older than the zombie time continue; //free, and older than the zombie time
count++; count++;
} }
Con_Printf("entities : %i/%i/%i (mem: %.1f%%)\n", count, sv.world.num_edicts, sv.world.max_edicts, 100*(float)(sv.world.progs->stringtablesize/(double)sv.world.progs->stringtablemaxsize)); Con_TPrintf("entities : %i/%i/%i (mem: %.1f%%)\n", count, sv.world.num_edicts, sv.world.max_edicts, 100*(float)(sv.world.progs->stringtablesize/(double)sv.world.progs->stringtablemaxsize));
for (count = 1; count < MAX_PRECACHE_MODELS; count++) for (count = 1; count < MAX_PRECACHE_MODELS; count++)
if (!sv.strings.model_precache[count]) if (!sv.strings.model_precache[count])
break; break;
Con_Printf("models : %i/%i\n", count, MAX_PRECACHE_MODELS); Con_TPrintf("models : %i/%i\n", count, MAX_PRECACHE_MODELS);
for (count = 1; count < MAX_PRECACHE_SOUNDS; count++) for (count = 1; count < MAX_PRECACHE_SOUNDS; count++)
if (!sv.strings.sound_precache[count]) if (!sv.strings.sound_precache[count])
break; break;
Con_Printf("sounds : %i/%i\n", count, MAX_PRECACHE_SOUNDS); Con_TPrintf("sounds : %i/%i\n", count, MAX_PRECACHE_SOUNDS);
for (count = 1; count < MAX_SSPARTICLESPRE; count++) for (count = 1; count < MAX_SSPARTICLESPRE; count++)
if (!sv.strings.particle_precache[count]) if (!sv.strings.particle_precache[count])
break; break;
if (count!=1) if (count!=1)
Con_Printf("particles : %i/%i\n", count, MAX_SSPARTICLESPRE); Con_TPrintf("particles : %i/%i\n", count, MAX_SSPARTICLESPRE);
} }
Con_Printf("gamedir : %s\n", FS_GetGamedir(true)); Con_TPrintf("gamedir : %s\n", FS_GetGamedir(true));
if (sv.csqcdebug) if (sv.csqcdebug)
Con_Printf("csqc debug : true\n"); Con_TPrintf("csqc debug : true\n");
#ifdef MVD_RECORDING #ifdef MVD_RECORDING
SV_Demo_PrintOutputs(); SV_Demo_PrintOutputs();
#endif #endif
@ -2133,9 +2133,9 @@ static void SV_Status_f (void)
{ {
// most remote clients are 40 columns // most remote clients are 40 columns
// 0123456789012345678901234567890123456789 // 0123456789012345678901234567890123456789
Con_Printf ("name userid frags\n"); Con_Printf ( "name userid frags\n"
Con_Printf (" address rate ping drop\n"); " address rate ping drop\n"
Con_Printf (" ---------------- ---- ---- -----\n"); " ---------------- ---- ---- -----\n");
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++) for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{ {
if (!cl->state) if (!cl->state)

View File

@ -158,47 +158,108 @@ int Sys_DebugLog(char *file, char *fmt, ...)
return 1; return 1;
} }
/*
================ static quint64_t timer_basetime; //used by all clocks to bias them to starting at 0
Sys_Milliseconds static void Sys_ClockType_Changed(cvar_t *var, char *oldval);
================ static cvar_t sys_clocktype = CVARFCD("sys_clocktype", "", CVAR_NOTFROMSERVER, Sys_ClockType_Changed, "Controls which system clock to base timings from.\n0: auto\n"
*/ "1: gettimeofday (may be discontinuous).\n"
unsigned int Sys_Milliseconds (void) "2: monotonic.");
static enum
{ {
struct timeval tp; QCLOCK_AUTO = 0,
struct timezone tzp;
static int secbase;
gettimeofday(&tp, &tzp); QCLOCK_GTOD,
QCLOCK_MONOTONIC,
QCLOCK_REALTIME,
if (!secbase) QCLOCK_INVALID
} timer_clocktype;
static quint64_t Sys_GetClock(quint64_t *freq)
{
quint64_t t;
if (timer_clocktype == QCLOCK_MONOTONIC)
{ {
secbase = tp.tv_sec; struct timespec ts;
return tp.tv_usec/1000; clock_gettime(CLOCK_MONOTONIC, &ts);
*freq = 1000000000;
t = (ts.tv_sec*(quint64_t)1000000000) + ts.tv_nsec;
} }
return (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000; else if (timer_clocktype == QCLOCK_REALTIME)
} {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
*freq = 1000000000;
t = (ts.tv_sec*(quint64_t)1000000000) + ts.tv_nsec;
/* //WARNING t can go backwards
================ }
Sys_DoubleTime else //if (timer_clocktype == QCLOCK_GTOD)
================ {
*/ struct timeval tp;
gettimeofday(&tp, NULL);
*freq = 1000000;
t = tp.tv_sec*(quint64_t)1000000 + tp.tv_usec;
//WARNING t can go backwards
}
return t - timer_basetime;
}
static void Sys_ClockType_Changed(cvar_t *var, char *oldval)
{
int newtype = var?var->ival:0;
if (newtype >= QCLOCK_INVALID)
newtype = QCLOCK_AUTO;
if (newtype <= QCLOCK_AUTO)
newtype = QCLOCK_MONOTONIC;
if (newtype != timer_clocktype)
{
quint64_t oldtime, oldfreq;
quint64_t newtime, newfreq;
oldtime = Sys_GetClock(&oldfreq);
timer_clocktype = newtype;
timer_basetime = 0;
newtime = Sys_GetClock(&newfreq);
timer_basetime = newtime - (newfreq * (oldtime) / oldfreq);
/*if (host_initialized)
{
const char *clockname = "unknown";
switch(timer_clocktype)
{
case QCLOCK_GTOD: clockname = "gettimeofday"; break;
case QCLOCK_MONOTONIC: clockname = "monotonic"; break;
case QCLOCK_REALTIME: clockname = "realtime"; break;
case QCLOCK_AUTO:
case QCLOCK_INVALID: break;
}
Con_Printf("Clock %s, wraps after %"PRIu64" days, %"PRIu64" years\n", clockname, (((quint64_t)-1)/newfreq)/(24*60*60), (((quint64_t)-1)/newfreq)/(24*60*60*365));
}*/
}
}
static void Sys_InitClock(void)
{
quint64_t freq;
Cvar_Register(&sys_clocktype, "System vars");
//calibrate it, and apply.
Sys_ClockType_Changed(NULL, NULL);
timer_basetime = 0;
timer_basetime = Sys_GetClock(&freq);
}
double Sys_DoubleTime (void) double Sys_DoubleTime (void)
{ {
struct timeval tp; quint64_t denum, num = Sys_GetClock(&denum);
struct timezone tzp; return num / (long double)denum;
static int secbase; }
unsigned int Sys_Milliseconds (void)
gettimeofday(&tp, &tzp); {
quint64_t denum, num = Sys_GetClock(&denum);
if (!secbase) num *= 1000;
{ return num / denum;
secbase = tp.tv_sec;
return tp.tv_usec/1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
} }
/* /*
@ -671,6 +732,8 @@ is marked
*/ */
void Sys_Init (void) void Sys_Init (void)
{ {
Sys_InitClock();
Cvar_Register (&sys_nostdout, "System configuration"); Cvar_Register (&sys_nostdout, "System configuration");
Cvar_Register (&sys_extrasleep, "System configuration"); Cvar_Register (&sys_extrasleep, "System configuration");

View File

@ -4539,7 +4539,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
if (sysextnames && (!vk.khr_swapchain || !surfext)) if (sysextnames && (!vk.khr_swapchain || !surfext))
{ {
Con_Printf(CON_ERROR"Vulkan instance lacks driver support for %s\n", sysextnames[0]); Con_TPrintf(CON_ERROR"Vulkan instance lacks driver support for %s\n", sysextnames[0]);
return false; return false;
} }
} }
@ -4796,7 +4796,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
case VK_PHYSICAL_DEVICE_TYPE_CPU: type = "software"; break; case VK_PHYSICAL_DEVICE_TYPE_CPU: type = "software"; break;
} }
Con_Printf("Vulkan %u.%u.%u: GPU%i %s %s %s (%u.%u.%u)\n", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion), Con_TPrintf("Vulkan %u.%u.%u: GPU%i %s %s %s (%u.%u.%u)\n", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion),
gpuidx, type, vendor, props.deviceName, gpuidx, type, vendor, props.deviceName,
VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion) VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion)
); );
@ -5017,7 +5017,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
switch(err) switch(err)
{ {
case VK_ERROR_INCOMPATIBLE_DRIVER: case VK_ERROR_INCOMPATIBLE_DRIVER:
Con_Printf(CON_ERROR"VK_ERROR_INCOMPATIBLE_DRIVER: please install an appropriate vulkan driver\n"); Con_TPrintf(CON_ERROR"VK_ERROR_INCOMPATIBLE_DRIVER: please install an appropriate vulkan driver\n");
return false; return false;
case VK_ERROR_EXTENSION_NOT_PRESENT: case VK_ERROR_EXTENSION_NOT_PRESENT:
case VK_ERROR_FEATURE_NOT_PRESENT: case VK_ERROR_FEATURE_NOT_PRESENT: