From 744b9a25db15c9262f53899c7d871b81255577a6 Mon Sep 17 00:00:00 2001 From: Spoike Date: Thu, 13 Aug 2020 08:39:48 +0000 Subject: [PATCH] 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 --- engine/client/cl_ents.c | 4 +- engine/client/cl_main.c | 7 + engine/client/cl_master.h | 2 +- engine/client/client.h | 2 +- engine/client/in_win.c | 13 +- engine/client/keys.c | 6 +- engine/client/m_download.c | 140 +++++-- engine/client/m_options.c | 17 +- engine/client/menu.c | 2 +- engine/client/menu.h | 2 +- engine/client/net_master.c | 2 +- engine/client/p_script.c | 2 + engine/client/pr_csqc.c | 47 +-- engine/client/pr_menu.c | 20 + engine/client/r_surf.c | 18 +- engine/client/render.h | 15 +- engine/client/renderer.c | 8 +- engine/client/skin.c | 271 +++++++------ engine/client/snd_al.c | 12 +- engine/client/sys_linux.c | 114 +++++- engine/client/zqtp.c | 2 +- engine/common/cmd.c | 25 +- engine/common/com_mesh.c | 419 +++++++++++--------- engine/common/common.c | 10 +- engine/common/common.h | 12 +- engine/common/cvar.c | 34 +- engine/common/cvar.h | 2 - engine/common/fs.c | 6 +- engine/common/fs_zip.c | 13 + engine/common/log.c | 67 +++- engine/common/net_ssl_gnutls.c | 49 ++- engine/common/net_wins.c | 30 +- engine/common/netinc.h | 13 +- engine/common/pr_bgcmd.c | 7 +- engine/common/translate.c | 179 ++++++--- engine/common/translate.h | 1 + engine/d3d/vid_d3d.c | 12 +- engine/d3d/vid_d3d11.c | 12 +- engine/d3d/vid_d3d8.c | 12 +- engine/gl/gl_alias.c | 44 +- engine/gl/gl_backend.c | 8 +- engine/gl/gl_hlmdl.c | 705 ++++++++++++++++++++++----------- engine/gl/gl_model.c | 6 +- engine/gl/gl_model.h | 33 +- engine/gl/gl_rlight.c | 8 +- engine/gl/gl_rmain.c | 6 +- engine/gl/gl_shadow.c | 6 +- engine/gl/gl_vidlinuxglx.c | 17 +- engine/gl/gl_vidnt.c | 9 +- engine/gl/glquake.h | 16 - engine/gl/model_hl.h | 13 +- engine/qclib/execloop.h | 25 +- engine/qclib/qcc_pr_comp.c | 2 +- engine/server/pr_cmds.c | 1 + engine/server/sv_ccmds.c | 48 +-- engine/server/sv_sys_unix.c | 129 ++++-- engine/vk/vk_init.c | 6 +- 57 files changed, 1680 insertions(+), 1011 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 923f1b76f..ad3b7538a 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -5696,7 +5696,7 @@ void CL_SetSolidEntities (void) if (state->modelindex <= 0) continue; mod = cl.model_precache[state->modelindex]; - if (!mod) + if (!mod || mod->loadstate != MLS_LOADED) continue; /*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. @@ -5709,8 +5709,6 @@ void CL_SetSolidEntities (void) pent = &pmove.physents[pmove.numphysent]; memset(pent, 0, sizeof(physent_t)); pent->model = mod; - if (pent->model->loadstate != MLS_LOADED) - continue; VectorCopy (state->angles, pent->angles); pent->angles[0]*=r_meshpitch.value; } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 18c72a97d..10db7882b 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2365,6 +2365,7 @@ void CL_CheckServerInfo(void) // Initialize cl.maxpitch & cl.minpitch if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE) { +#ifdef NQPROT s = InfoBuf_ValueForKey(&cl.serverinfo, "maxpitch"); cl.maxpitch = *s ? Q_atof(s) : ((cl_fullpitch_nq.ival && !cl.haveserverinfo)?90.0f:80.0f); 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 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 { diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 980991ca1..b65d9d36d 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -154,7 +154,7 @@ typedef struct serverinfo_s char gamedir[8+1]; char map[16]; - unsigned short gameversion; +// unsigned short gameversion; unsigned short ping; short tl; diff --git a/engine/client/client.h b/engine/client/client.h index e32e9e0d9..782f481c0 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1597,7 +1597,7 @@ qbyte *ReadPCXData(qbyte *buf, int length, int width, int height, qbyte *result) qwskin_t *Skin_Lookup (char *fullname); char *Skin_FindName (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_FlushSkin(char *name); void Skin_AllSkins_f (void); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 05f35f15a..5bd3a0600 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -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_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_rightvibrator = CVARFD("xinput_rightvibrator","0", CVAR_ARCHIVE, ""); +static cvar_t xinput_leftvibrator = CVARF("xinput_leftvibrator","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_threshold_noforce = CVAR("m_threshold_noforce", "0"); @@ -116,6 +116,12 @@ extern qboolean multicursor_active[8]; POINT current_mouse_pos; + +HWND mainwindow; +int window_center_x, window_center_y; +RECT window_rect; + + typedef struct { union { HANDLE rawinputhandle; @@ -1569,10 +1575,9 @@ void INS_Accumulate (void) if (!mouseactive) { - extern int window_x, window_y; GetCursorPos (¤t_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; } } diff --git a/engine/client/keys.c b/engine/client/keys.c index 8e8bddbf2..69abfd984 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -432,14 +432,14 @@ void Key_UpdateCompletionDesc(void) if (var) { 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 Con_Footerf(NULL, false, "%s %s", cmd, var->string); } else { if (desc) - Con_Footerf(NULL, false, "%s: %s", cmd, desc); + Con_Footerf(NULL, false, "%s: %s", cmd, localtext(desc)); else Con_Footerf(NULL, false, ""); } @@ -508,7 +508,7 @@ void CompleteCommand (qboolean force, int direction) con_commandmatch = 1; if (desc) - Con_Footerf(NULL, false, "%s: %s", cmd, desc); + Con_Footerf(NULL, false, "%s: %s", cmd, localtext(desc)); else Con_Footerf(NULL, false, ""); return; diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 56cd07a1c..f9e0c6206 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -175,6 +175,7 @@ typedef struct package_s { // DEP_MIRROR, // DEP_FAILEDMIRROR, + DEP_SOURCE, //which source url we found this package from DEP_EXTRACTNAME, //a file that will be installed DEP_FILE //a file that will be installed } dtype; @@ -286,6 +287,37 @@ static void PM_FreePackage(package_t *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) { //corrupt packages must be purged @@ -310,7 +342,7 @@ void PM_ValidateAuthenticity(package_t *p) int r; char authority[MAX_QPATH], *sig; -#if 1//ndef _DEBUG +#ifndef _DEBUG #pragma message("Temporary code.") //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. @@ -381,6 +413,7 @@ void PM_ValidateAuthenticity(package_t *p) r = OSSL_VerifyHash(hashdata, hashsize, authority, signdata, signsize); #endif + p->flags &= ~(DPF_SIGNATUREACCEPTED|DPF_SIGNATUREREJECTED|DPF_SIGNATUREUNKNOWN); if (r == VH_CORRECT) p->flags |= DPF_SIGNATUREACCEPTED; 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 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; - } - if (nd->dtype == DEP_FILE) - { - nd = nd->next; - continue; - } + od = od->next; + continue; + } + if ((nd->dtype == DEP_FILE && ignorefiles) || nd->dtype == DEP_SOURCE) + { + nd = nd->next; + continue; } 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->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->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; 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. 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); return true; } @@ -786,24 +831,6 @@ static qboolean PM_CheckFile(const char *filename, enum fs_relative base) } 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) { @@ -845,6 +872,8 @@ static void PM_RemSubList(const char *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) DL_Close(downloadablelist[i].curdl); 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 } + if (url) + PM_AddDep(p, DEP_SOURCE, url); + PM_InsertPackage(p); } } @@ -3450,7 +3482,7 @@ static void PM_PromptApplyChanges(void) pkg_updating = true; #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))) Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel"); else @@ -3585,6 +3617,7 @@ void PM_Command_f(void) int i, count; package_t **sorted; const char *category = "", *newcat; + struct packagedep_s *dep; for (count = 0, p = availablepackages; p; p=p->next) count++; sorted = Z_Malloc(sizeof(*sorted)*count); @@ -3659,6 +3692,12 @@ void PM_Command_f(void) //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":""); + 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)) 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)) @@ -3670,22 +3709,31 @@ void PM_Command_f(void) } else if (!strcmp(act, "show")) { + struct packagedep_s *dep; + int found = 0; key = Cmd_Argv(2); - p = PM_FindPackage(key); - if (p) + for (p = availablepackages; p; p=p->next) { + if (Q_strcasecmp(p->name, key)) + continue; + if (p->previewimage) Con_Printf("^[%s (%s)\\tipimg\\%s\\tip\\%s^]\n", p->name, p->version, p->previewimage, ""); else Con_Printf("%s (%s)\n", p->name, p->version); if (p->title) - Con_Printf(" title: %s\n", p->title); + Con_Printf(" ^mtitle: ^m%s\n", p->title); if (p->license) - Con_Printf(" license: %s\n", p->license); + Con_Printf(" ^mlicense: ^m%s\n", p->license); if (p->author) - Con_Printf(" author: %s\n", p->author); + Con_Printf(" ^mauthor: ^m%s\n", p->author); 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) Con_Printf("%s\n", p->description); @@ -3728,10 +3776,22 @@ void PM_Command_f(void) if (p->flags & DPF_ENGINE) Con_Printf(" package is an engine update\n"); if (p->flags & DPF_TESTING) - Con_Printf(" package is untested\n"); - return; + Con_Printf(S_COLOR_YELLOW" package is untested\n"); + 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("\n"); + if (!found) + Con_Printf("\n"); } else if (!strcmp(act, "search") || !strcmp(act, "find")) { diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 71b9417dd..af033c6c9 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -3590,7 +3590,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu { case MV_NONE: 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" "s: zoom out\n" "m: mode\n" @@ -3644,7 +3644,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu if (!*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, - 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" "surfflags: %#x\n" "body: %i\n" @@ -3675,11 +3676,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu else { 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); } break; case MV_NORMALS: + Draw_FunString(0, y, va("Normals")); break; case MV_BONES: #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)); if (!body) + { + Draw_FunString(0, y, "Shader info not available"); break; + } if (*mods->shaderfile) mods->shadertext = Z_StrDup(va("\n\nPress space to view+edit the shader\n\n%s", body)); else @@ -3790,8 +3796,13 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu else Draw_FunString(0, y, va("%s: ", t)); } + else + Draw_FunString(0, y, "Texture info not available"); } 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) diff --git a/engine/client/menu.c b/engine/client/menu.c index aad499db7..6836fbc33 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -572,7 +572,7 @@ static void Prompt_Release(struct menu_s *gm) callback(ctx, PROMPT_CANCEL); 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; char *t; diff --git a/engine/client/menu.h b/engine/client/menu.h index 1f534c1cd..cd48d1354 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -127,7 +127,7 @@ typedef enum PROMPT_NO = 1, PROMPT_CANCEL = -1, } 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 diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 6343c4285..d40c4b39d 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -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->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->numhumans = info->players - info->numbots; diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 94fb674eb..c4db435a1 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -1381,6 +1381,8 @@ void P_ParticleEffect_f(void) ptype->count = 1/atof(value); if (Cmd_Argc()>2) ptype->countrand = 1/atof(Cmd_Argv(2)); + if (Cmd_Argc()>3) + ptype->countextra = atof(Cmd_Argv(3)); } else if (!strcmp(var, "count")) { diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 19fd02453..5148a3c88 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2797,6 +2797,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars if (csqc_worldchanged) { csqc_worldchanged = false; + cl.worldmodel = r_worldentity.model = csqc_world.worldmodel; Surf_NewMap(); CL_UpdateWindowTitle(); @@ -3144,7 +3145,7 @@ static void QCBUILTIN PF_cs_pointcontents(pubprogfuncs_t *prinst, struct globalv 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) G_FLOAT(OFS_RETURN) = Q1CONTENTS_SOLID; 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); if (!ent->entnum) - { - cl.worldmodel = r_worldentity.model = csqc_world.worldmodel = model; + { //setmodel(world, "maps/foo.bsp"); may be used to switch the csqc's worldmodel. + csqc_world.worldmodel = model; csqc_worldchanged = true; VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin); 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 @@ -4028,7 +4033,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo return; } - if (!cl.worldmodel) + if (!csqc_world.worldmodel) return; //urm.. 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) { 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) - COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); - s = Mod_GetEntitiesString(cl.worldmodel); + if (csqc_world.worldmodel->loadstate == MLS_LOADING) + COM_WorkerPartialSync(csqc_world.worldmodel, &csqc_world.worldmodel->loadstate, MLS_LOADING); + s = Mod_GetEntitiesString(csqc_world.worldmodel); } csqcmapentitydata = s; 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 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]); } @@ -5268,7 +5268,7 @@ static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvar { /* #ifdef Q2BSPS - if (cl.worldmodel->fromgame == fg_quake2) + if (csqc_world.worldmodel->fromgame == fg_quake2) { int portal; 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. else 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 */ #ifdef Q3BSPS - if (cl.worldmodel->fromgame == fg_quake3) + if (csqc_world.worldmodel->fromgame == fg_quake3) { int state = G_FLOAT(OFS_PARM1)!=0; wedict_t *portal = G_WEDICT(prinst, OFS_PARM0); int area1 = portal->pvsinfo.areanum, area2 = portal->pvsinfo.areanum2; if (area1 == area2 || area1<0 || area2<0) 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 } @@ -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) { 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); 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)); } } @@ -8291,15 +8291,16 @@ void CSQC_WorldLoaded(void) if (csqc_isdarkplaces) CSQC_FindGlobals(false); - csqcmapentitydataloaded = true; - csqcmapentitydata = Mod_GetEntitiesString(cl.worldmodel); - csqc_world.worldmodel = cl.worldmodel; + + csqcmapentitydataloaded = true; + csqcmapentitydata = Mod_GetEntitiesString(csqc_world.worldmodel); + World_RBE_Start(&csqc_world); worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0); 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; csqc_setmodel(csqcprogs, worldent, wmodelindex); csqc_worldchanged = tmp; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index bb2a66c6d..2290cfd9b 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -1359,6 +1359,8 @@ static struct evalc_t frame2time; evalc_t renderflags; evalc_t skinobject; + evalc_t colourmod; + evalc_t alpha; } menuc_eval; 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 *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 *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 rflags; @@ -2163,6 +2167,22 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e 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) out->flags |= RF_ADDITIVE; if (rflags & CSQCRF_DEPTHHACK) diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index f3c5a2629..1e0f24482 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2958,12 +2958,12 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent) *b = *ob; if (b->vbo && b->maxmeshes) { - b->meshbuf = *b->mesh[0]; - b->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 = *b->mesh[0]; + b->user.meshbuf.numindexes = b->mesh[b->maxmeshes-1]->indexes+b->mesh[b->maxmeshes-1]->numindexes-b->mesh[0]->indexes; + 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->meshptr = &b->meshbuf; + b->mesh = &b->user.meshptr; + b->user.meshptr = &b->user.meshbuf; b->meshes = b->maxmeshes = 1; } else @@ -3182,7 +3182,7 @@ static void Surf_SimpleWorld_Q1BSP(struct webostate_s *es, qbyte *pvs) Surf_RenderDynamicLightmaps_Worker (wmodel, surf, es->lightstylevalues); mesh = surf->mesh; - eb = &es->batches[surf->sbatch->ebobatch]; + eb = &es->batches[surf->sbatch->user.bmodel.ebobatch]; if (eb->maxidx < eb->numidx + mesh->numindexes) { //FIXME: pre-allocate @@ -3253,7 +3253,7 @@ static void Surf_SimpleWorld_Q3BSP(struct webostate_s *es, qbyte *pvs) surf->visframe = fc; mesh = surf->mesh; - eb = &es->batches[surf->sbatch->ebobatch]; + eb = &es->batches[surf->sbatch->user.bmodel.ebobatch]; if (eb->maxidx < eb->numidx + mesh->numindexes) { //FIXME: pre-allocate @@ -3431,7 +3431,7 @@ void Surf_DrawWorld (void) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next) { - batch->ebobatch = currentmodel->numbatches; + batch->user.bmodel.ebobatch = currentmodel->numbatches; currentmodel->numbatches++; } /*TODO submodels too*/ @@ -3469,7 +3469,7 @@ void Surf_DrawWorld (void) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (batch = currentmodel->batches[sortid]; batch != NULL; batch = batch->next) { - batch->ebobatch = currentmodel->numbatches; + batch->user.bmodel.ebobatch = currentmodel->numbatches; currentmodel->numbatches++; } } diff --git a/engine/client/render.h b/engine/client/render.h index a7f815016..8b3a04d8d 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -411,6 +411,19 @@ void GLVID_Console_Resize(void); int R_LightPoint (vec3_t p); 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 { /*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_HIGHPRIORITY = 1<<23, //pushed to start of worker queue instead of end... 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_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*/ diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 763f5fb99..8603466b1 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -408,15 +408,15 @@ cvar_t gl_conback = CVARFCD ("gl_conback", "", // CVAR_ARCHIVE); //cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); 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" "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_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" "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_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", "", diff --git a/engine/client/skin.c b/engine/client/skin.c index caddf3b16..3a8659fcc 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -120,7 +120,7 @@ qwskin_t *Skin_Lookup (char *fullname) if (!strcmp (cleanname, skins[i].name)) { skin = &skins[i]; - Skin_Cache8 (skin); + Skin_TryCache8 (skin); return skin; } } @@ -136,7 +136,7 @@ qwskin_t *Skin_Lookup (char *fullname) memset (skin, 0, sizeof(*skin)); Q_strncpyz(skin->name, cleanname, sizeof(skin->name)); - Skin_Cache8 (skin); + Skin_TryCache8 (skin); return skin; } /* @@ -187,6 +187,126 @@ void Skin_Find (player_info_t *sc) 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) { 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; char name[MAX_QPATH]; - qbyte *raw; - qbyte *out, *pix; - pcx_t *pcx; - int x, y, srcw, srch; - int dataByte; - int runLength; - int fbremap[256]; + qbyte *out; + int srcw, srch; size_t pcxsize; + + void *pcxfiledata; Q_snprintfz (name, sizeof(name), "skins/%s.pcx", skin->name); - raw = COM_LoadTempFile (name, FSLF_IGNOREPURE, &pcxsize); - if (!raw) + pcxfiledata = FS_LoadMallocFileFlags (name, FSLF_IGNOREPURE, &pcxsize); + if (!pcxfiledata) { //use 24bit skins even if gl_load24bit is failed 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) { 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); return; } } -// -// 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) + if (pcxfiledata) { - Con_Printf ("Bad skin %s (unsupported format)\n", name); - Skin_WorkerDone(skin, NULL, 0, 0); - return; + out = Skin_ParsePCX(name, pcxfiledata, pcxsize, &srcw, &srch); + FS_FreeFile(pcxfiledata); } - - 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) + else { - Con_Printf ("Bad skin %s (unsupported size)\n", name); - Skin_WorkerDone(skin, NULL, 0, 0); - return; + out = NULL; + srcw = srch = 0; } - skin->width = srcw; - skin->height = srch; - - out = BZ_Malloc(skin->width*skin->height); 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 += 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); + COM_AddWork(WG_MAIN, Skin_WorkerDone, skin, NULL, 0, 0); + else + COM_AddWork(WG_MAIN, 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 ========== */ -qbyte *Skin_Cache8 (qwskin_t *skin) +qbyte *Skin_TryCache8 (qwskin_t *skin) { char name[1024]; char *skinpath; @@ -436,10 +457,8 @@ qbyte *Skin_Cache8 (qwskin_t *skin) if (skin->loadstate == SKIN_FAILED) return NULL; skin->loadstate = SKIN_LOADING; - - Skin_WorkerLoad(skin, NULL, 0, 0); - - return skin->skindata; + COM_AddWork(WG_LOADER, Skin_WorkerLoad, skin, NULL,0,0); + return NULL; } /* @@ -512,7 +531,7 @@ void Skin_NextDownload (void) sc = &cl.players[i]; if (!sc->name[0] || !sc->qwskin) continue; - Skin_Cache8 (sc->qwskin); + Skin_TryCache8 (sc->qwskin); //sc->qwskin = NULL; } } @@ -561,7 +580,7 @@ void Skin_Skins_f (void) 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; } @@ -627,7 +646,7 @@ void Skin_Skins_f (void) { 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; } diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 1e597c60a..b3c1ab580 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -1180,7 +1180,7 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname) devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); } 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)); sc->handle = oali; @@ -1489,11 +1489,11 @@ static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname) return false; oali = sc->handle; - Con_Printf( SDRVNAME" AL_VERSION: %s\n",palGetString(AL_VERSION)); - Con_Printf( SDRVNAME" AL_RENDERER: %s\n",palGetString(AL_RENDERER)); - Con_Printf( SDRVNAME" AL_VENDOR: %s\n",palGetString(AL_VENDOR)); - Con_DPrintf(SDRVNAME" AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS)); - Con_DPrintf(SDRVNAME" ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); + Con_Printf( "AL_VERSION: %s\n",palGetString(AL_VERSION)); + Con_Printf( "AL_RENDERER: %s\n",palGetString(AL_RENDERER)); + Con_Printf( "AL_VENDOR: %s\n",palGetString(AL_VENDOR)); + Con_DPrintf("AL_EXTENSIONS: %s\n",palGetString(AL_EXTENSIONS)); + Con_DPrintf("ALC_EXTENSIONS: %s\n",palcGetString(oali->OpenAL_Device,ALC_EXTENSIONS)); sc->Shutdown = OpenAL_Shutdown; #ifdef USEEFX diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 8cc95fd19..f143dc32f 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -78,6 +78,7 @@ long sys_parentwindow; qboolean sys_gracefulexit; 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. { @@ -424,6 +425,7 @@ static void Sys_Register_File_Associations_f(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"); } 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); } -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) { - struct timeval tp; - struct timezone tzp; - - 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; + quint64_t denum, num = Sys_GetClock(&denum); + return num / (long double)denum; } - unsigned int Sys_Milliseconds (void) { - return Sys_DoubleTime() * 1000; + quint64_t denum, num = Sys_GetClock(&denum); + num *= 1000; + return num / denum; } + + #ifdef USE_LIBTOOL void Sys_CloseLibrary(dllhandle_t *lib) { diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index fd1457bbb..655cd6e55 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -3798,7 +3798,7 @@ void CL_Say (qboolean team, char *extra) 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; } diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 22ef9f3b8..5e6c80474 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2521,15 +2521,17 @@ static void Cmd_Apropos_f (void) char escapedvalue[1024]; char latchedvalue[1024]; char *query = Cmd_Argv(1); + const char *d; for (grp=cvar_groups ; grp ; grp=grp->next) for (var=grp->cvars ; var ; var=var->next) { + d = var->description?localtext(var->description):NULL; if (var->name && Q_strcasestr(var->name, query)) name = var->name; else if (var->name2 && Q_strcasestr(var->name2, query)) name = var->name2; - else if (var->description && Q_strcasestr(var->description, query)) + else if (d && Q_strcasestr(d, query)) name = var->name; else continue; @@ -2539,21 +2541,34 @@ static void Cmd_Apropos_f (void) if (var->latched_string) { 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 - 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) { + d = cmd->description?localtext(cmd->description):NULL; if (cmd->name && Q_strcasestr(cmd->name, query)) ; - else if (cmd->description && strstr(cmd->description, query)) + else if (d && strstr(d, query)) ; else 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. } diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 0cc9c7ef7..8cc961eb7 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -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) 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; 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]) Con_ThrottlePrintf(&printtimer, 1, "Alias_GAliasBuildMesh(%s): non-skeletal animation only supports two animations\n", e->model->name); #endif @@ -2128,174 +2112,190 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in //used by the modelviewer. void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qboolean normals) { - galiasinfo_t *mod; scenetris_t *t; vecV_t *posedata = NULL; vec3_t *normdata = NULL, tmp; - int surfnum = 0, i; -#ifdef SKELETALMODELS - int cursurfnum = -1; -#endif + int i, j; - 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; - 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) - { - if (!mod->contents) - continue; - } - else if (surfnum != surfaceidx) + case mod_alias: + R_GAlias_GenerateBatches(ent, batches); + break; + +#ifdef HALFLIFEMODELS + case mod_halflife: + R_HalfLife_GenerateBatches(ent, batches); + break; +#endif + default: + return; + } + + for (s = 0; s < countof(batches); s++) + { + if (!batches[s]) continue; - - normdata = NULL; -#ifdef SKELETALMODELS - if (mod->numbones) + for (b = batches[s]; b; b = b->next) { - if (!mod->ofs_skel_idx) - posedata = mod->ofs_skel_xyz; //if there's no weights, don't try animating anything. - else if (mod->shares_verts != cursurfnum || !posedata) + if (b->buildmeshes) + b->buildmeshes(b); + + 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)); - 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 + m = b->mesh[meshidx]; - - if (normals && normdata) - { //pegs, one on each vertex. - 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 = mod->numverts*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 < 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) + posedata = m->xyz_array; + normdata = normals?m->normals_array:NULL; + if (m->numbones) + { //intended shader might have caused it to use skeletal stuff. + //we're too lame for that though. + posedata = alloca(m->numvertexes*sizeof(vecV_t)); + if (normdata) + { + normdata = alloca(m->numvertexes*sizeof(vec3_t)); + 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]); + } + else + Alias_TransformVerticies_V(m->bones, m->numvertexes, m->bonenums[0], m->boneweights[0], m->xyz_array[0], posedata[0]); + } + else { - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+0]; - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+1]; - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+1]; - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+2]; - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+2]; - cl_strisidx[cl_numstrisidx++] = mod->ofs_indexes[i+0]; + if (m->xyz_blendw[1] == 1 && m->xyz2_array) + posedata = m->xyz2_array; + else if (m->xyz_blendw[0] != 1 && m->xyz2_array) + { + posedata = alloca(m->numvertexes*sizeof(vecV_t)); + 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; } - 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); while(surfaceidx-->0 && inf) @@ -5498,11 +5504,9 @@ shader_t *Mod_ShaderForSkin(model_t *model, int surfaceidx, int num) return NULL; skin = inf->ofsskins; return skin[num].frame[0].shader; - } - else if (model->type == mod_brush && surfaceidx < model->numtextures && !num) - return model->textures[surfaceidx]->shader; - else + default: return NULL; + } } #endif 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; } - 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 NULL; - } - inf = Mod_Extradata(model); + case mod_alias: + inf = Mod_Extradata(model); - while(surfaceidx-->0 && inf) - inf = inf->nextsurf; - if (!inf || num >= inf->numskins) + while(surfaceidx-->0 && inf) + inf = inf->nextsurf; + 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; - skin = inf->ofsskins; -// if (!*skin[num].name) -// return skin[num].frame[0].shadername; -// else - return skin[num].name; + } #endif } @@ -5550,20 +5558,39 @@ const char *Mod_SurfaceNameForNum(model_t *model, int num) #else 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) return model->textures[num]->name; return NULL; - } - inf = Mod_Extradata(model); - - while(num-->0 && inf) - inf = inf->nextsurf; - if (inf) - return inf->surfacename; - else + case mod_halflife: 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 } diff --git a/engine/common/common.c b/engine/common/common.c index 191c897cd..32d1d38cd 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1022,7 +1022,7 @@ coorddata MSG_ToAngle(float f, int bytes) //return value is NOT byteswapped. void MSG_WriteCoord (sizebuf_t *sb, float f) { 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) @@ -1684,13 +1684,13 @@ float MSG_ReadCoord (void) coorddata c = {{0}}; if (net_message.prim.coordtype == COORDTYPE_UNDEFINED) 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); } float MSG_ReadCoordFloat (void) { 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); } @@ -7775,7 +7775,7 @@ void Con_TPrintf (translation_t stringnum, ...) if (!Sys_IsMainThread()) { //shouldn't be redirected anyway... - fmt = langtext(stringnum,com_language); + fmt = localtext(stringnum); va_start (argptr,stringnum); vsnprintf (msg,sizeof(msg)-1, fmt,argptr); va_end (argptr); @@ -7799,7 +7799,7 @@ void Con_TPrintf (translation_t stringnum, ...) } #endif - fmt = langtext(stringnum,com_language); + fmt = localtext(stringnum); va_start (argptr,stringnum); vsnprintf (msg,sizeof(msg)-1, fmt,argptr); diff --git a/engine/common/common.h b/engine/common/common.h index ff4c19848..659c0f6eb 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -160,6 +160,7 @@ struct netprim_s #define COORDTYPE_FIXED_16_8 3 //rmq #define COORDTYPE_FIXED_28_4 4 //rmq, pointless #define COORDTYPE_FLOAT_32 (4|0x80) //fte/dp/rmq + #define COORDTYPE_SIZE_MASK 0xf //coordtype&mask == number of bytes. qbyte anglesize; qbyte flags; #define NPQ2_ANG16 (1u<<0) @@ -756,6 +757,7 @@ int FS_GetManifestArgv(char **argv, int maxargs); struct zonegroup_s; 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_LoadMallocFileFlags (const char *path, unsigned int locateflags, size_t *fsize); qofs_t FS_LoadFile(const char *name, 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. qboolean IPLog_Merge_File(const char *fname); #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) qboolean Log_CheckMapCompletion(const char *packagename, const char *mapname, float *besttime, float *fulltime, float *bestkills, float *bestsecrets); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 4dddb59d6..5f6dbd621 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -1239,8 +1239,8 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c if (var) return var; - if (!description) - description = ""; + if (!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. 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) { - 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; } 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; } @@ -1330,36 +1330,36 @@ qboolean Cvar_Command (int level) { if (v->flags & CVAR_LATCH) { - Con_Printf ("\"%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 ("\"%s\" is currently \"%s\"\n", v->name, COM_QuotedString(v->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) { - Con_Printf ("\"%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 ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->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) { - Con_Printf ("\"%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 ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->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 { - Con_Printf ("\"%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 ("\"%s\" is \"%s\"\n", v->name, COM_QuotedString(v->latched_string, buffer, sizeof(buffer), true)); + Con_TPrintf ("Effective value is \"%s\"\n", COM_QuotedString(v->string, buffer, sizeof(buffer), true)); } 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 { 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 { - 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) - 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; @@ -1373,7 +1373,7 @@ qboolean Cvar_Command (int level) if (v->flags & CVAR_NOSET) { 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; } diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 3bd4846f9..166fe6294 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -103,8 +103,6 @@ typedef struct cvar_s #define CVARD(ConsoleName,Value,Description) CVARAFCD(ConsoleName, Value, NULL, 0, NULL, Description) #define CVAR(ConsoleName,Value) CVARD(ConsoleName, Value, NULL) -#define CVARDP4(Flags,ConsoleName,Value,Description) CVARFD(ConsoleName, Value, Flags,Description) - typedef struct cvar_group_s { const char *name; diff --git a/engine/common/fs.c b/engine/common/fs.c index 78479494b..46401e76f 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2601,6 +2601,10 @@ qbyte *FS_LoadMallocFile (const char *path, size_t *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) { @@ -5206,7 +5210,7 @@ static ftemanifest_t *FS_GenerateLegacyManifest(int game, const char *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 *e = strchr(cexec, '\n'); diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 75bf42b8d..62e8aa76f 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -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. extra += extrachunk_len; 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: /* Con_Printf("Unknown chunk %x\n", extrachunk_tag); case 0x5455: //extended timestamp diff --git a/engine/common/log.c b/engine/common/log.c index f2b2e9963..c1dd8d019 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -640,7 +640,10 @@ struct certlog_s size_t certsize; qbyte cert[1]; }; +#define CERTLOG_FILENAME "knowncerts.txt" 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) { 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) { 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) { 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] = 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); Z_Free(l); } + + certlog_inited = false; } static int hexdecode(char c) { @@ -715,7 +722,13 @@ static void CertLog_Import(const char *filename) char certdata[16384]; char line[65536], *l; 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(); VFS_GETS(f, line, sizeof(line)); if (strncmp(line, "version 1.", 10)) @@ -743,8 +756,10 @@ static void CertLog_UntrustAll_f(void) static void CertLog_Import_f(void) { const char *fname = Cmd_Argv(1); + if (Cmd_IsInsecure()) + return; if (!*fname) - fname = "knowncerts.txt"; + fname = NULL; CertLog_Import(fname); } 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_Write(); + + CL_BeginServerReconnect(); } else CL_Disconnect("Server certificate rejected"); 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) return false; + if (!certlog_inited) + CertLog_Import(NULL); + l = CertLog_Find(hostname); + if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize)) - { + { //new or different 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)); ctx->hostname = ctx->cert + certsize; ctx->certsize = certsize; memcpy(ctx->cert, cert, certsize); strcpy(ctx->hostname, hostname); - //FIXME: display some sort of fingerprint - if (!l) - Menu_Prompt(CertLog_Add_Prompted, ctx, va("%s\nServer certificate is\nself-signed", hostname), "Trust", NULL, "Disconnect"); + if (l) //FIXME: show expiry info for the old cert, warn if more than a month? + accepttext = localtext("Replace Trust"); + else if (!certlogproblems) + accepttext = localtext("Pin Trust"); 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... } diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 24502d762..b1d54a710 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -469,9 +469,11 @@ static qboolean QDECL SSL_CloseFile(vfsfile_t *vfs) 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 + unsigned int ferrcode; //when using dtls, we expect self-signed certs and persistent trust. 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); 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 - *errorcode = GNUTLS_E_CERTIFICATE_ERROR; //user didn't trust it yet + ret = GNUTLS_E_CERTIFICATE_ERROR; //user didn't trust it yet free(certdata); - return true; } #endif - return false; + return ret; } 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_certificate_type_t type; + int ret; if (preverified && (certstatus&~GNUTLS_CERT_EXPIRED) == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND)) return 0; - if (certstatus == 0) - return SSL_CheckUserTrust(session, file, 0); - if (certstatus == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND)) - { - if (SSL_CheckUserTrust(session, file, &errcode)) - return errcode; - } + ret = SSL_CheckUserTrust(session, file, certstatus); + if (!ret) + return ret; type = qgnutls_certificate_type_get (session); 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) { //and make sure the hostname on it actually makes sense. + int ret; gnutls_x509_crt_t cert; qgnutls_x509_crt_init(&cert); 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)) return 0; - if (certstatus == 0) - return SSL_CheckUserTrust(session, file, 0); - if (certstatus == (GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND) && SSL_CheckUserTrust(session, file, GNUTLS_E_CERTIFICATE_ERROR)) - return 0; + + ret = SSL_CheckUserTrust(session, file, certstatus); //looks okay... pin it by default... + if (!ret) + return ret; if (certstatus & GNUTLS_CERT_SIGNER_NOT_FOUND) 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) { gnutls_datum_t hash = {hashdata, hashsize}; @@ -1264,7 +1275,7 @@ int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, 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) { gnutls_datum_t hash = {hashdata, hashsize}; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index c1a5410c8..38abd2ca1 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -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) { int scope = ASCOPE_NET; - char *desc = NULL; + const char *desc = NULL; 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 - scope = ASCOPE_LAN, desc = "private"; + scope = ASCOPE_LAN, desc = localtext("private"); else if ((ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8 scope = ASCOPE_HOST, desc = "localhost"; 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 - scope = ASCOPE_LAN, desc = "private"; + scope = ASCOPE_LAN, desc = localtext("private"); 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 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) { //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) { 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 - scope = ASCOPE_LAN, desc = "ULA/private"; + scope = ASCOPE_LAN, desc = localtext("ULA/private"); else if (*(int*)adr->address.ip6 == BigLong(0x20010000)) //2001::/32 scope = ASCOPE_NET, desc = "toredo"; 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); if (!desc) - desc = "vp-mapped"; + desc = localtext("v4-mapped"); } } #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].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 - 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) - 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 - 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) - Con_Printf("net address: no public addresses\n"); + Con_TPrintf("net address: no public addresses\n"); } void NET_PrintConnectionsStatus(ftenet_connections_t *collection) diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 67edec136..49362046b 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -344,6 +344,7 @@ enum hashvalidation_e VH_INCORRECT, //signature is wrong for that authority (bad, probably maliciously so) VH_CORRECT //all is well. }; +struct dtlsfuncs_s; #ifdef HAVE_DTLS typedef struct dtlsfuncs_s { @@ -360,23 +361,23 @@ const dtlsfuncs_t *DTLS_InitClient(void); #ifdef HAVE_WINSSPI vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); 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 dtlsfuncs_t *SSPI_DTLS_InitClient(void); //should always return something, if implemented. + const struct dtlsfuncs_s *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available. + 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); #endif #ifdef HAVE_GNUTLS vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); 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 dtlsfuncs_t *GNUDTLS_InitClient(void); //should always return something, if implemented. + const struct dtlsfuncs_s *GNUDTLS_InitServer(void); //returns NULL if there's no cert available. + 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); int GNUTLS_GenerateSignature(qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax); #endif #ifdef HAVE_OPENSSL vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); 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 dtlsfuncs_t *OSSL_InitClient(void); //should always return something, if implemented. + const struct dtlsfuncs_s *OSSL_InitServer(void); //returns NULL if there's no cert available. + 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); #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index b301f6f64..5ace1bc84 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1572,7 +1572,12 @@ void QCBUILTIN PF_cvar_description (pubprogfuncs_t *prinst, struct globalvars_s const char *str = PR_GetStringOfs(prinst, OFS_PARM0); cvar_t *cv = PF_Cvar_FindOrGet(str); 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 G_INT(OFS_RETURN) = 0; } diff --git a/engine/common/translate.c b/engine/common/translate.c index 9d596a768..8a4a06ab2 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -1,5 +1,8 @@ #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. //server may remap progs messages @@ -74,7 +77,9 @@ static int TL_LoadLanguage(char *lang) languages[j].name = strdup(lang); languages[j].po = NULL; +#ifndef COLOURUNTRANSLATEDSTRINGS if (f) +#endif { languages[j].po = PO_Create(); PO_Merge(languages[j].po, f); @@ -299,17 +304,7 @@ struct po_s struct poline_s *lines; }; -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); - if (line) - return line->translated; - return msg; -} -static void PO_AddText(struct po_s *po, const char *orig, const char *trans) +static struct poline_s *PO_AddText(struct po_s *po, const char *orig, const char *trans) { size_t olen = strlen(orig)+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; po->lines = line; + return line; } 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; char msgid[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"); if (!file) @@ -343,61 +348,95 @@ void PO_Merge(struct po_s *po, vfsfile_t *file) if (file) VFS_CLOSE(file); - end = in + inlen; - while(in < end) + moheader = (void*)in; + if (inlen >= sizeof(*moheader) && moheader->magic == 0x950412de) { - while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') - in++; - if (*in == '#') + struct { - 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++; - } - 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) + if (*in == '#') { - while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') + while (*in && *in != '\n') in++; - if (*in == '\"') - { - in = COM_ParseCString(in, msgid+start, sizeof(msgid) - start, &ofs); - start += ofs; - } - 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) + else if (!strncmp(in, "msgid", 5) && (in[5] == ' ' || in[5] == '\t' || in[5] == '\r' || in[5] == '\n')) { - while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') - in++; - if (*in == '\"') + size_t start = 0; + size_t ofs = 0; + in += 5; + while(1) { - in = COM_ParseCString(in, msgstr+start, sizeof(msgstr) - start, &ofs); - start += ofs; + while(*in == ' ' || *in == '\n' || *in == '\r' || *in == '\t') + 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) - PO_AddText(po, msgid, msgstr); - } - else - { - //some sort of junk? - in++; - while (*in && *in != '\n') + if ((*msgid && start) || allowblanks) + PO_AddText(po, msgid, msgstr); +#ifdef COLOURUNTRANSLATEDSTRINGS + else if (!start) + { + char temp[1024]; + int i; + 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++; + while (*in && *in != '\n') + in++; + } } } @@ -424,3 +463,35 @@ void PO_Close(struct po_s *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; +} diff --git a/engine/common/translate.h b/engine/common/translate.h index 24080d824..635b900bf 100644 --- a/engine/common/translate.h +++ b/engine/common/translate.h @@ -17,6 +17,7 @@ extern struct language_s languages[MAX_LANGUAGES]; extern int com_language; extern cvar_t language; #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); #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index c62ad71d4..143851444 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -62,7 +62,7 @@ static D3DPRESENT_PARAMETERS d3dpp; float d3d_trueprojection_std[16]; float d3d_trueprojection_view[16]; -qboolean vid_initializing; +static qboolean vid_initializing; extern qboolean scr_initialized; // ready to draw extern qboolean scr_drawloading; @@ -73,15 +73,6 @@ extern cvar_t vid_hardwaregamma; 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); static void D3D9_VID_GenPaletteTables (unsigned char *palette) { @@ -161,6 +152,7 @@ static void D3DVID_UpdateWindowStatus (HWND hWnd) { POINT p; RECT nr; + int window_x, window_y; int window_width, window_height; GetClientRect(hWnd, &nr); diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 1b14799d5..071376a73 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -78,22 +78,13 @@ static DXGI_FORMAT depthformat; void *d3d11mod; static unsigned int d3d11multisample_count, d3d11multisample_quality; -qboolean vid_initializing; +static qboolean vid_initializing; extern qboolean scr_initialized; // ready to draw extern qboolean scr_drawloading; extern qboolean scr_con_forcedraw; 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 qboolean resetd3dbackbuffer(int width, int height); @@ -218,6 +209,7 @@ static void D3DVID_UpdateWindowStatus (HWND hWnd) { POINT p; RECT nr; + int window_x, window_y; int window_width, window_height; GetClientRect(hWnd, &nr); diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index e92ded1bf..de4e9fdb4 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -63,7 +63,7 @@ LPDIRECT3DDEVICE8 pD3DDev8; static D3DPRESENT_PARAMETERS d3dpp; float d3d_trueprojection[16]; -qboolean vid_initializing; +static qboolean vid_initializing; extern qboolean scr_initialized; // ready to draw extern qboolean scr_drawloading; @@ -72,16 +72,6 @@ static qboolean d3d_resized; 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); static void D3D8_VID_GenPaletteTables (unsigned char *palette) { diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index 99a88aa52..4d64572d3 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -693,7 +693,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e 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; } 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. cm = Z_Malloc(sizeof(*cm)); *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); 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)) { 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; } } - else - { - original = NULL; - inwidth = 0; - inheight = 0; - } if (!original) { if (skins && skins->numframes && skins->frame[subframe].texels) @@ -1653,7 +1657,7 @@ void R_GAlias_DrawBatch(batch_t *batch) galiasinfo_t *inf; model_t *clmodel; - int surfnum; + unsigned int surfnum; static mesh_t mesh; static mesh_t *meshl = &mesh; @@ -1673,7 +1677,7 @@ void R_GAlias_DrawBatch(batch_t *batch) memset(&mesh, 0, sizeof(mesh)); 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)); batch->mesh = &meshl; @@ -1806,8 +1810,11 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) b->texture = NULL; b->shader = shader; for (j = 0; j < MAXRLIGHTMAPS; j++) + { b->lightmap[j] = -1; - b->surf_first = surfnum; + b->lmlightstyle[j] = INVALID_LIGHTSTYLE; + } + b->user.alias.surfrefs[0] = surfnum; b->flags = 0; sort = shader->sort; if (e->flags & RF_FORCECOLOURMOD) @@ -2732,7 +2739,7 @@ static void R_DB_Poly(batch_t *batch) { static mesh_t mesh; static mesh_t *meshptr = &mesh; - unsigned int i = batch->surf_first; + unsigned int i = batch->user.poly.surface; batch->mesh = &meshptr; @@ -2776,7 +2783,7 @@ static void BE_GenPolyBatches(batch_t **batches) b->shader = shader; for (j = 0; j < MAXRLIGHTMAPS; j++) b->lightmap[j] = -1; - b->surf_first = i; + b->user.poly.surface = i; b->flags = cl_stris[i].flags; b->vbo = 0; @@ -2792,7 +2799,6 @@ static void BE_GenPolyBatches(batch_t **batches) batches[sort] = b; } } -void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches); void PR_Route_Visualise(void); void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode, const qbyte *worldpvs, const int *worldareas) { diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index ddc3de028..641407a94 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -4150,6 +4150,8 @@ void GLBE_SelectEntity(entity_t *ent) nd = 1; if (shaderstate.depthrange != nd) { + shaderstate.depthrange = nd; + if (nd < 1) memcpy(shaderstate.projectionmatrix, r_refdef.m_projection_view, sizeof(shaderstate.projectionmatrix)); else @@ -4160,12 +4162,6 @@ void GLBE_SelectEntity(entity_t *ent) qglLoadMatrixf(shaderstate.projectionmatrix); 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; diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 98c10cb29..355d5aaf6 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -78,10 +78,10 @@ struct hlvremaps unsigned short scoord; 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; - 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]) 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 -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; - size_t uvertcount, uvertstart; + size_t uvertcount=0, uvertstart; unsigned short count; int i; - size_t idx = 0, v, m, maxidx=65536*3; + size_t idx = 0, m, maxidx=65536*3; size_t maxverts = 65536; - mesh_t *mesh = &submodel->mesh; index_t *index; + mesh_t *mesh, *submesh; - vec3_t *verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex); - qbyte *bone = ((qbyte *) model->header + amodel->vertinfoindex); - vec3_t *norms = (vec3_t *) ((qbyte *) model->header + amodel->normindex); + int body; - uvertcount = 0; 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; - unsigned short *order = (unsigned short *) ((qbyte *) model->header + inmesh->index); - - uvertstart = uvertcount; - submodel->submesh[m].firstindex = mesh->numindexes; - submodel->submesh[m].numindexes = 0; - - for(;;) + 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++) { - count = *order++; /* get the vertex count and primitive type */ - if(!count) break; /* done */ + hlmdl_submodel_t *amodel = (hlmdl_submodel_t *) ((qbyte *) model->header + bodypart->modelindex) + bodyindex; + struct hlalternative_s *submodel; - if(count & 0x8000) - { //fan - int first = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, maxverts); - int prev = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, 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, maxverts); - } - } - else + 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); + + submodel = &model->geomset[body].alternatives[bodyindex]; + + for(m = 0; m < amodel->nummesh; m++) { - int v0 = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, maxverts); - int v1 = HLMDL_DeDupe(order+1*4, uvert, &uvertcount, 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++) + hlmdl_mesh_t *inmesh = (hlmdl_mesh_t *) ((qbyte *) model->header + amodel->meshindex) + m; + unsigned short *order = (unsigned short *) ((qbyte *) model->header + inmesh->index); + + uvertstart = uvertcount; + submodel->submesh[m].vbofirstvert = uvertstart; + submodel->submesh[m].vbofirstelement = idx; + submodel->submesh[m].numvertexes = 0; + submodel->submesh[m].numindexes = 0; + + for(;;) { - if (i & 1) - { - index[idx++] = v1; - index[idx++] = v0; + count = *order++; /* get the vertex count and primitive type */ + if(!count) break; /* done */ + + 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 { - index[idx++] = v0; - index[idx++] = v1; + int v0 = HLMDL_DeDupe(order+0*4, uvert, &uvertcount, uvertstart, maxverts); + 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; - index[idx++] = v1 = HLMDL_DeDupe(order+i*4, uvert, &uvertcount, maxverts); + 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].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->numvertexes = uvertcount; - + mesh = &model->mesh; 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->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->xyz_array = ZG_Malloc(model->memgroup, sizeof(*mesh->xyz_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) mesh->snormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->snormals_array)*uvertcount); mesh->tnormals_array = ZG_Malloc(model->memgroup, sizeof(*mesh->tnormals_array)*uvertcount); #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 - for(v = 0; v < uvertcount; v++) + mesh->numindexes = idx; + 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]; - Vector4Set(mesh->boneweights[v], 1, 0, 0, 0); - Vector4Set(mesh->colors4b_array[v], 255, 255, 255, 255); //why bytes? why not? + hlmdl_bodypart_t *bodypart = (hlmdl_bodypart_t *) ((qbyte *) model->header + model->header->bodypartindex) + body; + int bodyindex; + 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; - mesh->lmst_array[0][v][1] = uvert[v].tcoord; - VectorCopy(verts[uvert[v].vertidx], mesh->xyz_array[v]); + vec3_t *verts = (vec3_t *) ((qbyte *) model->header + amodel->vertindex); + qbyte *bone = ((qbyte *) model->header + amodel->vertinfoindex); + vec3_t *norms = (vec3_t *) ((qbyte *) model->header + amodel->normindex); + size_t iv, 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[v].normalidx], mesh->normals_array[v]); + struct hlalternative_s *submodel = &model->geomset[body].alternatives[bodyindex]; + for(m = 0; m < amodel->nummesh; m++) + { + 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 free(uvert); 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 @@ -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) { #ifndef SERVERONLY - int i; - int body; + int i, j; struct hlmodelshaders_s *shaders; hlmdl_tex_t *tex; + + lmalloc_t atlas; #endif 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)); model->shaders = shaders; + 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)); @@ -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_CHROME) + { shader = HLSHADER_FULLBRIGHTCHROME; + Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_fullbrightchrome"); + } else + { shader = HLSHADER_FULLBRIGHT; + Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_fullbright"); + } } else if (tex[i].flags & HLMDLFL_CHROME) + { shader = HLSHADER_CHROME; + Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_chrome"); + } else + { shader = ""; + Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel_other"); + } shaders[i].defaultshadertext = shader; } else + { shaders[i].defaultshadertext = NULL; + Q_snprintfz(shaders[i].name, sizeof(shaders[i].name), "common/hlmodel"); + } 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].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->numskingroups = texheader->skingroups; @@ -364,20 +527,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize) #ifndef SERVERONLY model->numgeomsets = model->header->numbodyparts; model->geomset = ZG_Malloc(&mod->memgroup, sizeof(*model->geomset) * model->numgeomsets); - for (body = 0; body < model->numgeomsets; body++) - { - 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]); - } - } + HLMDL_PrepareVerticies(mod, model); //FIXME: No VBOs used. #endif return true; @@ -1149,63 +1299,127 @@ unsigned int HLMDL_Contents (model_t *model, int hulloverride, const framestate_ #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 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! - if (curent->framestate.bonecount >= model->header->numbones) - { - if (curent->framestate.skeltype == SKEL_RELATIVE) + if (rent->framestate.bonecount >= model->header->numbones) + { //skeletal object... + int b; + if (rent->framestate.skeltype == SKEL_RELATIVE) { - mesh->numbones = model->header->numbones; - for (b = 0; b < mesh->numbones; b++) + numbones = model->header->numbones; + for (b = 0; b < numbones; b++) { /* If we have a parent, take the addition. Otherwise just copy the values */ 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 { - 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 { - mesh->bones = curent->framestate.bonestate; - mesh->numbones = curent->framestate.bonecount; + bones = rent->framestate.bonestate; + numbones = rent->framestate.bonecount; } } else - { + { //lerp the bone data ourselves. float relatives[12*MAX_BONES]; - mesh->bones = transform_matrix[0][0]; - mesh->numbones = model->header->numbones; + int cbone, b; + bones = transform_matrix[0][0]; + numbones = model->header->numbones; -/* //FIXME: needs caching. - 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); + cbone = HLMDL_GetBoneData_Internal(model, 0, model->header->numbones, &rent->framestate, relatives); //convert relative to absolutes 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; - mesh->numindexes = model->geomset[bodypart].alternatives[bodyidx].submesh[meshidx].numindexes; + model->mesh.bones = bones; + model->mesh.numbones = numbones; - if (gpubones && model->header->numbones < sh_config.max_gpu_bones) - { //get the backend to do the skeletal stuff (read: glsl) - 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; + for (surf = 0; surf < b->meshes; surf++) + { + body = b->user.alias.surfrefs[surf] >> 8; + { + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + 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 - { //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; - } + b->meshes = 1; } +qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel); -static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, 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) +void R_HalfLife_GenerateBatches(entity_t *rent, batch_t **batches) { hlmodel_t *model = Mod_Extradata(rent->model); int body, m; - int batchid = 0; - static mesh_t bmesh, *mptr = &bmesh; - skinfile_t *sk = NULL; + skinfile_t *sk = rent->customskin?Mod_LookupSkin(rent->customskin):NULL; - unsigned int entity_body = 0; + const unsigned int entity_body = 0/*rent->body*/; + batch_t *b = NULL; - if (rent->customskin) - sk = Mod_LookupSkin(rent->customskin); - //entity_body = rent->body; //hey, if its there, lets use it. + unsigned int surfidx = 0; + + 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++) { @@ -1289,14 +1524,15 @@ static void R_HalfLife_WalkMeshes(entity_t *rent, batch_t *b, batch_t **batches) /* 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; - float tex_w; - float tex_h; struct hlmodelshaders_s *s; int skinidx = mesh->skinindex; + texnums_t *skin; + shader_t *shader; + int sort, j; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 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; 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(); if (!b) return; + b->skin = skin; + b->shader = shader; - - 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->buildmeshes = R_HL_BuildMeshes; b->ent = rent; b->mesh = NULL; b->firstmesh = 0; - b->meshes = 1; + b->meshes = 0; b->texture = NULL; for (j = 0; j < MAXRLIGHTMAPS; j++) + { b->lightmap[j] = -1; - b->surf_first = batchid; + b->lmlightstyle[j] = INVALID_LIGHTSTYLE; + } b->flags = 0; - sort = b->shader->sort; + sort = shader->sort; //fixme: we probably need to force some blend modes based on the surface flags. if (rent->flags & RF_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) b->flags |= BEF_NOSHADOWS; - b->vbo = NULL; + b->vbo = NULL;//&model->vbo; b->next = batches[sort]; batches[sort] = b; } - else - { - if (batchid == b->surf_first) - { - tex_w = 1.0f / s->w; - tex_h = 1.0f / s->h; - - b->mesh = &mptr; - 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++; + b->user.alias.surfrefs[b->meshes++] = (body<<8)|(m&0xff); } } } -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) { hlmodel_t *model = Mod_Extradata(rent->model); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index a91a8df9d..ccb14c3b2 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -2730,7 +2730,7 @@ static int Mod_Batches_Generate(model_t *mod) lbatch->texture == surf->texinfo->texture && lbatch->shader == shader && lbatch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && - Vector4Compare(plane, lbatch->plane) && + Vector4Compare(plane, lbatch->user.bmodel.plane) && lbatch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && #if MAXRLIGHTMAPS > 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->shader == shader && batch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && - Vector4Compare(plane, batch->plane) && + Vector4Compare(plane, batch->user.bmodel.plane) && batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && #if MAXRLIGHTMAPS > 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->fog = surf->fog; batch->envmap = envmap; - Vector4Copy(plane, batch->plane); + Vector4Copy(plane, batch->user.bmodel.plane); mod->batches[sortid] = batch; } diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index ee01e5c23..b55fc0bb5 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -160,21 +160,36 @@ typedef struct batch_s struct { unsigned int shadowbatch; //a unique index to accelerate shadowmesh generation (dlights, yay!) - unsigned int ebobatch; // - unsigned int webobatch; //su - }; - struct + 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. +// } 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 { - unsigned int surf_first; - unsigned int surf_count; - }; - vec4_t plane; /*used only at load (for portal surfaces, so multiple planes are not part of the same batch)*/ + unsigned int lightidx; + unsigned int lightmode; + } dlight; //deferred light batches + 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 { mesh_t meshbuf; mesh_t *meshptr; }; - }; + } user; } batch_t; /* diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index c2e9afceb..a44d41a00 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -551,10 +551,10 @@ qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis); void R_GenDlightMesh(struct batch_s *batch) { static mesh_t *meshptr; - dlight_t *l = cl_dlights + batch->surf_first; + dlight_t *l = cl_dlights + batch->user.dlight.lightidx; vec3_t colour; - int lightflags = batch->surf_count; + int lightflags = batch->user.dlight.lightmode; VectorCopy(l->color, colour); if (l->style>=0 && l->style < cl_max_lightstyles) @@ -698,8 +698,8 @@ void R_GenDlightBatches(batch_t *batches[]) b->texture = NULL; for (j = 0; j < MAXRLIGHTMAPS; j++) b->lightmap[j] = -1; - b->surf_first = i; - b->surf_count = lmode; + b->user.dlight.lightidx = i; + b->user.dlight.lightmode = lmode; b->flags |= BEF_NOSHADOWS|BEF_NODLIGHT; //that would be weeird b->vbo = NULL; b->next = batches[sort]; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 90abc08a7..488c472b8 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -270,12 +270,12 @@ void GL_SetupSceneProcessingTextures (void) 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 vm[16]; - if (e->flags & RF_WEAPONMODELNOBOB) + if ((e->flags & RF_WEAPONMODELNOBOB) || r_refdef.playerview->viewentity <= 0) { vm[0] = vpn[0]; vm[1] = vpn[1]; @@ -625,7 +625,7 @@ static void R_SetupGL (vec3_t axisorigin[4], vec4_t fovoverrides, float projmatr } 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); } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 1f485785c..17b117240 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -355,7 +355,7 @@ static void SHM_Shadow_Cache_Surface(msurface_t *surf) { int i; - i = surf->sbatch->shadowbatch; + i = surf->sbatch->user.bmodel.shadowbatch; if (i < 0) return; @@ -451,11 +451,11 @@ static void SH_CalcShadowBatches(model_t *mod) { if (!l || l->vbo != b->vbo || l->texture != b->texture) { - b->shadowbatch = mod->numshadowbatches++; + b->user.bmodel.shadowbatch = mod->numshadowbatches++; l = b; } else - b->shadowbatch = l->shadowbatch; + b->user.bmodel.shadowbatch = l->user.bmodel.shadowbatch; } } diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 0ef1e39c1..2e0271158 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -3387,7 +3387,6 @@ static void GLVID_Shutdown(void) #ifdef USE_EGL case PSL_EGL: EGL_Shutdown(); - EGL_UnloadLibrary(); GL_ForgetPointers(); break; #endif @@ -3431,10 +3430,24 @@ static void GLVID_Shutdown(void) vm.modes = NULL; vm.num_modes = 0; #endif + x11.pXCloseDisplay(vid_dpy); } - x11.pXCloseDisplay(vid_dpy); vid_dpy = 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; } diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index bfe8b1963..79dcacdc2 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -141,21 +141,18 @@ extern qboolean vid_isfullscreen; static unsigned short originalgammaramps[3][256]; -qboolean vid_initializing; +static qboolean vid_initializing; static int DIBWidth, DIBHeight; static RECT WindowRect; static DWORD WindowStyle, ExWindowStyle; -HWND mainwindow; static HWND dibwindow; static HDC maindc; HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); -viddef_t vid; // global video state - //unsigned short d_8to16rgbtable[256]; //unsigned d_8to24rgbtable[256]; //unsigned short d_8to16bgrtable[256]; @@ -176,10 +173,8 @@ extern cvar_t vid_desktopgamma; extern cvar_t gl_lateswap; extern cvar_t vid_preservegamma; -int window_x, window_y; +static int window_x, window_y; 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); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 829de89ba..ac0110a59 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -39,22 +39,6 @@ struct builddata_s }; 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 #if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/ #ifndef GLSLONLY diff --git a/engine/gl/model_hl.h b/engine/gl/model_hl.h index d3e8fd154..d78336960 100644 --- a/engine/gl/model_hl.h +++ b/engine/gl/model_hl.h @@ -295,6 +295,8 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra texnums_t defaulttex; shader_t *shader; int w, h; + int atlasid; + unsigned short x,y; } *shaders; short *skinref; int numskinrefs; @@ -306,15 +308,13 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra int numalternatives; struct hlalternative_s { - mesh_t mesh; int numsubmeshes; - struct - { - int firstindex; - int numindexes; - } *submesh; + mesh_t *submesh; } *alternatives; } *geomset; + mesh_t mesh; + vbo_t vbo; + qboolean vbobuilt; } hlmodel_t; /* 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 void R_DrawHLModel(entity_t *curent); void HLMDL_DrawHitBoxes(entity_t *ent); +void R_HalfLife_GenerateBatches(entity_t *rent, batch_t **batches); #endif diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 83052a0d4..a4e38f73b 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -447,9 +447,6 @@ reeval: break; } 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) { //boot it over to the debugger #if INTSIZE == 16 @@ -492,9 +489,6 @@ reeval: break; } 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) { //boot it over to the debugger #if INTSIZE == 16 @@ -790,7 +784,6 @@ reeval: PR_SwitchProgsParms(progfuncs, 0); } i = -newf->first_statement; - // p = pr_typecurrent; if (i < externs->numglobalbuiltins) { #ifndef QCGC @@ -802,26 +795,18 @@ reeval: num_edicts = sv_num_edicts; } else - { -// 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], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t)); + PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement); PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs); //decide weather non debugger wants to start debugging. return prinst.pr_xstatement; } - // PR_SwitchProgsParms((OPA->function & 0xff000000)>>24); s = PR_EnterFunction (progfuncs, newf, callerprogs); st = &pr_statements[s]; } //resume at the new statement, which might be in a different progs return s; -// break; case OP_DONE: case OP_RETURN: @@ -831,13 +816,7 @@ reeval: glob[OFS_RETURN] = glob[st->a]; glob[OFS_RETURN+1] = glob[st->a+1]; 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); st = &pr_statements[s]; if (prinst.pr_depth == prinst.exitdepth) diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index cecdcbe29..95233d50b 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -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 (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) { op = &pr_opcodes[OP_ADD_PIW]; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 10634bf50..e736f9fa8 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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."}, {"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}, + {"__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}, {"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."}, diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index c98461c49..8dc276cb3 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -2010,7 +2010,7 @@ static void SV_Status_f (void) if (!sv.state) { - Con_Printf("Server is not running\n"); + Con_TPrintf("Server is not running\n"); return; } @@ -2021,30 +2021,30 @@ static void SV_Status_f (void) if (cpu) cpu = 100*svs.stats.latched_active/cpu; - Con_Printf("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_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("cpu utilization : %3i%%\n",(int)cpu); + 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_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)) - Con_Printf("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_Printf("public : %s\n", sv_public.value?"yes":"no"); + Con_TPrintf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit. + Con_TPrintf("server uptime : %s\n", ShowTime(realtime)); + Con_TPrintf("public : %s\n", sv_public.value?"yes":"no"); switch(svs.gametype) { #ifdef Q3SERVER 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; #endif #ifdef Q2SERVER 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; #endif default: - Con_Printf("client types :%s", sv_listen_qw.ival?" QW":""); + Con_TPrintf("client types :%s", sv_listen_qw.ival?" QW":""); #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 #ifdef QWOVERQ3 if (sv_listen_q3.ival) Con_Printf(" Q3"); @@ -2057,7 +2057,7 @@ static void SV_Status_f (void) #endif Con_Printf("\n"); #if defined(TCPCONNECT) && !defined(CLIENTONLY) - Con_Printf("tcp services :"); + Con_TPrintf("tcp services :"); #if defined(HAVE_SSL) if (net_enable_tls.ival) Con_Printf(" TLS"); @@ -2085,12 +2085,12 @@ static void SV_Status_f (void) return; } #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) 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 - Con_Printf ("current map : %s\n", svs.name); + Con_TPrintf ("current map : %s\n", svs.name); if (svs.gametype == GT_PROGS) { @@ -2103,25 +2103,25 @@ static void SV_Status_f (void) continue; //free, and older than the zombie time 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++) if (!sv.strings.model_precache[count]) 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++) if (!sv.strings.sound_precache[count]) 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++) if (!sv.strings.particle_precache[count]) break; 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) - Con_Printf("csqc debug : true\n"); + Con_TPrintf("csqc debug : true\n"); #ifdef MVD_RECORDING SV_Demo_PrintOutputs(); #endif @@ -2133,9 +2133,9 @@ static void SV_Status_f (void) { // most remote clients are 40 columns // 0123456789012345678901234567890123456789 - Con_Printf ("name userid frags\n"); - Con_Printf (" address rate ping drop\n"); - Con_Printf (" ---------------- ---- ---- -----\n"); + Con_Printf ( "name userid frags\n" + " address rate ping drop\n" + " ---------------- ---- ---- -----\n"); for (i=0,cl=svs.clients ; istate) diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index a209c6e81..53e6cad2c 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -158,47 +158,108 @@ int Sys_DebugLog(char *file, char *fmt, ...) return 1; } -/* -================ -Sys_Milliseconds -================ -*/ -unsigned int Sys_Milliseconds (void) + +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 { - struct timeval tp; - struct timezone tzp; - static int secbase; + QCLOCK_AUTO = 0, - 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; - return tp.tv_usec/1000; + struct timespec ts; + 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; -/* -================ -Sys_DoubleTime -================ -*/ + //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) { - struct timeval tp; - struct timezone tzp; - static int secbase; - - 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; + quint64_t denum, num = Sys_GetClock(&denum); + return num / (long double)denum; +} +unsigned int Sys_Milliseconds (void) +{ + quint64_t denum, num = Sys_GetClock(&denum); + num *= 1000; + return num / denum; } /* @@ -671,6 +732,8 @@ is marked */ void Sys_Init (void) { + Sys_InitClock(); + Cvar_Register (&sys_nostdout, "System configuration"); Cvar_Register (&sys_extrasleep, "System configuration"); diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 0b5a47924..5d5f997d9 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -4539,7 +4539,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre 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; } } @@ -4796,7 +4796,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre 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, 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) { 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; case VK_ERROR_EXTENSION_NOT_PRESENT: case VK_ERROR_FEATURE_NOT_PRESENT: