1
0
Fork 0
forked from fte/fteqw

tweaked console completion to be less spammy and to show descriptions for commands where available.

added a few descriptions to a few cvars.
tweaked strzone/strunzone, added memalloc/memfree/memcpy/memset (use pr_dumpplatform to dump out a new defs).
tweaked android to use a smaller audio buffer, hopefully reducing latency slightly. let me know if this results in bugs...

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4005 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2012-03-19 06:30:41 +00:00
parent 8e77971422
commit 53116a9763
25 changed files with 616 additions and 185 deletions

View file

@ -44,25 +44,25 @@ cvar_t rcon_address = SCVARF("rcon_address", "", CVAR_NOUNSAFEEXPAND);
cvar_t cl_timeout = SCVAR("cl_timeout", "60"); cvar_t cl_timeout = SCVAR("cl_timeout", "60");
cvar_t cl_shownet = SCVAR("cl_shownet","0"); // can be 0, 1, or 2 cvar_t cl_shownet = CVAR("cl_shownet","0", "Debugging var. 0 shows nothing. 1 shows incoming packet sizes. 2 shows individual messages. 3 shows entities too."); // can be 0, 1, or 2
cvar_t cl_pure = CVARD("cl_pure", "0", "If enabled, the filesystem will be restricted to allow only the content of the current server."); cvar_t cl_pure = CVARD("cl_pure", "0", "If enabled, the filesystem will be restricted to allow only the content of the current server.");
cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback); cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback);
cvar_t cl_hudswap = CVARF("cl_hudswap", "0", CVAR_ARCHIVE); cvar_t cl_hudswap = CVARF("cl_hudswap", "0", CVAR_ARCHIVE);
cvar_t cl_maxfps = CVARF("cl_maxfps", "500", CVAR_ARCHIVE); cvar_t cl_maxfps = CVARF("cl_maxfps", "500", CVAR_ARCHIVE);
cvar_t cl_idlefps = CVARF("cl_idlefps", "0", CVAR_ARCHIVE); cvar_t cl_idlefps = CVARF("cl_idlefps", "0", CVAR_ARCHIVE, "This is the maximum framerate to attain while idle/paused.");
cvar_t cl_yieldcpu = CVARF("cl_yieldcpu", "0", CVAR_ARCHIVE); cvar_t cl_yieldcpu = CVARFD("cl_yieldcpu", "0", CVAR_ARCHIVE, "Attempt to yield between frames. This can resolve issues with certain drivers and background software, but can mean less consistant frame times. Will reduce power consumption/heat generation so should be set on laptops or similar (over-hot/battery powered) devices.");
cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE); cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE);
cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff");
cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be smoother, but they may be more laggy. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'."); cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be smoother, but they may be more laggy. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'.");
cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this.");
cvar_t hud_tracking_show = CVAR("hud_tracking_show", "1"); cvar_t hud_tracking_show = CVAR("hud_tracking_show", "1");
cvar_t cl_defaultport = CVARAF("cl_defaultport", STRINGIFY(PORT_QWSERVER), "port", 0); cvar_t cl_defaultport = CVARAFD("cl_defaultport", STRINGIFY(PORT_QWSERVER), "port", 0, "The default port to connect to servers.\nQW: "STRINGIFY(PORT_QWSERVER)", NQ: "STRINGIFY(PORT_NQSERVER)", Q2: "STRINGIFY(PORT_Q2SERVER)".");
cvar_t cfg_save_name = CVARF("cfg_save_name", "fte", CVAR_ARCHIVE); cvar_t cfg_save_name = CVARF("cfg_save_name", "fte", CVAR_ARCHIVE);
cvar_t cl_splitscreen = CVAR("cl_splitscreen", "0"); cvar_t cl_splitscreen = CVARD("cl_splitscreen", "0", "Enables splitscreen support. See also: allow_splitscreen, in_rawinput*, the \"p\" command.");
cvar_t lookspring = CVARF("lookspring","0", CVAR_ARCHIVE); cvar_t lookspring = CVARF("lookspring","0", CVAR_ARCHIVE);
cvar_t lookstrafe = CVARF("lookstrafe","0", CVAR_ARCHIVE); cvar_t lookstrafe = CVARF("lookstrafe","0", CVAR_ARCHIVE);
@ -116,7 +116,7 @@ cvar_t noaim = CVARF("noaim", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t msg = CVARF("msg", "1", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t msg = CVARF("msg", "1", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t b_switch = CVARF("b_switch", "", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t b_switch = CVARF("b_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t w_switch = CVARF("w_switch", "", CVAR_ARCHIVE | CVAR_USERINFO); cvar_t w_switch = CVARF("w_switch", "", CVAR_ARCHIVE | CVAR_USERINFO);
cvar_t cl_nofake = CVAR("cl_nofake", "2"); cvar_t cl_nofake = CVARD("cl_nofake", "2", "value 0: permits \\r chars in chat messages\nvalue 1: blocks all \\r chars\nvalue 2: allows \\r chars, but only from teammates");
cvar_t cl_chatsound = CVAR("cl_chatsound","1"); cvar_t cl_chatsound = CVAR("cl_chatsound","1");
cvar_t cl_enemychatsound = CVAR("cl_enemychatsound", "misc/talk.wav"); cvar_t cl_enemychatsound = CVAR("cl_enemychatsound", "misc/talk.wav");
cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav"); cvar_t cl_teamchatsound = CVAR("cl_teamchatsound", "misc/talk.wav");
@ -152,7 +152,7 @@ cvar_t cl_countpendingpl = SCVAR("cl_countpendingpl", "0");
cvar_t cl_standardchat = SCVARF("cl_standardchat", "0", CVAR_ARCHIVE); cvar_t cl_standardchat = SCVARF("cl_standardchat", "0", CVAR_ARCHIVE);
cvar_t msg_filter = SCVAR("msg_filter", "0"); //0 for neither, 1 for mm1, 2 for mm2, 3 for both cvar_t msg_filter = SCVAR("msg_filter", "0"); //0 for neither, 1 for mm1, 2 for mm2, 3 for both
cvar_t cl_standardmsg = SCVARF("cl_standardmsg", "0", CVAR_ARCHIVE); cvar_t cl_standardmsg = SCVARF("cl_standardmsg", "0", CVAR_ARCHIVE);
cvar_t cl_parsewhitetext = SCVAR("cl_parsewhitetext", "1"); cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red");
cvar_t cl_dlemptyterminate = SCVAR("cl_dlemptyterminate", "1"); cvar_t cl_dlemptyterminate = SCVAR("cl_dlemptyterminate", "1");
@ -3770,6 +3770,8 @@ void Host_Init (quakeparms_t *parms)
int i; int i;
int qrc, hrc, def; int qrc, hrc, def;
#endif #endif
extern cvar_t com_parseutf8;
com_parseutf8.ival = 1;
COM_InitArgv (parms->argc, parms->argv); COM_InitArgv (parms->argc, parms->argv);

View file

@ -562,7 +562,6 @@ void Con_PrintCon (console_t *con, char *txt)
conchar_t expanded[4096]; conchar_t expanded[4096];
conchar_t *c; conchar_t *c;
conline_t *oc; conline_t *oc;
static int cr;
COM_ParseFunString(CON_WHITEMASK, txt, expanded, sizeof(expanded), false); COM_ParseFunString(CON_WHITEMASK, txt, expanded, sizeof(expanded), false);
@ -574,10 +573,10 @@ void Con_PrintCon (console_t *con, char *txt)
switch (*c & (CON_CHARMASK)) switch (*c & (CON_CHARMASK))
{ {
case '\r': case '\r':
cr = true; con->cr = true;
break; break;
case '\n': case '\n':
cr = false; con->cr = false;
while (con->linecount >= con_maxlines.ival) while (con->linecount >= con_maxlines.ival)
{ {
if (con->oldest == con->current) if (con->oldest == con->current)
@ -616,10 +615,10 @@ void Con_PrintCon (console_t *con, char *txt)
con->display = con->current; con->display = con->current;
break; break;
default: default:
if (cr) if (con->cr)
{ {
con->current->length = 0; con->current->length = 0;
cr = false; con->cr = false;
} }
if (selstartline == con->current) if (selstartline == con->current)
@ -798,9 +797,11 @@ DRAWING
Con_DrawInput Con_DrawInput
The input line scrolls horizontally if typing goes beyond the right edge The input line scrolls horizontally if typing goes beyond the right edge
y is the bottom of the input
return value is the top of the region
================ ================
*/ */
void Con_DrawInput (int left, int right, int y) int Con_DrawInput (int left, int right, int y)
{ {
#ifdef _WIN32 #ifdef _WIN32
extern qboolean ActiveApp; extern qboolean ActiveApp;
@ -808,9 +809,9 @@ void Con_DrawInput (int left, int right, int y)
int i; int i;
int lhs, rhs; int lhs, rhs;
int p; int p;
unsigned char *text, *fname; unsigned char *text, *fname = NULL;
extern int con_commandmatch; extern int con_commandmatch;
conchar_t maskedtext[MAXCMDLINE]; conchar_t maskedtext[2048];
conchar_t *endmtext; conchar_t *endmtext;
conchar_t *cursor; conchar_t *cursor;
conchar_t *cchar; conchar_t *cchar;
@ -818,11 +819,13 @@ void Con_DrawInput (int left, int right, int y)
int x; int x;
y -= Font_CharHeight();
if (key_dest != key_console && con_current->vislines != vid.height) if (key_dest != key_console && con_current->vislines != vid.height)
return; // don't draw anything (always draw if not active) return y; // don't draw anything (always draw if not active)
if (!con_current->linebuffered) if (!con_current->linebuffered)
return; //fixme: draw any unfinished lines of the current console instead. return y; //fixme: draw any unfinished lines of the current console instead.
text = key_lines[edit_line]; text = key_lines[edit_line];
@ -833,9 +836,9 @@ void Con_DrawInput (int left, int right, int y)
i = text[key_linepos]; i = text[key_linepos];
text[key_linepos] = 0; text[key_linepos] = 0;
cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext)-1*sizeof(conchar_t), true); cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true);
text[key_linepos] = i; text[key_linepos] = i;
endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext)-1*sizeof(conchar_t), true); endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true);
endmtext[1] = 0; endmtext[1] = 0;
@ -859,9 +862,11 @@ void Con_DrawInput (int left, int right, int y)
fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch); fname = Cmd_CompleteCommand(text+cmdstart, true, true, con_commandmatch);
if (fname) //we can compleate it to: if (fname) //we can compleate it to:
{ {
for (p = key_linepos-cmdstart; fname[p]>' '; p++) for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>' '; p++)
maskedtext[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<<CON_FGSHIFT); maskedtext[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<<CON_FGSHIFT);
maskedtext[p+cmdstart] = '\0'; if (p < key_linepos-cmdstart)
p = key_linepos-cmdstart;
maskedtext[p+cmdstart] = 0;
} }
} }
} }
@ -914,6 +919,81 @@ void Con_DrawInput (int left, int right, int y)
{ {
rhs = Font_DrawChar(rhs, y, *cchar); rhs = Font_DrawChar(rhs, y, *cchar);
} }
/*if its getting completed to something, show some help about the command that is going to be used*/
if (!text[1])
con_commandmatch = 0;
if (con_commandmatch && Cmd_IsCommand(text+(text[1] == '/'?2:1)))
{
cvar_t *var;
char *desc = NULL;
if (!desc)
{
var = Cvar_FindVar(fname);
if (var && var->description)
desc = var->description;
}
if (!desc)
{
desc = Cmd_Describe(fname);
}
if (desc)
{
int lines;
conchar_t *starts[8];
conchar_t *ends[8];
conchar_t *end;
end = maskedtext;
end = COM_ParseFunString((COLOR_YELLOW<<CON_FGSHIFT), va("%s: %s", fname, desc), end, (maskedtext+sizeof(maskedtext)/sizeof(maskedtext[0])-1-end)*sizeof(maskedtext[0]), true);
lines = Font_LineBreaks(maskedtext, end, right - left, 8, starts, ends);
while(lines-->0)
{
rhs = left;
y -= Font_CharHeight();
for (cchar = starts[lines]; cchar < ends[lines]; cchar++)
{
rhs = Font_DrawChar(rhs, y, *cchar);
}
}
}
}
/*just above that, we have the tab completion list*/
if (con_commandmatch && con_displaypossibilities.value)
{
int lines;
conchar_t *starts[32];
conchar_t *ends[32];
conchar_t *end;
char *cmd;
int cmdstart;
cmdstart = text[1] == '/'?2:1;
end = maskedtext;
for (i = 1; ; i++)
{
cmd = Cmd_CompleteCommand (text+cmdstart, true, true, i);
if (!cmd)
break;
end = COM_ParseFunString((COLOR_GREEN<<CON_FGSHIFT), va("%s\t", cmd), end, (maskedtext+sizeof(maskedtext)/sizeof(maskedtext[0])-1-end)*sizeof(maskedtext[0]), true);
}
lines = Font_LineBreaks(maskedtext, end, right - left, 32, starts, ends);
while(lines-->0)
{
rhs = left;
y -= Font_CharHeight();
for (cchar = starts[lines]; cchar < ends[lines]; cchar++)
{
rhs = Font_DrawChar(rhs, y, *cchar);
}
}
}
return y;
} }
/* /*
@ -1304,8 +1384,7 @@ void Con_DrawConsole (int lines, qboolean noback)
y -= Font_CharHeight(); y -= Font_CharHeight();
haveprogress = Con_DrawProgress(x, ex - x, y) != y; haveprogress = Con_DrawProgress(x, ex - x, y) != y;
y -= Font_CharHeight(); y = Con_DrawInput (x, ex - x, y);
Con_DrawInput (x, ex - x, y);
if (selactive) if (selactive)
{ {

View file

@ -266,9 +266,9 @@ int rawkbdcount;
RAWINPUT *raw; RAWINPUT *raw;
int ribuffersize; int ribuffersize;
cvar_t in_rawinput = SCVAR("in_rawinput", "0"); cvar_t in_rawinput = CVARD("in_rawinput", "0", "Enables rawinput support for mice in XP onwards. Rawinput permits independant device identification (ie: splitscreen clients can each have their own mouse)");
cvar_t in_rawinput_keyboard = SCVAR("in_rawinput_keyboard", "0"); cvar_t in_rawinput_keyboard = SCVAR("in_rawinput_keyboard", "0", "Enables rawinput support for keyboards in XP onwards as well as just mice. Requires in_rawinput to be set.");
cvar_t in_rawinput_rdp = SCVAR("in_rawinput_rdp", "0"); cvar_t in_rawinput_rdp = CVARD("in_rawinput_rdp", "0", "Activate Remote Desktop Protocol devices too.");
void IN_RawInput_MouseDeRegister(void); void IN_RawInput_MouseDeRegister(void);
int IN_RawInput_MouseRegister(void); int IN_RawInput_MouseRegister(void);

View file

@ -251,7 +251,7 @@ qboolean Cmd_IsCommand (char *line)
int PaddedPrint (char *s, int x) int PaddedPrint (char *s, int x)
{ {
Con_Printf ("%s\t", s); Con_Printf ("^4%s\t", s);
x+=strlen(s); x+=strlen(s);
return x; return x;
@ -268,22 +268,6 @@ void CompleteCommand (qboolean force)
if (*s == '\\' || *s == '/') if (*s == '\\' || *s == '/')
s++; s++;
if (!force && con_displaypossibilities.value)
{
int x=0;
for (i = 1; ; i++)
{
cmd = Cmd_CompleteCommand (s, true, true, i);
if (!cmd)
break;
if (i == 1)
Con_Printf("---------\n");
x = PaddedPrint(cmd, x);
}
if (i != 1)
Con_Printf("\n");
}
cmd = Cmd_CompleteCommand (s, true, true, 2); cmd = Cmd_CompleteCommand (s, true, true, 2);
if (!cmd || force) if (!cmd || force)
{ {
@ -311,6 +295,8 @@ void CompleteCommand (qboolean force)
} }
} }
key_lines[edit_line][key_linepos] = 0; key_lines[edit_line][key_linepos] = 0;
if (!con_commandmatch)
con_commandmatch = 1;
return; return;
} }
} }
@ -330,6 +316,8 @@ void CompleteCommand (qboolean force)
key_lines[edit_line][key_linepos] = 0; key_lines[edit_line][key_linepos] = 0;
if (!con_commandmatch)
con_commandmatch = 1;
return; //don't alter con_commandmatch if we compleated a tiny bit more return; //don't alter con_commandmatch if we compleated a tiny bit more
} }
} }
@ -533,7 +521,7 @@ void Key_Console (unsigned int unicode, int key)
CompleteCommand (false); CompleteCommand (false);
return; return;
} }
if (key != K_SHIFT) if (key != K_SHIFT && con_commandmatch)
con_commandmatch=1; con_commandmatch=1;
if (key == K_LEFTARROW) if (key == K_LEFTARROW)

View file

@ -1843,6 +1843,11 @@ static void P_ImportEffectInfo_f(void)
ptype->looks.type = PT_BEAM; ptype->looks.type = PT_BEAM;
ptype->looks.blendmode = BM_ADD; ptype->looks.blendmode = BM_ADD;
} }
// else if (!strcmp(arg[1], "snow"))
// {
// ptype->looks.type = PT_NORMAL;
// ptype->looks.blendmode = BM_BLEND;
// }
else else
{ {
Con_Printf("effectinfo type %s not supported\n", arg[1]); Con_Printf("effectinfo type %s not supported\n", arg[1]);
@ -1963,6 +1968,8 @@ static void P_ImportEffectInfo_f(void)
; ;
else if (!strcmp(arg[0], "rotate") && args == 2) else if (!strcmp(arg[0], "rotate") && args == 2)
; ;
else if (!strcmp(arg[0], "rotate") && args == 4)
;
#endif #endif
else else
Con_Printf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]); Con_Printf("Particle effect token not recognised, or invalid args: %s %s %s %s %s %s\n", arg[0], args<2?"":arg[1], args<3?"":arg[2], args<4?"":arg[3], args<5?"":arg[4], args<6?"":arg[5]);

View file

@ -4334,6 +4334,12 @@ static struct {
{"skel_ragupdate", PF_skel_ragedit, 281},// (FTE_QC_RAGDOLL) {"skel_ragupdate", PF_skel_ragedit, 281},// (FTE_QC_RAGDOLL)
{"skel_mmap", PF_skel_mmap, 282},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 282},// (FTE_QC_RAGDOLL)
{"skel_set_bone_world", PF_skel_set_bone_world, 283}, {"skel_set_bone_world", PF_skel_set_bone_world, 283},
{"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385},
{"memcpy", PF_memcpy, 386},
{"memset", PF_memset, 387},
//300 //300
{"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC) {"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC)
{"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC) {"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC)

View file

@ -1756,6 +1756,8 @@ void Surf_SetupFrame(void)
leaf = RMod_PointInLeaf (cl.worldmodel, r_origin); leaf = RMod_PointInLeaf (cl.worldmodel, r_origin);
r_viewcluster = r_viewcluster2 = leaf->cluster; r_viewcluster = r_viewcluster2 = leaf->cluster;
r_viewcontents = 0;//leaf->contents;
// check above and below so crossing solid water doesn't draw wrong // check above and below so crossing solid water doesn't draw wrong
if (!leaf->contents) if (!leaf->contents)
{ // look down a bit { // look down a bit
@ -1779,8 +1781,6 @@ void Surf_SetupFrame(void)
(leaf->cluster != r_viewcluster2) ) (leaf->cluster != r_viewcluster2) )
r_viewcluster2 = leaf->cluster; r_viewcluster2 = leaf->cluster;
} }
r_viewcontents = leaf->contents;
} }
#endif #endif
else if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3) else if (cl.worldmodel && cl.worldmodel->fromgame == fg_doom3)

View file

@ -239,8 +239,11 @@ cvar_t gl_contrast = CVAR ("gl_contrast", "1");
cvar_t gl_detail = CVARF ("gl_detail", "0", cvar_t gl_detail = CVARF ("gl_detail", "0",
CVAR_ARCHIVE); CVAR_ARCHIVE);
cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); cvar_t gl_detailscale = CVAR ("gl_detailscale", "5");
cvar_t gl_font = CVARF ("gl_font", "", cvar_t gl_font = CVARFD ("gl_font", "",
CVAR_RENDERERCALLBACK); CVAR_RENDERERCALLBACK, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used."
"When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this."
"TTF fonts may be loaded from your windows directory. \'gl_font cour\' loads eg: c:\\windows\\fonts\\cour.ttf."
));
cvar_t gl_lateswap = CVAR ("gl_lateswap", "0"); cvar_t gl_lateswap = CVAR ("gl_lateswap", "0");
cvar_t gl_lerpimages = CVARF ("gl_lerpimages", "1", CVAR_ARCHIVE); cvar_t gl_lerpimages = CVARF ("gl_lerpimages", "1", CVAR_ARCHIVE);
//cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "", //cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "",

View file

@ -106,7 +106,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float *px,
void Font_Transform(int vx, int vy, int *px, int *py); void Font_Transform(int vx, int vy, int *px, int *py);
int Font_CharHeight(void); int Font_CharHeight(void);
int Font_CharWidth(unsigned int charcode); int Font_CharWidth(unsigned int charcode);
int Font_CharEndCoord(int x, unsigned int charcode); int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode);
int Font_DrawChar(int px, int py, unsigned int charcode); int Font_DrawChar(int px, int py, unsigned int charcode);
float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/
void Font_EndString(struct font_s *font); void Font_EndString(struct font_s *font);

View file

@ -80,20 +80,20 @@ cvar_t snd_noextraupdate = CVARAF( "s_noextraupdate", "0",
"snd_noextraupdate", 0); "snd_noextraupdate", 0);
cvar_t snd_show = CVARAF( "s_show", "0", cvar_t snd_show = CVARAF( "s_show", "0",
"snd_show", 0); "snd_show", 0);
cvar_t snd_khz = CVARAF( "s_khz", "44", cvar_t snd_khz = CVARAFD( "s_khz", "44",
"snd_khz", CVAR_ARCHIVE); "snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "0", cvar_t snd_inactive = CVARAFD( "s_inactive", "0",
"snd_inactive", 0, "snd_inactive", 0,
"Play sound while application is inactive (ex. tabbed out)." "Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed."
); //set if you want sound even when tabbed out. ); //set if you want sound even when tabbed out.
cvar_t _snd_mixahead = CVARAF( "s_mixahead", "0.08", cvar_t _snd_mixahead = CVARAFD( "s_mixahead", "0.08",
"_snd_mixahead", CVAR_ARCHIVE); "_snd_mixahead", CVAR_ARCHIVE, "Specifies how many seconds to prebuffer audio. Lower values give less latency, but might result in crackling. Different hardware/drivers have different tolerances.");
cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0", cvar_t snd_leftisright = CVARAF( "s_swapstereo", "0",
"snd_leftisright", CVAR_ARCHIVE); "snd_leftisright", CVAR_ARCHIVE);
cvar_t snd_eax = CVARAF( "s_eax", "0", cvar_t snd_eax = CVARAF( "s_eax", "0",
"snd_eax", 0); "snd_eax", 0);
cvar_t snd_speakers = CVARAF( "s_numspeakers", "2", cvar_t snd_speakers = CVARAFD( "s_numspeakers", "2",
"snd_numspeakers", 0); "snd_numspeakers", 0, "Number of hardware audio channels to use. "DISTRIBUTION" supports up to 6.");
cvar_t snd_buffersize = CVARAF( "s_buffersize", "0", cvar_t snd_buffersize = CVARAF( "s_buffersize", "0",
"snd_buffersize", 0); "snd_buffersize", 0);
cvar_t snd_samplebits = CVARAF( "s_bits", "16", cvar_t snd_samplebits = CVARAF( "s_bits", "16",
@ -109,8 +109,8 @@ cvar_t snd_linearresample = CVARAF( "s_linearresample", "1",
cvar_t snd_linearresample_stream = CVARAF( "s_linearresample_stream", "0", cvar_t snd_linearresample_stream = CVARAF( "s_linearresample_stream", "0",
"snd_linearresample_stream", 0); "snd_linearresample_stream", 0);
cvar_t snd_usemultipledevices = CVARAF( "s_multipledevices", "0", cvar_t snd_usemultipledevices = CVARAFD( "s_multipledevices", "0",
"snd_multipledevices", 0); "snd_multipledevices", 0, "If enabled, all output sound devices in your computer will be initialised for playback, not just the default device.");
cvar_t snd_driver = CVARAF( "s_driver", "", cvar_t snd_driver = CVARAF( "s_driver", "",
"snd_driver", 0); "snd_driver", 0);

View file

@ -988,6 +988,7 @@ typedef struct cmd_function_s
{ {
struct cmd_function_s *next; struct cmd_function_s *next;
char *name; char *name;
char *description;
xcommand_t function; xcommand_t function;
qbyte restriction; //restriction of admin level qbyte restriction; //restriction of admin level
@ -1679,6 +1680,23 @@ qboolean Cmd_Exists (char *cmd_name)
return false; return false;
} }
/*
============
Cmd_Exists
============
*/
char *Cmd_Describe (char *cmd_name)
{
cmd_function_t *cmd;
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
{
if (!Q_strcmp (cmd_name,cmd->name))
return cmd->description;
}
return NULL;
}
/* /*
@ -1734,8 +1752,13 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens
cvar_group_t *grp; cvar_group_t *grp;
cvar_t *cvar; cvar_t *cvar;
char *sp;
len = Q_strlen(partial); sp = strchr(partial, ' ');
if (sp)
len = sp - partial;
else
len = Q_strlen(partial);
if (!len) if (!len)
return NULL; return NULL;
@ -1756,17 +1779,17 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens
if (caseinsens) if (caseinsens)
{ {
for (cmd=cmd_functions ; cmd ; cmd=cmd->next) for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
if (!Q_strncasecmp (partial,cmd->name, len)) if (!Q_strncasecmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len))
Cmd_CompleteCheck(cmd->name, &match); Cmd_CompleteCheck(cmd->name, &match);
for (a=cmd_alias ; a ; a=a->next) for (a=cmd_alias ; a ; a=a->next)
if (!Q_strncasecmp (partial, a->name, len)) if (!Q_strncasecmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len))
Cmd_CompleteCheck(a->name, &match); Cmd_CompleteCheck(a->name, &match);
for (grp=cvar_groups ; grp ; grp=grp->next) for (grp=cvar_groups ; grp ; grp=grp->next)
for (cvar=grp->cvars ; cvar ; cvar=cvar->next) for (cvar=grp->cvars ; cvar ; cvar=cvar->next)
{ {
if (!Q_strncasecmp (partial,cvar->name, len)) if (!Q_strncasecmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len))
Cmd_CompleteCheck(cvar->name, &match); Cmd_CompleteCheck(cvar->name, &match);
if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len)) if (cvar->name2 && !Q_strncasecmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len))
Cmd_CompleteCheck(cvar->name2, &match); Cmd_CompleteCheck(cvar->name2, &match);
} }
@ -1774,17 +1797,17 @@ char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens
else else
{ {
for (cmd=cmd_functions ; cmd ; cmd=cmd->next) for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
if (!Q_strncmp (partial,cmd->name, len)) if (!Q_strncmp (partial,cmd->name, len) && (matchnum == -1 || !partial[len] || strlen(cmd->name) == len))
Cmd_CompleteCheck(cmd->name, &match); Cmd_CompleteCheck(cmd->name, &match);
for (a=cmd_alias ; a ; a=a->next) for (a=cmd_alias ; a ; a=a->next)
if (!Q_strncmp (partial, a->name, len)) if (!Q_strncmp (partial, a->name, len) && (matchnum == -1 || !partial[len] || strlen(a->name) == len))
Cmd_CompleteCheck(a->name, &match); Cmd_CompleteCheck(a->name, &match);
for (grp=cvar_groups ; grp ; grp=grp->next) for (grp=cvar_groups ; grp ; grp=grp->next)
for (cvar=grp->cvars ; cvar ; cvar=cvar->next) for (cvar=grp->cvars ; cvar ; cvar=cvar->next)
{ {
if (!Q_strncmp (partial,cvar->name, len)) if (!Q_strncmp (partial,cvar->name, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name) == len))
Cmd_CompleteCheck(cvar->name, &match); Cmd_CompleteCheck(cvar->name, &match);
if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len)) if (cvar->name2 && !Q_strncmp (partial,cvar->name2, len) && (matchnum == -1 || !partial[len] || strlen(cvar->name2) == len))
Cmd_CompleteCheck(cvar->name2, &match); Cmd_CompleteCheck(cvar->name2, &match);
} }
} }

View file

@ -84,6 +84,8 @@ qboolean Cmd_AddCommand (char *cmd_name, xcommand_t function);
qboolean Cmd_Exists (char *cmd_name); qboolean Cmd_Exists (char *cmd_name);
// used by the cvar code to check for cvar / command name overlap // used by the cvar code to check for cvar / command name overlap
char *Cmd_Describe (char *cmd_name);
char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum); char *Cmd_CompleteCommand (char *partial, qboolean fullonly, qboolean caseinsens, int matchnum);
qboolean Cmd_IsCommand (char *line); qboolean Cmd_IsCommand (char *line);
// attempts to match a partial command for automatic command line completion // attempts to match a partial command for automatic command line completion

View file

@ -112,6 +112,7 @@ typedef struct console_s
conline_t *oldest; conline_t *oldest;
conline_t *current; // line where next message will be printed conline_t *current; // line where next message will be printed
int x; // offset in current line for next print int x; // offset in current line for next print
int cr;
conline_t *display; // bottom of console displays this line conline_t *display; // bottom of console displays this line
int subline; int subline;
int vislines; // pixel lines int vislines; // pixel lines

View file

@ -84,7 +84,11 @@ typedef struct cvar_s
bucket_t hbn1, hbn2; bucket_t hbn1, hbn2;
} cvar_t; } cvar_t;
#ifdef MINIMAL
#define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, NULL}
#else
#define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, Description} #define CVARAFDC(ConsoleName,Value,ConsoleName2,Flags,Description,Callback) {ConsoleName, Value, NULL, Flags, 0, 0, 0, ConsoleName2, Callback, Description}
#endif
#define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL) #define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL)
#define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback) #define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback)
#define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL) #define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL)

View file

@ -186,12 +186,12 @@ void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a)
a->port = ((struct sockaddr_ipx *)s)->sa_socket; a->port = ((struct sockaddr_ipx *)s)->sa_socket;
break; break;
#endif #endif
default:
Con_Printf("SockadrToNetadr: bad socket family - %i", ((struct sockaddr*)s)->sa_family);
case AF_UNSPEC: case AF_UNSPEC:
memset(a, 0, sizeof(*a)); memset(a, 0, sizeof(*a));
a->type = NA_INVALID; a->type = NA_INVALID;
break; break;
default:
Sys_Error("SockadrToNetadr: bad socket family");
} }
} }
@ -293,7 +293,9 @@ qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
qboolean NET_AddressSmellsFunny(netadr_t a) qboolean NET_AddressSmellsFunny(netadr_t a)
{ {
#ifdef IPPROTO_IPV6
int i; int i;
#endif
//rejects certain blacklisted addresses //rejects certain blacklisted addresses
switch(a.type) switch(a.type)
@ -342,9 +344,11 @@ qboolean NET_AddressSmellsFunny(netadr_t a)
char *NET_AdrToString (char *s, int len, netadr_t a) char *NET_AdrToString (char *s, int len, netadr_t a)
{ {
char *rs = s; char *rs = s;
qboolean doneblank;
char *p; char *p;
int i; int i;
#ifdef IPPROTO_IPV6
qboolean doneblank;
#endif
switch(a.type) switch(a.type)
{ {
@ -1577,6 +1581,12 @@ int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *o
continue; continue;
} }
if (itr->ai_addr->sa_family == AF_INET
|| itr->ai_addr->sa_family == AF_INET6
#ifdef USEIPX
|| itr->ai_addr->sa_family == AF_IPX
#endif
)
if (idx++ == count) if (idx++ == count)
{ {
SockadrToNetadr((struct sockaddr_qstorage*)itr->ai_addr, out); SockadrToNetadr((struct sockaddr_qstorage*)itr->ai_addr, out);
@ -1831,7 +1841,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i
temp = NetadrToSockadr(&adr, &qs); temp = NetadrToSockadr(&adr, &qs);
family = ((struct sockaddr*)&qs)->sa_family; family = ((struct sockaddr*)&qs)->sa_family;
#ifdef IPV6_V6ONLY #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (isserver && family == AF_INET && net_hybriddualstack.ival && !((struct sockaddr_in*)&qs)->sin_addr.s_addr) if (isserver && family == AF_INET && net_hybriddualstack.ival && !((struct sockaddr_in*)&qs)->sin_addr.s_addr)
{ {
unsigned long _false = false; unsigned long _false = false;
@ -1875,7 +1885,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i
return NULL; return NULL;
} }
#ifdef IPV6_V6ONLY #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (family == AF_INET6) if (family == AF_INET6)
setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true)); setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true));
#endif #endif

View file

@ -715,6 +715,47 @@ void QCBUILTIN PF_registercvar (progfuncs_t *prinst, struct globalvars_s *pr_glo
//Cvars //Cvars
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
//memory stuff
void QCBUILTIN PF_memalloc (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
void *ptr = prinst->AddressableAlloc(prinst, G_INT(OFS_PARM0));
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
}
void QCBUILTIN PF_memfree (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0));
}
void QCBUILTIN PF_memcpy (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int dst = G_INT(OFS_PARM0);
int src = G_INT(OFS_PARM1);
int size = G_INT(OFS_PARM2);
if (dst < 0 || dst+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_memcpy: invalid dest\n");
return;
}
if (src < 0 || src+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_memcpy: invalid source\n");
return;
}
memcpy(prinst->stringtable + dst, prinst->stringtable + src, size);
}
void QCBUILTIN PF_memset (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int dst = G_INT(OFS_PARM0);
int val = G_INT(OFS_PARM1);
int size = G_INT(OFS_PARM2);
if (dst < 0 || dst+size >= prinst->stringtablesize)
{
PR_BIError(prinst, "PF_memcpy: invalid dest\n");
return;
}
memset(prinst->stringtable + dst, val, size);
}
//memory stuff
////////////////////////////////////////////////////
//File access //File access
#define MAX_QC_FILES 256 #define MAX_QC_FILES 256
@ -1817,8 +1858,12 @@ void QCBUILTIN PF_vtos (progfuncs_t *prinst, struct globalvars_s *pr_globals)
RETURN_TSTRING(pr_string_temp); RETURN_TSTRING(pr_string_temp);
} }
void QCBUILTIN PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
#if 1
prinst->AddressableFree(prinst, prinst->stringtable + G_INT(OFS_PARM0));
#else
char *s=PR_RemoveProgsString(prinst, G_INT(OFS_PARM0)); char *s=PR_RemoveProgsString(prinst, G_INT(OFS_PARM0));
if (!s) if (!s)
{ {
@ -1838,7 +1883,7 @@ void QCBUILTIN PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_glob
} }
((int *)s)[0] = 0xabcd1234; ((int *)s)[0] = 0xabcd1234;
Z_TagFree(s); Z_TagFree(s);
#endif
} }
void QCBUILTIN PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals) //frik_file void QCBUILTIN PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals) //frik_file
@ -1856,11 +1901,21 @@ void QCBUILTIN PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals
} }
len++; /*for the null*/ len++; /*for the null*/
#if 1
buf = prinst->AddressableAlloc(prinst, len);
if (!buf)
{
G_INT(OFS_RETURN) = 0;
return;
}
G_INT(OFS_RETURN) = (char*)buf - prinst->stringtable;
#else
buf = Z_TagMalloc(len+8, Z_QC_TAG); buf = Z_TagMalloc(len+8, Z_QC_TAG);
RETURN_SSTRING(buf+8); RETURN_SSTRING(buf+8);
((int *)buf)[0] = PRSTR; ((int *)buf)[0] = PRSTR;
((int *)buf)[1] = len; ((int *)buf)[1] = len;
buf += 8; buf += 8;
#endif
len = 0; len = 0;
for (i = 0; i < *prinst->callargc; i++) for (i = 0; i < *prinst->callargc; i++)
@ -3663,6 +3718,7 @@ lh_extension_t QSG_Extensions[] = {
{"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}}, {"FTE_FORCEINFOKEY", 1, NULL, {"forceinfokey"}},
{"FTE_GFX_QUAKE3SHADERS"}, {"FTE_GFX_QUAKE3SHADERS"},
{"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}}, {"FTE_ISBACKBUFFERED", 1, NULL, {"isbackbuffered"}},
{"FTE_MEMALLOC", 4, NULL, {"memalloc", "memfree", "memcpy", "memset"}},
#ifndef NOMEDIA #ifndef NOMEDIA
{"FTE_MEDIA_AVI"}, //playfilm supports avi files. {"FTE_MEDIA_AVI"}, //playfilm supports avi files.
{"FTE_MEDIA_CIN"}, //playfilm command supports q2 cin files. {"FTE_MEDIA_CIN"}, //playfilm command supports q2 cin files.

View file

@ -298,6 +298,11 @@ void QCBUILTIN PF_bufstr_add (progfuncs_t *prinst, struct globalvars_s *pr_glob
void QCBUILTIN PF_bufstr_free (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_bufstr_free (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_buf_cvarlist (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_buf_cvarlist (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memalloc (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memfree (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memcpy (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memset (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_calltimeofday (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_calltimeofday (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_whichpack (progfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_whichpack (progfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -114,7 +114,10 @@ public class FTEDroidActivity extends Activity
int sspeed = 11025; int sspeed = 11025;
int speakers = 1; int speakers = 1;
int sz = 4*AudioTrack.getMinBufferSize(sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT); int sz = 2*AudioTrack.getMinBufferSize(sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT);
// if (sz < sspeed * 0.05)
// sz = sspeed * 0.05;
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT, sz, AudioTrack.MODE_STREAM); AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, sspeed, ((speakers==2)?AudioFormat.CHANNEL_CONFIGURATION_STEREO:AudioFormat.CHANNEL_CONFIGURATION_MONO), AudioFormat.ENCODING_PCM_16BIT, sz, AudioTrack.MODE_STREAM);

View file

@ -16,7 +16,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float *px,
void Font_Transform(int vx, int vy, int *px, int *py); void Font_Transform(int vx, int vy, int *px, int *py);
int Font_CharHeight(void); int Font_CharHeight(void);
int Font_CharWidth(unsigned int charcode); int Font_CharWidth(unsigned int charcode);
int Font_CharEndCoord(int x, unsigned int charcode); int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode);
int Font_DrawChar(int px, int py, unsigned int charcode); int Font_DrawChar(int px, int py, unsigned int charcode);
float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int charcode); /*avoid using*/
void Font_EndString(struct font_s *font); void Font_EndString(struct font_s *font);
@ -189,6 +189,7 @@ typedef struct font_s
FT_Face face; FT_Face face;
void *membuf; void *membuf;
#endif #endif
struct font_s *alt;
} font_t; } font_t;
typedef struct { typedef struct {
@ -901,6 +902,7 @@ struct font_s *Font_LoadFont(int height, char *fontfilename)
struct font_s *f; struct font_s *f;
int i = 0; int i = 0;
int defaultplane; int defaultplane;
char *aname;
f = Z_Malloc(sizeof(*f)); f = Z_Malloc(sizeof(*f));
f->charheight = height; f->charheight = height;
@ -1026,6 +1028,12 @@ struct font_s *Font_LoadFont(int height, char *fontfilename)
return f; return f;
} }
aname = strstr(fontfilename, ":");
if (aname)
{
*aname = 0;
f->alt = Font_LoadFont(height, aname+1);
}
if (!Font_LoadFreeTypeFont(f, height, fontfilename)) if (!Font_LoadFreeTypeFont(f, height, fontfilename))
{ {
if (*fontfilename) if (*fontfilename)
@ -1046,6 +1054,8 @@ struct font_s *Font_LoadFont(int height, char *fontfilename)
f->chars[i].texplane = BITMAPPLANE; f->chars[i].texplane = BITMAPPLANE;
} }
} }
if (aname)
*aname = ':';
defaultplane = BITMAPPLANE;/*assume the bitmap plane - don't use the fallback as people don't think to use com_parseutf8*/ defaultplane = BITMAPPLANE;/*assume the bitmap plane - don't use the fallback as people don't think to use com_parseutf8*/
if (!TEXVALID(f->singletexture)) if (!TEXVALID(f->singletexture))
@ -1146,17 +1156,20 @@ int Font_CharHeight(void)
This is where the character ends. This is where the character ends.
Note: this function supports tabs - x must always be based off 0, with Font_LineDraw actually used to draw the line. Note: this function supports tabs - x must always be based off 0, with Font_LineDraw actually used to draw the line.
*/ */
int Font_CharEndCoord(int x, unsigned int charcode) int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode)
{ {
struct charcache_s *c; struct charcache_s *c;
#define TABWIDTH (8*20) #define TABWIDTH (8*20)
if ((charcode&CON_CHARMASK) == '\t') if ((charcode&CON_CHARMASK) == '\t')
return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH); return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH);
c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); if ((charcode & CON_2NDCHARSETTEXT) && font->alt)
font = font->alt;
c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
{ {
c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
return x+0; return x+0;
} }
@ -1168,6 +1181,9 @@ int Font_CharEndCoord(int x, unsigned int charcode)
int Font_CharWidth(unsigned int charcode) int Font_CharWidth(unsigned int charcode)
{ {
struct charcache_s *c; struct charcache_s *c;
struct font_s *font = curfont;
if ((charcode & CON_2NDCHARSETTEXT) && font->alt)
font = font->alt;
c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
@ -1190,6 +1206,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
int l, bt; int l, bt;
int px; int px;
int foundlines = 0; int foundlines = 0;
struct font_s *font = curfont;
while (start < end) while (start < end)
{ {
@ -1199,7 +1216,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
l++; l++;
if (start+l >= end || (start[l-1]&CON_CHARMASK) == '\n') if (start+l >= end || (start[l-1]&CON_CHARMASK) == '\n')
break; break;
px = Font_CharEndCoord(px, start[l]); px = Font_CharEndCoord(font, px, start[l]);
} }
//if we did get to the end //if we did get to the end
if (px > maxpixelwidth) if (px > maxpixelwidth)
@ -1234,19 +1251,21 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
int Font_LineWidth(conchar_t *start, conchar_t *end) int Font_LineWidth(conchar_t *start, conchar_t *end)
{ {
int x = 0; int x = 0;
struct font_s *font = curfont;
for (; start < end; start++) for (; start < end; start++)
{ {
x = Font_CharEndCoord(x, *start); x = Font_CharEndCoord(font, x, *start);
} }
return x; return x;
} }
void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end) void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end)
{ {
int lx = 0; int lx = 0;
struct font_s *font = curfont;
for (; start < end; start++) for (; start < end; start++)
{ {
Font_DrawChar(x+lx, y, *start); Font_DrawChar(x+lx, y, *start);
lx = Font_CharEndCoord(lx, *start); lx = Font_CharEndCoord(font, lx, *start);
} }
} }
@ -1283,18 +1302,23 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
float sx, sy, sw, sh; float sx, sy, sw, sh;
int col; int col;
int v; int v;
struct font_s *font = curfont;
if ((charcode & CON_2NDCHARSETTEXT) && font->alt)
font = font->alt;
//crash if there is no current font. //crash if there is no current font.
c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
{ {
c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
return px; return px;
} }
nextx = px + c->advance; nextx = px + c->advance;
if ((charcode & CON_CHARMASK) == '\t')
return px + ((TABWIDTH - (px % TABWIDTH)) % TABWIDTH);
if ((charcode & CON_CHARMASK) == ' ') if ((charcode & CON_CHARMASK) == ' ')
return nextx; return nextx;
@ -1335,23 +1359,23 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
case DEFAULTPLANE: case DEFAULTPLANE:
sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth;
sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight;
sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth;
sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight;
v = Font_BeginChar(fontplanes.defaultfont); v = Font_BeginChar(fontplanes.defaultfont);
break; break;
case BITMAPPLANE: case BITMAPPLANE:
sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth;
sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight;
sw = ((curfont->charheight)*vid.width) / (float)vid.rotpixelwidth; sw = ((font->charheight)*vid.width) / (float)vid.rotpixelwidth;
sh = ((curfont->charheight)*vid.height) / (float)vid.rotpixelheight; sh = ((font->charheight)*vid.height) / (float)vid.rotpixelheight;
v = Font_BeginChar(curfont->singletexture); v = Font_BeginChar(font->singletexture);
break; break;
case SINGLEPLANE: case SINGLEPLANE:
sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth;
sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight; sy = ((py+c->top)*(int)vid.height) / (float)vid.rotpixelheight;
sw = ((c->bmw)*vid.width) / (float)vid.rotpixelwidth; sw = ((c->bmw)*vid.width) / (float)vid.rotpixelwidth;
sh = ((c->bmh)*vid.height) / (float)vid.rotpixelheight; sh = ((c->bmh)*vid.height) / (float)vid.rotpixelheight;
v = Font_BeginChar(curfont->singletexture); v = Font_BeginChar(font->singletexture);
break; break;
default: default:
sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth; sx = ((px+c->left)*(int)vid.width) / (float)vid.rotpixelwidth;
@ -1402,16 +1426,19 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch
float sx, sy, sw, sh; float sx, sy, sw, sh;
int col; int col;
int v; int v;
struct font_s *font = curfont;
if ((charcode & CON_2NDCHARSETTEXT) && font->alt)
font = font->alt;
cw /= curfont->charheight; cw /= font->charheight;
ch /= curfont->charheight; ch /= font->charheight;
//crash if there is no current font. //crash if there is no current font.
c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_GetChar(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
{ {
c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK)); c = Font_TryLoadGlyph(font, (CHARIDXTYPE)(charcode&CON_CHARMASK));
if (!c) if (!c)
return px; return px;
} }
@ -1457,13 +1484,13 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch
{ {
sx = ((px+c->left)); sx = ((px+c->left));
sy = ((py+c->top)); sy = ((py+c->top));
sw = ((curfont->charheight*cw)); sw = ((font->charheight*cw));
sh = ((curfont->charheight*ch)); sh = ((font->charheight*ch));
if (c->texplane == DEFAULTPLANE) if (c->texplane == DEFAULTPLANE)
v = Font_BeginChar(fontplanes.defaultfont); v = Font_BeginChar(fontplanes.defaultfont);
else else
v = Font_BeginChar(curfont->singletexture); v = Font_BeginChar(font->singletexture);
} }
else else
{ {

View file

@ -294,7 +294,7 @@ reeval:
//store a value to a pointer //store a value to a pointer
case OP_STOREP_IF: case OP_STOREP_IF:
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -303,7 +303,7 @@ reeval:
ptr->_float = (float)OPA->_int; ptr->_float = (float)OPA->_int;
break; break;
case OP_STOREP_FI: case OP_STOREP_FI:
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -313,7 +313,7 @@ reeval:
break; break;
case OP_STOREP_I: case OP_STOREP_I:
case OP_GSTOREP_I: case OP_GSTOREP_I:
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -331,17 +331,17 @@ reeval:
case OP_GSTOREP_S: case OP_GSTOREP_S:
case OP_STOREP_FNC: // pointers case OP_STOREP_FNC: // pointers
case OP_GSTOREP_FNC: case OP_GSTOREP_FNC:
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(progfuncs, pr_xfunction->s_name), OPB->_int, addressableused); PR_RunError (progfuncs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(progfuncs, pr_xfunction->s_name), OPB->_int, prinst->addressableused);
} }
ptr = QCPOINTER(OPB); ptr = QCPOINTER(OPB);
ptr->_int = OPA->_int; ptr->_int = OPA->_int;
break; break;
case OP_STOREP_V: case OP_STOREP_V:
case OP_GSTOREP_V: case OP_GSTOREP_V:
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -353,7 +353,7 @@ reeval:
break; break;
case OP_STOREP_C: //store character in a string case OP_STOREP_C: //store character in a string
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -371,7 +371,7 @@ reeval:
OPB->_vector[2] *= OPA->_float; OPB->_vector[2] *= OPA->_float;
break; break;
case OP_MULSTOREP_F: // e.f *= f case OP_MULSTOREP_F: // e.f *= f
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -380,7 +380,7 @@ reeval:
OPC->_float = (ptr->_float *= OPA->_float); OPC->_float = (ptr->_float *= OPA->_float);
break; break;
case OP_MULSTOREP_VF: // e.v *= f case OP_MULSTOREP_VF: // e.v *= f
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -395,7 +395,7 @@ reeval:
OPB->_float /= OPA->_float; OPB->_float /= OPA->_float;
break; break;
case OP_DIVSTOREP_F: // e.f /= f case OP_DIVSTOREP_F: // e.f /= f
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -413,7 +413,7 @@ reeval:
OPB->_vector[2] += OPA->_vector[2]; OPB->_vector[2] += OPA->_vector[2];
break; break;
case OP_ADDSTOREP_F: // e.f += f case OP_ADDSTOREP_F: // e.f += f
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -422,7 +422,7 @@ reeval:
OPC->_float = (ptr->_float += OPA->_float); OPC->_float = (ptr->_float += OPA->_float);
break; break;
case OP_ADDSTOREP_V: // e.v += v case OP_ADDSTOREP_V: // e.v += v
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -442,7 +442,7 @@ reeval:
OPB->_vector[2] -= OPA->_vector[2]; OPB->_vector[2] -= OPA->_vector[2];
break; break;
case OP_SUBSTOREP_F: // e.f -= f case OP_SUBSTOREP_F: // e.f -= f
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -451,7 +451,7 @@ reeval:
OPC->_float = (ptr->_float -= OPA->_float); OPC->_float = (ptr->_float -= OPA->_float);
break; break;
case OP_SUBSTOREP_V: // e.v -= v case OP_SUBSTOREP_V: // e.v -= v
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -818,7 +818,7 @@ reeval:
break; break;
case OP_LOADP_C: //load character from a string case OP_LOADP_C: //load character from a string
i = (unsigned int)OPA->_int + (unsigned int)OPB->_float; i = (unsigned int)OPA->_int + (unsigned int)OPB->_float;
if ((unsigned int)i >= addressableused) if ((unsigned int)i >= prinst->addressableused)
{ {
i = (unsigned int)OPB->_float; i = (unsigned int)OPB->_float;
ptr = (eval_t*)PR_StringToNative(progfuncs, OPA->_int); ptr = (eval_t*)PR_StringToNative(progfuncs, OPA->_int);
@ -840,7 +840,7 @@ reeval:
case OP_LOADP_S: case OP_LOADP_S:
case OP_LOADP_FNC: case OP_LOADP_FNC:
i = OPA->_int + OPB->_int*4; i = OPA->_int + OPB->_int*4;
if ((unsigned int)i >= addressableused) if ((unsigned int)i >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -851,7 +851,7 @@ reeval:
case OP_LOADP_V: case OP_LOADP_V:
i = OPA->_int + OPB->_int*4; i = OPA->_int + OPB->_int*4;
if ((unsigned int)i >= addressableused) if ((unsigned int)i >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer read in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -914,7 +914,7 @@ reeval:
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float); OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
break; break;
case OP_BITSETP: // .b (+) a case OP_BITSETP: // .b (+) a
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));
@ -926,7 +926,7 @@ reeval:
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float)); OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
break; break;
case OP_BITCLRP: // .b (-) a case OP_BITCLRP: // .b (-) a
if ((unsigned int)OPB->_int >= addressableused) if ((unsigned int)OPB->_int >= prinst->addressableused)
{ {
pr_xstatement = st-pr_statements; pr_xstatement = st-pr_statements;
PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name)); PR_RunError (progfuncs, "bad pointer write in %s", PR_StringToNative(progfuncs, pr_xfunction->s_name));

View file

@ -76,10 +76,10 @@ void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int o
//for 64bit systems. :) //for 64bit systems. :)
//addressable memory is memory available to the vm itself for writing. //addressable memory is memory available to the vm itself for writing.
//once allocated, it cannot be freed for the lifetime of the VM. //once allocated, it cannot be freed for the lifetime of the VM.
void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount) void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount)
{ {
ammount = (ammount + 4)&~3; //round up to 4 ammount = (ammount + 4)&~3; //round up to 4
if (addressableused + ammount > addressablesize) if (prinst->addressableused + ammount > prinst->addressablesize)
{ {
/*only do this if the caller states that it can cope with addressable-block relocations/resizes*/ /*only do this if the caller states that it can cope with addressable-block relocations/resizes*/
if (externs->addressablerelocated) if (externs->addressablerelocated)
@ -89,74 +89,277 @@ void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount)
#if 0//def _DEBUG #if 0//def _DEBUG
int oldtot = addressablesize; int oldtot = addressablesize;
#endif #endif
int newsize = (addressableused + ammount + 4096) & ~(4096-1); int newsize = (prinst->addressableused + ammount + 4096) & ~(4096-1);
newblock = VirtualAlloc (NULL, addressablesize, MEM_RESERVE, PAGE_NOACCESS); newblock = VirtualAlloc (NULL, prinst->addressablesize, MEM_RESERVE, PAGE_NOACCESS);
if (newblock) if (newblock)
{ {
VirtualAlloc (newblock, addressableused, MEM_COMMIT, PAGE_READWRITE); VirtualAlloc (newblock, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE);
memcpy(newblock, addressablehunk, addressableused); memcpy(newblock, prinst->addressablehunk, prinst->addressableused);
#if 0//def _DEBUG #if 0//def _DEBUG
VirtualAlloc (addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS); VirtualAlloc (prinst->addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS);
#else #else
VirtualFree (addressablehunk, 0, MEM_RELEASE); VirtualFree (prinst->addressablehunk, 0, MEM_RELEASE);
#endif #endif
PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused); PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
addressablehunk = newblock; prinst->addressablehunk = newblock;
addressablesize = newsize; prinst->addressablesize = newsize;
} }
#else #else
char *newblock; char *newblock;
int newsize = (addressableused + ammount + 1024*1024) & ~(1024*1024-1); int newsize = (prinst->addressableused + ammount + 1024*1024) & ~(1024*1024-1);
newblock = realloc(newblock, addressablesize); newblock = realloc(newblock, prinst->addressablesize);
if (newblock) if (newblock)
{ {
PRAddressableRelocate(progfuncs, addressablehunk, newblock, addressableused); PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
addressablehunk = newblock; prinst->addressablehunk = newblock;
addressablesize = newsize; prinst->addressablesize = newsize;
} }
#endif #endif
} }
if (addressableused + ammount > addressablesize) if (prinst->addressableused + ammount > prinst->addressablesize)
Sys_Error("Not enough addressable memory for progs VM"); Sys_Error("Not enough addressable memory for progs VM");
} }
addressableused += ammount; prinst->addressableused += ammount;
#ifdef _WIN32 #ifdef _WIN32
if (!VirtualAlloc (addressablehunk, addressableused, MEM_COMMIT, PAGE_READWRITE)) if (!VirtualAlloc (prinst->addressablehunk, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE))
Sys_Error("VirtualAlloc failed. Blame windows."); Sys_Error("VirtualAlloc failed. Blame windows.");
#endif #endif
return &addressablehunk[addressableused-ammount]; return &prinst->addressablehunk[prinst->addressableused-ammount];
}
#define MARKER 0xF1E3E3E7u
typedef struct
{
unsigned int next;
unsigned int prev;
unsigned int size;
} qcmemfreeblock_t;
typedef struct
{
unsigned int marker;
unsigned int size;
} qcmemusedblock_t;
static void PF_fmem_unlink(progfuncs_t *pr, qcmemfreeblock_t *p)
{
qcmemfreeblock_t *np;
if (p->prev)
{
np = (qcmemfreeblock_t*)(pr->stringtable + p->prev);
np->next = p->next;
}
else
pr->inst->mfreelist = p->next;
if (p->next)
{
np = (qcmemfreeblock_t*)(pr->stringtable + p->next);
np->prev = p->prev;
}
}
static void *PR_memalloc (progfuncs_t *progfuncs, unsigned int size)
{
qcmemfreeblock_t *p, *np;
qcmemusedblock_t *ub = NULL;
unsigned int b,n;
/*round size up*/
size = (size+sizeof(qcmemusedblock_t) + 63) & ~63;
b = prinst->mfreelist;
while (b)
{
if (b < 0 || b >= prinst->addressableused)
{
printf("PF_memalloc: memory corruption\n");
PR_StackTrace(progfuncs);
return NULL;
}
p = (qcmemfreeblock_t*)(progfuncs->stringtable + b);
if (p->size >= size)
{
if (p->next && p->next < b + p->size ||
p->next >= prinst->addressableused ||
b + p->size >= prinst->addressableused ||
p->prev >= b)
{
printf("PF_memalloc: memory corruption\n");
PR_StackTrace(progfuncs);
return NULL;
}
ub = (qcmemusedblock_t*)p;
if (p->size > size + 63)
{
/*make a new header just after it, with basically the same properties, and shift the important fields over*/
n = b + size;
np = (qcmemfreeblock_t*)(progfuncs->stringtable + b + size);
np->prev = p->prev;
np->next = p->next;
np->size = p->size - size;
if (np->prev)
{
p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->prev);
p->next = n;
}
else
prinst->mfreelist = n;
if (p->next)
{
p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->next);
p->prev = n;
}
}
else
{
size = p->size; /*alloc the entire block*/
/*unlink this entry*/
PF_fmem_unlink(progfuncs, p);
}
break;
}
}
/*assign more space*/
if (!ub)
{
ub = PRAddressableExtend(progfuncs, size);
if (!ub)
{
printf("PF_memalloc: memory exausted\n");
PR_StackTrace(progfuncs);
return NULL;
}
}
memset(ub, 0, size);
ub->marker = MARKER;
ub->size = size;
return ub+1;
}
static void PR_memfree (progfuncs_t *progfuncs, void *memptr)
{
qcmemusedblock_t *ub;
qcmemfreeblock_t *p, *np;
unsigned int l, ln;
unsigned int size;
unsigned int ptr = memptr?((char*)memptr - progfuncs->stringtable):0;
/*freeing NULL is ignored*/
if (!ptr)
return;
if (ptr < sizeof(qcmemusedblock_t) || ptr >= prinst->addressableused)
{
printf("PF_memfree: pointer invalid - out of range (%u >= %u)\n", ptr, prinst->addressableused);
PR_StackTrace(progfuncs);
return;
}
ub = (qcmemusedblock_t*)(progfuncs->stringtable + ptr);
ub--;
ptr = (char*)ub - progfuncs->stringtable;
if (ub->marker != MARKER || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst->addressableused)
{
printf("PF_memfree: memory corruption or double free\n");
PR_StackTrace(progfuncs);
return;
}
ub->marker = 0;
size = ub->size;
for (ln = prinst->mfreelist, l = 0; ;)
{
if (ln < 0 || ln >= prinst->addressableused)
{
printf("PF_memfree: memory corruption\n");
PR_StackTrace(progfuncs);
return;
}
if (!ln || ln >= ptr)
{
np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
if (l && l+np->size>ptr)
{
printf("PF_memfree: double free\n");
PR_StackTrace(progfuncs);
return;
}
/*generate the free block, now we know its proper values*/
p = (qcmemfreeblock_t*)(progfuncs->stringtable + ptr);
p->prev = l;
p->next = ln;
p->size = size;
/*update the next's previous*/
if (p->next)
{
np = (qcmemfreeblock_t*)(progfuncs->stringtable + p->next);
np->prev = p->prev;
/*extend this block and kill the next if they are adjacent*/
if (p->next == ptr + size)
{
p->size += np->size;
PF_fmem_unlink(progfuncs, np);
}
}
/*update the link to get here*/
if (!l)
prinst->mfreelist = ptr;
else
{
np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
np->next = ptr;
/*we're adjacent to the previous block, so merge them by killing the newly freed region*/
if (l + np->size == ptr)
{
np->size += size;
PF_fmem_unlink(progfuncs, p);
}
}
break;
}
l = ln;
p = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
ln = p->next;
}
} }
void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount) void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount)
{ {
addressableused = 0; prinst->addressableused = 0;
if (totalammount < 0) //flush if (totalammount < 0) //flush
{ {
totalammount = addressablesize; totalammount = prinst->addressablesize;
// return; // return;
} }
#ifdef _WIN32 #ifdef _WIN32
if (addressablehunk && addressablesize != totalammount) if (prinst->addressablehunk && prinst->addressablesize != totalammount)
{ {
VirtualFree(addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p VirtualFree(prinst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
addressablehunk = NULL; prinst->addressablehunk = NULL;
} }
if (!addressablehunk) if (!prinst->addressablehunk)
addressablehunk = VirtualAlloc (addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS); prinst->addressablehunk = VirtualAlloc (prinst->addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS);
#else #else
if (addressablehunk) if (prinst->addressablehunk && prinst->addressablesize != totalammount)
free(addressablehunk); {
addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy. free(prinst->addressablehunk);
// memset(addressablehunk, 0xff, totalammount); prinst->addressablehunk = NULL;
}
if (!prinst->addressablehunk)
prinst->addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
// memset(prinst->addressablehunk, 0xff, totalammount);
#endif #endif
if (!addressablehunk) if (!prinst->addressablehunk)
Sys_Error("Out of memory\n"); Sys_Error("Out of memory\n");
addressablesize = totalammount; prinst->addressablesize = totalammount;
} }
int PR_InitEnts(progfuncs_t *progfuncs, int max_ents) int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
@ -170,7 +373,7 @@ int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *)); prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize); sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize);
prinst->edicttable[0] = sv_edicts; prinst->edicttable[0] = sv_edicts;
((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableAlloc(progfuncs, max_fields_size); ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableExtend(progfuncs, max_fields_size);
QC_ClearEdict(progfuncs, sv_edicts); QC_ClearEdict(progfuncs, sv_edicts);
sv_num_edicts = 1; sv_num_edicts = 1;
@ -505,7 +708,7 @@ string_t PR_StringToProgs (progfuncs_t *progfuncs, char *str)
if (!str) if (!str)
return 0; return 0;
if (str >= progfuncs->stringtable && str < progfuncs->stringtable + addressableused) if (str >= progfuncs->stringtable && str < progfuncs->stringtable + prinst->addressableused)
return str - progfuncs->stringtable; return str - progfuncs->stringtable;
for (i = prinst->numallocedstrings-1; i >= 0; i--) for (i = prinst->numallocedstrings-1; i >= 0; i--)
@ -615,7 +818,7 @@ char *ASMCALL PR_StringToNative (progfuncs_t *progfuncs, string_t str)
} }
} }
if (str >= addressableused) if ((unsigned int)str >= (unsigned int)prinst->addressableused)
{ {
printf("invalid string offset %x\n", str); printf("invalid string offset %x\n", str);
PR_StackTrace(progfuncs); PR_StackTrace(progfuncs);
@ -803,8 +1006,9 @@ progfuncs_t deffuncs = {
PR_QueryField, PR_QueryField,
QC_ClearEdict, QC_ClearEdict,
QC_FindPrefixedGlobals, QC_FindPrefixedGlobals,
PRAddressableAlloc, PR_memalloc,
PR_AllocTempStringLen PR_AllocTempStringLen,
PR_memfree,
}; };
#undef printf #undef printf
@ -859,6 +1063,7 @@ progexterns_t defexterns = {
#undef extensionbuiltin #undef extensionbuiltin
#undef field #undef field
#undef shares #undef shares
#undef maxedicts
#undef sv_num_edicts #undef sv_num_edicts
@ -875,10 +1080,10 @@ void CloseProgs(progfuncs_t *inst)
f = inst->parms->memfree; f = inst->parms->memfree;
for ( i=1 ; i<inst->maxedicts; i++) for ( i=1 ; i<inst->inst->maxedicts; i++)
{ {
e = (edictrun_t *)(inst->prinst->edicttable[i]); e = (edictrun_t *)(inst->inst->edicttable[i]);
inst->prinst->edicttable[i] = NULL; inst->inst->edicttable[i] = NULL;
if (e) if (e)
{ {
// e->entnum = i; // e->entnum = i;
@ -889,17 +1094,17 @@ void CloseProgs(progfuncs_t *inst)
PRHunkFree(inst, 0); PRHunkFree(inst, 0);
#ifdef _WIN32 #ifdef _WIN32
VirtualFree(inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p VirtualFree(inst->inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
#else #else
free(inst->addressablehunk); free(inst->inst->addressablehunk);
#endif #endif
if (inst->prinst->allocedstrings) if (inst->inst->allocedstrings)
f(inst->prinst->allocedstrings); f(inst->inst->allocedstrings);
inst->prinst->allocedstrings = NULL; inst->inst->allocedstrings = NULL;
if (inst->prinst->tempstrings) if (inst->inst->tempstrings)
f(inst->prinst->tempstrings); f(inst->inst->tempstrings);
inst->prinst->tempstrings = NULL; inst->inst->tempstrings = NULL;
/* /*
@ -910,11 +1115,11 @@ void CloseProgs(progfuncs_t *inst)
inst->prinst->extensionbuiltin = eb; inst->prinst->extensionbuiltin = eb;
} }
*/ */
if (inst->prinst->field) if (inst->inst->field)
f(inst->prinst->field); f(inst->inst->field);
if (inst->prinst->shares) if (inst->inst->shares)
f(inst->prinst->shares); //free memory f(inst->inst->shares); //free memory
f(inst->prinst); f(inst->inst);
f(inst); f(inst);
} }
@ -955,15 +1160,17 @@ progfuncs_t * InitProgs(progexterns_t *ext)
} }
#undef memalloc #undef memalloc
#undef pr_trace #undef pr_trace
#undef pr_progstate
#undef pr_argc
funcs = ext->memalloc(sizeof(progfuncs_t)); funcs = ext->memalloc(sizeof(progfuncs_t));
memcpy(funcs, &deffuncs, sizeof(progfuncs_t)); memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
funcs->prinst = ext->memalloc(sizeof(prinst_t)); funcs->inst = ext->memalloc(sizeof(prinst_t));
memset(funcs->prinst,0, sizeof(prinst_t)); memset(funcs->inst,0, sizeof(prinst_t));
funcs->pr_trace = &funcs->prinst->pr_trace; funcs->pr_trace = &funcs->inst->pr_trace;
funcs->progstate = &funcs->pr_progstate; funcs->progstate = &funcs->inst->progstate;
funcs->callargc = &funcs->pr_argc; funcs->callargc = &funcs->inst->pr_argc;
funcs->parms = ext; funcs->parms = ext;

View file

@ -38,7 +38,7 @@ edictrun_t *ED_AllocIntoTable (progfuncs_t *progfuncs, int num)
prinst->edicttable[num] = *(struct edict_s **)&e = (void*)memalloc(externs->edictsize); prinst->edicttable[num] = *(struct edict_s **)&e = (void*)memalloc(externs->edictsize);
memset(e, 0, externs->edictsize); memset(e, 0, externs->edictsize);
e->fields = PRAddressableAlloc(progfuncs, fields_size); e->fields = PRAddressableExtend(progfuncs, fields_size);
e->entnum = num; e->entnum = num;
QC_ClearEdict(progfuncs, (struct edict_s*)e); QC_ClearEdict(progfuncs, (struct edict_s*)e);
@ -996,7 +996,10 @@ char *ED_NewString (progfuncs_t *progfuncs, char *string, int minlength)
l = strlen(string) + 1; l = strlen(string) + 1;
newc = PRAddressableAlloc (progfuncs, l<minlength?minlength:l); newc = progfuncs->AddressableAlloc (progfuncs, l<minlength?minlength:l);
if (!newc)
return progfuncs->stringtable;
new_p = newc; new_p = newc;
for (i=0 ; i< l ; i++) for (i=0 ; i< l ; i++)
@ -2586,12 +2589,12 @@ retry:
} }
len=sizeof(char)*pr_progs->numstrings; len=sizeof(char)*pr_progs->numstrings;
s = PRAddressableAlloc(progfuncs, len); s = PRAddressableExtend(progfuncs, len);
memcpy(s, pr_strings, len); memcpy(s, pr_strings, len);
pr_strings = (char *)s; pr_strings = (char *)s;
len=sizeof(float)*pr_progs->numglobals; len=sizeof(float)*pr_progs->numglobals;
s = PRAddressableAlloc(progfuncs, len); s = PRAddressableExtend(progfuncs, len);
memcpy(s, pr_globals, len); memcpy(s, pr_globals, len);
glob = pr_globals = (float *)s; glob = pr_globals = (float *)s;

View file

@ -46,7 +46,7 @@ typedef unsigned char qbyte;
//extern progfuncs_t *progfuncs; //extern progfuncs_t *progfuncs;
#define prinst progfuncs->prinst #define prinst progfuncs->inst
#define externs progfuncs->parms #define externs progfuncs->parms
#include "pr_comp.h" #include "pr_comp.h"
@ -87,7 +87,7 @@ extern QCC_opcode_t pr_opcodes[]; // sized by initialization
int PRHunkMark(progfuncs_t *progfuncs); int PRHunkMark(progfuncs_t *progfuncs);
void PRHunkFree(progfuncs_t *progfuncs, int mark); void PRHunkFree(progfuncs_t *progfuncs, int mark);
void *PRHunkAlloc(progfuncs_t *progfuncs, int size); void *PRHunkAlloc(progfuncs_t *progfuncs, int size);
void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount); void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount);
#ifdef printf #ifdef printf
#undef LIKEPRINTF #undef LIKEPRINTF
@ -432,12 +432,10 @@ var(unsigned int, max_fields_size);
//initlib.c //initlib.c
int mfreelist;
var(char *, addressablehunk); var(char *, addressablehunk);
#define addressablehunk prinst->addressablehunk
var(unsigned int, addressableused); var(unsigned int, addressableused);
#define addressableused prinst->addressableused
var(unsigned int, addressablesize); var(unsigned int, addressablesize);
#define addressablesize prinst->addressablesize
//var(extensionbuiltin_t *, extensionbuiltin); //var(extensionbuiltin_t *, extensionbuiltin);

View file

@ -109,7 +109,7 @@ struct progfuncs_s {
pbool (*Decompile) (progfuncs_t *prinst, char *fname); pbool (*Decompile) (progfuncs_t *prinst, char *fname);
struct prinst_s *prinst; //internal variables. Leave alone. struct prinst_s *inst; //internal variables. Leave alone.
int *callargc; //number of args of built-in call int *callargc; //number of args of built-in call
void (*RegisterBuiltin) (progfuncs_t *prinst, char *, builtin_t); void (*RegisterBuiltin) (progfuncs_t *prinst, char *, builtin_t);
@ -139,9 +139,10 @@ struct progfuncs_s {
void (*EntClear) (progfuncs_t *progfuncs, struct edict_s *e); void (*EntClear) (progfuncs_t *progfuncs, struct edict_s *e);
void (*FindPrefixGlobals) (progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) ); void (*FindPrefixGlobals) (progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) );
void *(*AddressableAlloc) (progfuncs_t *progfuncs, int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/ void *(*AddressableAlloc) (progfuncs_t *progfuncs, unsigned int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/
string_t (*AllocTempString) (progfuncs_t *prinst, char **str, unsigned int len); string_t (*AllocTempString) (progfuncs_t *prinst, char **str, unsigned int len);
void (*AddressableFree) (progfuncs_t *progfuncs, void *mem); /*frees a block of addressable memory*/
}; };
typedef struct progexterns_s { typedef struct progexterns_s {

View file

@ -8938,6 +8938,12 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, "float*(float skel)"},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, "float*(float skel)"},// (FTE_QC_RAGDOLL)
{"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, "void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)"}, {"skel_set_bone_world",PF_skel_set_bone_world,0,0, 0, 283, "void(entity ent, float bonenum, vector org, optional vector angorfwd, optional vector right, optional vector up)"},
{"memalloc", PF_memalloc, 0, 0, 0, 384, "void*(int size)"},
{"memfree", PF_memfree, 0, 0, 0, 385, "void(void *ptr)"},
{"memcpy", PF_memcpy, 0, 0, 0, 386, "void(void *dst, void *src, int size)"},
{"memset", PF_memset, 0, 0, 0, 387, "void(void *dst, int val, int size)"},
// {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, 284, "void(string cvarname, optional string value)"}, //72 // {"cvar_setlatch", PF_cvar_setlatch, 0, 0, 0, 284, "void(string cvarname, optional string value)"}, //72