fix q2 bsp texture animations.

fix q2 prediction.
fix q2 saved games issues.
fix q2bsp fullbright/fullwhite lights.
fix potential issues from svs.clients no longer being preallocated.
fix rtlights not doing q1 bsp texture animations.
misc crash fixes.
hack to allow a clickable hud when using a touchscreen.
gl_max_size no longer affects 2d images.
select faithful fps preset option by default.
gl_font a,b,c works to select fallback fonts. freetype fonts reused to reduce memory usage when the same font is used multiple times either with different sizes or as fallbacks as part of other fonts.
allow static member functions. allow static locals.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4552 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-12-02 14:30:30 +00:00
parent 409c17b9fc
commit 218006198d
41 changed files with 503 additions and 237 deletions

View file

@ -917,7 +917,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
# The extra object file called resources.o is specific for MinGW to link the icon in
#cygwin's gcc requires an extra command to use mingw instead of cygwin (default paths, etc).
ifneq ($(shell $(CC) -v 2>&1 | grep cygwin),)
ifneq ($(shell $(CC) -dumpmachine 2>&1 | grep cygwin),)
W32_CFLAGS=-mno-cygwin
endif

View file

@ -672,7 +672,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
Cam_Lock(pv, i);
return;
}
i = (i + 1) % MAX_CLIENTS;
i = (i + 1) % cl.allocated_client_slots;
} while (i != end);
// stay on same guy?
i = pv->cam_spec_track;

View file

@ -3327,7 +3327,7 @@ void CL_LinkPacketEntities (void)
ent->topcolour = (state->colormap>>4) & 0xf;
ent->bottomcolour = (state->colormap>>0) & 0xf;
}
else if (state->colormap > 0 && state->colormap <= MAX_CLIENTS)
else if (state->colormap > 0 && state->colormap <= cl.allocated_client_slots)
{
ent->playerindex = state->colormap-1;
ent->topcolour = cl.players[ent->playerindex].ttopcolor;

View file

@ -285,6 +285,7 @@ void CLQ2_PredictMovement (void) //q2 doesn't support split clients.
{
frame = ack & (UPDATE_MASK);
cmd = (q2usercmd_t*)&cl.outframes[frame].cmd[0];
cmd->msec = cl.outframes[frame].cmd[0].msec;
pm.cmd = *cmd;
Q2_Pmove (&pm);
@ -296,6 +297,7 @@ void CLQ2_PredictMovement (void) //q2 doesn't support split clients.
if (independantphysics[0].msec)
{
cmd = (q2usercmd_t*)&independantphysics[0];
cmd->msec = independantphysics[0].msec;
pm.cmd = *cmd;
Q2_Pmove (&pm);

View file

@ -1726,7 +1726,7 @@ typedef struct _TargaHeader {
#if defined(AVAIL_JPEGLIB) && !defined(NO_JPEG)
void screenshotJPEG(char *filename, int compression, qbyte *screendata, int screenwidth, int screenheight);
qboolean screenshotJPEG(char *filename, int compression, qbyte *screendata, int screenwidth, int screenheight);
#endif
#ifdef AVAIL_PNGLIB
int Image_WritePNG (char *filename, int compression, qbyte *pixels, int width, int height);
@ -1783,14 +1783,14 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height
#ifdef AVAIL_PNGLIB
if (!strcmp(ext, "png"))
{
Image_WritePNG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
return Image_WritePNG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
}
else
#endif
#ifdef AVAIL_JPEGLIB
if (!strcmp(ext, "jpeg") || !strcmp(ext, "jpg"))
{
screenshotJPEG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
return screenshotJPEG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
}
else
#endif

View file

@ -1306,7 +1306,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
{ // use custom player skin
ent.skinnum = 0;
player = &cl.players[s1->skinnum%MAX_CLIENTS];
player = &cl.players[(s1->skinnum&0xff)%cl.allocated_client_slots];
ent.model = player->model;
if (!ent.model || ent.model->needload) //we need to do better than this
{
@ -1316,7 +1316,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
if (!ent.model || ent.model->needload)
ent.model = Mod_ForName("players/male/tris.md2", false);
}
ent.playerindex = s1->skinnum%MAX_CLIENTS;
ent.playerindex = (s1->skinnum&0xff)%cl.allocated_client_slots;
player->model = ent.model;
/* ci = &cl.clientinfo[s1->skinnum & 0xff];
// ent.skin = ci->skin;
@ -1404,7 +1404,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame)
ent.angles[0]*=-1; //q2 has it fixed.
if (s1->number == cl.playerview[pnum].playernum+1) //woo! this is us!
if (s1->number == cl.playerview[0].playernum+1) //woo! this is us!
{
// VectorCopy(cl.predicted_origin, ent.origin);
// VectorCopy(cl.predicted_origin, ent.oldorigin);

View file

@ -1877,7 +1877,8 @@ void Con_DrawConsole (int lines, qboolean noback)
char *key;
if (!info)
info = "";
*end = 0;
if (end)
*end = 0;
#ifdef PLUGINS
if (!Plug_ConsoleLinkMouseOver(mousecursor_x, mousecursor_y, mouseover+2, info))
#endif

View file

@ -607,7 +607,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, qboolean *
}
else
Con_Printf("Unsupported version\n");
return NULL;
return NULL;
}
#ifdef AVAIL_PNGLIB
@ -746,16 +746,6 @@ qboolean LibPNG_Init(void)
return LIBPNG_LOADED();
}
#if defined(MING) //hehehe... add annother symbol so the statically linked cygwin libpng can link
#undef setjmp
int setjmp (jmp_buf jb)
{
return _setjmp(jb);
}
#endif
typedef struct {
char *data;
int readposition;
@ -1441,7 +1431,7 @@ METHODDEF(void) jpeg_error_exit (j_common_ptr cinfo)
{
longjmp(((jpeg_error_mgr_wrapper *) cinfo->err)->setjmp_buffer, 1);
}
void screenshotJPEG(char *filename, int compression, qbyte *screendata, int screenwidth, int screenheight) //input is rgb NOT rgba
qboolean screenshotJPEG(char *filename, int compression, qbyte *screendata, int screenwidth, int screenheight) //input is rgb NOT rgba
{
qbyte *buffer;
vfsfile_t *outfile;
@ -1450,7 +1440,7 @@ void screenshotJPEG(char *filename, int compression, qbyte *screendata, int scre
JSAMPROW row_pointer[1];
if (!LIBJPEG_LOADED())
return;
return false;
if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY)))
{
@ -1458,7 +1448,7 @@ void screenshotJPEG(char *filename, int compression, qbyte *screendata, int scre
if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY)))
{
Con_Printf("Error opening %s\n", filename);
return;
return false;
}
}
@ -1478,7 +1468,7 @@ void screenshotJPEG(char *filename, int compression, qbyte *screendata, int scre
VFS_CLOSE(outfile);
FS_Remove(filename, FS_GAME);
Con_Printf("Failed to create jpeg\n");
return;
return false;
}
#ifdef DYNAMIC_LIBJPEG
qjpeg_create_compress(&cinfo);
@ -1529,6 +1519,7 @@ void screenshotJPEG(char *filename, int compression, qbyte *screendata, int scre
#else
jpeg_destroy_compress(&cinfo);
#endif
return true;
}
#endif
#endif

View file

@ -349,7 +349,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum)
if (mouse->type == M_TOUCH)
{
if (m_strafeonright.ival && mouse->downpos[0] > vid.pixelwidth/2 && movements != NULL && !Key_Dest_Has(kdm_game))
if (m_strafeonright.ival && mouse->downpos[0] > vid.pixelwidth/2 && movements != NULL && !Key_Dest_Has(~kdm_game))
{
//if they're strafing, calculate the speed to move at based upon their displacement
if (mouse->down)

View file

@ -533,7 +533,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
{
unsigned int player = atoi(c);
int i;
if (player >= MAX_CLIENTS || !*cl.players[player].name)
if (player >= cl.allocated_client_slots || !*cl.players[player].name)
return;
c = Info_ValueForKey(info, "action");
@ -1874,6 +1874,7 @@ qboolean Key_MouseShouldBeFree(void)
return false;
}
int Sbar_TranslateHudClick(void);
/*
===================
Key_Event
@ -2196,6 +2197,18 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
if (key == K_RSHIFT)//simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead.
key = K_SHIFT;
if ((key == K_MOUSE1 || key == K_MOUSE2) && 1)
{
int nkey = Sbar_TranslateHudClick();
if (nkey)
{
//handle +/- events 'properly' the only safe way we can - by releasing them instantly and discarding the mouse-up event.
Key_Event(devid, nkey, 0, true);
Key_Event(devid, nkey, 0, false);
return;
}
}
kb = keybindings[key][keystate];
if (kb)
{

View file

@ -649,8 +649,8 @@ void M_Menu_Preset_f (void)
};
menu = M_Options_Title(&y, 0);
MC_AddBulk(menu, bulk, 16, 216, y);
//bottoms up! highlight 'fast' as the default option
menu->selecteditem = menu->options->common.next->common.next->common.next->common.next;
//bottoms up! highlight 'normal' as the default option
menu->selecteditem = menu->options->common.next->common.next->common.next;
menu->cursoritem->common.posy = menu->selecteditem->common.posy;
}

View file

@ -967,8 +967,15 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva
{
if (mask & MASK_DELTA)
{
CL_LinkPlayers ();
CL_LinkPacketEntities ();
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
CLQ2_AddEntities();
else
#endif
{
CL_LinkPlayers ();
CL_LinkPacketEntities ();
}
}
}

View file

@ -979,6 +979,8 @@ void QCBUILTIN PF_cl_setkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr
// key_menu
m_state = m_menu_dat;
Key_Dest_Remove(kdm_message);
if (!Key_Dest_Has(kdm_menu))
Key_Dest_Remove(kdm_console);
Key_Dest_Add(kdm_menu);
break;
case 1:
@ -1525,7 +1527,7 @@ static struct {
{"bufstr_add", PF_bufstr_add, 448},
{"bufstr_free", PF_bufstr_free, 449},
//gap
{"is_cached_pic", PF_CL_is_cached_pic, 451},
{"iscachedpic", PF_CL_is_cached_pic, 451},
{"precache_pic", PF_CL_precache_pic, 452},
{"free_pic", PF_CL_free_pic, 453},
{"drawcharacter", PF_CL_drawcharacter, 454},
@ -1568,7 +1570,7 @@ static struct {
{"gecko_keyevent", PF_cs_gecko_keyevent, 490},
{"gecko_mousemove", PF_cs_gecko_mousemove, 491},
{"gecko_resize", PF_cs_gecko_resize, 492},
{"gecko_get_texture_extent",PF_gecko_get_texture_extent,493},
{"gecko_get_texture_extent",PF_cs_gecko_get_texture_extent,493},
{"crc16", PF_crc16, 494},
{"cvar_type", PF_cvar_type, 495},
{"numentityfields", PF_numentityfields, 496},

View file

@ -608,6 +608,56 @@ void R2D_Conback_Callback(struct cvar_s *var, char *oldvalue)
#ifdef _WIN32
#include <windows.h>
qboolean R2D_Font_WasAdded(char *buffer, char *fontfilename)
{
char *match;
if (!fontfilename)
return true;
match = strstr(buffer, fontfilename);
if (!match)
return false;
if (!(match == buffer || match[-1] == ','))
return false;
match += strlen(fontfilename);
if (*match && *match != ',')
return false;
return true;
}
extern qboolean WinNT;
qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen);
qboolean MyRegGetStringValueMultiSz(HKEY base, char *keyname, char *valuename, void *data, int datalen);
void R2D_Font_AddFontLink(char *buffer, int buffersize, char *fontname)
{
char link[1024];
char *res, *comma, *othercomma, *nl;
if (fontname)
if (MyRegGetStringValueMultiSz(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\FontLink\\SystemLink", fontname, link, sizeof(link)))
{
res = nl = link;
while (*nl)
{
nl += strlen(nl);
nl++;
comma = strchr(res, ',');
if (comma)
{
*comma++ = 0;
othercomma = strchr(comma, ',');
if (othercomma)
*othercomma = 0;
}
else
comma = "";
if (!R2D_Font_WasAdded(buffer, res))
{
Q_strncatz(buffer, ",", buffersize);
Q_strncatz(buffer, res, buffersize);
R2D_Font_AddFontLink(buffer, buffersize, comma);
}
res = nl;
}
}
}
#endif
void R2D_Font_Callback(struct cvar_s *var, char *oldvalue)
{
@ -631,7 +681,6 @@ void R2D_Font_Callback(struct cvar_s *var, char *oldvalue)
LOGFONT lf = {0};
CHOOSEFONTA cf = {sizeof(cf)};
extern HWND mainwindow;
extern qboolean WinNT;
font_conchar = Font_LoadFont(8, "");
cf.hwndOwner = mainwindow;
@ -643,22 +692,26 @@ void R2D_Font_Callback(struct cvar_s *var, char *oldvalue)
if (pChooseFontA && pChooseFontA(&cf))
{
char fname[MAX_OSPATH];
char fname[MAX_OSPATH*8];
char *keyname;
keyname = va("%s%s%s (TrueType)", lf.lfFaceName, lf.lfWeight>=FW_BOLD?" Bold":"", lf.lfItalic?" Italic":"");
if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname)))
*fname = 0;
//FIXME: should enumerate and split & and ignore sizes and () crap.
if (!*fname)
{
Cvar_Set(var, fname);
return;
keyname = va("%s%s%s (TrueType)", lf.lfFaceName, lf.lfWeight>=FW_BOLD?" Bold":"", lf.lfItalic?" Italic":"");
if (!MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname)))
*fname = 0;
}
keyname = va("%s (OpenType)", lf.lfFaceName);
if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname)))
if (!*fname)
{
Cvar_Set(var, fname);
return;
keyname = va("%s (OpenType)", lf.lfFaceName);
if (!MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname)))
*fname = 0;
}
R2D_Font_AddFontLink(fname, sizeof(fname), lf.lfFaceName);
Cvar_Set(var, fname);
}
Cvar_Set(var, "");
return;
}
#endif

View file

@ -2182,12 +2182,15 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
if (!b)
continue;
*b = *ob;
if (b->texture)
b->shader = R_TextureAnimation(ent->framestate.g[FS_REG].frame[0], b->texture)->shader;
// if (b->texture)
// b->shader = R_TextureAnimation(ent->framestate.g[FS_REG].frame[0], b->texture)->shader;
b->meshes = b->maxmeshes;
b->ent = ent;
b->flags = bef;
if (b->buildmeshes)
b->buildmeshes(b);
if (bef & BEF_FORCEADDITIVE)
{
b->next = batches[SHADER_SORT_ADDITIVE];

View file

@ -1627,6 +1627,54 @@ void Sbar_DrawInventory (playerview_t *pv)
}
}
static qboolean PointInBox(float px, float py, float x, float y, float w, float h)
{
if (px >= x && px < x+w)
if (py >= y && py < y+h)
return true;
return false;
}
int Sbar_TranslateHudClick(void)
{
int i;
float vx = mousecursor_x - sbar_rect.x;
float vy = mousecursor_y - (sbar_rect.y + (sbar_rect.height-SBAR_HEIGHT));
qboolean headsup = !(cl_sbar.value || (scr_viewsize.value<100&&cl.splitclients==1));
qboolean hudswap = cl_hudswap.value; // Get that nasty float out :)
//inventory. clicks do specific-weapon impulses.
if (sb_lines > 24)
{
for (i=0 ; i<7 ; i++)
{
if (headsup)
{
if (i || sbar_rect.height>200)
if (PointInBox (vx, vy, (hudswap) ? 0 : (sbar_rect.width-24),-68-(7-i)*16, 24,16))
return '2' + i;
}
else
{
if (PointInBox (vx, vy, i*24, -16, (i==6)?48:24, 16))
return '2' + i;
}
}
}
//armour. trigger backtick, to toggle the console (which enables the on-screen keyboard on android).
if (PointInBox (vx, vy, 0, 0, 96, 24))
return '`';
//face. do showscores.
if (PointInBox (vx, vy, 112, 0, 96, 24))
return K_TAB;
//currentammo+icon. trigger '/' binding, which defaults to weapon-switch (impulse 10)
if (PointInBox (vx, vy, 224, 0, 96, 24))
return '/';
return 0;
}
//=============================================================================
/*

View file

@ -2141,6 +2141,23 @@ qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *da
((char*)data)[0] = 0;
return result;
}
qboolean MyRegGetStringValueMultiSz(HKEY base, char *keyname, char *valuename, void *data, int datalen)
{
qboolean result = false;
HKEY subkey;
DWORD type = REG_NONE;
if (RegOpenKeyEx(base, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS)
{
DWORD dwlen;
result = ERROR_SUCCESS == RegQueryValueEx(subkey, valuename, NULL, &type, data, &dwlen);
datalen = dwlen;
RegCloseKey (subkey);
}
if (type == REG_MULTI_SZ)
return result;
return false;
}
qboolean MyRegSetValue(HKEY base, char *keyname, char *valuename, int type, void *data, int datalen)
{

View file

@ -1238,11 +1238,16 @@ qboolean CMod_LoadTexInfo (lump_t *l) //yes I know these load from the same plac
out->mipadjust = 1;
if (out->flags & TI_SKY)
snprintf(sname, sizeof(sname), "sky/%s", in->texture);
snprintf(sname, sizeof(sname), "sky/%s%s", in->texture, in->nexttexinfo==-1?"":"#ANIMLOOP");
else if (out->flags & (TI_WARP|TI_TRANS33|TI_TRANS66))
snprintf(sname, sizeof(sname), "%s/%s#ALPHA=%s", ((out->flags&TI_WARP)?"warp":"trans"), in->texture, ((out->flags&TI_TRANS66)?"0.66":(out->flags&TI_TRANS33?"0.33":"1")));
snprintf(sname, sizeof(sname), "%s/%s#ALPHA=%s%s", ((out->flags&TI_WARP)?"warp":"trans"), in->texture, ((out->flags&TI_TRANS66)?"0.66":(out->flags&TI_TRANS33?"0.33":"1")), in->nexttexinfo==-1?"":"#ANIMLOOP");
else
snprintf(sname, sizeof(sname), "wall/%s", in->texture);
snprintf(sname, sizeof(sname), "wall/%s%s", in->texture, in->nexttexinfo==-1?"":"#ANIMLOOP");
//in q2, 'TEX_SPECIAL' is TI_LIGHT, and that conflicts.
out->flags &= ~TI_LIGHT;
if (out->flags & (TI_SKY|TI_TRANS33|TI_TRANS66|TI_WARP))
out->flags |= TEX_SPECIAL;
//compact the textures.
for (j=0; j < texcount; j++)
@ -1275,6 +1280,29 @@ qboolean CMod_LoadTexInfo (lump_t *l) //yes I know these load from the same plac
loadmodel->textures[texcount++] = out->texture;
}
if (in->nexttexinfo != -1)
{
Con_DPrintf("FIXME: %s should animate to %s\n", in->texture, (in->nexttexinfo+(q2texinfo_t *)(cmod_base + l->fileofs))->texture);
}
}
in = (void *)(cmod_base + l->fileofs);
out = loadmodel->texinfo;
for (i=0 ; i<count ; i++)
{
if (in[i].nexttexinfo >= 0 && in[i].nexttexinfo < count)
out[i].texture->anim_next = out[in[i].nexttexinfo].texture;
}
for (i=0 ; i<count ; i++)
{
texture_t *tex;
if (!out[i].texture->anim_next)
continue;
out[i].texture->anim_total = 1;
for (tex = out[i].texture->anim_next ; tex && tex != out[i].texture ; tex=tex->anim_next)
out[i].texture->anim_total++;
}
loadmodel->numtextures = texcount;
@ -6035,4 +6063,3 @@ void CM_Init(void) //register cvars.
Cvar_Register(&r_subdivisions, MAPOPTIONS);
}
#endif

View file

@ -268,7 +268,7 @@ static void BE_CreateSamplerStates(void)
if (flags & SHADER_PASS_NEAREST)
sampdesc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
else
sampdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampdesc.Filter = /*D3D11_FILTER_MIN_MAG_MIP_POINT;D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;*/D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampdesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
}
if (flags & SHADER_PASS_CLAMP)
@ -2799,7 +2799,7 @@ void D3D11BE_SubmitBatch(batch_t *batch)
shaderstate.batchvbo = batch->vbo;
shaderstate.meshlist = batch->mesh + batch->firstmesh;
shaderstate.curshader = batch->shader;
shaderstate.curtexnums = batch->skin;
shaderstate.curtexnums = batch->skin?batch->skin:&batch->shader->defaulttextures;
shaderstate.flags = batch->flags;
if (!shaderstate.batchvbo)
@ -2864,11 +2864,6 @@ static void BE_SubmitMeshesSortList(batch_t *sortlist)
if (batch->buildmeshes)
batch->buildmeshes(batch);
else if (batch->texture)
{
batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
batch->skin = &batch->shader->defaulttextures;
}
if (batch->shader->flags & SHADER_NODLIGHT)
if (shaderstate.mode == BEM_LIGHT)
@ -3149,9 +3144,6 @@ static void BE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
if (batch->buildmeshes)
batch->buildmeshes(batch);
else
batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
/*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/
BE_SelectMode(BEM_DEPTHONLY);

View file

@ -29640,43 +29640,6 @@
RelativePath="..\common\net_ice.c"
>
</File>
<File
RelativePath="..\common\net_sellingmysoultothedevil.cpp"
>
<FileConfiguration
Name="MinGLDebug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="GLDebug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
CompileAs="2"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug Dedicated Server|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="D3DRelease|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\net_ssl_winsspi.c"
>

View file

@ -4115,8 +4115,8 @@ static void GLBE_SubmitMeshesPortals(batch_t **worldlist, batch_t *dynamiclist)
if (batch->buildmeshes)
batch->buildmeshes(batch);
else
batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
// else
// batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
/*draw already-drawn portals as depth-only, to ensure that their contents are not harmed*/
@ -4165,13 +4165,14 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows.
continue;
//buildmeshes updates shaders and generates pose information for sufaces that need it.
//the shader flags checked *after* this call may be a performance issue if it generated lots of new mesh data.
//FIXME: should we assume that the batch's shader will have the same flags?
if (batch->buildmeshes)
{
TRACE(("GLBE_SubmitMeshesSortList: build\n"));
batch->buildmeshes(batch);
}
else if (batch->texture)
batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader;
TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", batch->shader->name));

View file

@ -138,6 +138,7 @@ unsigned char *d_15to8table;
qboolean inited15to8;
#endif
int maxtexsize; //max_size for 2d images.
extern cvar_t gl_max_size;
extern cvar_t gl_picmip;
extern cvar_t gl_lerpimages;
@ -450,14 +451,13 @@ void GLDraw_Init (void)
{
char ver[40];
int maxtexsize;
if (gltextures)
gltextures = NULL;
memset(gltexturetablebuckets, 0, sizeof(gltexturetablebuckets));
Hash_InitTable(&gltexturetable, sizeof(gltexturetablebuckets)/sizeof(gltexturetablebuckets[0]), gltexturetablebuckets);
maxtexsize = 256;
qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
if (gl_max_size.value > maxtexsize)
{
@ -465,8 +465,6 @@ void GLDraw_Init (void)
Cvar_ForceSet (&gl_max_size, ver);
}
maxtexsize = gl_max_size.value;
if (uploadmemorybuffer)
BZ_Free(uploadmemorybuffer);
if (uploadmemorybufferintermediate)
@ -1035,8 +1033,9 @@ qboolean GL_UploadCompressed (qbyte *file, int *out_width, int *out_height, unsi
}
void GL_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap)
void GL_RoundDimensions(int *scaled_width, int *scaled_height, unsigned int flags)
{
qboolean mipmap = flags & IF_NOMIPMAP;
if (r_config.texture_non_power_of_two) //NPOT is a simple extension that relaxes errors.
{
TRACE(("dbg: GL_RoundDimensions: GL_ARB_texture_non_power_of_two\n"));
@ -1060,25 +1059,36 @@ void GL_RoundDimensions(int *scaled_width, int *scaled_height, qboolean mipmap)
}
}
if (mipmap)
if (flags & IF_NOMIPMAP)
{
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value));
*scaled_width >>= (int)gl_picmip.value;
*scaled_height >>= (int)gl_picmip.value;
*scaled_width >>= gl_picmip2d.ival;
*scaled_height >>= gl_picmip2d.ival;
}
else
{
*scaled_width >>= (int)gl_picmip2d.value;
*scaled_height >>= (int)gl_picmip2d.value;
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value));
*scaled_width >>= gl_picmip.ival;
*scaled_height >>= gl_picmip.ival;
}
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_max_size.value));
if (gl_max_size.value)
if (maxtexsize)
{
if (*scaled_width > gl_max_size.value)
*scaled_width = gl_max_size.value;
if (*scaled_height > gl_max_size.value)
*scaled_height = gl_max_size.value;
if (*scaled_width > maxtexsize)
*scaled_width = maxtexsize;
if (*scaled_height > maxtexsize)
*scaled_height = maxtexsize;
}
if (!(flags & IF_UIPIC))
{
if (gl_max_size.value)
{
if (*scaled_width > gl_max_size.value)
*scaled_width = gl_max_size.value;
if (*scaled_height > gl_max_size.value)
*scaled_height = gl_max_size.value;
}
}
if (*scaled_width < 1)
@ -1139,7 +1149,7 @@ void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigne
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, !(flags & IF_NOMIPMAP));
GL_RoundDimensions(&scaled_width, &scaled_height, flags);
if (!(flags & IF_NOALPHA))
{ //make sure it does actually have those alpha pixels (q3 compat)
@ -1402,7 +1412,7 @@ void GL_Upload24BGR (char *name, qbyte *framedata, int inwidth, int inheight, un
outwidth = inwidth;
outheight = inheight;
GL_RoundDimensions(&outwidth, &outheight, !(flags&IF_NOMIPMAP));
GL_RoundDimensions(&outwidth, &outheight, flags);
if (outwidth*outheight*4 > sizeofuploadmemorybufferintermediate)
{
@ -1472,7 +1482,7 @@ void GL_Upload24BGR_Flip (char *name, qbyte *framedata, int inwidth, int inheigh
outwidth = inwidth;
outheight = inheight;
GL_RoundDimensions(&outwidth, &outheight, !(flags&IF_NOMIPMAP));
GL_RoundDimensions(&outwidth, &outheight, flags);
if (outwidth*outheight*4 > sizeofuploadmemorybufferintermediate)
{
@ -1540,7 +1550,7 @@ void GL_Upload8Grey (unsigned char*data, int width, int height, unsigned int fla
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, !(flags&IF_NOMIPMAP));
GL_RoundDimensions(&scaled_width, &scaled_height, flags);
if (scaled_width * scaled_height*4 > sizeofuploadmemorybuffer)
{
@ -1718,7 +1728,7 @@ static unsigned int * genNormalMap(qbyte *pixels, int w, int h, float scale)
}
//PENTA
void GL_UploadBump(qbyte *data, int width, int height, unsigned int mipmap, float bumpscale)
void GL_UploadBump(qbyte *data, int width, int height, unsigned int flags, float bumpscale)
{
unsigned char *scaled;
int scaled_width, scaled_height;
@ -1728,7 +1738,7 @@ void GL_UploadBump(qbyte *data, int width, int height, unsigned int mipmap, floa
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
GL_RoundDimensions(&scaled_width, &scaled_height, flags);
if (scaled_width*scaled_height*4 > sizeofuploadmemorybuffer)
{
@ -1757,7 +1767,7 @@ void GL_UploadBump(qbyte *data, int width, int height, unsigned int mipmap, floa
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (mipmap)
if (!(flags & IF_NOMIPMAP))
{
int miplevel;
@ -1781,7 +1791,7 @@ void GL_UploadBump(qbyte *data, int width, int height, unsigned int mipmap, floa
}
}
if (mipmap)
if (!(flags & IF_NOMIPMAP))
{
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
if (0 & IF_NEAREST)
@ -1809,7 +1819,7 @@ void GL_UploadBump(qbyte *data, int width, int height, unsigned int mipmap, floa
#ifdef GL_USE8BITTEX
#ifdef GL_EXT_paletted_texture
void GL_Upload8_EXT (qbyte *data, int width, int height, qboolean mipmap, qboolean alpha)
void GL_Upload8_EXT (qbyte *data, int width, int height, unsigned int flags, qboolean alpha)
{
int i, s;
qboolean noalpha;
@ -1837,7 +1847,7 @@ void GL_Upload8_EXT (qbyte *data, int width, int height, qboolean mipmap, qbool
scaled_width = width;
scaled_height = height;
GL_RoundDimensions(&scaled_width, &scaled_height, mipmap);
GL_RoundDimensions(&scaled_width, &scaled_height, flags);
if (scaled_width*scaled_height*4 > sizeofuploadmemorybuffer)
{
@ -2014,7 +2024,7 @@ void GL_Upload8 (char *name, qbyte *data, int width, int height, unsigned int fl
#ifdef GL_USE8BITTEX
#ifdef GL_EXT_paletted_texture
if (GLVID_Is8bit() && !alpha && (data!=scrap_texels[0])) {
GL_Upload8_EXT (data, width, height, mipmap, alpha);
GL_Upload8_EXT (data, width, height, flags, alpha);
return;
}
#endif

View file

@ -39,6 +39,7 @@ qboolean triedtoloadfreetype;
dllhandle_t *fontmodule;
FT_Error (VARGS *pFT_Init_FreeType) (FT_Library *alibrary);
FT_Error (VARGS *pFT_Load_Char) (FT_Face face, FT_ULong char_code, FT_Int32 load_flags);
FT_UInt (VARGS *pFT_Get_Char_Index) (FT_Face face, FT_ULong charcode);
FT_Error (VARGS *pFT_Set_Pixel_Sizes) (FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height);
FT_Error (VARGS *pFT_New_Face) (FT_Library library, const char *pathname, FT_Long face_index, FT_Face *aface);
FT_Error (VARGS *pFT_New_Memory_Face) (FT_Library library, const FT_Byte* file_base, FT_Long file_size, FT_Long face_index, FT_Face *aface);
@ -162,6 +163,22 @@ static const char *imgs[] =
#define PLANEWIDTH (1<<8)
#define PLANEHEIGHT PLANEWIDTH
//windows' font linking allows linking multiple extra fonts to a main font.
//this means that a single selected font can use chars from lots of different files if the first one(s) didn't provide that font.
//they're provided as fallbacks.
#define MAX_FTFACES 32
typedef struct ftfontface_s
{
struct ftfontface_s *next;
struct ftfontface_s **link; //like prev, but not.
char name[MAX_OSPATH];
int refs;
int activeheight; //needs reconfiguring when different sizes are used
FT_Face face;
void *membuf;
} ftfontface_t;
static ftfontface_t *ftfaces;
#define GEN_CONCHAR_GLYPHS 0 //set to 0 or 1 to define whether to generate glyphs from conchars too, or if it should just draw them as glquake always used to
@ -170,6 +187,8 @@ extern cvar_t con_ocranaleds;
typedef struct font_s
{
//FIXME: use a hash table? will need it if we go beyond ucs-2.
//currently they're in a single block so the font can be checked from scanning the active chars when shutting down. we could instead scan all 65k chars in every font instead...
struct charcache_s
{
struct charcache_s *nextchar;
@ -186,18 +205,20 @@ typedef struct font_s
short top;
short left;
} chars[FONTCHARS];
char name[64];
char name[MAX_OSPATH];
short charheight;
texid_t singletexture;
#ifdef AVAIL_FREETYPE
FT_Face face;
void *membuf;
//FIXME: multiple sized font_t objects should refer to a single FT_Face.
int ftfaces;
ftfontface_t *face[MAX_FTFACES];
#endif
struct font_s *alt;
vec3_t alttint;
} font_t;
//shared between fonts.
typedef struct {
texid_t texnum[FONTPLANES];
texid_t defaultfont;
@ -214,7 +235,6 @@ typedef struct {
shader_t *shader;
shader_t *backshader;
} fontplanes_t;
static fontplanes_t fontplanes;
#define FONT_CHAR_BUFFER 512
@ -582,23 +602,34 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
}
#ifdef AVAIL_FREETYPE
if (f->face)
if (f->ftfaces)
{
if (pFT_Load_Char(f->face, charidx, FT_LOAD_RENDER) == 0)
int file;
for (file = 0; file < f->ftfaces; file++)
{
FT_GlyphSlot slot;
FT_Bitmap *bm;
slot = f->face->glyph;
bm = &slot->bitmap;
c = Font_LoadGlyphData(f, charidx, true, bm->buffer, bm->width, bm->rows, bm->pitch);
if (c)
FT_Face face = f->face[file]->face;
if (f->face[file]->activeheight != f->charheight)
{
c->advance = slot->advance.x >> 6;
c->left = slot->bitmap_left;
c->top = f->charheight*3/4 - slot->bitmap_top;
return c;
f->face[file]->activeheight = f->charheight;
pFT_Set_Pixel_Sizes(face, 0, f->charheight);
}
if (charidx == 0xfffe || pFT_Get_Char_Index(face, charidx)) //ignore glyph 0 (undefined)
if (pFT_Load_Char(face, charidx, FT_LOAD_RENDER) == 0)
{
FT_GlyphSlot slot;
FT_Bitmap *bm;
slot = face->glyph;
bm = &slot->bitmap;
c = Font_LoadGlyphData(f, charidx, true, bm->buffer, bm->width, bm->rows, bm->pitch);
if (c)
{
c->advance = slot->advance.x >> 6;
c->left = slot->bitmap_left;
c->top = f->charheight*3/4 - slot->bitmap_top;
return c;
}
}
}
}
@ -658,18 +689,35 @@ static struct charcache_s *Font_GetChar(font_t *f, CHARIDXTYPE charidx)
qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename)
{
#ifdef AVAIL_FREETYPE
ftfontface_t *qface;
FT_Face face = NULL;
FT_Error error;
flocation_t loc;
void *fbase = NULL;
if (!*fontfilename)
return false;
//ran out of font slots.
if (f->ftfaces == MAX_FTFACES)
return false;
for (qface = ftfaces; qface; qface = qface->next)
{
if (!strcmp(qface->name, fontfilename))
{
qface->refs++;
f->face[f->ftfaces++] = qface;
return true;
}
}
if (!fontlib)
{
dllfunction_t ft2funcs[] =
{
{(void**)&pFT_Init_FreeType, "FT_Init_FreeType"},
{(void**)&pFT_Load_Char, "FT_Load_Char"},
{(void**)&pFT_Get_Char_Index, "FT_Get_Char_Index"},
{(void**)&pFT_Set_Pixel_Sizes, "FT_Set_Pixel_Sizes"},
{(void**)&pFT_New_Face, "FT_New_Face"},
{(void**)&pFT_New_Memory_Face, "FT_New_Memory_Face"},
@ -763,8 +811,17 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, char *fontfilename)
if (!error)
{
/*success!*/
f->membuf = fbase;
f->face = face;
qface = Z_Malloc(sizeof(*qface));
qface->link = &ftfaces;
qface->next = *qface->link;
*qface->link = qface;
qface->face = face;
qface->membuf = fbase;
qface->refs++;
qface->activeheight = height;
Q_strncpyz(qface->name, fontfilename, sizeof(qface->name));
f->face[f->ftfaces++] = qface;
return true;
}
}
@ -1149,7 +1206,27 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename)
else
f->alt = Font_LoadFont(vheight, aname+1);
}
if (!Font_LoadFreeTypeFont(f, height, fontfilename))
{
char *start;
start = fontfilename;
for(;;)
{
char *end = strchr(start, ',');
if (end)
*end = 0;
Font_LoadFreeTypeFont(f, height, start);
if (end)
{
*end = ',';
start = end+1;
}
else
break;
}
}
if (!f->ftfaces)
{
//default to only map the ascii-compatible chars from the quake font.
if (*fontfilename)
@ -1245,10 +1322,22 @@ void Font_Free(struct font_s *f)
}
#ifdef AVAIL_FREETYPE
if (f->face)
pFT_Done_Face(f->face);
if (f->membuf)
BZ_Free(f->membuf);
while(f->ftfaces --> 0)
{
ftfontface_t *qface = f->face[f->ftfaces];
qface->refs--;
if (!qface->refs)
{
if (qface->face)
pFT_Done_Face(qface->face);
if (qface->membuf)
BZ_Free(qface->membuf);
*qface->link = qface->next;
if (qface->next)
qface->next->link = qface->link;
Z_Free(qface);
}
}
#endif
Z_Free(f);
}

View file

@ -2619,6 +2619,60 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi
}
}
//q1 autoanimates. if the frame is set, it uses the alternate animation.
void Mod_UpdateBatchShader_Q1 (struct batch_s *batch)
{
texture_t *base = batch->texture;
int reletive;
int count;
if (batch->ent->framestate.g[FS_REG].frame[0])
{
if (base->alternate_anims)
base = base->alternate_anims;
}
if (base->anim_total)
{
reletive = (int)(cl.time*10) % base->anim_total;
count = 0;
while (base->anim_min > reletive || base->anim_max <= reletive)
{
base = base->anim_next;
if (!base)
Sys_Error ("R_TextureAnimation: broken cycle");
if (++count > 100)
Sys_Error ("R_TextureAnimation: infinite cycle");
}
}
batch->shader = base->shader;
}
//q2 has direct control over the texture frames used, but typically has the client generate the frame (different flags autogenerate different ranges).
void Mod_UpdateBatchShader_Q2 (struct batch_s *batch)
{
texture_t *base = batch->texture;
int reletive;
int frame = batch->ent->framestate.g[FS_REG].frame[0];
if (batch->ent == &r_worldentity)
frame = cl.time*2;
if (base->anim_total)
{
reletive = frame % base->anim_total;
while (reletive --> 0)
{
base = base->anim_next;
if (!base)
Sys_Error ("R_TextureAnimation: broken cycle");
}
}
batch->shader = base->shader;
}
/*
batch->firstmesh is set only in and for this function, its cleared out elsewhere
*/
@ -2709,6 +2763,14 @@ static void Mod_Batches_Generate(model_t *mod)
batch->lightmap[3] = surf->lightmaptexturenums[3];
#endif
batch->texture = surf->texinfo->texture;
batch->shader = surf->texinfo->texture->shader;
if (surf->texinfo->texture->alternate_anims || surf->texinfo->texture->anim_total)
{
if (mod->fromgame == fg_quake2)
batch->buildmeshes = Mod_UpdateBatchShader_Q2;
else
batch->buildmeshes = Mod_UpdateBatchShader_Q1;
}
batch->next = mod->batches[sortid];
batch->ent = &r_worldentity;
batch->fog = surf->fog;

View file

@ -2242,7 +2242,7 @@ static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int sms
if (!smesh->batches[tno].count)
continue;
tex = cl.worldmodel->shadowbatches[tno].tex;
if (tex->shader->flags & SHADER_NODLIGHT)
if (tex->shader->flags & SHADER_NODLIGHT) //FIXME: shadows not lights
continue;
BE_DrawMesh_List(tex->shader, smesh->batches[tno].count, smesh->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &tex->shader->defaulttextures, 0);
}
@ -2588,6 +2588,7 @@ static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour)
{
int tno;
texture_t *tex;
shader_t *shader;
shadowmesh_t *sm;
sm = light->worldshadowmesh;
@ -2600,10 +2601,11 @@ static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour)
if (!sm->batches[tno].count)
continue;
tex = cl.worldmodel->shadowbatches[tno].tex;
if (tex->shader->flags & SHADER_NODLIGHT)
shader = R_TextureAnimation(false, tex)->shader;
if (shader->flags & SHADER_NODLIGHT)
continue;
//FIXME: it may be worth building a dedicated ebo
BE_DrawMesh_List(tex->shader, sm->batches[tno].count, sm->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &tex->shader->defaulttextures, 0);
BE_DrawMesh_List(shader, sm->batches[tno].count, sm->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &shader->defaulttextures, 0);
RQuantAdd(RQUANT_LITFACES, sm->batches[tno].count);
}

View file

@ -10714,7 +10714,7 @@ void QCC_PR_ParseDefs (char *classname)
isconstant = true;
else if (QCC_PR_CheckKeyword(keyword_var, "var"))
isvar = true;
else if (!pr_scope && QCC_PR_CheckKeyword(keyword_var, "static"))
else if (QCC_PR_CheckKeyword(keyword_var, "static"))
isstatic = true;
else if (!pr_scope && QCC_PR_CheckKeyword(keyword_var, "nonstatic"))
isstatic = false;

View file

@ -4079,14 +4079,18 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (newparm->type == ev_function)
{
if (isstatic)
QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static functions are not supported at this time.", classname, parmname);
{
isstatic = false;
isnonvirt = true;
// QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static member functions are not supported at this time.", classname, parmname);
}
if (!strcmp(classname, parmname))
{
if (isstatic)
QCC_PR_ParseError(ERR_INTERNAL, "Constructor %s::%s may not be static.", classname, pr_token);
if (!isvirt)
isnonvirt = true;//silently promote constructors to nonvirt
isnonvirt = true;//silently promote constructors to static
}
else if (!isvirt && !isnonvirt && !isstatic)
{

View file

@ -10364,6 +10364,8 @@ void PR_DumpPlatform_f(void)
{"noise3", ".string", QW|NQ},
{"end_sys_fields", "void", QW|NQ|CS|MENU},
{"time", "float", MENU, "The current local time. Increases while paused."},
#define comfieldfloat(name,desc) {#name, ".float", FL, desc},
#define comfieldvector(name,desc) {#name, ".vector", FL, desc},
#define comfieldentity(name,desc) {#name, ".entity", FL, desc},

View file

@ -769,8 +769,8 @@ typedef struct
struct ftenet_connections_s *sockets;
int allocated_client_slots;
client_t *clients;
int allocated_client_slots; //number of entries in the clients array
client_t *clients; //[svs.allocated_client_slots]
int serverflags; // episode completion information
double last_heartbeat;

View file

@ -1491,7 +1491,7 @@ void SV_Status_f (void)
Con_Printf ("name userid frags\n");
Con_Printf (" address rate ping drop\n");
Con_Printf (" ---------------- ---- ---- -----\n");
for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0,cl=svs.clients ; i<svs.allocated_client_slots ; i++,cl++)
{
if (!cl->state)
continue;
@ -2059,7 +2059,7 @@ void SV_Snap (int uid)
if (cl->userid == uid)
break;
}
if (i >= MAX_CLIENTS)
if (i >= svs.allocated_client_slots)
{
Con_TPrintf ("Couldn't find user number %i\n", uid);
return;

View file

@ -310,7 +310,7 @@ void SV_LoadClientDemo_f (void)
SV_BroadcastCommand ("changing\n"); //but this arrives BEFORE the serverdata
ohc = host_client;
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
if (host_client->state != cs_spawned)
continue;
@ -506,7 +506,7 @@ qboolean SV_ReadMVD (void)
sv.democausesreconnect = false;
svs.spawncount++;
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
if (host_client->state != cs_spawned)
continue;
@ -525,7 +525,7 @@ qboolean SV_ReadMVD (void)
{
if (!svd.demofile)
{ //demo ended.
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
cl->sendinfo = true;
}
@ -561,7 +561,7 @@ qboolean SV_ReadMVD (void)
break;
// case dem_read: //baseline stuff
case dem_single:
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
if (!cl->state)
continue;
@ -585,7 +585,7 @@ qboolean SV_ReadMVD (void)
VFS_CLOSE(svd.demofile);
svd.demofile = NULL;
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
if (host_client->state != cs_spawned)
continue;

View file

@ -2138,7 +2138,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
clstate_t clst;
extern float olddemotime, nextdemotime;
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
//FIXME: Add PVS stuff.
@ -2222,7 +2222,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
clst.fteext = 0;//client->fteprotocolextensions;
clst.zext = 0;//client->zquake_extensions;
clst.vw_index = 0;
clst.playernum = MAX_CLIENTS-1;
clst.playernum = svs.allocated_client_slots-1;
clst.isself = true;
clst.modelindex = 0;
clst.hull = 1;
@ -2761,7 +2761,7 @@ static void SV_Snapshot_Build_Playback(client_t *client, packet_entities_t *pack
if (!dement->modelindex)
continue;
if (e >= 1 && e <= MAX_CLIENTS)
if (e >= 1 && e <= svs.allocated_client_slots)
continue;
if (pack->num_entities == pack->max_entities)

View file

@ -166,7 +166,7 @@ baseline will be transmitted
continue;
// create baselines for all player slots,
// and any other edict that has a visible model
if (entnum > MAX_CLIENTS && !svent->v->modelindex)
if (entnum > svs.allocated_client_slots && !svent->v->modelindex)
continue;
//
@ -176,7 +176,7 @@ baseline will be transmitted
VectorCopy (svent->v->angles, svent->baseline.angles);
svent->baseline.frame = svent->v->frame;
svent->baseline.skinnum = svent->v->skin;
if (entnum > 0 && entnum <= MAX_CLIENTS)
if (entnum > 0 && entnum <= svs.allocated_client_slots)
{
svent->baseline.colormap = entnum;
svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl")&255;
@ -1330,53 +1330,30 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
char crc[12];
sprintf(crc, "%i", QCRC_Block(file, com_filesize));
Info_SetValueForStarKey(svs.info, "*entfile", crc, MAX_SERVERINFO_STRING);
switch(svs.gametype)
{
case GT_MAX:
break;
case GT_Q1QVM:
case GT_PROGS:
sv.world.edict_size = PR_LoadEnts(svprogfuncs, file, spawnflagmask);
break;
case GT_QUAKE2:
#ifdef Q2SERVER
ge->SpawnEntities(sv.name, file, startspot?startspot:"");
#endif
break;
case GT_QUAKE3:
break;
case GT_HALFLIFE:
#ifdef HLSERVER
SVHL_SpawnEntities(file);
#endif
break;
}
BZ_Free(file);
}
else
{
Info_SetValueForStarKey(svs.info, "*entfile", "", MAX_SERVERINFO_STRING);
switch(svs.gametype)
{
case GT_MAX:
break;
case GT_Q1QVM:
case GT_PROGS:
sv.world.edict_size = PR_LoadEnts(svprogfuncs, sv.world.worldmodel->entities, spawnflagmask);
break;
case GT_QUAKE2:
switch(svs.gametype)
{
case GT_MAX:
break;
case GT_Q1QVM:
case GT_PROGS:
sv.world.edict_size = PR_LoadEnts(svprogfuncs, file?file :sv.world.worldmodel->entities, spawnflagmask);
break;
case GT_QUAKE2:
#ifdef Q2SERVER
ge->SpawnEntities(sv.name, sv.world.worldmodel->entities, startspot?startspot:"");
ge->SpawnEntities(sv.name, file?file :sv.world.worldmodel->entities, startspot?startspot:"");
#endif
break;
case GT_QUAKE3:
break;
case GT_HALFLIFE:
break;
case GT_QUAKE3:
break;
case GT_HALFLIFE:
#ifdef HLSERVER
SVHL_SpawnEntities(sv.world.worldmodel->entities);
SVHL_SpawnEntities(file?file :sv.world.worldmodel->entities));
#endif
break;
}
break;
}
#ifndef SERVERONLY

View file

@ -114,8 +114,8 @@ cvar_t allow_download_sounds = CVAR("allow_download_sounds", "1");
cvar_t allow_download_demos = CVAR("allow_download_demos", "1");
cvar_t allow_download_maps = CVAR("allow_download_maps", "1");
cvar_t allow_download_anymap = CVAR("allow_download_pakmaps", "0");
cvar_t allow_download_pakcontents = CVAR("allow_download_pakcontents", "1");
cvar_t allow_download_root = CVAR("allow_download_root", "0");
cvar_t allow_download_pakcontents = CVARD("allow_download_pakcontents", "1", "controls whether clients connected to this server are allowed to download files from within packages. Does NOT implicitly allow downloading bsps, set allow_download_pakmaps to enable that.");
cvar_t allow_download_root = CVAR("allow_download_root", "0", "If set, enables downloading from the root of the gamedir (not the basedir). This setting is dangerous as it can allow downloading configs.");
cvar_t allow_download_textures = CVAR("allow_download_textures", "1");
cvar_t allow_download_packages = CVAR("allow_download_packages", "1");
cvar_t allow_download_refpackages = CVARD("allow_download_refpackages", "1", "If set to 1, packages that contain files needed during spawn functions will be become 'referenced' and automatically downloaded to clients.\nThis cvar should probably not be set if you have large packages that provide replacement pickup models on public servers.\nThe path command will show a '(ref)' tag next to packages which clients will automatically attempt to download.");
@ -1044,7 +1044,7 @@ void SVC_Status (void)
SV_BeginRedirect (RD_PACKET, TL_FindLanguage(""));
if (displayflags&STATUS_SERVERINFO)
Con_Printf ("%s\n", svs.info);
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
cl = &svs.clients[i];
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && ((cl->spectator && displayflags&STATUS_SPECTATORS) || (!cl->spectator && displayflags&STATUS_PLAYERS)))
@ -1107,7 +1107,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
if (!sv_listen_nq.ival && !sv_listen_dp.ival)
return;
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
cl = &svs.clients[i];
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && !cl->spectator)
@ -1167,7 +1167,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
resp[-1] = '\n'; //replace the null terminator that we already wrote
//on the following lines we have an entry for each client
for (i=0 ; i<MAX_CLIENTS ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
{
cl = &svs.clients[i];
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && !cl->spectator)
@ -1221,7 +1221,7 @@ void SVC_InfoQ2 (void)
else
{
count = 0;
for (i=0 ; i<maxclients.value ; i++)
for (i=0 ; i<svs.allocated_client_slots ; i++)
if (svs.clients[i].state >= cs_connected)
count++;
@ -2517,7 +2517,7 @@ client_t *SVC_DirectConnect(void)
newcl->realip_ping = (((rand()^(rand()<<8) ^ *(int*)&realtime)&0xffffff)<<8) | (newcl-svs.clients);
if (newcl->istobeloaded)
if (newcl->istobeloaded && newcl->edict)
newcl->playerclass = newcl->edict->xv->playerclass;
// parse some info from the info strings
@ -2902,7 +2902,7 @@ void SVC_RealIP (void)
slotnum = atoi(Cmd_Argv(1));
cookie = atoi(Cmd_Argv(2));
if (slotnum >= MAX_CLIENTS)
if (slotnum >= svs.allocated_client_slots)
{
//a malitious user
return;
@ -4516,7 +4516,7 @@ void Master_Heartbeat (void)
{
// count active users
active = 0;
for (j=0 ; j<MAX_CLIENTS ; j++)
for (j=0 ; j<svs.allocated_client_slots ; j++)
if (svs.clients[j].state == cs_connected ||
svs.clients[j].state == cs_spawned )
active++;

View file

@ -802,7 +802,7 @@ void Rank_Refresh_f(void)
return;
}
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
for (i=0, host_client = svs.clients ; i<svs.allocated_client_slots ; i++, host_client++)
{
if (host_client->state != cs_spawned)
continue;

View file

@ -476,7 +476,7 @@ void VARGS SV_BroadcastCommand (char *fmt, ...)
vsnprintf (string,sizeof(string), fmt,argptr);
va_end (argptr);
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
for (i=0, cl = svs.clients ; i<svs.allocated_client_slots ; i++, cl++)
{
if (cl->controller)
continue;
@ -2140,7 +2140,7 @@ void SV_UpdateToReliableMessages (void)
{
if (host_client->old_frags != (int)host_client->edict->v->frags)
{
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
for (j=0, client = svs.clients ; j<svs.allocated_client_slots ; j++, client++)
{
if (client->state < cs_connected)
continue;

View file

@ -1617,7 +1617,7 @@ void SV_SpawnSpectator (void)
// search for an info_playerstart to spawn the spectator at
//this is only useful when a mod doesn't nativly support spectators. old qw on nq mods.
for (i=MAX_CLIENTS+1 ; i<sv.world.num_edicts ; i++)
for (i=svs.allocated_client_slots+1 ; i<sv.world.num_edicts ; i++)
{
e = EDICT_NUM(svprogfuncs, i);
if (!strcmp(PR_GetString(svprogfuncs, e->v->classname), "info_player_start"))
@ -2307,7 +2307,7 @@ void SV_VoiceReadPacket(void)
/*figure out which team members are meant to receive it*/
for (j = 0; j < (MAX_CLIENTS+7)/8; j++)
ring->receiver[j] = 0;
for (j = 0, cl = svs.clients; j < sv.allocated_client_slots; j++, cl++)
for (j = 0, cl = svs.clients; j < svs.allocated_client_slots; j++, cl++)
{
if (cl->state != cs_spawned && cl->state != cs_connected)
continue;
@ -2458,7 +2458,7 @@ void SV_Voice_Ignore_f(void)
type = -1;
}
other = atoi(Cmd_Argv(1));
if (other >= MAX_CLIENTS)
if (other >= svs.allocated_client_slots)
return;
switch(type)
@ -2486,7 +2486,7 @@ void SV_Voice_Target_f(void)
else if (*t >= '0' && *t <= '9')
{
other = atoi(t);
if (other >= MAX_CLIENTS)
if (other >= svs.allocated_client_slots)
return;
host_client->voice_target = VT_PLAYERSLOT0 + other;
}
@ -3334,7 +3334,7 @@ void SV_Pings_f (void)
if (ISNQCLIENT(host_client))
{
char *s;
ClientReliableWrite_Begin(host_client, svc_stufftext, 15+10*MAX_CLIENTS);
ClientReliableWrite_Begin(host_client, svc_stufftext, 15+10*sv.allocated_client_slots);
ClientReliableWrite_SZ(host_client, "pingplreport", 12);
for (j = 0, client = svs.clients; j < sv.allocated_client_slots && j < host_client->max_net_clients; j++, client++)
{
@ -4784,7 +4784,7 @@ void SVNQ_Ping_f(void)
//don't translate this, most advanced clients (including us) automate and parse them, the results being visible in the scoreboard and NOT the console.
//translating these prints can thus confuse things greatly.
SV_PrintToClient(host_client, PRINT_HIGH, "Client ping times:\n");
for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
for (i=0,cl=svs.clients ; i<sv.allocated_client_slots ; i++,cl++)
{
if (!cl->state)
continue;

View file

@ -1322,7 +1322,7 @@ void SVHL_SpawnEntities(char *entstring)
//initialise globals
SVHL_Globals.stringbase = "";
SVHL_Globals.maxclients = MAX_CLIENTS;
SVHL_Globals.maxclients = svs.allocated_client_slots;
SVHL_Globals.deathmatch = deathmatch.value;
SVHL_Globals.coop = coop.value;
SVHL_Globals.serverflags = 0;

View file

@ -287,7 +287,7 @@ void SVQ2_EmitPacketEntities (q2client_frame_t *from, q2client_frame_t *to, size
if (msg->cursize+128 > msg->maxsize)
memcpy(newent, oldent, sizeof(*newent)); //too much data, so set the ent up as the same as the old, so it's sent next frame
else
MSGQ2_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= MAX_CLIENTS);
MSGQ2_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= svs.allocated_client_slots);
oldindex++;
newindex++;
continue;

View file

@ -92,7 +92,7 @@ static void VARGS PFQ2_Unicast (q2edict_t *ent, qboolean reliable)
return;
p = Q2NUM_FOR_EDICT(ent);
if (p < 1 || p > MAX_CLIENTS)
if (p < 1 || p > svs.allocated_client_slots)
return;
client = svs.clients + (p-1);
@ -145,7 +145,7 @@ static void VARGS PFQ2_cprintf (q2edict_t *ent, int level, char *fmt, ...)
if (ent)
{
n = Q2NUM_FOR_EDICT(ent);
if (n < 1 || n > MAX_CLIENTS)
if (n < 1 || n > svs.allocated_client_slots)
{
Sys_Error ("cprintf to a non-client");
return;
@ -183,7 +183,7 @@ static void VARGS PFQ2_centerprintf (q2edict_t *ent, char *fmt, ...)
int n;
n = Q2NUM_FOR_EDICT(ent);
if (n < 1 || n > MAX_CLIENTS)
if (n < 1 || n > svs.allocated_client_slots)
return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
if (svs.clients[n-1].state < cs_connected)

View file

@ -3206,7 +3206,7 @@ void JCL_CheckClientCaps(jclient_t *jcl, buddy_t *buddy, bresource_t *bres)
//one of google's nodes. ONLY google get this fucked up evil hack because they're the only ones that are arrogant enough to not bother to query what that 'ext' actually means - and then to not even bother to tell other clients.
//every other client is expected to have its act together and not fuck up like this.
googlefuckedup = !!strstr(bres->client_node, "google.com") || !!strstr(bres->client_node, "android.com");
googlefuckedup = bres->client_node && (!!strstr(bres->client_node, "google.com") || !!strstr(bres->client_node, "android.com"));
//and ask for info about each extension too. which should only be used if the specified version isn't a hash.
if (bres->client_hash && !*bres->client_hash)