fix colormod

added frag message filter, and dedicated frag tracker.
added 'windowed consoles' for social-type stuff without depending upon csqc mods for it.
added in_deviceids command which allows listing/renumbering device ids.
slider widgets now support inverted ranges, so gamma selection isn't so weird.
fix top/bottom colour selection bug.
software banding feature is now part of the 'software' preset (now that it supports mipmaps).
support for loading .maps, and editing their brushes etc (with appropriate qc mod). 'map mymap.map' to use. expect problems with missing wads and replacement textures overriding them and messing up texture scales.
snd_inactive is now default.
fix threading issue with wavs, no more error from 0-sample-but-otherwise-valid wavs.
added -makeinstaller option to embed a manifest inside the exe (and icon).
the resulting program will insist on installing the game if its run from outside a valid basedir.
framegroup support for q1mdl.
textures are now loaded on multiple worker threads, for reduced load times. moo har har.
netgraph shows packet+byte rates too.
added r_lightstylescale, pretty similar to contrast, but doesn't impose any framerate cost, but may have overbrighting issues.
r_softwarebanding now works on q2bsp too.
fixed crepuscular lights.
gzip transfer encoding is performed while downloading, instead of inducing stalls.
FINALLY fix ezquake download compat issue (dimman found the issue).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4851 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-04-14 23:12:17 +00:00
parent 18de6445ba
commit 2201b920c8
107 changed files with 6483 additions and 1851 deletions

View file

@ -46,6 +46,7 @@ cvar_t cl_selfcam = SCVAR("cl_selfcam", "1");
//cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" }; //cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
//cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" }; //cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
static int Cam_FindSortedPlayer(int number);
int selfcam=1; int selfcam=1;
@ -524,6 +525,15 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
if (cmd->impulse) if (cmd->impulse)
{ {
int pl = cmd->impulse; int pl = cmd->impulse;
#if 1
do
{
Cam_Lock(pv, Cam_FindSortedPlayer(pl));
pv++;
pl++;
} while (pv >= &cl.playerview[0] && pv < &cl.playerview[cl.splitclients]);
#else
for (i = 0; ; i++) for (i = 0; ; i++)
{ {
if (i == MAX_CLIENTS) if (i == MAX_CLIENTS)
@ -550,6 +560,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
} }
} }
} }
#endif
return; return;
} }
} }
@ -612,7 +623,9 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
do do
{ {
s = &cl.players[i]; s = &cl.players[i];
if (s->name[0] && !s->spectator) //players with userid 0 are typically bots.
//trying to spectate such bots just does not work (we have no idea which entity slot the bot is actually using, so don't try to track them).
if (s->name[0] && !s->spectator && s->userid)
{ {
Cam_Lock(pv, i); Cam_Lock(pv, i);
return; return;
@ -622,7 +635,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
// stay on same guy? // stay on same guy?
i = pv->cam_spec_track; i = pv->cam_spec_track;
s = &cl.players[i]; s = &cl.players[i];
if (s->name[0] && !s->spectator) if (s->name[0] && !s->spectator && s->userid)
{ {
Cam_Lock(pv, i); Cam_Lock(pv, i);
return; return;
@ -642,11 +655,46 @@ void Cam_Reset(void)
} }
} }
static int QDECL Cam_SortPlayers(const void *p1,const void *p2)
{
const player_info_t *a = *(player_info_t**)p1;
const player_info_t *b = *(player_info_t**)p2;
if (!*a->team)
return *b->team;
if (!*b->team)
return -*a->team;
// if (a->spectator || b->spectator)
// return a->spectator - b->spectator;
return Q_strcasecmp(a->team, b->team);
}
static int Cam_FindSortedPlayer(int number)
{
player_info_t *playerlist[MAX_CLIENTS], *s;
int i;
int slots;
number--;
for (slots = 0, i = 0; i < cl.allocated_client_slots; i++)
{
s = &cl.players[i];
if (s->name[0] && !s->spectator)
playerlist[slots++] = s;
}
if (!slots)
return 0;
// if (number > slot)
// return cl.allocated_client_slots; //error
qsort(playerlist, slots, sizeof(playerlist[0]), Cam_SortPlayers);
return playerlist[number % slots] - cl.players;
}
void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg) void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg)
{ {
playerview_t *pv = &cl.playerview[seat]; playerview_t *pv = &cl.playerview[seat];
int slot; int slot, sortednum;
player_info_t *s; player_info_t *s;
char *e;
if (seat >= MAX_SPLITS) if (seat >= MAX_SPLITS)
return; return;
@ -669,12 +717,17 @@ void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg)
return; return;
} }
// search nicks first if (*plrarg == '#' && (slot=strtoul(plrarg+1, &e, 10)) && !*e)
for (slot = 0; slot < cl.allocated_client_slots; slot++) slot = Cam_FindSortedPlayer(slot);
else
{ {
s = &cl.players[slot]; // search nicks first
if (s->name[0] && !s->spectator && !Q_strcasecmp(s->name, plrarg)) for (slot = 0; slot < cl.allocated_client_slots; slot++)
break; {
s = &cl.players[slot];
if (s->name[0] && !s->spectator && !Q_strcasecmp(s->name, plrarg))
break;
}
} }
if (slot == cl.allocated_client_slots) if (slot == cl.allocated_client_slots)

View file

@ -3522,9 +3522,15 @@ void CL_LinkPacketEntities (void)
//set scale //set scale
ent->scale = state->scale/16.0; ent->scale = state->scale/16.0;
#endif #endif
ent->shaderRGBAf[0] = (state->colormod[0]*8.0f)/256; if (state->colormod[0] == 32 && state->colormod[1] == 32 && state->colormod[2] == 32)
ent->shaderRGBAf[1] = (state->colormod[1]*8.0f)/256; ent->shaderRGBAf[0] = ent->shaderRGBAf[1] = ent->shaderRGBAf[2] = 1;
ent->shaderRGBAf[2] = (state->colormod[2]*8.0f)/256; else
{
ent->flags |= RF_FORCECOLOURMOD;
ent->shaderRGBAf[0] = (state->colormod[0]*8.0f)/256;
ent->shaderRGBAf[1] = (state->colormod[1]*8.0f)/256;
ent->shaderRGBAf[2] = (state->colormod[2]*8.0f)/256;
}
ent->shaderRGBAf[3] = state->trans/255.0f; ent->shaderRGBAf[3] = state->trans/255.0f;
#ifdef PEXT_FATNESS #ifdef PEXT_FATNESS

View file

@ -148,7 +148,7 @@ kbutton_t in_rollleft, in_rollright, in_up, in_down;
kbutton_t in_button3, in_button4, in_button5, in_button6, in_button7, in_button8; kbutton_t in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
#define IN_IMPULSECACHE 256 #define IN_IMPULSECACHE 32
int in_impulse[MAX_SPLITS][IN_IMPULSECACHE]; int in_impulse[MAX_SPLITS][IN_IMPULSECACHE];
int in_nextimpulse[MAX_SPLITS]; int in_nextimpulse[MAX_SPLITS];
int in_impulsespending[MAX_SPLITS]; int in_impulsespending[MAX_SPLITS];
@ -837,7 +837,6 @@ CL_FinishMove
void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum) void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum)
{ {
int i; int i;
int bits;
CL_ClampPitch(pnum); CL_ClampPitch(pnum);
@ -1463,7 +1462,7 @@ qboolean CLQW_SendCmd (sizebuf_t *buf)
cmd->cursor_start[0] || cmd->cursor_start[1] || cmd->cursor_start[2] || cmd->cursor_start[0] || cmd->cursor_start[1] || cmd->cursor_start[2] ||
cmd->cursor_impact[0] || cmd->cursor_impact[1] || cmd->cursor_impact[2]) cmd->cursor_impact[0] || cmd->cursor_impact[1] || cmd->cursor_impact[2])
{ {
MSG_WriteByte (buf, clc_prydoncursor); MSG_WriteByte (buf, clcfte_prydoncursor);
MSG_WriteShort(buf, cmd->cursor_screen[0] * 32767.0f); MSG_WriteShort(buf, cmd->cursor_screen[0] * 32767.0f);
MSG_WriteShort(buf, cmd->cursor_screen[1] * 32767.0f); MSG_WriteShort(buf, cmd->cursor_screen[1] * 32767.0f);
MSG_WriteFloat(buf, cmd->cursor_start[0]); MSG_WriteFloat(buf, cmd->cursor_start[0]);
@ -1895,7 +1894,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cls.protocol == CP_QUAKE2) if (cls.protocol == CP_QUAKE2)
S_Voip_Transmit(clcq2_voicechat, &buf); S_Voip_Transmit(clcq2_voicechat, &buf);
else else
S_Voip_Transmit(clc_voicechat, &buf); S_Voip_Transmit(clcfte_voicechat, &buf);
#endif #endif
// //

View file

@ -160,6 +160,7 @@ cvar_t cl_countpendingpl = CVARD("cl_countpendingpl", "0", "If set to 1, packet
cvar_t cl_standardchat = CVARFD("cl_standardchat", "0", CVAR_ARCHIVE, "Disables auto colour coding in chat messages."); cvar_t cl_standardchat = CVARFD("cl_standardchat", "0", CVAR_ARCHIVE, "Disables auto colour coding in chat messages.");
cvar_t msg_filter = CVARD("msg_filter", "0", "Filter out chat messages: 0=neither. 1=broadcast chat. 2=team chat. 3=all chat."); cvar_t msg_filter = CVARD("msg_filter", "0", "Filter out chat messages: 0=neither. 1=broadcast chat. 2=team chat. 3=all chat.");
cvar_t msg_filter_frags = CVARD("msg_filter_frags", "0", "Prevents frag messages from appearing on the console.");
cvar_t cl_standardmsg = CVARFD("cl_standardmsg", "0", CVAR_ARCHIVE, "Disables auto colour coding in console prints."); cvar_t cl_standardmsg = CVARFD("cl_standardmsg", "0", CVAR_ARCHIVE, "Disables auto colour coding in console prints.");
cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red"); cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red");
@ -362,7 +363,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
connectinfo.time = realtime; // for retransmit requests connectinfo.time = realtime; // for retransmit requests
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\challenge\\%s", 255, 255, 255, 255, challenge); Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5\\challenge\\%s", 255, 255, 255, 255, challenge);
NET_SendPacket (NS_CLIENT, strlen(data), data, adr); NET_SendPacket (NS_CLIENT, strlen(data), data, adr);
@ -718,12 +719,12 @@ void CL_CheckForResend (void)
} }
else if (!strcmp(cl_loopbackprotocol.string, "q3")) else if (!strcmp(cl_loopbackprotocol.string, "q3"))
cls.protocol = CP_QUAKE3; cls.protocol = CP_QUAKE3;
else if (!strcmp(cl_loopbackprotocol.string, "dp6")) else if (!strcmp(cl_loopbackprotocol.string, "dp6") || !strcmp(cl_loopbackprotocol.string, "dpp6"))
{ {
cls.protocol = CP_NETQUAKE; cls.protocol = CP_NETQUAKE;
cls.protocol_nq = CPNQ_DP7; cls.protocol_nq = CPNQ_DP6;
} }
else if (!strcmp(cl_loopbackprotocol.string, "dp7")) else if (!strcmp(cl_loopbackprotocol.string, "dp7") || !strcmp(cl_loopbackprotocol.string, "dpp7"))
{ {
cls.protocol = CP_NETQUAKE; cls.protocol = CP_NETQUAKE;
cls.protocol_nq = CPNQ_DP7; cls.protocol_nq = CPNQ_DP7;
@ -1817,6 +1818,8 @@ void CL_CheckServerInfo(void)
cls.allow_fbskins = atof(s); cls.allow_fbskins = atof(s);
else if (cl.teamfortress) else if (cl.teamfortress)
cls.allow_fbskins = 0; cls.allow_fbskins = 0;
else
cls.allow_fbskins = 1;
s = Info_ValueForKey(cl.serverinfo, "*cheats"); s = Info_ValueForKey(cl.serverinfo, "*cheats");
if (cl.spectator || cls.demoplayback || !stricmp(s, "on")) if (cl.spectator || cls.demoplayback || !stricmp(s, "on"))
@ -2335,7 +2338,7 @@ drop to full console
void CL_Changing_f (void) void CL_Changing_f (void)
{ {
char *mapname = Cmd_Argv(1); char *mapname = Cmd_Argv(1);
if (cls.download) // don't change when downloading if (cls.download && cls.download->method <= DL_QWPENDING) // don't change when downloading
return; return;
cls.demoseeking = false; //don't seek over it cls.demoseeking = false; //don't seek over it
@ -2370,7 +2373,7 @@ The server is changing levels
*/ */
void CL_Reconnect_f (void) void CL_Reconnect_f (void)
{ {
if (cls.download) // don't change when downloading if (cls.download && cls.download->method <= DL_QWPENDING) // don't change when downloading
return; return;
#ifdef NQPROT #ifdef NQPROT
if (cls.protocol == CP_NETQUAKE && Cmd_FromGamecode()) if (cls.protocol == CP_NETQUAKE && Cmd_FromGamecode())
@ -2528,7 +2531,7 @@ void CL_ConnectionlessPacket (void)
if (c == S2C_CHALLENGE) if (c == S2C_CHALLENGE)
{ {
static unsigned int lasttime = 0xdeadbeef; static unsigned int lasttime = 0xdeadbeef;
netadr_t lastadr; static netadr_t lastadr;
unsigned int curtime = Sys_Milliseconds(); unsigned int curtime = Sys_Milliseconds();
unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0; unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0;
Con_TPrintf ("challenge\n"); Con_TPrintf ("challenge\n");
@ -2831,6 +2834,8 @@ client_connect: //fixme: make function
cls.challenge = connectinfo.challenge; cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, cls.qport); Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, cls.qport);
cls.netchan.fragmentsize = connectinfo.mtu; cls.netchan.fragmentsize = connectinfo.mtu;
if (connectinfo.mtu >= 64)
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
#ifdef HUFFNETWORK #ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc); cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc);
#else #else
@ -3635,10 +3640,11 @@ void CL_Init (void)
Cvar_Register (&requiredownloads, cl_controlgroup); Cvar_Register (&requiredownloads, cl_controlgroup);
Cvar_Register (&cl_standardchat, cl_controlgroup); Cvar_Register (&cl_standardchat, cl_controlgroup);
Cvar_Register (&msg_filter, cl_controlgroup); Cvar_Register (&msg_filter, cl_controlgroup);
Cvar_Register (&msg_filter_frags, cl_controlgroup);
Cvar_Register (&cl_standardmsg, cl_controlgroup); Cvar_Register (&cl_standardmsg, cl_controlgroup);
Cvar_Register (&cl_parsewhitetext, cl_controlgroup); Cvar_Register (&cl_parsewhitetext, cl_controlgroup);
Cvar_Register (&cl_nopext, cl_controlgroup); Cvar_Register (&cl_nopext, cl_controlgroup);
Cvar_Register (&cl_pext_mask, cl_controlgroup); Cvar_Register (&cl_pext_mask, cl_controlgroup);
Cvar_Register (&cl_splitscreen, cl_controlgroup); Cvar_Register (&cl_splitscreen, cl_controlgroup);
@ -4258,7 +4264,7 @@ void Host_DoRunFile(hrf_t *f)
// if (f->flags & HRF_DOWNLOADED) // if (f->flags & HRF_DOWNLOADED)
man->blockupdate = true; man->blockupdate = true;
BZ_Free(fdata); BZ_Free(fdata);
FS_ChangeGame(man, true); FS_ChangeGame(man, true, true);
} }
else else
{ {
@ -4457,7 +4463,7 @@ Runs all active servers
extern cvar_t cl_netfps; extern cvar_t cl_netfps;
extern cvar_t cl_sparemsec; extern cvar_t cl_sparemsec;
qboolean startuppending; int startuppending;
void CL_StartCinematicOrMenu(void); void CL_StartCinematicOrMenu(void);
int nopacketcount; int nopacketcount;
void SNDDMA_SetUnderWater(qboolean underwater); void SNDDMA_SetUnderWater(qboolean underwater);
@ -4815,6 +4821,11 @@ void CL_StartCinematicOrMenu(void)
{ {
COM_MainThreadWork(); COM_MainThreadWork();
if (FS_DownloadingPackage())
{
startuppending = true;
return;
}
if (cls.download) if (cls.download)
{ {
startuppending = true; startuppending = true;
@ -4822,6 +4833,8 @@ void CL_StartCinematicOrMenu(void)
} }
if (startuppending) if (startuppending)
{ {
if (startuppending == 2)
Cbuf_AddText("\nfs_restart\nvid_restart\n", RESTRICT_LOCAL);
startuppending = false; startuppending = false;
Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly. Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly.
} }
@ -4831,7 +4844,9 @@ void CL_StartCinematicOrMenu(void)
UI_Start(); UI_Start();
#endif #endif
Con_TPrintf ("^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081 %s Initialized ^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082\n", *fs_gamename.string?fs_gamename.string:"Nothing"); Cbuf_AddText("menu_restart\n", RESTRICT_LOCAL);
Con_TPrintf ("^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081 %s %sInitialized ^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082\n", *fs_gamename.string?fs_gamename.string:"Nothing", com_installer?"Installer ":"");
//there might be some console command or somesuch waiting for the renderer to begin (demos or map command or whatever all need model support). //there might be some console command or somesuch waiting for the renderer to begin (demos or map command or whatever all need model support).
realtime+=1; realtime+=1;
@ -4839,6 +4854,19 @@ void CL_StartCinematicOrMenu(void)
Con_ClearNotify(); Con_ClearNotify();
TP_ExecTrigger("f_startup");
Cbuf_Execute ();
if (com_installer)
{
com_installer = false;
#if 0
Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly.
M_Menu_Installer();
return;
#endif
}
//and any startup cinematics //and any startup cinematics
#ifndef NOMEDIA #ifndef NOMEDIA
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -5006,7 +5034,10 @@ void Host_FinishLoading(void)
//the filesystem has retrieved its manifest, but might still be waiting for paks to finish downloading. //the filesystem has retrieved its manifest, but might still be waiting for paks to finish downloading.
//make sure the filesystem has some default if no manifest was loaded. //make sure the filesystem has some default if no manifest was loaded.
FS_ChangeGame(NULL, true); FS_ChangeGame(NULL, true, true);
if (waitingformanifest)
return;
Con_History_Load(); Con_History_Load();
@ -5028,6 +5059,11 @@ void Host_FinishLoading(void)
"\n" "\n"
"See the GNU General Public License for more details.\n"); "See the GNU General Public License for more details.\n");
#ifdef _WIN32
if (Sys_RunInstaller())
Sys_Quit();
#endif
Renderer_Start(); Renderer_Start();
CL_StartCinematicOrMenu(); CL_StartCinematicOrMenu();
@ -5176,6 +5212,7 @@ void Host_Shutdown(void)
CL_FreeVisEdicts(); CL_FreeVisEdicts();
M_Shutdown(true); M_Shutdown(true);
Mod_Shutdown(true); Mod_Shutdown(true);
Wads_Flush();
#ifndef CLIENTONLY #ifndef CLIENTONLY
SV_Shutdown(); SV_Shutdown();
#else #else

View file

@ -27,8 +27,6 @@ void CLDP_ParseDarkPlaces5Entities(void);
void CL_SetStatInt (int pnum, int stat, int value); void CL_SetStatInt (int pnum, int stat, int value);
static qboolean CL_CheckModelResources (char *name); static qboolean CL_CheckModelResources (char *name);
int msgflags;
char cl_dp_csqc_progsname[128]; char cl_dp_csqc_progsname[128];
int cl_dp_csqc_progssize; int cl_dp_csqc_progssize;
int cl_dp_csqc_progscrc; int cl_dp_csqc_progscrc;
@ -266,7 +264,7 @@ char *svc_nqstrings[] =
"NEW PROTOCOL(88)" //88 "NEW PROTOCOL(88)" //88
}; };
extern cvar_t requiredownloads, cl_standardchat, msg_filter, cl_countpendingpl, cl_download_mapsrc; extern cvar_t requiredownloads, cl_standardchat, msg_filter, msg_filter_frags, cl_countpendingpl, cl_download_mapsrc;
int oldparsecountmod; int oldparsecountmod;
int parsecountmod; int parsecountmod;
double parsecounttime; double parsecounttime;
@ -5082,7 +5080,7 @@ void CLQ2_ParseInventory (void)
#endif #endif
//return if we want to print the message. //return if we want to print the message.
char *CL_ParseChat(char *text, player_info_t **player) char *CL_ParseChat(char *text, player_info_t **player, int *msgflags)
{ {
extern cvar_t cl_chatsound, cl_nofake, cl_teamchatsound, cl_enemychatsound; extern cvar_t cl_chatsound, cl_nofake, cl_teamchatsound, cl_enemychatsound;
int flags; int flags;
@ -5167,35 +5165,11 @@ char *CL_ParseChat(char *text, player_info_t **player)
} }
} }
msgflags = flags; *msgflags = flags;
return s; return s;
} }
char printtext[4096];
void CL_ParsePrint(char *msg, int level)
{
if (strlen(printtext) + strlen(msg) >= sizeof(printtext))
{
Con_Printf("%s", printtext);
Q_strncpyz(printtext, msg, sizeof(printtext));
}
else
strcat(printtext, msg); //safe due to size on if.
while((msg = strchr(printtext, '\n')))
{
*msg = '\0';
if (level != PRINT_CHAT)
Stats_ParsePrintLine(printtext);
TP_SearchForMsgTriggers(printtext, level);
*msg = '\n';
msg++;
memmove(printtext, msg, strlen(msg)+1);
}
}
// CL_PlayerColor: returns color and mask for player_info_t // CL_PlayerColor: returns color and mask for player_info_t
int CL_PlayerColor(player_info_t *plr, qboolean *name_coloured) int CL_PlayerColor(player_info_t *plr, qboolean *name_coloured)
{ {
@ -5206,6 +5180,12 @@ int CL_PlayerColor(player_info_t *plr, qboolean *name_coloured)
if (cl.teamfortress) //override based on team if (cl.teamfortress) //override based on team
{ {
//damn spies
if (!Q_strcasecmp(plr->team, "red"))
c = 1;
else if (!Q_strcasecmp(plr->team, "blue"))
c = 5;
else
// TODO: needs some work // TODO: needs some work
switch (plr->rbottomcolor) switch (plr->rbottomcolor)
{ //translate q1 skin colours to console colours { //translate q1 skin colours to console colours
@ -5296,7 +5276,7 @@ void TTS_SayChatString(char **stringtosay);
// CL_PrintChat: takes chat strings and performs name coloring and cl_parsewhitetext parsing // CL_PrintChat: takes chat strings and performs name coloring and cl_parsewhitetext parsing
// NOTE: text in rawmsg/msg is assumed destroyable and should not be used afterwards // NOTE: text in rawmsg/msg is assumed destroyable and should not be used afterwards
void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags) void CL_PrintChat(player_info_t *plr, char *msg, int plrflags)
{ {
extern cvar_t con_separatechat; extern cvar_t con_separatechat;
char *name = NULL; char *name = NULL;
@ -5307,12 +5287,12 @@ void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags)
char fullchatmessage[2048]; char fullchatmessage[2048];
fullchatmessage[0] = 0; fullchatmessage[0] = 0;
if (plrflags & TPM_FAKED) /*if (plrflags & TPM_FAKED)
{ {
name = rawmsg; // use rawmsg pointer and msg modification to generate null-terminated string name = rawmsg; // use rawmsg pointer and msg modification to generate null-terminated string
if (msg) if (msg)
*(msg - 2) = 0; // it's assumed that msg has 2 chars before it due to strstr *(msg - 2) = 0; // it's assumed that msg has 2 chars before it due to strstr
} }*/
if (msg[0] == '/' && msg[1] == 'm' && msg[2] == 'e' && msg[3] == ' ') if (msg[0] == '/' && msg[1] == 'm' && msg[2] == 'e' && msg[3] == ' ')
{ {
@ -5540,13 +5520,63 @@ void CL_PrintStandardMessage(char *msg, int printlevel)
// print final chunk // print final chunk
Q_strncatz(fullmessage, msg, sizeof(fullmessage)); Q_strncatz(fullmessage, msg, sizeof(fullmessage));
#ifdef CSQC_DAT
if (CSQC_ParsePrint(fullmessage, printlevel))
return;
#endif
Con_Printf("%s", fullmessage); Con_Printf("%s", fullmessage);
} }
char printtext[4096];
void CL_ParsePrint(char *msg, int level)
{
char n;
if (strlen(printtext) + strlen(msg) >= sizeof(printtext))
{
Con_Printf("%s", printtext);
Q_strncpyz(printtext, msg, sizeof(printtext));
}
else
strcat(printtext, msg); //safe due to size on if.
while((msg = strchr(printtext, '\n')))
{
n = msg[1];
msg[1] = 0;
if (!cls.demoseeking)
{
if (level == PRINT_CHAT)
{
char *body;
int msgflags;
player_info_t *plr = NULL;
if (!TP_SuppressMessage(printtext))
{
body = CL_ParseChat(printtext, &plr, &msgflags);
if (body)
CL_PrintChat(plr, body, msgflags);
}
}
else
{
#ifdef PLUGINS
if (Plug_ServerMessage(printtext, level))
#endif
#ifdef CSQC_DAT
if (!CSQC_ParsePrint(printtext, level))
#endif
if (!Stats_ParsePrintLine(printtext) || !msg_filter_frags.ival)
CL_PrintStandardMessage(printtext, level);
}
}
TP_SearchForMsgTriggers(printtext, level);
msg[1] = n;
msg++;
memmove(printtext, msg, strlen(msg)+1);
}
}
char stufftext[4096]; char stufftext[4096];
void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from network segregation. void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from network segregation.
{ {
@ -5625,7 +5655,7 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n
flocation_t loc; flocation_t loc;
Cmd_TokenizeString(stufftext+2, false, false); Cmd_TokenizeString(stufftext+2, false, false);
if (FS_FLocateFile(Cmd_Argv(1), FSLFRT_IFFOUND, &loc)) if (FS_FLocateFile(Cmd_Argv(1), FSLFRT_IFFOUND, &loc))
Con_Printf("You have been kicked due to a modified file located at %s.\n", Cmd_Argv(0)); Con_Printf("You have been kicked due to the file \"%s\" being modified.\n", Cmd_Argv(1));
} }
#ifdef PLUGINS #ifdef PLUGINS
else if (!strncmp(stufftext, "//tinfo ", 8)) else if (!strncmp(stufftext, "//tinfo ", 8))
@ -5916,33 +5946,7 @@ void CLQW_ParseServerMessage (void)
case svc_print: case svc_print:
i = MSG_ReadByte (); i = MSG_ReadByte ();
s = MSG_ReadString (); s = MSG_ReadString ();
CL_ParsePrint(s, i);
if (i == PRINT_CHAT)
{
char *msg;
player_info_t *plr = NULL;
if (TP_SuppressMessage(s))
break; //if this was unseen-sent from us, ignore it.
if ((msg = CL_ParseChat(s, &plr)))
{
CL_ParsePrint(s, i);
if (!cls.demoseeking)
CL_PrintChat(plr, s, msg, msgflags);
}
}
else
{
#ifdef PLUGINS
if (Plug_ServerMessage(s, i))
#endif
{
CL_ParsePrint(s, i);
if (!cls.demoseeking)
CL_PrintStandardMessage(s, i);
}
}
break; break;
case svc_centerprint: case svc_centerprint:
@ -6060,6 +6064,12 @@ void CLQW_ParseServerMessage (void)
break; break;
#endif #endif
#ifdef TERRAIN
case svcfte_brushedit:
CL_Parse_BrushEdit();
break;
#endif
case svc_updatefrags: case svc_updatefrags:
Sbar_Changed (); Sbar_Changed ();
i = MSG_ReadByte (); i = MSG_ReadByte ();
@ -6448,27 +6458,7 @@ void CLQ2_ParseServerMessage (void)
i = MSG_ReadByte (); i = MSG_ReadByte ();
s = MSG_ReadString (); s = MSG_ReadString ();
if (i == PRINT_CHAT) CL_ParsePrint(s, i);
{
char *msg;
player_info_t *plr = NULL;
if ((msg = CL_ParseChat(s, &plr)))
{
CL_ParsePrint(s, i);
CL_PrintChat(plr, s, msg, msgflags);
}
}
else
{
#ifdef PLUGINS
if (Plug_ServerMessage(s, i))
#endif
{
CL_ParsePrint(s, i);
CL_PrintStandardMessage(s, i);
}
}
break; break;
case svcq2_stufftext: //11 // [string] stuffed into client's console buffer, should be \n terminated case svcq2_stufftext: //11 // [string] stuffed into client's console buffer, should be \n terminated
s = MSG_ReadString (); s = MSG_ReadString ();
@ -6721,28 +6711,11 @@ void CLNQ_ParseServerMessage (void)
s = MSG_ReadString (); s = MSG_ReadString ();
if (*s == 1 || *s == 2) if (*s == 1 || *s == 2)
{ CL_ParsePrint(s+1, PRINT_CHAT);
char *msg; else if (CLNQ_ParseNQPrints(s))
player_info_t *plr = NULL; break;
if ((msg = CL_ParseChat(s+1, &plr)))
{
CL_ParsePrint(s+1, PRINT_CHAT);
CL_PrintChat(plr, s+1, msg, msgflags);
}
}
else else
{ CL_ParsePrint(s, PRINT_HIGH);
if (CLNQ_ParseNQPrints(s))
break;
#ifdef PLUGINS
if (Plug_ServerMessage(s, PRINT_HIGH))
#endif
{
CL_ParsePrint(s, PRINT_HIGH);
CL_PrintStandardMessage(s, PRINT_HIGH);
}
}
break; break;
case svc_disconnect: case svc_disconnect:
@ -7117,7 +7090,7 @@ void CLNQ_ParseServerMessage (void)
CL_ParseStatic (3); CL_ParseStatic (3);
break; break;
case svcfitz_spawnstaticsound2: case svcfitz_spawnstaticsound2:
Host_EndGame("svcfitz_spawnstaticsound2: not implemented"); CL_ParseStaticSound(true);
break; break;

View file

@ -11,7 +11,7 @@ static plugin_t *protocolclientplugin;
qintptr_t VARGS Plug_Menu_Control(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Menu_Control(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
return 0; return 0;
@ -45,7 +45,7 @@ qintptr_t VARGS Plug_Menu_Control(void *offset, quintptr_t mask, const qintptr_t
} }
} }
qintptr_t VARGS Plug_Key_GetKeyCode(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Key_GetKeyCode(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int modifier; int modifier;
return Key_StringToKeynum(VM_POINTER(arg[0]), &modifier); return Key_StringToKeynum(VM_POINTER(arg[0]), &modifier);
@ -54,7 +54,7 @@ qintptr_t VARGS Plug_Key_GetKeyCode(void *offset, quintptr_t mask, const qintptr
qintptr_t VARGS Plug_SCR_CenterPrint(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_SCR_CenterPrint(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
return 0; return 0;
@ -79,7 +79,7 @@ pluginimagearray_t *pluginimagearray;
#include "shader.h" #include "shader.h"
qintptr_t VARGS Plug_Draw_LoadImage(char *name, int type, char *script) static qintptr_t VARGS Plug_Draw_LoadImage(char *name, int type, char *script)
{ {
int i; int i;
@ -131,7 +131,7 @@ qintptr_t VARGS Plug_Draw_LoadImage(char *name, int type, char *script)
} }
qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean *hasalpha, char *fname); qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean *hasalpha, char *fname);
qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
qintptr_t ret = 0; qintptr_t ret = 0;
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
@ -147,7 +147,7 @@ qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qin
if ((rgbdata = Read32BitImageFile(codeddata, datalength, &width, &height, NULL, name))) if ((rgbdata = Read32BitImageFile(codeddata, datalength, &width, &height, NULL, name)))
{ {
name = va("%s/", name); // name = va("%s", name);
t = Image_FindTexture(name, NULL, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP); t = Image_FindTexture(name, NULL, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
if (!TEXVALID(t)) if (!TEXVALID(t))
@ -162,13 +162,13 @@ qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qin
} }
return ret; return ret;
} }
qintptr_t VARGS Plug_Draw_LoadImageShader(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_LoadImageShader(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
char *script = VM_POINTER(arg[1]); char *script = VM_POINTER(arg[1]);
return Plug_Draw_LoadImage(name, 2, script); return Plug_Draw_LoadImage(name, 2, script);
} }
qintptr_t VARGS Plug_Draw_LoadImagePic(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_LoadImagePic(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
int type = arg[1]; int type = arg[1];
@ -209,7 +209,7 @@ static void Plug_FreePlugImages(plugin_t *plug)
} }
//int R2D_Image (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image) //int R2D_Image (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image)
qintptr_t VARGS Plug_Draw_Image(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Image(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
mpic_t *pic; mpic_t *pic;
int i; int i;
@ -238,7 +238,7 @@ qintptr_t VARGS Plug_Draw_Image(void *offset, quintptr_t mask, const qintptr_t *
return 1; return 1;
} }
//x1,y1,x2,y2 //x1,y1,x2,y2
qintptr_t VARGS Plug_Draw_Line(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Line(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
switch(qrenderer) //FIXME: I don't want qrenderer seen outside the refresh switch(qrenderer) //FIXME: I don't want qrenderer seen outside the refresh
{ {
@ -257,7 +257,7 @@ qintptr_t VARGS Plug_Draw_Line(void *offset, quintptr_t mask, const qintptr_t *a
} }
return 1; return 1;
} }
qintptr_t VARGS Plug_Draw_Character(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Character(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int x, y; int x, y;
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
@ -267,7 +267,7 @@ qintptr_t VARGS Plug_Draw_Character(void *offset, quintptr_t mask, const qintptr
Font_EndString(font_default); Font_EndString(font_default);
return 0; return 0;
} }
qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int ipx, px, py; int ipx, px, py;
conchar_t buffer[2048], *str; conchar_t buffer[2048], *str;
@ -291,7 +291,7 @@ qintptr_t VARGS Plug_Draw_String(void *offset, quintptr_t mask, const qintptr_t
return 0; return 0;
} }
qintptr_t VARGS Plug_Draw_Fill(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Fill(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
float x, y, width, height; float x, y, width, height;
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
@ -304,7 +304,7 @@ qintptr_t VARGS Plug_Draw_Fill(void *offset, quintptr_t mask, const qintptr_t *a
R2D_FillBlock(x, y, width, height); R2D_FillBlock(x, y, width, height);
return 0; return 0;
} }
qintptr_t VARGS Plug_Draw_ColourP(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_ColourP(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
if (arg[0]<0 || arg[0]>255) if (arg[0]<0 || arg[0]>255)
return false; return false;
@ -312,12 +312,12 @@ qintptr_t VARGS Plug_Draw_ColourP(void *offset, quintptr_t mask, const qintptr_t
R2D_ImagePaletteColour(arg[0], 1); R2D_ImagePaletteColour(arg[0], 1);
return 1; return 1;
} }
qintptr_t VARGS Plug_Draw_Colour3f(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Colour3f(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
R2D_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), 1); R2D_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), 1);
return 1; return 1;
} }
qintptr_t VARGS Plug_Draw_Colour4f(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Draw_Colour4f(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
R2D_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3])); R2D_ImageColours(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]));
return 1; return 1;
@ -331,7 +331,7 @@ qintptr_t VARGS Plug_Draw_Colour4f(void *offset, quintptr_t mask, const qintptr_
qintptr_t VARGS Plug_LocalSound(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_LocalSound(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
return false; return false;
@ -342,7 +342,7 @@ qintptr_t VARGS Plug_LocalSound(void *offset, quintptr_t mask, const qintptr_t *
qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int i; int i;
int pnum = VM_LONG(arg[0]); int pnum = VM_LONG(arg[0]);
@ -383,7 +383,7 @@ typedef struct {
char team[8]; char team[8];
} vmplugclientinfo_t; } vmplugclientinfo_t;
qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int i, pt; int i, pt;
vmplugclientinfo_t *out; vmplugclientinfo_t *out;
@ -427,12 +427,12 @@ qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_
return pt == i; return pt == i;
} }
qintptr_t VARGS Plug_LocalPlayerNumber(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_LocalPlayerNumber(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
return cl.playerview[0].playernum; return cl.playerview[0].playernum;
} }
qintptr_t VARGS Plug_GetServerInfo(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_GetServerInfo(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *outptr = VM_POINTER(arg[0]); char *outptr = VM_POINTER(arg[0]);
unsigned int outlen = VM_LONG(arg[1]); unsigned int outlen = VM_LONG(arg[1]);
@ -445,7 +445,7 @@ qintptr_t VARGS Plug_GetServerInfo(void *offset, quintptr_t mask, const qintptr_
return true; return true;
} }
qintptr_t VARGS Plug_SetUserInfo(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_SetUserInfo(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *key = VM_POINTER(arg[0]); char *key = VM_POINTER(arg[0]);
char *value = VM_POINTER(arg[1]); char *value = VM_POINTER(arg[1]);
@ -455,7 +455,7 @@ qintptr_t VARGS Plug_SetUserInfo(void *offset, quintptr_t mask, const qintptr_t
return true; return true;
} }
qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
float *locpoint = VM_POINTER(arg[0]); float *locpoint = VM_POINTER(arg[0]);
char *locname = VM_POINTER(arg[1]); char *locname = VM_POINTER(arg[1]);
@ -470,7 +470,7 @@ qintptr_t VARGS Plug_GetLocationName(void *offset, quintptr_t mask, const qintpt
return VM_LONG(arg[1]); return VM_LONG(arg[1]);
} }
qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
char *text = VM_POINTER(arg[1]); char *text = VM_POINTER(arg[1]);
@ -511,7 +511,7 @@ qintptr_t VARGS Plug_Con_SubPrint(void *offset, quintptr_t mask, const qintptr_t
return 1; return 1;
} }
qintptr_t VARGS Plug_Con_RenameSub(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_RenameSub(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
console_t *con; console_t *con;
@ -525,7 +525,7 @@ qintptr_t VARGS Plug_Con_RenameSub(void *offset, quintptr_t mask, const qintptr_
return 1; return 1;
} }
qintptr_t VARGS Plug_Con_IsActive(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_IsActive(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
console_t *con; console_t *con;
@ -537,7 +537,7 @@ qintptr_t VARGS Plug_Con_IsActive(void *offset, quintptr_t mask, const qintptr_t
return Con_IsActive(con); return Con_IsActive(con);
} }
qintptr_t VARGS Plug_Con_SetActive(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_SetActive(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
console_t *con; console_t *con;
@ -550,7 +550,7 @@ qintptr_t VARGS Plug_Con_SetActive(void *offset, quintptr_t mask, const qintptr_
Con_SetActive(con); Con_SetActive(con);
return true; return true;
} }
qintptr_t VARGS Plug_Con_Destroy(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_Destroy(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char *name = VM_POINTER(arg[0]); char *name = VM_POINTER(arg[0]);
console_t *con; console_t *con;
@ -563,7 +563,7 @@ qintptr_t VARGS Plug_Con_Destroy(void *offset, quintptr_t mask, const qintptr_t
Con_Destroy(con); Con_Destroy(con);
return true; return true;
} }
qintptr_t VARGS Plug_Con_NameForNum(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_NameForNum(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
char num = VM_LONG(arg[0]); char num = VM_LONG(arg[0]);
char *buffer = VM_POINTER(arg[1]); char *buffer = VM_POINTER(arg[1]);
@ -576,7 +576,157 @@ qintptr_t VARGS Plug_Con_NameForNum(void *offset, quintptr_t mask, const qintptr
return Con_NameForNum(num, buffer, buffersize); return Con_NameForNum(num, buffer, buffersize);
} }
qintptr_t VARGS Plug_S_RawAudio(void *offset, quintptr_t mask, const qintptr_t *arg) static qintptr_t VARGS Plug_Con_GetConsoleFloat(void *offset, quintptr_t mask, const qintptr_t *arg)
{
char *conname = VM_POINTER(arg[0]);
char *attrib = VM_POINTER(arg[1]);
int retbuf;
float ret;
console_t *con = Con_FindConsole(conname);
ret = -1;
if (!con)
ret = -1;
else if (!strcmp(attrib, "unseen"))
ret = con->unseentext;
else if (!strcmp(attrib, "markup"))
{
if (con->parseflags & PFS_NOMARKUP)
ret = 0;
else if (con->parseflags & PFS_KEEPMARKUP)
ret = 2;
else
ret = 1;
}
else if (!strcmp(attrib, "forceutf8"))
ret = (con->parseflags&PFS_FORCEUTF8)?true:false;
else if (!strcmp(attrib, "hidden"))
ret = (con->flags & CONF_HIDDEN)?true:false;
else if (!strcmp(attrib, "iswindow"))
ret = (con->flags & CONF_ISWINDOW)?true:false;
else if (!strcmp(attrib, "wnd_x"))
ret = con->wnd_x;
else if (!strcmp(attrib, "wnd_y"))
ret = con->wnd_y;
else if (!strcmp(attrib, "wnd_w"))
ret = con->wnd_w;
else if (!strcmp(attrib, "wnd_h"))
ret = con->wnd_h;
else if (!strcmp(attrib, "linecount"))
ret = con->linecount;
VM_FLOAT(retbuf) = ret;
return retbuf;
}
static qintptr_t VARGS Plug_Con_SetConsoleFloat(void *offset, quintptr_t mask, const qintptr_t *arg)
{
char *conname = VM_POINTER(arg[0]);
char *attrib = VM_POINTER(arg[1]);
float val = VM_FLOAT(arg[2]);
console_t *con = Con_FindConsole(conname);
if (!con)
{
con = Con_Create(conname, 0);
if (!con)
return -1;
con->userdata = currentplug;
con->linebuffered = Plug_SubConsoleCommand;
}
if (!strcmp(attrib, "unseen"))
con->unseentext = !!val;
else if (!strcmp(attrib, "markup"))
{
int cur = val;
con->parseflags &= ~(PFS_NOMARKUP|PFS_KEEPMARKUP);
if (cur == 0)
con->parseflags |= PFS_NOMARKUP;
else if (cur == 2)
con->parseflags |= PFS_KEEPMARKUP;
}
else if (!strcmp(attrib, "forceutf8"))
con->parseflags = (con->parseflags & ~PFS_FORCEUTF8) | (val?PFS_FORCEUTF8:0);
else if (!strcmp(attrib, "hidden"))
con->flags = (con->flags & ~CONF_HIDDEN) | (val?CONF_HIDDEN:0);
else if (!strcmp(attrib, "iswindow"))
{
con->flags = (con->flags & ~CONF_ISWINDOW) | (val?CONF_ISWINDOW:0);
if (con_curwindow == con && !(con->flags & CONF_ISWINDOW))
con_curwindow = NULL;
else if (!con_curwindow && (con->flags & CONF_ISWINDOW))
con_curwindow = con;
}
else if (!strcmp(attrib, "wnd_x"))
con->wnd_x = val;
else if (!strcmp(attrib, "wnd_y"))
con->wnd_y = val;
else if (!strcmp(attrib, "wnd_w"))
con->wnd_w = val;
else if (!strcmp(attrib, "wnd_h"))
con->wnd_h = val;
else if (!strcmp(attrib, "linebuffered"))
{
con->userdata = currentplug;
con->linebuffered = val?Plug_SubConsoleCommand:0;
}
else if (!strcmp(attrib, "linecount"))
{
if (val == 0)
Con_ClearCon(con);
else
return -1;
}
else
return -1;
return true;
}
static qintptr_t VARGS Plug_Con_GetConsoleString(void *offset, quintptr_t mask, const qintptr_t *arg)
{
const char *conname = VM_POINTER(arg[0]);
const char *attrib = VM_POINTER(arg[1]);
const char *value = VM_POINTER(arg[2]);
size_t size = VM_LONG(arg[3]);
console_t *con = Con_FindConsole(conname);
if (VM_OOB(arg[2], arg[3]))
return 0;
if (!con)
return 0;
else if (!strcmp(attrib, "footer"))
;
return 0;
}
static qintptr_t VARGS Plug_Con_SetConsoleString(void *offset, quintptr_t mask, const qintptr_t *arg)
{
const char *conname = VM_POINTER(arg[0]);
const char *attrib = VM_POINTER(arg[1]);
const char *value = VM_POINTER(arg[2]);
console_t *con = Con_FindConsole(conname);
if (!con)
{
con = Con_Create(conname, 0);
if (!con)
return -1;
con->userdata = currentplug;
con->linebuffered = Plug_SubConsoleCommand;
}
if (!con)
return 0;
else if (!strcmp(attrib, "footer"))
Con_Footerf(con, false, "%s", value);
else if (!strcmp(attrib, "title"))
Q_strncpyz(con->title, value, sizeof(con->title));
else
return -1;
return 0;
}
static qintptr_t VARGS Plug_S_RawAudio(void *offset, quintptr_t mask, const qintptr_t *arg)
{ {
int sourceid = VM_LONG(arg[0]); int sourceid = VM_LONG(arg[0]);
qbyte *data = VM_POINTER(arg[1]); qbyte *data = VM_POINTER(arg[1]);
@ -598,22 +748,22 @@ qintptr_t VARGS Plug_S_RawAudio(void *offset, quintptr_t mask, const qintptr_t *
#include "com_mesh.h" #include "com_mesh.h"
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
int QDECL Plug_RegisterModelFormatText(const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)) static int QDECL Plug_RegisterModelFormatText(const char *formatname, char *magictext, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize))
{ {
void *module = currentplug; void *module = currentplug;
return Mod_RegisterModelFormatText(module, formatname, magictext, load); return Mod_RegisterModelFormatText(module, formatname, magictext, load);
} }
int QDECL Plug_RegisterModelFormatMagic(const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize)) static int QDECL Plug_RegisterModelFormatMagic(const char *formatname, unsigned int magic, qboolean (QDECL *load) (struct model_s *mod, void *buffer, size_t fsize))
{ {
void *module = currentplug; void *module = currentplug;
return Mod_RegisterModelFormatMagic(module, formatname, magic, load); return Mod_RegisterModelFormatMagic(module, formatname, magic, load);
} }
void QDECL Plug_UnRegisterModelFormat(int idx) static void QDECL Plug_UnRegisterModelFormat(int idx)
{ {
void *module = currentplug; void *module = currentplug;
Mod_UnRegisterModelFormat(module, idx); Mod_UnRegisterModelFormat(module, idx);
} }
void QDECL Plug_UnRegisterAllModelFormats(void) static void QDECL Plug_UnRegisterAllModelFormats(void)
{ {
void *module = currentplug; void *module = currentplug;
Mod_UnRegisterAllModelFormats(module); Mod_UnRegisterAllModelFormats(module);
@ -671,6 +821,10 @@ void Plug_Client_Init(void)
Plug_RegisterBuiltin("Con_SetActive", Plug_Con_SetActive, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Con_SetActive", Plug_Con_SetActive, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_Destroy", Plug_Con_Destroy, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Con_Destroy", Plug_Con_Destroy, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_NameForNum", Plug_Con_NameForNum, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("Con_NameForNum", Plug_Con_NameForNum, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_GetConsoleFloat", Plug_Con_GetConsoleFloat, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_SetConsoleFloat", Plug_Con_SetConsoleFloat, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_GetConsoleString", Plug_Con_GetConsoleString, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("Con_SetConsoleString", Plug_Con_SetConsoleString, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("LocalSound", Plug_LocalSound, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("LocalSound", Plug_LocalSound, PLUG_BIF_NEEDSRENDERER);
Plug_RegisterBuiltin("SCR_CenterPrint", Plug_SCR_CenterPrint, PLUG_BIF_NEEDSRENDERER); Plug_RegisterBuiltin("SCR_CenterPrint", Plug_SCR_CenterPrint, PLUG_BIF_NEEDSRENDERER);

View file

@ -560,15 +560,7 @@ void CL_CalcClientTime(void)
extern float olddemotime; extern float olddemotime;
cl.servertime = olddemotime; cl.servertime = olddemotime;
} }
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD && !(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) if (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !cls.demoplayback)) && cls.demoplayback != DPB_MVD)
{
extern float nextdemotime, olddemotime, demtime;
float f;
f = (demtime - olddemotime) / (nextdemotime - olddemotime);
f = bound(0, f, 1);
cl.servertime = cl.gametime*f + cl.oldgametime*(1-f);
}
else if (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !cls.demoplayback)))
{ {
float f; float f;
f = cl.gametime - cl.oldgametime; f = cl.gametime - cl.oldgametime;

View file

@ -93,7 +93,7 @@ void RSpeedShow(void)
} }
for (i = 0; i < RQUANT_MAX; i++) for (i = 0; i < RQUANT_MAX; i++)
{ {
s = va("%g %-20s", samplerquant[i]/100.0, RQntNames[i]); s = va("%u.%.3u %-20s", samplerquant[i]/100, (samplerquant[i]%100), RQntNames[i]);
Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s); Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s);
} }
if (r_speeds.ival > 1) if (r_speeds.ival > 1)
@ -245,6 +245,7 @@ void *scr_curcursor;
extern char cl_screengroup[]; extern char cl_screengroup[];
void CLSCR_Init(void) void CLSCR_Init(void)
{ {
int i;
Cmd_AddCommand("cprint", SCR_CPrint_f); Cmd_AddCommand("cprint", SCR_CPrint_f);
Cvar_Register(&con_stayhidden, cl_screengroup); Cvar_Register(&con_stayhidden, cl_screengroup);
@ -265,6 +266,8 @@ void CLSCR_Init(void)
memset(&key_customcursor, 0, sizeof(key_customcursor)); memset(&key_customcursor, 0, sizeof(key_customcursor));
for (i = 0; i < kc_max; i++)
key_customcursor[i].dirty = true;
scr_curcursor = NULL; scr_curcursor = NULL;
if (rf && rf->VID_SetCursor) if (rf && rf->VID_SetCursor)
rf->VID_SetCursor(scr_curcursor); rf->VID_SetCursor(scr_curcursor);
@ -417,6 +420,25 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode)
p->time_start = cl.time; p->time_start = cl.time;
} }
void VARGS Stats_Message(char *msg, ...)
{
va_list argptr;
char str[2048];
cprint_t *p = &scr_centerprint[0];
if (p->time_off >= 0)
return;
va_start (argptr, msg);
vsnprintf (str,sizeof(str)-1, msg, argptr);
va_end (argptr);
p->flags = CPRINT_OBITUARTY;
p->titleimage[0] = 0;
p->charcount = COM_ParseFunString(CON_WHITEMASK, str, p->string, sizeof(p->string), false) - p->string;
p->time_off = scr_centertime.value;
p->time_start = cl.time;
}
void SCR_CPrint_f(void) void SCR_CPrint_f(void)
{ {
if (Cmd_Argc() == 2) if (Cmd_Argc() == 2)
@ -650,7 +672,7 @@ void SCR_DrawCursor(void)
return; return;
//choose the cursor based upon the module that has primary focus //choose the cursor based upon the module that has primary focus
if (key_dest_mask & key_dest_absolutemouse & (kdm_console|kdm_editor)) if (key_dest_mask & key_dest_absolutemouse & (kdm_console|kdm_cwindows|kdm_editor))
cmod = kc_console; cmod = kc_console;
else if ((key_dest_mask & key_dest_absolutemouse & kdm_menu)) else if ((key_dest_mask & key_dest_absolutemouse & kdm_menu))
{ {
@ -680,6 +702,13 @@ void SCR_DrawCursor(void)
if (key_customcursor[cmod].dirty) if (key_customcursor[cmod].dirty)
{ {
if (key_customcursor[cmod].scale <= 0)
{
key_customcursor[cmod].hotspot[0] = cl_cursorbiasx.value;
key_customcursor[cmod].hotspot[1] = cl_cursorbiasy.value;
key_customcursor[cmod].scale = cl_cursorscale.value;
}
key_customcursor[cmod].dirty = false; key_customcursor[cmod].dirty = false;
oldcurs = key_customcursor[cmod].handle; oldcurs = key_customcursor[cmod].handle;
if (rf->VID_CreateCursor) if (rf->VID_CreateCursor)
@ -1173,7 +1202,7 @@ void SCR_Init (void)
// //
// register our commands // register our commands
// //
Cmd_AddCommand ("screenshot_mega",SCR_ScreenShot_Mega_f); Cmd_AddCommandD ("screenshot_mega",SCR_ScreenShot_Mega_f, "screenshot_mega <name> [width] [height]\nTakes a screenshot with explicit sizes that are not tied to the size of your monitor, allowing for true monstrosities.");
Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
Cmd_AddCommand ("sizeup",SCR_SizeUp_f); Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
Cmd_AddCommand ("sizedown",SCR_SizeDown_f); Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
@ -1794,7 +1823,7 @@ SCR_SetUpToDrawConsole
*/ */
void SCR_SetUpToDrawConsole (void) void SCR_SetUpToDrawConsole (void)
{ {
extern qboolean startuppending; //true if we're downloading media or something and have not yet triggered the startup action (read: main menu or cinematic) extern int startuppending; //true if we're downloading media or something and have not yet triggered the startup action (read: main menu or cinematic)
#ifdef TEXTEDITOR #ifdef TEXTEDITOR
//extern qboolean editoractive; //unused variable //extern qboolean editoractive; //unused variable
#endif #endif
@ -1818,17 +1847,22 @@ void SCR_SetUpToDrawConsole (void)
else if (!startuppending && !Key_Dest_Has(kdm_menu) && (!Key_Dest_Has(~((!con_stayhidden.ival?kdm_console:0)|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false)) else if (!startuppending && !Key_Dest_Has(kdm_menu) && (!Key_Dest_Has(~((!con_stayhidden.ival?kdm_console:0)|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false))
{ {
//go fullscreen if we're not doing anything //go fullscreen if we're not doing anything
if (con_curwindow && !cls.state)
{
Key_Dest_Add(kdm_cwindows);
scr_conlines = 0;
}
#ifdef VM_UI #ifdef VM_UI
if (UI_MenuState() || UI_OpenMenu()) else if (UI_MenuState() || UI_OpenMenu())
scr_con_current = scr_conlines = 0; scr_con_current = scr_conlines = 0;
else
#endif #endif
else
{ {
if (cls.state < ca_demostart) if (cls.state < ca_demostart)
{ {
if (con_stayhidden.ival) if (con_stayhidden.ival)
{ {
extern qboolean startuppending; extern int startuppending;
scr_conlines = 0; scr_conlines = 0;
if (SCR_GetLoadingStage() == LS_NONE) if (SCR_GetLoadingStage() == LS_NONE)
{ {
@ -1845,7 +1879,7 @@ void SCR_SetUpToDrawConsole (void)
if (!con_stayhidden.ival && !startuppending && Key_Dest_Has(kdm_console)) if (!con_stayhidden.ival && !startuppending && Key_Dest_Has(kdm_console))
scr_con_current = scr_conlines = vid.height * fullscreenpercent; scr_con_current = scr_conlines = vid.height * fullscreenpercent;
} }
else if (Key_Dest_Has(kdm_console) || scr_chatmode) else if ((Key_Dest_Has(kdm_console) || scr_chatmode))
{ {
//go half-screen if we're meant to have the console visible //go half-screen if we're meant to have the console visible
scr_conlines = vid.height*scr_consize.value; // half screen scr_conlines = vid.height*scr_consize.value; // half screen
@ -1891,16 +1925,16 @@ SCR_DrawConsole
*/ */
void SCR_DrawConsole (qboolean noback) void SCR_DrawConsole (qboolean noback)
{ {
if (scr_con_current) if (!scr_con_current)
{
Con_DrawConsole (scr_con_current, noback);
clearconsole = 0;
}
else
{ {
if (!Key_Dest_Has(kdm_console|kdm_menu)) if (!Key_Dest_Has(kdm_console|kdm_menu))
Con_DrawNotify (); // only draw notify in game Con_DrawNotify (); // only draw notify in game
} }
if (scr_con_current || Key_Dest_Has(kdm_cwindows))
{
Con_DrawConsole (scr_con_current, noback);
clearconsole = 0;
}
} }
@ -2133,6 +2167,9 @@ void SCR_ScreenShot_Mega_f(void)
unsigned int fbwidth = strtoul(Cmd_Argv(2), NULL, 0); unsigned int fbwidth = strtoul(Cmd_Argv(2), NULL, 0);
unsigned int fbheight = strtoul(Cmd_Argv(3), NULL, 0); unsigned int fbheight = strtoul(Cmd_Argv(3), NULL, 0);
if (Cmd_IsInsecure())
return;
if (qrenderer <= QR_HEADLESS) if (qrenderer <= QR_HEADLESS)
{ {
Con_Printf("No renderer active\n"); Con_Printf("No renderer active\n");
@ -2177,7 +2214,12 @@ void SCR_ScreenShot_Mega_f(void)
rgbbuffer = VID_GetRGBInfo(0, &width, &height); rgbbuffer = VID_GetRGBInfo(0, &width, &height);
if (rgbbuffer) if (rgbbuffer)
{ {
SCR_ScreenShot(filename, rgbbuffer, width, height); if (SCR_ScreenShot(filename, rgbbuffer, width, height))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
}
BZ_Free(rgbbuffer); BZ_Free(rgbbuffer);
} }
} }
@ -2452,6 +2494,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
{ {
SCR_DrawFPS (); SCR_DrawFPS ();
SCR_DrawUPS (); SCR_DrawUPS ();
SCR_DrawClock();
SCR_DrawGameClock();
} }
SCR_CheckDrawCenterString (); SCR_CheckDrawCenterString ();
} }

View file

@ -1475,7 +1475,7 @@ qboolean Stats_HaveKills(void);
void VARGS Stats_Message(char *msg, ...) LIKEPRINTF(1); void VARGS Stats_Message(char *msg, ...) LIKEPRINTF(1);
int qm_strcmp(char *s1, char *s2); int qm_strcmp(char *s1, char *s2);
int qm_stricmp(char *s1, char *s2); int qm_stricmp(char *s1, char *s2);
void Stats_ParsePrintLine(char *line); qboolean Stats_ParsePrintLine(char *line);
void Stats_NewMap(void); void Stats_NewMap(void);
void Stats_Clear(void); void Stats_Clear(void);

View file

@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h" #include "quakedef.h"
console_t con_main; console_t con_main;
console_t *con_curwindow;
console_t *con_current; // points to whatever is the visible console console_t *con_current; // points to whatever is the visible console
console_t *con_mouseover; // points to whichever console's title is currently mouseovered, or null console_t *con_mouseover; // points to whichever console's title is currently mouseovered, or null
console_t *con_chat; // points to a chat console console_t *con_chat; // points to a chat console
@ -128,8 +129,6 @@ void Con_Destroy (console_t *con)
return; return;
} }
con_mouseover = NULL;
for (prev = &con_main; prev->next; prev = prev->next) for (prev = &con_main; prev->next; prev = prev->next)
{ {
if (prev->next == con) if (prev->next == con)
@ -143,6 +142,18 @@ void Con_Destroy (console_t *con)
if (con_current == con) if (con_current == con)
con_current = &con_main; con_current = &con_main;
if (con_curwindow == con)
{
for (con_curwindow = &con_main; con_curwindow; con_curwindow = con_curwindow->next)
{
if (con_curwindow->flags & CONF_ISWINDOW)
break;
}
if (!con_curwindow)
Key_Dest_Remove(kdm_cwindows);
}
con_mouseover = NULL;
} }
/*obtains a console_t without creating*/ /*obtains a console_t without creating*/
console_t *Con_FindConsole(const char *name) console_t *Con_FindConsole(const char *name)
@ -177,7 +188,14 @@ console_t *Con_Create(const char *name, unsigned int flags)
/*sets a console as the active one*/ /*sets a console as the active one*/
void Con_SetActive (console_t *con) void Con_SetActive (console_t *con)
{ {
con_current = con; if (con->flags & CONF_ISWINDOW)
{
con_curwindow = con;
Key_Dest_Add(kdm_cwindows);
Key_Dest_Remove(kdm_console);
}
else
con_current = con;
if (con->footerline) if (con->footerline)
{ {
@ -186,6 +204,7 @@ void Con_SetActive (console_t *con)
Z_Free(con->footerline); Z_Free(con->footerline);
con->footerline = NULL; con->footerline = NULL;
} }
con->buttonsdown = CB_NONE;
} }
/*for enumerating consoles*/ /*for enumerating consoles*/
qboolean Con_NameForNum(int num, char *buffer, int buffersize) qboolean Con_NameForNum(int num, char *buffer, int buffersize)
@ -448,6 +467,20 @@ void Con_ToggleConsole_Force(void)
void Con_ToggleConsole_f (void) void Con_ToggleConsole_f (void)
{ {
extern cvar_t con_stayhidden; extern cvar_t con_stayhidden;
if (!con_curwindow)
{
for (con_curwindow = &con_main; con_curwindow; con_curwindow = con_curwindow->next)
if (con_curwindow->flags & CONF_ISWINDOW)
break;
}
if (con_curwindow && !Key_Dest_Has(kdm_cwindows|kdm_console))
{
Key_Dest_Add(kdm_cwindows);
return;
}
#ifdef CSQC_DAT #ifdef CSQC_DAT
if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole")) if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole"))
{ {
@ -457,7 +490,10 @@ void Con_ToggleConsole_f (void)
#endif #endif
if (con_stayhidden.ival >= 3) if (con_stayhidden.ival >= 3)
{
Key_Dest_Remove(kdm_cwindows);
return; //its hiding! return; //its hiding!
}
Con_ToggleConsole_Force(); Con_ToggleConsole_Force();
} }
@ -672,6 +708,12 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
conchar_t *c; conchar_t *c;
conline_t *oc; conline_t *oc;
conline_t *reuse; conline_t *reuse;
int maxlines;
if (con->maxlines)
maxlines = con->maxlines;
else
maxlines = con_maxlines.ival;
COM_ParseFunString(con->defaultcharbits, txt, expanded, sizeof(expanded), parseflags); COM_ParseFunString(con->defaultcharbits, txt, expanded, sizeof(expanded), parseflags);
@ -690,7 +732,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
case '\n': case '\n':
con->cr = false; con->cr = false;
reuse = NULL; reuse = NULL;
while (con->linecount >= con_maxlines.ival) while (con->linecount >= maxlines)
{ {
if (con->oldest == con->current) if (con->oldest == con->current)
break; break;
@ -714,7 +756,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
if (con->flags & CONF_NOTIMES) if (con->flags & CONF_NOTIMES)
con->current->time = 0; con->current->time = 0;
else else
con->current->time = realtime; con->current->time = realtime + con->notif_t;
#if defined(_WIN32) && !defined(NOMEDIA) && !defined(WINRT) #if defined(_WIN32) && !defined(NOMEDIA) && !defined(WINRT)
if (con->current) if (con->current)
@ -789,7 +831,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
if (con->flags & CONF_NOTIMES) if (con->flags & CONF_NOTIMES)
con->current->time = 0; con->current->time = 0;
else else
con->current->time = realtime; con->current->time = realtime + con->notif_t;
} }
void Con_Print (char *txt) void Con_Print (char *txt)
@ -811,7 +853,7 @@ void Con_CycleConsole(void)
if (!con_current) if (!con_current)
con_current = &con_main; con_current = &con_main;
if (con_current->flags & CONF_HIDDEN) if (con_current->flags & (CONF_HIDDEN|CONF_ISWINDOW))
continue; continue;
break; break;
} }
@ -960,14 +1002,15 @@ void VARGS Con_DPrintf (const char *fmt, ...)
} }
/*description text at the bottom of the console*/ /*description text at the bottom of the console*/
void Con_Footerf(qboolean append, char *fmt, ...) void Con_Footerf(console_t *con, qboolean append, char *fmt, ...)
{ {
console_t *con = con_current;
va_list argptr; va_list argptr;
char msg[MAXPRINTMSG]; char msg[MAXPRINTMSG];
conchar_t marked[MAXPRINTMSG], *markedend; conchar_t marked[MAXPRINTMSG], *markedend;
int oldlen, newlen; int oldlen, newlen;
conline_t *newf; conline_t *newf;
if (!con)
con = con_current;
va_start (argptr,fmt); va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr); vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
@ -1038,7 +1081,13 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
int x; int x;
if (!con->linebuffered) if (!con->linebuffered)
{
if (con->footerline)
{
y = Con_DrawConsoleLines(con, con->footerline, left, right, y, 0, selactive, selsx, selex, selsy, seley);
}
return y; //fixme: draw any unfinished lines of the current console instead. return y; //fixme: draw any unfinished lines of the current console instead.
}
y -= Font_CharHeight(); y -= Font_CharHeight();
@ -1203,18 +1252,20 @@ Draws the last few lines of output transparently over the game top
void Con_DrawNotifyOne (console_t *con) void Con_DrawNotifyOne (console_t *con)
{ {
conchar_t *starts[NUM_CON_TIMES], *ends[NUM_CON_TIMES]; conchar_t *starts[NUM_CON_TIMES], *ends[NUM_CON_TIMES];
float alphas[NUM_CON_TIMES], a;
conchar_t *c; conchar_t *c;
conline_t *l; conline_t *l;
int lines=con->notif_l; int lines=con->notif_l;
int line; int line;
int x = con->notif_x, y = con->notif_y; int nx, y;
int w = con->notif_w; int nw;
int x;
int maxlines; int maxlines;
float t; float t;
Font_BeginString(font_console, x, y, &x, &y); Font_BeginString(font_console, con->notif_x * vid.width, con->notif_y * vid.height, &nx, &y);
Font_Transform(con->notif_w, 0, &w, NULL); Font_Transform(con->notif_w * vid.width, 0, &nw, NULL);
if (con->notif_l < 0) if (con->notif_l < 0)
con->notif_l = 0; con->notif_l = 0;
@ -1222,8 +1273,8 @@ void Con_DrawNotifyOne (console_t *con)
con->notif_l = NUM_CON_TIMES; con->notif_l = NUM_CON_TIMES;
lines = maxlines = con->notif_l; lines = maxlines = con->notif_l;
if (x == 0 && y == 0 && con->notif_w == vid.width) if (!con->notif_x && !con->notif_y && con->notif_w == 1)
y = Con_DrawProgress(0, w, 0); y = Con_DrawProgress(0, nw, 0);
l = con->current; l = con->current;
if (!l->length) if (!l->length)
@ -1234,21 +1285,31 @@ void Con_DrawNotifyOne (console_t *con)
if (!t) if (!t)
continue; //hidden from notify continue; //hidden from notify
t = realtime - t; t = realtime - t;
if (t > con->notif_t) if (t > 0)
break; {
if (t > con->notif_fade)
{
l->time = 0;
break;
}
a = 1 - (t/con->notif_fade);
}
else a = 1;
line = Font_LineBreaks((conchar_t*)(l+1), (conchar_t*)(l+1)+l->length, w, lines, starts, ends); line = Font_LineBreaks((conchar_t*)(l+1), (conchar_t*)(l+1)+l->length, nw, lines, starts, ends);
if (!line && lines > 0) if (!line && lines > 0)
{ {
lines--; lines--;
starts[lines] = NULL; starts[lines] = NULL;
ends[lines] = NULL; ends[lines] = NULL;
alphas[lines] = a;
} }
while(line --> 0 && lines > 0) while(line --> 0 && lines > 0)
{ {
lines--; lines--;
starts[lines] = starts[line]; starts[lines] = starts[line];
ends[lines] = ends[line]; ends[lines] = ends[line];
alphas[lines] = a;
} }
if (lines == 0) if (lines == 0)
break; break;
@ -1265,15 +1326,24 @@ void Con_DrawNotifyOne (console_t *con)
while (lines < con->notif_l) while (lines < con->notif_l)
{ {
x = 0; x = 0;
if (con_centernotify.value) Font_ForceColour(1, 1, 1, alphas[lines]);
if (con->flags & CONF_NOTIFY_RIGHT)
{ {
for (c = starts[lines]; c < ends[lines]; c++) for (c = starts[lines]; c < ends[lines]; c++)
{ {
x += Font_CharWidth(*c); x += Font_CharWidth(*c);
} }
x = (w - x) / 2; x = (nw - x);
} }
Font_LineDraw(x, y, starts[lines], ends[lines]); else if (con_centernotify.value)
{
for (c = starts[lines]; c < ends[lines]; c++)
{
x += Font_CharWidth(*c);
}
x = (nw - x) / 2;
}
Font_LineDraw(nx+x, y, starts[lines], ends[lines]);
y += Font_CharHeight(); y += Font_CharHeight();
@ -1281,6 +1351,8 @@ void Con_DrawNotifyOne (console_t *con)
} }
Font_EndString(font_console); Font_EndString(font_console);
Font_InvalidateColour();
} }
void Con_ClearNotify(void) void Con_ClearNotify(void)
@ -1295,20 +1367,20 @@ void Con_ClearNotify(void)
} }
void Con_DrawNotify (void) void Con_DrawNotify (void)
{ {
extern qboolean startuppending; extern int startuppending;
console_t *con; console_t *con;
con_main.flags |= CONF_NOTIFY; con_main.flags |= CONF_NOTIFY;
/*keep the main console up to date*/ /*keep the main console up to date*/
con_main.notif_l = con_numnotifylines.ival; con_main.notif_l = con_numnotifylines.ival;
con_main.notif_w = vid.width; con_main.notif_w = 1;
con_main.notif_t = con_notifytime.value; con_main.notif_t = con_notifytime.value;
if (con_chat) if (con_chat)
{ {
con_chat->notif_l = con_numnotifylines_chat.ival; con_chat->notif_l = con_numnotifylines_chat.ival;
con_chat->notif_w = vid.width - 64; con_chat->notif_w = 1;
con_chat->notif_y = vid.height - sb_lines - 8*4; con_chat->notif_y = (vid.height - sb_lines - 8*4) / vid.width;
con_chat->notif_t = con_notifytime_chat.value; con_chat->notif_t = con_notifytime_chat.value;
} }
@ -1447,6 +1519,12 @@ static int Con_DrawProgress(int left, int right, int y)
{ {
sprintf(progresspercenttext, " (%u%skb)", (int)(total/1024), extra?"+":""); sprintf(progresspercenttext, " (%u%skb)", (int)(total/1024), extra?"+":"");
} }
//do some marquee thing, so the user gets the impression that SOMETHING is happening.
progresspercent = realtime - (int)realtime;
if ((int)realtime & 1)
progresspercent = 1 - progresspercent;
progresspercent *= 100;
} }
else else
{ {
@ -1568,11 +1646,9 @@ int Con_DrawAlternateConsoles(int lines)
console_t *con = &con_main, *om = con_mouseover; console_t *con = &con_main, *om = con_mouseover;
conchar_t buffer[512], *end, *start; conchar_t buffer[512], *end, *start;
con_mouseover = NULL;
for (con = &con_main; con; con = con->next) for (con = &con_main; con; con = con->next)
{ {
if (!(con->flags & CONF_HIDDEN)) if (!(con->flags & (CONF_HIDDEN|CONF_ISWINDOW)))
consshown++; consshown++;
} }
@ -1584,7 +1660,7 @@ int Con_DrawAlternateConsoles(int lines)
h = Font_CharHeight(); h = Font_CharHeight();
for (x = 0, con = &con_main; con; con = con->next) for (x = 0, con = &con_main; con; con = con->next)
{ {
if (con->flags & CONF_HIDDEN) if (con->flags & (CONF_HIDDEN|CONF_ISWINDOW))
continue; continue;
txt = con->title; txt = con->title;
@ -1629,6 +1705,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
conchar_t *s; conchar_t *s;
int i; int i;
int x; int x;
int charh = Font_CharHeight();
if (l != con->completionline) if (l != con->completionline)
if (l != con->footerline) if (l != con->footerline)
@ -1668,13 +1745,11 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
//scale the y coord to be in lines instead of pixels //scale the y coord to be in lines instead of pixels
selsy -= y; selsy -= y;
seley -= y; seley -= y;
selsy /= Font_CharHeight(); // selsy -= charh;
seley /= Font_CharHeight(); // seley -= charh;
selsy--;
seley--;
//invert the selections to make sense, text-wise //invert the selections to make sense, text-wise
if (selsy == seley) /*if (selsy == seley)
{ {
//single line selected backwards //single line selected backwards
if (selex < selsx) if (selex < selsx)
@ -1684,6 +1759,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
selsx = x; selsx = x;
} }
} }
*/
if (seley < selsy) if (seley < selsy)
{ //selection goes upwards { //selection goes upwards
x = selsy; x = selsy;
@ -1694,8 +1770,8 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
selex = selsx; selex = selsx;
selsx = x; selsx = x;
} }
selsy *= Font_CharHeight(); // selsy *= Font_CharHeight();
seley *= Font_CharHeight(); // seley *= Font_CharHeight();
selsy += y; selsy += y;
seley += y; seley += y;
} }
@ -1727,14 +1803,14 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
{ {
imgname = Info_ValueForKey(linkinfo, "w"); imgname = Info_ValueForKey(linkinfo, "w");
if (*imgname) if (*imgname)
picw = atoi(imgname); picw = (atoi(imgname) * charh) / 8.0;
else if (pic->width) else if (pic->width)
picw = (pic->width * vid.pixelwidth) / vid.width; picw = (pic->width * vid.pixelwidth) / vid.width;
else else
picw = 64; picw = 64;
imgname = Info_ValueForKey(linkinfo, "h"); imgname = Info_ValueForKey(linkinfo, "h");
if (*imgname) if (*imgname)
pich = atoi(imgname); pich = (atoi(imgname) * charh) / 8.0;
else if (pic->height) else if (pic->height)
pich = (pic->height * vid.pixelheight) / vid.height; pich = (pic->height * vid.pixelheight) / vid.height;
else else
@ -1773,6 +1849,9 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
pich -= texth; pich -= texth;
y-= pich/2; //skip some space above and below the text block, to keep the text and image aligned. y-= pich/2; //skip some space above and below the text block, to keep the text and image aligned.
} }
// if (selsx < picw && selex < picw)
} }
l->lines = linecount; l->lines = linecount;
@ -1789,9 +1868,9 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
if (selactive) if (selactive)
{ {
if (y >= selsy) if (y+charh >= selsy)
{ {
if (y <= seley) if (y < seley)
{ {
int sstart; int sstart;
int send; int send;
@ -1804,7 +1883,17 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
if (send == sstart) if (send == sstart)
send = Font_CharEndCoord(font_console, send, ' '); send = Font_CharEndCoord(font_console, send, ' ');
if (y >= seley) if (y+charh >= seley && y < selsy)
{ //if they're both on the same line, make sure sx is to the left of ex, so our stuff makes sense
if (selex < selsx)
{
x = selex;
selex = selsx;
selsx = x;
}
}
if (y+charh >= seley)
{ {
send = sstart; send = sstart;
for (i = 0; i < linelength; ) for (i = 0; i < linelength; )
@ -1821,7 +1910,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
else else
con->selendoffset = 0; con->selendoffset = 0;
} }
if (y <= selsy) if (y < selsy)
{ {
for (i = 0; i < linelength; i++) for (i = 0; i < linelength; i++)
{ {
@ -1837,10 +1926,14 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
else else
con->selstartoffset = 0; con->selstartoffset = 0;
} }
if (selactive == 1) if (selactive == 1)
{ {
R2D_ImagePaletteColour(0, 1.0); R2D_ImagePaletteColour(0, 1.0);
R2D_FillBlock((sstart*vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((send - sstart)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight); if (send < sstart)
R2D_FillBlock((send*vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((sstart - send)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight);
else
R2D_FillBlock((sstart*vid.width)/(float)vid.rotpixelwidth, (y*vid.height)/(float)vid.rotpixelheight, ((send - sstart)*vid.width)/(float)vid.rotpixelwidth, (Font_CharHeight()*vid.height)/(float)vid.rotpixelheight);
} }
} }
} }
@ -1877,69 +1970,142 @@ void Con_DrawConsole (int lines, qboolean noback)
int selsx, selsy, selex, seley, selactive; int selsx, selsy, selex, seley, selactive;
int top; int top;
qboolean haveprogress; qboolean haveprogress;
console_t *w, *mouseconsole;
if (lines <= 0) con_mouseover = NULL;
return;
//draw any windowed consoles (under main console)
if (Key_Dest_Has(kdm_cwindows))
for (w = &con_main; w; w = w->next)
{
srect_t srect;
if ((w->flags & (CONF_HIDDEN|CONF_ISWINDOW)) != CONF_ISWINDOW)
continue;
if (w->wnd_w > vid.width)
w->wnd_w = vid.width;
if (w->wnd_h > vid.height)
w->wnd_h = vid.height;
if (w->wnd_w < 64)
w->wnd_w = 64;
if (w->wnd_h < 16)
w->wnd_h = 16;
//windows that move off the top of the screen somehow are bad.
if (w->wnd_y > vid.height - 8)
w->wnd_y = vid.height - 8;
if (w->wnd_y < 0)
w->wnd_y = 0;
if (w->wnd_x > vid.width-32)
w->wnd_x = vid.width-32;
if (w->wnd_x < -w->wnd_w+32)
w->wnd_x = -w->wnd_w+32;
if (w->wnd_h < 8)
w->wnd_h = 8;
if (mousecursor_x >= w->wnd_x && mousecursor_x < w->wnd_x+w->wnd_w && mousecursor_y >= w->wnd_y && mousecursor_y < w->wnd_y+w->wnd_h && mousecursor_y > lines)
con_mouseover = w;
w->mousecursor[0] = mousecursor_x - w->wnd_x;
w->mousecursor[1] = mousecursor_y - w->wnd_y;
R2D_ImageColours(0.0, 0.05, 0.1, 0.5);
R2D_FillBlock(w->wnd_x, w->wnd_y, w->wnd_w, w->wnd_h);
Draw_FunStringWidth(w->wnd_x, w->wnd_y, w->title, w->wnd_w-16, 2, (con_curwindow==w)?true:false);
Draw_FunStringWidth(w->wnd_x+w->wnd_w-8, w->wnd_y, "X", 8, 2, (w->buttonsdown == CB_CLOSE&& w->mousecursor[0] > w->wnd_w-8 && w->mousecursor[1] < 8)?true:false);
srect.x = w->wnd_x / vid.width;
srect.y = (w->wnd_y+8) / vid.height;
srect.width = w->wnd_w / vid.width;
srect.height = (w->wnd_h-8) / vid.height;
srect.dmin = -99999;
srect.dmax = 99999;
srect.y = (1-srect.y) - srect.height;
if (srect.width && srect.height)
{
BE_Scissor(&srect);
R2D_ImageColours(0, 0.1, 0.2, 1.0);
if (w->buttonsdown & CB_SIZELEFT)
R2D_FillBlock(w->wnd_x, w->wnd_y+8, 8, w->wnd_h-8);
if (w->buttonsdown & CB_SIZERIGHT)
R2D_FillBlock(w->wnd_x+w->wnd_w-8, w->wnd_y+8, 8, w->wnd_h-8);
if (w->buttonsdown & CB_SIZEBOTTOM)
R2D_FillBlock(w->wnd_x, w->wnd_y+w->wnd_h-8, w->wnd_w, 8);
Con_DrawOneConsole(w, con_curwindow == w && !Key_Dest_Has(kdm_console), font_console, w->wnd_x+8, w->wnd_y, w->wnd_w-16, w->wnd_h-8);
BE_Scissor(NULL);
}
if (w->selstartline)
mouseconsole = w;
if (!con_curwindow)
con_curwindow = w;
}
if (lines > 0)
{
#ifdef QTERM #ifdef QTERM
if (qterms) if (qterms)
QT_Update(); QT_Update();
#endif #endif
// draw the background // draw the background
if (!noback) if (!noback)
R2D_ConsoleBackground (0, lines, scr_con_forcedraw); R2D_ConsoleBackground (0, lines, scr_con_forcedraw);
con_current->unseentext = false; con_current->unseentext = false;
con_current->vislines = lines; con_current->vislines = lines;
top = Con_DrawAlternateConsoles(lines); top = Con_DrawAlternateConsoles(lines);
if (!con_current->display) if (!con_current->display)
con_current->display = con_current->current; con_current->display = con_current->current;
x = 8; x = 8;
y = lines; y = lines;
con_current->mousecursor[0] = mousecursor_x; con_current->mousecursor[0] = mousecursor_x;
con_current->mousecursor[1] = mousecursor_y; con_current->mousecursor[1] = mousecursor_y;
con_current->selstartline = NULL; con_current->selstartline = NULL;
con_current->selendline = NULL; con_current->selendline = NULL;
selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley); selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley);
Font_BeginString(font_console, x, y, &x, &y); Font_BeginString(font_console, x, y, &x, &y);
Font_BeginString(font_console, selsx, selsy, &selsx, &selsy); Font_BeginString(font_console, selsx, selsy, &selsx, &selsy);
Font_BeginString(font_console, selex, seley, &selex, &seley); Font_BeginString(font_console, selex, seley, &selex, &seley);
ex = Font_ScreenWidth(); ex = Font_ScreenWidth();
sx = x; sx = x;
ex -= sx; ex -= sx;
y -= Font_CharHeight();
haveprogress = Con_DrawProgress(x, ex - x, y) != y;
y = Con_DrawInput (con_current, Key_Dest_Has(kdm_console), x, ex - x, y, selactive, selsx, selex, selsy, seley);
l = con_current->display;
y = Con_DrawConsoleLines(con_current, l, sx, ex, y, top, selactive, selsx, selex, selsy, seley);
if (!haveprogress && lines == vid.height)
{
char *version = version_string();
int i;
Font_BeginString(font_console, vid.width, lines, &x, &y);
y -= Font_CharHeight(); y -= Font_CharHeight();
for (i = 0; version[i]; i++) haveprogress = Con_DrawProgress(x, ex - x, y) != y;
x -= Font_CharWidth(version[i] | CON_WHITEMASK|CON_HALFALPHA); y = Con_DrawInput (con_current, Key_Dest_Has(kdm_console), x, ex - x, y, selactive, selsx, selex, selsy, seley);
for (i = 0; version[i]; i++)
x = Font_DrawChar(x, y, version[i] | CON_WHITEMASK|CON_HALFALPHA); l = con_current->display;
y = Con_DrawConsoleLines(con_current, l, sx, ex, y, top, selactive, selsx, selex, selsy, seley);
if (!haveprogress && lines == vid.height)
{
char *version = version_string();
int i;
Font_BeginString(font_console, vid.width, lines, &x, &y);
y -= Font_CharHeight();
for (i = 0; version[i]; i++)
x -= Font_CharWidth(version[i] | CON_WHITEMASK|CON_HALFALPHA);
for (i = 0; version[i]; i++)
x = Font_DrawChar(x, y, version[i] | CON_WHITEMASK|CON_HALFALPHA);
}
Font_EndString(font_console);
mouseconsole = con_mouseover?con_mouseover:con_current;
} }
else
mouseconsole = con_mouseover?con_mouseover:NULL;
Font_EndString(font_console); if (mouseconsole && mouseconsole->selstartline)
if (con_current->selstartline)
{ {
char *mouseover = Con_CopyConsole(false, true); char *mouseover = Con_CopyConsole(mouseconsole, false, true);
if (mouseover) if (mouseover)
{ {
char *end = strstr(mouseover, "^]"); char *end = strstr(mouseover, "^]");
@ -1992,7 +2158,7 @@ void Con_DrawConsole (int lines, qboolean noback)
} }
} }
void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy, float fsx, float fsy) void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, float fx, float fy, float fsx, float fsy)
{ {
int selactive, selsx, selsy, selex, seley; int selactive, selsx, selsy, selex, seley;
int x, y, sx, sy; int x, y, sx, sy;
@ -2018,7 +2184,7 @@ void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy,
seley += y; seley += y;
} }
sy = Con_DrawInput (con, con->flags & CONF_KEYFOCUSED, x, sx, sy, selactive, selsx, selex, selsy, seley); sy = Con_DrawInput (con, focused, x, sx, sy, selactive, selsx, selex, selsy, seley);
if (!con->display) if (!con->display)
con->display = con->current; con->display = con->current;
@ -2028,9 +2194,8 @@ void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy,
} }
char *Con_CopyConsole(qboolean nomarkup, qboolean onlyiflink) char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink)
{ {
console_t *con = con_current;
conchar_t *cur; conchar_t *cur;
conline_t *l; conline_t *l;
conchar_t *lend; conchar_t *lend;

View file

@ -53,6 +53,7 @@ typedef struct {
stat ownsuicides; stat ownsuicides;
char *fullname; char *fullname;
char *abrev; char *abrev;
char *image;
char *codename; char *codename;
} weapontotals[MAX_WEAPONS]; } weapontotals[MAX_WEAPONS];
@ -75,6 +76,7 @@ typedef struct {
statmessage_t *message; statmessage_t *message;
} fragstats_t; } fragstats_t;
cvar_t r_tracker_frags = CVARD("r_tracker_frags", "0", "0: like vanilla quake\n1: shows only your kills/deaths\n2: shows all kills\n");
static fragstats_t fragstats; static fragstats_t fragstats;
int Stats_GetKills(int playernum) int Stats_GetKills(int playernum)
@ -107,8 +109,149 @@ qboolean Stats_HaveKills(void)
return fragstats.readkills; return fragstats.readkills;
} }
void VARGS Stats_Message(char *msg, ...) void VARGS Stats_Message(char *msg, ...);
static char *Stats_GenTrackerImageString(char *in)
{ //images are of the form "foo \sg\ bar \q\"
//which should eg be remapped to: "foo ^Ue200 bar foo ^Ue201"
char res[256];
char image[MAX_QPATH];
char *outi;
char *out;
int i;
if (!in || !*in)
return NULL;
for (out = res; *in && out < res+sizeof(res)-10; )
{
if (*in == '\\')
{
in++;
for (outi = image; *in && outi < image+sizeof(image)-10; )
{
if (*in == '\\')
break;
*outi++ = *in++;
}
*outi = 0;
in++;
i = Font_RegisterTrackerImage(va("tracker/%s", image));
if (i)
{
char hexchars[16] = "0123456789abcdef";
*out++ = '^';
*out++ = 'U';
*out++ = hexchars[(i>>12)&15];
*out++ = hexchars[(i>>8)&15];
*out++ = hexchars[(i>>4)&15];
*out++ = hexchars[(i>>0)&15];
}
else
{
//just copy the short name over, not much else we can do.
for(outi = image; out < res+sizeof(res)-10 && *outi; )
*out++ = *outi++;
}
}
else
*out++ = *in++;
}
*out = 0;
return Z_StrDup(res);
}
void Stats_FragMessage(int p1, int wid, int p2, qboolean teamkill)
{ {
static const char *nonplayers[] = {
"BUG",
"(teamkill)",
"(suicide)",
"(death)",
"(unknown)",
"(fixme)",
"(fixme)"
};
char message[512];
console_t *tracker;
struct wt_s *w = &fragstats.weapontotals[wid];
const char *p1n = (p1 < 0)?nonplayers[-p1]:cl.players[p1].name;
const char *p2n = (p2 < 0)?nonplayers[-p2]:cl.players[p2].name;
int localplayer = (cl.spectator && cl.playerview[0].cam_locked)?cl.playerview[0].cam_spec_track:cl.playerview[0].playernum;
#define YOU_GOOD S_COLOR_GREEN
#define YOU_BAD S_COLOR_BLUE
#define TEAM_GOOD S_COLOR_GREEN
#define TEAM_BAD S_COLOR_RED
#define TEAM_VBAD S_COLOR_BLUE
#define TEAM_NEUTRAL S_COLOR_WHITE //enemy team thing that does not directly affect us
#define ENEMY_GOOD S_COLOR_RED
#define ENEMY_BAD S_COLOR_GREEN
#define ENEMY_NEUTRAL S_COLOR_WHITE
char *p1c = S_COLOR_WHITE;
char *p2c = S_COLOR_WHITE;
if (!r_tracker_frags.ival)
return;
if (r_tracker_frags.ival < 2)
if (p1 != localplayer && p2 != localplayer)
return;
if (teamkill)
{//team kills/suicides are always considered bad.
if (p1 == localplayer)
p1c = YOU_BAD;
else if (cl.teamplay && !strcmp(cl.players[p1].team, cl.players[localplayer].team))
p1c = TEAM_VBAD;
else
p1c = TEAM_NEUTRAL;
p2c = p1c;
}
else if (p1 == p2)
p1c = p2c = YOU_BAD;
else if (cl.teamplay && p1 >= 0 && p2 >= 0 && !strcmp(cl.players[p1].team, cl.players[p2].team))
p1c = p2c = TEAM_VBAD;
else
{
if (p2 >= 0)
{
//us/teammate killing is good - unless it was a teammate.
if (p2 == localplayer)
p2c = YOU_GOOD;
else if (cl.teamplay && !strcmp(cl.players[p2].team, cl.players[localplayer].team))
p2c = TEAM_GOOD;
else
p2c = ENEMY_GOOD;
}
if (p1 >= 0)
{
//us/teammate dying is bad.
if (p1 == localplayer)
p1c = YOU_BAD;
else if (cl.teamplay && !strcmp(cl.players[p1].team, cl.players[localplayer].team))
p1c = TEAM_BAD;
else
p1c = p2c;
}
}
Q_snprintfz(message, sizeof(message), "%s%s ^7%s %s%s\n", p1c, p1n, w->image?w->image:w->abrev, p2c, p2n);
tracker = Con_FindConsole("tracker");
if (!tracker)
{
tracker = Con_Create("tracker", CONF_HIDDEN|CONF_NOTIFY|CONF_NOTIFY_RIGHT|CONF_NOTIFY_BOTTOM);
//this stuff should be configurable
tracker->notif_l = tracker->maxlines = 8;
tracker->notif_x = 0.5;
tracker->notif_y = 0.333;
tracker->notif_w = 1-tracker->notif_x;
tracker->notif_t = 4;
tracker->notif_fade = 1;
}
Con_PrintCon(tracker, message, tracker->parseflags);
} }
void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2) void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
@ -126,6 +269,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
u1 = (p1 == (cl.playerview[0].playernum)); u1 = (p1 == (cl.playerview[0].playernum));
u2 = (p2 == (cl.playerview[0].playernum)); u2 = (p2 == (cl.playerview[0].playernum));
//messages are killed weapon killer
switch(mt) switch(mt)
{ {
case ff_death: case ff_death:
@ -134,9 +278,15 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].owndeaths++; fragstats.weapontotals[wid].owndeaths++;
fragstats.weapontotals[wid].ownkills++; fragstats.weapontotals[wid].ownkills++;
} }
fragstats.weapontotals[wid].kills++; fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].deaths++; fragstats.clienttotals[p1].deaths++;
fragstats.totaldeaths++; fragstats.totaldeaths++;
Stats_FragMessage(p1, wid, -3, true);
if (u1)
Stats_Message("You died\n%s deaths: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].owndeaths);
break; break;
case ff_suicide: case ff_suicide:
if (u1) if (u1)
@ -144,15 +294,18 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].ownsuicides++; fragstats.weapontotals[wid].ownsuicides++;
fragstats.weapontotals[wid].owndeaths++; fragstats.weapontotals[wid].owndeaths++;
fragstats.weapontotals[wid].ownkills++; fragstats.weapontotals[wid].ownkills++;
Stats_Message("You are a fool\n");
} }
fragstats.weapontotals[wid].suicides++; fragstats.weapontotals[wid].suicides++;
fragstats.weapontotals[wid].kills++; fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].suisides++; fragstats.clienttotals[p1].suisides++;
fragstats.clienttotals[p1].deaths++; fragstats.clienttotals[p1].deaths++;
fragstats.totalsuicides++; fragstats.totalsuicides++;
fragstats.totaldeaths++; fragstats.totaldeaths++;
Stats_FragMessage(p1, wid, -2, true);
if (u1)
Stats_Message("You killed your own dumb self\n%s suicides: %i (%i)\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].ownsuicides, fragstats.weapontotals[wid].suicides);
break; break;
case ff_bonusfrag: case ff_bonusfrag:
if (u1) if (u1)
@ -160,6 +313,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].kills++; fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].kills++; fragstats.clienttotals[p1].kills++;
fragstats.totalkills++; fragstats.totalkills++;
Stats_FragMessage(-4, wid, p1, false);
if (u1)
Stats_Message("You killed someone\n%s kills: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].ownkills);
break; break;
case ff_tkbonus: case ff_tkbonus:
if (u1) if (u1)
@ -173,6 +330,11 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].teamkills++; fragstats.weapontotals[wid].teamkills++;
fragstats.clienttotals[p1].teamkills++; fragstats.clienttotals[p1].teamkills++;
fragstats.totalteamkills++; fragstats.totalteamkills++;
Stats_FragMessage(-1, wid, p1, true);
if (u1)
Stats_Message("You killed your teammate\n%s teamkills: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].ownteamkills);
break; break;
case ff_flagtouch: case ff_flagtouch:
fragstats.clienttotals[p1].grabs++; fragstats.clienttotals[p1].grabs++;
@ -180,8 +342,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1) if (u1)
{ {
Stats_Message("You grabbed the flag\n"); Stats_Message("You grabbed the flag\nflag grabs: %i (%i)\n", fragstats.clienttotals[p1].grabs, fragstats.totaltouches);
Stats_Message("flag grabs: %i (%i)\n", fragstats.clienttotals[p1].grabs, fragstats.totaltouches);
} }
break; break;
case ff_flagcaps: case ff_flagcaps:
@ -190,8 +351,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1) if (u1)
{ {
Stats_Message("You captured the flag\n"); Stats_Message("You captured the flag\nflag captures: %i (%i)\n", fragstats.clienttotals[p1].caps, fragstats.totalcaps);
Stats_Message("flag captures: %i (%i)\n", fragstats.clienttotals[p1].caps, fragstats.totalcaps);
} }
break; break;
case ff_flagdrops: case ff_flagdrops:
@ -200,8 +360,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1) if (u1)
{ {
Stats_Message("You dropped the flag\n"); Stats_Message("You dropped the flag\nflag drops: %i (%i)\n", fragstats.clienttotals[p1].drops, fragstats.totaldrops);
Stats_Message("flag drops: %i (%i)\n", fragstats.clienttotals[p1].drops, fragstats.totaldrops);
} }
break; break;
@ -215,8 +374,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1) if (u1)
{ {
fragstats.weapontotals[wid].owndeaths++; fragstats.weapontotals[wid].owndeaths++;
Stats_Message("%s killed you\n", cl.players[p2].name); Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
Stats_Message("%s deaths: %i (%i/%i)\n", fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
} }
fragstats.clienttotals[p2].kills++; fragstats.clienttotals[p2].kills++;
@ -224,9 +382,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u2) if (u2)
{ {
fragstats.weapontotals[wid].ownkills++; fragstats.weapontotals[wid].ownkills++;
Stats_Message("You killed %s\n", cl.players[p1].name); Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
Stats_Message("%s kills: %i (%i/%i)\n", fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
} }
Stats_FragMessage(p1, wid, p2, false);
break; break;
case ff_tkdeath: case ff_tkdeath:
//killed by a teammate, but we don't know who //killed by a teammate, but we don't know who
@ -236,9 +395,16 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.totalkills++; //its a kill, but we don't know who from fragstats.totalkills++; //its a kill, but we don't know who from
fragstats.totalteamkills++; fragstats.totalteamkills++;
if (u1)
fragstats.weapontotals[wid].owndeaths++;
fragstats.clienttotals[p1].teamdeaths++; fragstats.clienttotals[p1].teamdeaths++;
fragstats.clienttotals[p1].deaths++; fragstats.clienttotals[p1].deaths++;
fragstats.totaldeaths++; fragstats.totaldeaths++;
Stats_FragMessage(p1, wid, -1, true);
if (u1)
Stats_Message("Your teammate killed you\n%s deaths: %i\n", fragstats.weapontotals[wid].fullname, fragstats.weapontotals[wid].owndeaths);
break; break;
case ff_tkills: case ff_tkills:
@ -266,6 +432,12 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.totalkills++; fragstats.totalkills++;
fragstats.totalteamkills++; fragstats.totalteamkills++;
Stats_FragMessage(p1, wid, p2, false);
if (u1)
Stats_Message("%s killed you\n%s deaths: %i (%i/%i)\n", cl.players[p2].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
if (u2)
Stats_Message("You killed %s\n%s kills: %i (%i/%i)\n", cl.players[p1].name, fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
break; break;
} }
} }
@ -344,6 +516,7 @@ void Stats_Clear(void)
if (fragstats.weapontotals[i].codename) Z_Free(fragstats.weapontotals[i].codename); if (fragstats.weapontotals[i].codename) Z_Free(fragstats.weapontotals[i].codename);
if (fragstats.weapontotals[i].fullname) Z_Free(fragstats.weapontotals[i].fullname); if (fragstats.weapontotals[i].fullname) Z_Free(fragstats.weapontotals[i].fullname);
if (fragstats.weapontotals[i].abrev) Z_Free(fragstats.weapontotals[i].abrev); if (fragstats.weapontotals[i].abrev) Z_Free(fragstats.weapontotals[i].abrev);
if (fragstats.weapontotals[i].image) Z_Free(fragstats.weapontotals[i].image);
} }
memset(&fragstats, 0, sizeof(fragstats)); memset(&fragstats, 0, sizeof(fragstats));
@ -424,6 +597,7 @@ static void Stats_LoadFragFile(char *name)
{ {
fragstats.weapontotals[wid].fullname = Z_Copy(Cmd_Argv(3)); fragstats.weapontotals[wid].fullname = Z_Copy(Cmd_Argv(3));
fragstats.weapontotals[wid].abrev = Z_Copy(Cmd_Argv(4)); fragstats.weapontotals[wid].abrev = Z_Copy(Cmd_Argv(4));
fragstats.weapontotals[wid].image = Stats_GenTrackerImageString(Cmd_Argv(5));
} }
} }
else if (!stricmp(tk, "obituary") || else if (!stricmp(tk, "obituary") ||
@ -526,7 +700,7 @@ static int Stats_ExtractName(char **line)
return bm; return bm;
} }
void Stats_ParsePrintLine(char *line) qboolean Stats_ParsePrintLine(char *line)
{ {
statmessage_t *ms; statmessage_t *ms;
int p1; int p1;
@ -536,7 +710,7 @@ void Stats_ParsePrintLine(char *line)
p1 = Stats_ExtractName(&line); p1 = Stats_ExtractName(&line);
if (p1<0) //reject it. if (p1<0) //reject it.
{ {
return; return false;
} }
for (ms = fragstats.message; ms; ms = ms->next) for (ms = fragstats.message; ms; ms = ms->next)
@ -552,16 +726,17 @@ void Stats_ParsePrintLine(char *line)
if (!qm_stricmp(ms->msgpart2, m2)) if (!qm_stricmp(ms->msgpart2, m2))
{ {
Stats_Evaluate(ms->type, ms->wid, p1, p2); Stats_Evaluate(ms->type, ms->wid, p1, p2);
return; //done. return true; //done.
} }
} }
else else
{ //one player { //one player
Stats_Evaluate(ms->type, ms->wid, p1, p1); Stats_Evaluate(ms->type, ms->wid, p1, p1);
return; //done. return true; //done.
} }
} }
} }
return false;
} }
void Stats_NewMap(void) void Stats_NewMap(void)

View file

@ -846,7 +846,7 @@ struct pngerr
static void VARGS png_onerror(png_structp png_ptr, png_const_charp error_msg) static void VARGS png_onerror(png_structp png_ptr, png_const_charp error_msg)
{ {
struct pngerr *err = qpng_get_error_ptr(png_ptr); struct pngerr *err = qpng_get_error_ptr(png_ptr);
Con_Printf("libpng %s: %s", err->fname, error_msg); Con_Printf("libpng %s: %s\n", err->fname, error_msg);
longjmp(err->jbuf, 1); longjmp(err->jbuf, 1);
abort(); abort();
} }
@ -854,7 +854,7 @@ static void VARGS png_onerror(png_structp png_ptr, png_const_charp error_msg)
static void VARGS png_onwarning(png_structp png_ptr, png_const_charp warning_msg) static void VARGS png_onwarning(png_structp png_ptr, png_const_charp warning_msg)
{ {
struct pngerr *err = qpng_get_error_ptr(png_ptr); struct pngerr *err = qpng_get_error_ptr(png_ptr);
Con_Printf("libpng %s: %s\n", err->fname, warning_msg); Con_DPrintf("libpng %s: %s\n", err->fname, warning_msg);
} }
qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *fname) qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *fname)
@ -2820,7 +2820,7 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla
case PTI_RGBX8: case PTI_RGBX8:
case PTI_BGRA8: case PTI_BGRA8:
case PTI_BGRX8: case PTI_BGRX8:
for (mip = 1; mip < 32; mip++) for (mip = mips->mipcount; mip < 32; mip++)
{ {
mips->mip[mip].width = mips->mip[mip-1].width >> 1; mips->mip[mip].width = mips->mip[mip-1].width >> 1;
mips->mip[mip].height = mips->mip[mip-1].height >> 1; mips->mip[mip].height = mips->mip[mip-1].height >> 1;
@ -3418,7 +3418,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_RGBA32F: case TF_RGBA32F:
if (rawdata) if (rawdata)
{ {
Con_Printf("R_LoadRawTexture: bad format"); Con_Printf("R_LoadRawTexture: bad format\n");
if (freedata) if (freedata)
BZ_Free(rawdata); BZ_Free(rawdata);
return false; return false;
@ -3428,7 +3428,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
default: default:
case TF_INVALID: case TF_INVALID:
Con_Printf("R_LoadRawTexture: bad format"); Con_Printf("R_LoadRawTexture: bad format\n");
if (freedata) if (freedata)
BZ_Free(rawdata); BZ_Free(rawdata);
return false; return false;
@ -3444,9 +3444,78 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_BGRA32: case TF_BGRA32:
mips->encoding = PTI_BGRA8; mips->encoding = PTI_BGRA8;
break; break;
case TF_MIP4_LUM8:
//8bit opaque data
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags);
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight)
{
unsigned int pixels =
(imgwidth>>0) * (imgheight>>0) +
(imgwidth>>1) * (imgheight>>1) +
(imgwidth>>2) * (imgheight>>2) +
(imgwidth>>3) * (imgheight>>3);
mips->encoding = PTI_R8;
rgbadata = BZ_Malloc(pixels);
memcpy(rgbadata, rawdata, pixels);
for (i = 0; i < 4; i++)
{
mips->mip[i].width = imgwidth>>i;
mips->mip[i].height = imgheight>>i;
mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height;
mips->mip[i].needfree = false;
}
mips->mipcount = i;
mips->mip[0].data = rgbadata;
mips->mip[1].data = (qbyte*)mips->mip[0].data + mips->mip[0].datasize;
mips->mip[2].data = (qbyte*)mips->mip[1].data + mips->mip[1].datasize;
mips->mip[3].data = (qbyte*)mips->mip[2].data + mips->mip[2].datasize;
mips->extrafree = rgbadata;
if (freedata)
BZ_Free(rawdata);
return true;
}
//fall through
case TF_LUM8: case TF_LUM8:
mips->encoding = PTI_R8; mips->encoding = PTI_R8;
break; break;
case TF_MIP4_SOLID8:
//8bit opaque data
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags);
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight && sh_config.texfmt[PTI_RGBX8])
{
unsigned int pixels =
(imgwidth>>0) * (imgheight>>0) +
(imgwidth>>1) * (imgheight>>1) +
(imgwidth>>2) * (imgheight>>2) +
(imgwidth>>3) * (imgheight>>3);
mips->encoding = PTI_RGBX8;
rgbadata = BZ_Malloc(pixels*4);
for (i = 0; i < pixels; i++)
rgbadata[i] = d_8to24rgbtable[((qbyte*)rawdata)[i]];
for (i = 0; i < 4; i++)
{
mips->mip[i].width = imgwidth>>i;
mips->mip[i].height = imgheight>>i;
mips->mip[i].datasize = mips->mip[i].width * mips->mip[i].height * 4;
mips->mip[i].needfree = false;
}
mips->mipcount = i;
mips->mip[0].data = rgbadata;
mips->mip[1].data = (qbyte*)mips->mip[0].data + mips->mip[0].datasize;
mips->mip[2].data = (qbyte*)mips->mip[1].data + mips->mip[1].datasize;
mips->mip[3].data = (qbyte*)mips->mip[2].data + mips->mip[2].datasize;
mips->extrafree = rgbadata;
if (freedata)
BZ_Free(rawdata);
return true;
}
//fall through
case TF_SOLID8: case TF_SOLID8:
rgbadata = BZ_Malloc(imgwidth * imgheight*4); rgbadata = BZ_Malloc(imgwidth * imgheight*4);
if (sh_config.texfmt[PTI_BGRX8]) if (sh_config.texfmt[PTI_BGRX8])
@ -4185,9 +4254,12 @@ image_t *Image_CreateTexture (const char *identifier, const char *subdir, unsign
image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt) image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned int flags, void *fallbackdata, void *fallbackpalette, int fallbackwidth, int fallbackheight, uploadfmt_t fallbackfmt)
{ {
image_t *tex; image_t *tex;
static int seq;
qboolean dontposttoworker = (flags & (IF_NOWORKER | IF_LOADNOW)); qboolean dontposttoworker = (flags & (IF_NOWORKER | IF_LOADNOW));
flags &= ~IF_LOADNOW; qboolean lowpri = (flags & IF_LOWPRIORITY);
qboolean highpri = (flags & IF_HIGHPRIORITY);
flags &= ~(IF_LOADNOW | IF_LOWPRIORITY | IF_HIGHPRIORITY);
#ifdef LOADERTHREAD #ifdef LOADERTHREAD
Sys_LockMutex(com_resourcemutex); Sys_LockMutex(com_resourcemutex);
@ -4214,16 +4286,16 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
tex->status = TEX_LOADING; tex->status = TEX_LOADING;
if (fallbackdata) if (fallbackdata)
{ {
int b, pb = 0; int b = fallbackwidth*fallbackheight, pb = 0;
switch(fallbackfmt) switch(fallbackfmt)
{ {
case TF_8PAL24: case TF_8PAL24:
pb = 3*256; pb = 3*256;
b = 1; b *= 1;
break; break;
case TF_8PAL32: case TF_8PAL32:
pb = 4*256; pb = 4*256;
b = 1; b *= 1;
break; break;
case TF_LUM8: case TF_LUM8:
case TF_SOLID8: case TF_SOLID8:
@ -4234,21 +4306,28 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
case TF_H2_T4A4: case TF_H2_T4A4:
case TF_HEIGHT8: case TF_HEIGHT8:
case TF_HEIGHT8PAL: //we don't care about the actual palette. case TF_HEIGHT8PAL: //we don't care about the actual palette.
b = 1; b *= 1;
break; break;
case TF_RGBX32: case TF_RGBX32:
case TF_RGBA32: case TF_RGBA32:
case TF_BGRX32: case TF_BGRX32:
case TF_BGRA32: case TF_BGRA32:
b = 4; b *= 4;
break;
case TF_MIP4_LUM8:
case TF_MIP4_SOLID8:
b = (fallbackwidth>>0)*(fallbackheight>>0) +
(fallbackwidth>>1)*(fallbackheight>>1) +
(fallbackwidth>>2)*(fallbackheight>>2) +
(fallbackwidth>>3)*(fallbackheight>>3);
break; break;
default: default:
Sys_Error("Image_GetTexture: bad format"); Sys_Error("Image_GetTexture: bad format");
} }
tex->fallbackdata = BZ_Malloc(fallbackwidth*fallbackheight*b + pb); tex->fallbackdata = BZ_Malloc(b + pb);
memcpy(tex->fallbackdata, fallbackdata, fallbackwidth*fallbackheight*b); memcpy(tex->fallbackdata, fallbackdata, b);
if (pb) if (pb)
memcpy((qbyte*)tex->fallbackdata + fallbackwidth*fallbackheight*b, fallbackpalette, pb); memcpy((qbyte*)tex->fallbackdata + b, fallbackpalette, pb);
tex->fallbackwidth = fallbackwidth; tex->fallbackwidth = fallbackwidth;
tex->fallbackheight = fallbackheight; tex->fallbackheight = fallbackheight;
tex->fallbackfmt = fallbackfmt; tex->fallbackfmt = fallbackfmt;
@ -4268,7 +4347,12 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
if (dontposttoworker) if (dontposttoworker)
Image_LoadHiResTextureWorker(tex, NULL, 0, 0); Image_LoadHiResTextureWorker(tex, NULL, 0, 0);
else else
COM_AddWork(1, Image_LoadHiResTextureWorker, tex, NULL, 0, 0); {
if (lowpri)
COM_AddWork(5, Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
else
COM_AddWork(2+(seq++%3), Image_LoadHiResTextureWorker, tex, NULL, 0, 0);
}
return tex; return tex;
} }
void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags) void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags)

View file

@ -114,6 +114,44 @@ void IN_ReInit(void)
INS_ReInit(); INS_ReInit();
} }
struct remapctx
{
char *type;
char *devicename;
int newdevid;
};
static void IN_DeviceIDs_DoRemap(void *vctx, char *type, char *devicename, int *qdevid)
{
struct remapctx *ctx = vctx;
if (!strcmp(ctx->type, type))
if (!strcmp(ctx->devicename, devicename))
*qdevid = ctx->newdevid;
}
void IN_DeviceIDs_Enumerate(void *ctx, char *type, char *devicename, int *qdevid)
{
if (!qdevid)
Con_Printf("%s (%s): %s\n", type, devicename, "device cannot be remapped");
else
Con_Printf("%s (%s): %i\n", type, devicename, *qdevid);
}
void IN_DeviceIDs_f(void)
{
int i;
char *s;
struct remapctx ctx;
if (Cmd_Argc() > 3)
{
ctx.type = Cmd_Argv(1);
ctx.devicename = Cmd_Argv(2);
ctx.newdevid = atoi(Cmd_Argv(3));
INS_EnumerateDevices(&ctx, IN_DeviceIDs_DoRemap);
}
else
INS_EnumerateDevices(NULL, IN_DeviceIDs_Enumerate);
}
void IN_Init(void) void IN_Init(void)
{ {
events_avail = 0; events_avail = 0;
@ -128,6 +166,8 @@ void IN_Init(void)
Cvar_Register (&m_slidethreshold, "input controls"); Cvar_Register (&m_slidethreshold, "input controls");
Cvar_Register (&m_touchmajoraxis, "input controls"); Cvar_Register (&m_touchmajoraxis, "input controls");
Cmd_AddCommand ("in_deviceids", IN_DeviceIDs_f);
INS_Init(); INS_Init();
} }

View file

@ -213,6 +213,9 @@ void INS_ProcessInputMessage(struct InputEvent *msg, qboolean consumemotion)
void INS_Commands(void) void INS_Commands(void)
{ {
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
}
void INS_Move (float *movements, int pnum) void INS_Move (float *movements, int pnum)
{ {
} }

View file

@ -913,6 +913,8 @@ void INS_Accumulate(void) //input polling
void INS_Commands (void) //used to Cbuf_AddText joystick button events in windows. void INS_Commands (void) //used to Cbuf_AddText joystick button events in windows.
{ {
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
}

View file

@ -65,6 +65,8 @@ static cvar_t cl_keypad = CVAR("cl_keypad", "1");
extern float multicursor_x[8], multicursor_y[8]; extern float multicursor_x[8], multicursor_y[8];
extern qboolean multicursor_active[8]; extern qboolean multicursor_active[8];
POINT current_mouse_pos;
typedef struct { typedef struct {
union { union {
HANDLE rawinputhandle; HANDLE rawinputhandle;
@ -534,9 +536,18 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
else else
grabmouse = false; grabmouse = false;
//visiblity if (activeapp)
if (!SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || grabmouse || (activeapp && mousecursor_x > 0 && mousecursor_y > 0 && mousecursor_x < vid.pixelwidth-1 && mousecursor_y < vid.pixelheight-1))) {
INS_HideMouse(); if (!SCR_HardwareCursorIsActive() && (fullscreen || in_simulatemultitouch.ival || _windowed_mouse.value) && (current_mouse_pos.x >= window_rect.left && current_mouse_pos.y >= window_rect.top && current_mouse_pos.x <= window_rect.right && current_mouse_pos.y <= window_rect.bottom))
{
INS_HideMouse();
}
else
{
INS_ShowMouse();
grabmouse = false;
}
}
else else
{ {
INS_ShowMouse(); INS_ShowMouse();
@ -573,7 +584,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
#ifdef AVAIL_DINPUT #ifdef AVAIL_DINPUT
BOOL CALLBACK INS_EnumerateDevices(LPCDIDEVICEINSTANCE inst, LPVOID parm) BOOL CALLBACK INS_EnumerateDI7Devices(LPCDIDEVICEINSTANCE inst, LPVOID parm)
{ {
Con_DPrintf("EnumerateDevices found: %s\n", inst->tszProductName); Con_DPrintf("EnumerateDevices found: %s\n", inst->tszProductName);
@ -620,7 +631,7 @@ int INS_InitDInput (void)
if (FAILED(hr)) if (FAILED(hr))
return 0; return 0;
IDirectInput7_EnumDevices(g_pdi7, 0, &INS_EnumerateDevices, NULL, DIEDFL_ATTACHEDONLY); IDirectInput7_EnumDevices(g_pdi7, 0, &INS_EnumerateDI7Devices, NULL, DIEDFL_ATTACHEDONLY);
// obtain an interface to the system mouse device. // obtain an interface to the system mouse device.
hr = IDirectInput7_CreateDeviceEx(g_pdi7, &fGUID_SysMouse, &fIID_IDirectInputDevice7A, &g_pMouse7, NULL); hr = IDirectInput7_CreateDeviceEx(g_pdi7, &fGUID_SysMouse, &fIID_IDirectInputDevice7A, &g_pMouse7, NULL);
@ -678,7 +689,7 @@ int INS_InitDInput (void)
{ {
return 0; return 0;
} }
IDirectInput_EnumDevices(g_pdi, 0, &INS_EnumerateDevices, NULL, DIEDFL_ATTACHEDONLY); IDirectInput_EnumDevices(g_pdi, 0, &INS_EnumerateDI7Devices, NULL, DIEDFL_ATTACHEDONLY);
// obtain an interface to the system mouse device. // obtain an interface to the system mouse device.
hr = IDirectInput_CreateDevice(g_pdi, &fGUID_SysMouse, &g_pMouse, NULL); hr = IDirectInput_CreateDevice(g_pdi, &fGUID_SysMouse, &g_pMouse, NULL);
@ -1330,6 +1341,8 @@ void INS_Move (float *movements, int pnum)
INS_MouseMove (movements, pnum); INS_MouseMove (movements, pnum);
INS_JoyMove (movements, pnum); INS_JoyMove (movements, pnum);
} }
else
INS_Accumulate();
} }
@ -1341,8 +1354,6 @@ potentially called multiple times per frame.
*/ */
void INS_Accumulate (void) void INS_Accumulate (void)
{ {
static POINT current_pos; //static to avoid bugs in vista(32) with largeaddressaware (this is fixed in win7). fixed exe base address prevents this from going above 2gb.
if (mouseactive && !dinput) if (mouseactive && !dinput)
{ {
#ifdef USINGRAWINPUT #ifdef USINGRAWINPUT
@ -1350,9 +1361,9 @@ void INS_Accumulate (void)
if (!rawmicecount) if (!rawmicecount)
#endif #endif
{ {
GetCursorPos (&current_pos); GetCursorPos (&current_mouse_pos);
IN_MouseMove(sysmouse.qdeviceid, false, current_pos.x - window_center_x, current_pos.y - window_center_y, 0, 0); IN_MouseMove(sysmouse.qdeviceid, false, current_mouse_pos.x - window_center_x, current_mouse_pos.y - window_center_y, 0, 0);
} }
// force the mouse to the center, so there's room to move (rawinput ignore this apparently) // force the mouse to the center, so there's room to move (rawinput ignore this apparently)
@ -1362,9 +1373,9 @@ void INS_Accumulate (void)
if (!mouseactive) if (!mouseactive)
{ {
extern int window_x, window_y; extern int window_x, window_y;
GetCursorPos (&current_pos); GetCursorPos (&current_mouse_pos);
IN_MouseMove(sysmouse.qdeviceid, true, current_pos.x-window_x, current_pos.y-window_y, 0, 0); IN_MouseMove(sysmouse.qdeviceid, true, current_mouse_pos.x-window_x, current_mouse_pos.y-window_y, 0, 0);
return; return;
} }
} }
@ -1790,6 +1801,15 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
} }
else else
{ {
joy->povstate = 0;
joy->buttonstate = 0;
joy->axis[JOY_AXIS_X] = 32768;
joy->axis[JOY_AXIS_Y] = 32768;
joy->axis[JOY_AXIS_Z] = 32768;
joy->axis[JOY_AXIS_R] = 32768;
joy->axis[JOY_AXIS_U] = 32768;
joy->axis[JOY_AXIS_V] = 32768;
// read error occurred // read error occurred
// turning off the joystick seems too harsh for 1 read error, // turning off the joystick seems too harsh for 1 read error,
// but what should be done? // but what should be done?
@ -1994,10 +2014,29 @@ void INS_JoyMove (float *movements, int pnum)
for (idx = 0; idx < joy_count; idx++) for (idx = 0; idx < joy_count; idx++)
{ {
INS_JoyMovePtr(&wjoy[idx], movements, idx); INS_JoyMovePtr(&wjoy[idx], movements, pnum);
} }
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
int idx;
for (idx = 0; idx < rawmicecount; idx++)
callback(ctx, "mouse", va("raw%i", idx), &rawmice[idx].qdeviceid);
for (idx = 0; idx < rawkbdcount; idx++)
callback(ctx, "keyboard", va("rawi", idx), &rawkbd[idx].qdeviceid);
if (dinput >= DINPUT_VERSION_DX7 && g_pMouse7)
callback(ctx, "mouse", "di7", NULL);
else if (dinput && g_pMouse7)
callback(ctx, "mouse", "di", NULL);
callback(ctx, "mouse", "system", NULL);
for (idx = 0; idx < joy_count; idx++)
callback(ctx, "joy", va("mmj%i", idx), &wjoy[idx].devid);
}
static qbyte scantokey[] = static qbyte scantokey[] =
{ {
// 0 1 2 3 4 5 6 7 // 0 1 2 3 4 5 6 7

View file

@ -57,6 +57,7 @@ void INS_ReInit (void);
void INS_Init (void); void INS_Init (void);
void INS_Shutdown (void); void INS_Shutdown (void);
void INS_Commands (void); //final chance to call IN_MouseMove/IN_KeyEvent each frame void INS_Commands (void); //final chance to call IN_MouseMove/IN_KeyEvent each frame
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid));
extern cvar_t cl_nodelta; extern cvar_t cl_nodelta;
extern cvar_t cl_c2spps; extern cvar_t cl_c2spps;

View file

@ -338,9 +338,9 @@ void CompleteCommand (qboolean force)
con_commandmatch = 1; con_commandmatch = 1;
if (desc) if (desc)
Con_Footerf(false, "%s: %s", cmd, desc); Con_Footerf(NULL, false, "%s: %s", cmd, desc);
else else
Con_Footerf(false, ""); Con_Footerf(NULL, false, "");
return; return;
} }
} }
@ -374,27 +374,27 @@ void CompleteCommand (qboolean force)
if (var) if (var)
{ {
if (desc) if (desc)
Con_Footerf(false, "%s %s\n%s", cmd, var->string, desc); Con_Footerf(NULL, false, "%s %s\n%s", cmd, var->string, desc);
else else
Con_Footerf(false, "%s %s", cmd, var->string); Con_Footerf(NULL, false, "%s %s", cmd, var->string);
} }
else else
{ {
if (desc) if (desc)
Con_Footerf(false, "%s: %s", cmd, desc); Con_Footerf(NULL, false, "%s: %s", cmd, desc);
else else
Con_Footerf(false, ""); Con_Footerf(NULL, false, "");
} }
} }
else else
{ {
Con_Footerf(false, ""); Con_Footerf(NULL, false, "");
con_commandmatch = 1; con_commandmatch = 1;
} }
} }
//lines typed at the main console enter here //lines typed at the main console enter here
void Con_ExecuteLine(console_t *con, char *line) int Con_ExecuteLine(console_t *con, char *line)
{ {
qboolean waschat = false; qboolean waschat = false;
char deutf8[8192]; char deutf8[8192];
@ -413,7 +413,7 @@ void Con_ExecuteLine(console_t *con, char *line)
} }
con_commandmatch=1; con_commandmatch=1;
Con_Footerf(false, ""); Con_Footerf(con, false, "");
if (cls.state >= ca_connected && cl_chatmode.value == 2) if (cls.state >= ca_connected && cl_chatmode.value == 2)
{ {
@ -465,10 +465,10 @@ void Con_ExecuteLine(console_t *con, char *line)
{ {
Con_Printf ("]%s\n",line); Con_Printf ("]%s\n",line);
Cmd_ExecuteString(exec, RESTRICT_SERVER); Cmd_ExecuteString(exec, RESTRICT_SERVER);
return; return true;
} }
Con_Footerf(false, "Commands cannot be execed while debugging QC"); Con_Footerf(con, false, "Commands cannot be execed while debugging QC");
} }
#endif #endif
Cbuf_AddText (exec, RESTRICT_LOCAL); Cbuf_AddText (exec, RESTRICT_LOCAL);
@ -482,6 +482,8 @@ void Con_ExecuteLine(console_t *con, char *line)
if (cls.state == ca_disconnected) if (cls.state == ca_disconnected)
SCR_UpdateScreen (); // force an update, because the command SCR_UpdateScreen (); // force an update, because the command
// may take some time // may take some time
return true;
} }
vec3_t sccolor; vec3_t sccolor;
@ -496,7 +498,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
{ {
*sx = *sy = *ex = *ey = 0; *sx = *sy = *ex = *ey = 0;
if (con->mousedown[2] == 1) if (con->buttonsdown == CB_SCROLL)
{ {
//left-mouse. //left-mouse.
//scroll the console with the mouse. trigger links on release. //scroll the console with the mouse. trigger links on release.
@ -517,7 +519,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
*ey = con->mousecursor[1]; *ey = con->mousecursor[1];
return true; return true;
} }
else if (con->mousedown[2] == 2) else if (con->buttonsdown == CB_COPY)
{ {
//right-mouse //right-mouse
//select. copy-to-clipboard on release. //select. copy-to-clipboard on release.
@ -529,6 +531,43 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
} }
else else
{ {
if (con_curwindow == con && con->buttonsdown)
{
if (con->buttonsdown == CB_MOVE)
{ //move window to track the cursor
con->wnd_x += con->mousecursor[0] - con->mousedown[0];
// con->mousedown[0] = con->mousecursor[0];
con->wnd_y += con->mousecursor[1] - con->mousedown[1];
// con->mousedown[1] = con->mousecursor[1];
}
if (con->buttonsdown & CB_SIZELEFT)
{
if (con->wnd_w - (con->mousecursor[0] - con->mousedown[0]) >= 64)
{
con->wnd_w -= con->mousecursor[0] - con->mousedown[0];
con->wnd_x += con->mousecursor[0] - con->mousedown[0];
}
}
if (con->buttonsdown & CB_SIZERIGHT)
{
if (con->wnd_w + (con->mousecursor[0] - con->mousedown[0]) >= 64)
{
con->wnd_w += con->mousecursor[0] - con->mousedown[0];
con->mousedown[0] = con->mousecursor[0];
}
}
if (con->buttonsdown & CB_SIZEBOTTOM)
{
if (con->wnd_h + (con->mousecursor[1] - con->mousedown[1]) >= 64)
{
con->wnd_h += con->mousecursor[1] - con->mousedown[1];
con->mousedown[1] = con->mousecursor[1];
}
}
}
else
con->buttonsdown = CB_NONE;
*sx = con->mousecursor[0]; *sx = con->mousecursor[0];
*sy = con->mousecursor[1]; *sy = con->mousecursor[1];
*ex = con->mousecursor[0]; *ex = con->mousecursor[0];
@ -564,7 +603,7 @@ void Key_ConsoleInsert(char *instext)
key_linepos += len; key_linepos += len;
} }
void Key_DefaultLinkClicked(char *text, char *info) void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
{ {
char *c; char *c;
/*the engine supports specific default links*/ /*the engine supports specific default links*/
@ -639,7 +678,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
return; return;
} }
Con_Footerf(false, "^m#^m ^[%s\\player\\%i^]: %if %ims", cl.players[player].name, player, cl.players[player].frags, cl.players[player].ping); Con_Footerf(con, false, "^m#^m ^[%s\\player\\%i^]: %if %ims", cl.players[player].name, player, cl.players[player].frags, cl.players[player].ping);
for (i = 0; i < cl.splitclients; i++) for (i = 0; i < cl.splitclients; i++)
{ {
@ -652,17 +691,17 @@ void Key_DefaultLinkClicked(char *text, char *info)
if (cl.spectator || cls.demoplayback) if (cl.spectator || cls.demoplayback)
{ {
//we're spectating, or an mvd //we're spectating, or an mvd
Con_Footerf(true, " ^[Spectate\\player\\%i\\action\\spec^]", player); Con_Footerf(con, true, " ^[Spectate\\player\\%i\\action\\spec^]", player);
} }
else else
{ {
//we're playing. //we're playing.
if (cls.protocol == CP_QUAKEWORLD && strcmp(cl.players[cl.playerview[0].playernum].team, cl.players[player].team)) if (cls.protocol == CP_QUAKEWORLD && strcmp(cl.players[cl.playerview[0].playernum].team, cl.players[player].team))
Con_Footerf(true, " ^[[Join Team %s]\\cmd\\setinfo team %s^]", cl.players[player].team, cl.players[player].team); Con_Footerf(con, true, " ^[[Join Team %s]\\cmd\\setinfo team %s^]", cl.players[player].team, cl.players[player].team);
} }
Con_Footerf(true, " ^[%sgnore\\player\\%i\\action\\ignore^]", cl.players[player].ignored?"Uni":"I", player); Con_Footerf(con, true, " ^[%sgnore\\player\\%i\\action\\ignore^]", cl.players[player].ignored?"Uni":"I", player);
// if (cl_voip_play.ival) // if (cl_voip_play.ival)
Con_Footerf(true, " ^[%sute\\player\\%i\\action\\mute^]", cl.players[player].vignored?"Unm":"M", player); Con_Footerf(con, true, " ^[%sute\\player\\%i\\action\\mute^]", cl.players[player].vignored?"Unm":"M", player);
if (!cls.demoplayback && (*rcon_password.string if (!cls.demoplayback && (*rcon_password.string
#ifndef CLIENTONLY #ifndef CLIENTONLY
@ -670,8 +709,8 @@ void Key_DefaultLinkClicked(char *text, char *info)
#endif #endif
)) ))
{ {
Con_Footerf(true, " ^[Kick\\player\\%i\\action\\kick^]", player); Con_Footerf(con, true, " ^[Kick\\player\\%i\\action\\kick^]", player);
Con_Footerf(true, " ^[Ban\\player\\%i\\action\\ban^]", player); Con_Footerf(con, true, " ^[Ban\\player\\%i\\action\\ban^]", player);
} }
} }
else else
@ -687,20 +726,20 @@ void Key_DefaultLinkClicked(char *text, char *info)
} }
else else
{ {
Con_Footerf(true, " ^[Suicide\\cmd\\kill^]"); Con_Footerf(con, true, " ^[Suicide\\cmd\\kill^]");
#ifndef CLIENTONLY #ifndef CLIENTONLY
if (!sv.state) if (!sv.state)
Con_Footerf(true, " ^[Disconnect\\cmd\\disconnect^]"); Con_Footerf(con, true, " ^[Disconnect\\cmd\\disconnect^]");
if (cls.allow_cheats || (sv.state && sv.allocated_client_slots == 1)) if (cls.allow_cheats || (sv.state && sv.allocated_client_slots == 1))
#else #else
Con_Footerf(true, " ^[Disconnect\\cmd\\disconnect^]"); Con_Footerf(con, true, " ^[Disconnect\\cmd\\disconnect^]");
if (cls.allow_cheats) if (cls.allow_cheats)
#endif #endif
{ {
Con_Footerf(true, " ^[Noclip\\cmd\\noclip^]"); Con_Footerf(con, true, " ^[Noclip\\cmd\\noclip^]");
Con_Footerf(true, " ^[Fly\\cmd\\fly^]"); Con_Footerf(con, true, " ^[Fly\\cmd\\fly^]");
Con_Footerf(true, " ^[God\\cmd\\god^]"); Con_Footerf(con, true, " ^[God\\cmd\\god^]");
Con_Footerf(true, " ^[Give\\impulse\\9^]"); Con_Footerf(con, true, " ^[Give\\impulse\\9^]");
} }
} }
} }
@ -781,7 +820,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
c = Info_ValueForKey(info, "desc"); c = Info_ValueForKey(info, "desc");
if (*c) if (*c)
{ {
Con_Footerf(false, "%s", c); Con_Footerf(con, false, "%s", c);
return; return;
} }
@ -805,13 +844,14 @@ void Key_DefaultLinkClicked(char *text, char *info)
void Key_ConsoleRelease(console_t *con, int key, int unicode) void Key_ConsoleRelease(console_t *con, int key, int unicode)
{ {
char *buffer; char *buffer;
if (key == K_MOUSE1 && con->mousedown[2] == 1)
if (key == K_MOUSE1 && con->buttonsdown == CB_SCROLL)
{ {
con->mousedown[2] = 0; con->buttonsdown = CB_NONE;
if (abs(con->mousedown[0] - con->mousecursor[0]) < 5 && abs(con->mousedown[1] - con->mousecursor[1]) < 5) if (abs(con->mousedown[0] - con->mousecursor[0]) < 5 && abs(con->mousedown[1] - con->mousecursor[1]) < 5)
{ {
buffer = Con_CopyConsole(false, false); buffer = Con_CopyConsole(con, false, false);
Con_Footerf(false, ""); Con_Footerf(con, false, "");
if (!buffer) if (!buffer)
return; return;
if (keydown[K_SHIFT]) if (keydown[K_SHIFT])
@ -866,7 +906,7 @@ void Key_ConsoleRelease(console_t *con, int key, int unicode)
if (!CSQC_ConsoleLink(buffer+2, info)) if (!CSQC_ConsoleLink(buffer+2, info))
#endif #endif
{ {
Key_DefaultLinkClicked(buffer+2, info); Key_DefaultLinkClicked(con, buffer+2, info);
} }
break; break;
@ -881,18 +921,27 @@ void Key_ConsoleRelease(console_t *con, int key, int unicode)
Z_Free(buffer); Z_Free(buffer);
} }
else else
Con_Footerf(false, ""); Con_Footerf(con, false, "");
} }
if (key == K_MOUSE2 && con->mousedown[2] == 2) if (key == K_MOUSE2 && con->buttonsdown == CB_COPY)
{ {
con->mousedown[2] = 0; con->buttonsdown = CB_NONE;
buffer = Con_CopyConsole(true, false); //don't keep markup if we're copying to the clipboard buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard
if (!buffer) if (!buffer)
return; return;
Sys_SaveClipboard(buffer); Sys_SaveClipboard(buffer);
Z_Free(buffer); Z_Free(buffer);
} }
if (con->buttonsdown == CB_CLOSE)
{ //window X (close)
if (con->mousecursor[0] > con->wnd_w-8 && con->mousecursor[1] < 8)
{
Con_Destroy (con);
return;
}
}
// if (con->buttonsdown == CB_MOVE) //window title(move)
con->buttonsdown = CB_NONE;
} }
//if the referenced (trailing) chevron is doubled up, then it doesn't act as part of any markup and should be ignored for such things. //if the referenced (trailing) chevron is doubled up, then it doesn't act as part of any markup and should be ignored for such things.
static qboolean utf_specialchevron(unsigned char *start, unsigned char *chev) static qboolean utf_specialchevron(unsigned char *start, unsigned char *chev)
@ -1226,40 +1275,71 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
if ((key == K_MOUSE1 || key == K_MOUSE2)) if ((key == K_MOUSE1 || key == K_MOUSE2))
{ {
// int xpos = (int)((con->mousecursor[0]*vid.width)/(vid.pixelwidth*8)); if (con->flags & CONF_ISWINDOW)
int ypos = (int)((con->mousecursor[1]*vid.height)/(vid.pixelheight*8)); if (con->mousecursor[0] < 0 || con->mousecursor[1] < 0 || con->mousecursor[0] > con->wnd_w || con->mousecursor[1] > con->wnd_h)
return true;
if (con == con_mouseover)
{
con->buttonsdown = CB_NONE;
if ((con->flags & CONF_ISWINDOW) && !keydown[K_SHIFT])
Con_SetActive(con);
}
con->mousedown[0] = con->mousecursor[0]; con->mousedown[0] = con->mousecursor[0];
con->mousedown[1] = con->mousecursor[1]; con->mousedown[1] = con->mousecursor[1];
if (ypos == 0 && con_mouseover) if (con_mouseover && con->mousedown[1] < 8)//(8.0*vid.height)/vid.pixelheight)
{ {
if (key == K_MOUSE2) if (key == K_MOUSE2 && !(con->flags & CONF_ISWINDOW))
Con_Destroy (con_mouseover); Con_Destroy (con);
else else
con_current = con_mouseover; {
Con_SetActive(con);
if ((con->flags & CONF_ISWINDOW))
con->buttonsdown = (con->mousedown[0] > con->wnd_w-8)?CB_CLOSE:CB_MOVE;
}
} }
else if (key == K_MOUSE2) else if (key == K_MOUSE2)
con->mousedown[2] = 2; con->buttonsdown = CB_COPY;
else else
con->mousedown[2] = 1; {
con->buttonsdown = CB_NONE;
if ((con->flags & CONF_ISWINDOW) && con->mousedown[0] < 8)
con->buttonsdown |= CB_SIZELEFT;
if ((con->flags & CONF_ISWINDOW) && con->mousedown[0] > con->wnd_w-8)
con->buttonsdown |= CB_SIZERIGHT;
if ((con->flags & CONF_ISWINDOW) && con->mousedown[1] > con->wnd_h-8)
con->buttonsdown |= CB_SIZEBOTTOM;
if (con->buttonsdown == CB_NONE)
con->buttonsdown = CB_SCROLL;
}
return true; return true;
} }
//console does not have any way to accept input, so don't try giving it any.
if (!con->linebuffered)
return false;
if (key == K_ENTER || key == K_KP_ENTER) if (key == K_ENTER || key == K_KP_ENTER)
{ // backslash text are commands, else chat { // backslash text are commands, else chat
int oldl = edit_line; int oldl = edit_line;
edit_line = (edit_line + 1) & (CON_EDIT_LINES_MASK);
history_line = edit_line; if (con->linebuffered)
{
if (con->linebuffered(con, key_lines[oldl]+1) != 2)
{
edit_line = (edit_line + 1) & (CON_EDIT_LINES_MASK);
history_line = edit_line;
}
}
con_commandmatch = 0;
Z_Free(key_lines[edit_line]); Z_Free(key_lines[edit_line]);
key_lines[edit_line] = BZ_Malloc(2); key_lines[edit_line] = BZ_Malloc(2);
key_lines[edit_line][0] = ']'; key_lines[edit_line][0] = ']';
key_lines[edit_line][1] = '\0'; key_lines[edit_line][1] = '\0';
key_linepos = 1; key_linepos = 1;
if (con->linebuffered)
con->linebuffered(con, key_lines[oldl]+1);
con_commandmatch = 0;
return true; return true;
} }
@ -1387,7 +1467,8 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
return true; return true;
} }
return Key_EntryLine(&key_lines[edit_line], 1, &key_linepos, key, unicode); Key_EntryLine(&key_lines[edit_line], 1, &key_linepos, key, unicode);
return true;
} }
//============================================================================ //============================================================================
@ -1699,9 +1780,9 @@ void Key_BindLevel_f (void)
c = Cmd_Argc(); c = Cmd_Argc();
if (c != 2 && c != 3) if (c != 2 && c != 4)
{ {
Con_Printf ("bindat <key> [<level> <command>] : attach a command to a key for a specific level of access\n"); Con_Printf ("%s <key> [<level> <command>] : attach a command to a key for a specific level of access\n", Cmd_Argv(0));
return; return;
} }
b = Key_StringToKeynum (Cmd_Argv(1), &modifier); b = Key_StringToKeynum (Cmd_Argv(1), &modifier);
@ -1726,7 +1807,7 @@ void Key_BindLevel_f (void)
if (Cmd_IsInsecure()) if (Cmd_IsInsecure())
{ {
Con_Printf("Server attempted usage of bindat\n"); Con_Printf("Server attempted usage of %s\n", Cmd_Argv(0));
return; return;
} }
@ -1812,7 +1893,7 @@ void Key_Init (void)
key_linepos = 1; key_linepos = 1;
key_dest_mask = kdm_game; key_dest_mask = kdm_game;
key_dest_absolutemouse = kdm_console | kdm_editor; key_dest_absolutemouse = kdm_console | kdm_editor | kdm_cwindows;
// //
// init ascii characters in console mode // init ascii characters in console mode
@ -2044,6 +2125,13 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
if (Key_Dest_Has(kdm_console)) if (Key_Dest_Has(kdm_console))
{ {
Key_Dest_Remove(kdm_console); Key_Dest_Remove(kdm_console);
Key_Dest_Remove(kdm_cwindows);
if (!cls.state && !Key_Dest_Has(~kdm_game))
M_ToggleMenu_f ();
}
else if (Key_Dest_Has(kdm_cwindows))
{
Key_Dest_Remove(kdm_cwindows);
if (!cls.state && !Key_Dest_Has(~kdm_game)) if (!cls.state && !Key_Dest_Has(~kdm_game))
M_ToggleMenu_f (); M_ToggleMenu_f ();
} }
@ -2078,11 +2166,19 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
// //
if (!down) if (!down)
{ {
if (Key_Dest_Has(kdm_console)) if (Key_Dest_Has(kdm_console|kdm_cwindows))
{ {
con_current->mousecursor[0] = mousecursor_x; console_t *con = Key_Dest_Has(kdm_console)?con_current:con_curwindow;
con_current->mousecursor[1] = mousecursor_y; if (con_mouseover && key >= K_MOUSE1 && key <= K_MWHEELDOWN)
Key_ConsoleRelease(con_current, key, unicode); con = con_mouseover;
if (con_curwindow && con_curwindow != con)
con_curwindow->buttonsdown = CB_NONE;
if (con)
{
con->mousecursor[0] = mousecursor_x - ((con->flags & CONF_ISWINDOW)?con->wnd_x:0);
con->mousecursor[1] = mousecursor_y - ((con->flags & CONF_ISWINDOW)?con->wnd_y:0);
Key_ConsoleRelease(con, key, unicode);
}
} }
if (Key_Dest_Has(kdm_menu)) if (Key_Dest_Has(kdm_menu))
M_Keyup (key, unicode); M_Keyup (key, unicode);
@ -2139,12 +2235,21 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
#endif #endif
if (conkey && Key_Dest_Has(kdm_console)) if (conkey && Key_Dest_Has(kdm_console|kdm_cwindows))
{ {
con_current->mousecursor[0] = mousecursor_x; console_t *con = Key_Dest_Has(kdm_console)?con_current:con_curwindow;
con_current->mousecursor[1] = mousecursor_y; if ((con_mouseover||!Key_Dest_Has(kdm_console)) && key >= K_MOUSE1 && key <= K_MWHEELDOWN)
Key_Console (con_current, unicode, key); con = con_mouseover;
return; if (con)
{
con->mousecursor[0] = mousecursor_x - ((con->flags & CONF_ISWINDOW)?con->wnd_x:0);
con->mousecursor[1] = mousecursor_y - ((con->flags & CONF_ISWINDOW)?con->wnd_y:0);
if (Key_Console (con, unicode, key))
return;
}
else
Key_Dest_Remove(kdm_cwindows);
} }
#ifdef TEXTEDITOR #ifdef TEXTEDITOR
if (Key_Dest_Has(kdm_editor)) if (Key_Dest_Has(kdm_editor))

View file

@ -172,11 +172,12 @@ K_MAX = 256
typedef enum //highest has priority typedef enum //highest has priority
{ {
kdm_game = 1u<<0, //should always be set kdm_game = 1u<<0, //should always be set
kdm_message = 1u<<1, kdm_message = 1u<<1,
kdm_menu = 1u<<2, kdm_menu = 1u<<2,
kdm_editor = 1u<<3, kdm_editor = 1u<<3,
kdm_console = 1u<<4, kdm_console = 1u<<4,
kdm_cwindows = 1u<<5,
} keydestmask_t; } keydestmask_t;
//unsigned int Key_Dest_Get(void); //returns highest priority destination //unsigned int Key_Dest_Get(void); //returns highest priority destination

View file

@ -1414,31 +1414,47 @@ void MC_Slider_Key(menuslider_t *option, int key)
if (key == K_LEFTARROW || key == K_MWHEELDOWN) if (key == K_LEFTARROW || key == K_MWHEELDOWN)
{ {
range -= delta; range -= delta;
if (range < option->min) if (option->min > option->max)
range = option->min; range = bound(option->max, range, option->min);
else
range = bound(option->min, range, option->max);
option->current = range; option->current = range;
} }
else if (key == K_RIGHTARROW || key == K_MWHEELUP) else if (key == K_RIGHTARROW || key == K_MWHEELUP)
{ {
range += delta; range += delta;
if (range > option->max) if (option->min > option->max)
range = option->max; range = bound(option->max, range, option->min);
else
range = bound(option->min, range, option->max);
option->current = range; option->current = range;
} }
else if (key == K_MOUSE1 && mousecursor_x >= ix-8 && mousecursor_x < ex+8) else if (key == K_MOUSE1 && mousecursor_x >= ix-8 && mousecursor_x < ex+8)
{ {
range = (mousecursor_x - ix) / (ex - ix); range = (mousecursor_x - ix) / (ex - ix);
range = option->min + range*(option->max-option->min); range = option->min + range*(option->max-option->min);
if (option->min > option->max)
range = bound(option->max, range, option->min);
else
range = bound(option->min, range, option->max);
option->current = range; option->current = range;
} }
else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{ {
range += delta; if (range == option->max)
if (range >= option->max + delta/2)
range = option->min; range = option->min;
if (range > option->max) else
range = option->max; {
range += delta;
if (option->min > option->max)
{
if (range < option->max-delta/2)
range = option->max;
}
else
if (range > option->max-delta/2)
range = option->max;
}
option->current = range; option->current = range;
} }
else else
@ -2183,6 +2199,7 @@ void M_Menu_Main_f (void)
#endif #endif
if (QBigFontWorks()) if (QBigFontWorks())
{ {
int y;
m_state = m_complex; m_state = m_complex;
Key_Dest_Add(kdm_menu); Key_Dest_Add(kdm_menu);
mainm = M_CreateMenu(0); mainm = M_CreateMenu(0);
@ -2203,18 +2220,35 @@ void M_Menu_Main_f (void)
MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp"); MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp");
y = 32;
mainm->selecteditem = (menuoption_t *) mainm->selecteditem = (menuoption_t *)
MC_AddConsoleCommandQBigFont (mainm, 72, 32, "Single ", "menu_single\n"); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Single ", "menu_single\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, 52, "Multiplayer ", "menu_multi\n"); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Multiplayer ", "menu_multi\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, 72, "Options ", "menu_options\n"); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Options ", "menu_options\n"); y += 20;
if (m_helpismedia.value) if (m_helpismedia.value)
MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Media ", "menu_media\n"); {
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Media ", "menu_media\n"); y += 20;
}
else else
MC_AddConsoleCommandQBigFont(mainm, 72, 92, "Help ", "help\n"); {
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Help ", "help\n"); y += 20;
}
if (Cmd_AliasExist("mod_menu", RESTRICT_LOCAL))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, va("%-13s", Cvar_Get("mod_menu", "Mod Menu", 0, NULL)->string), "mod_menu\n"); y += 20;
}
if (Cmd_Exists("xmpp"))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "Social ", "xmpp\n"); y += 20;
}
if (Cmd_Exists("irc"))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, "IRC ", "irc\n"); y += 20;
}
#ifdef FTE_TARGET_WEB #ifdef FTE_TARGET_WEB
MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Save Settings", "menu_quit\n"); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Save Settings", "menu_quit\n"); y += 20;
#else #else
MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Quit ", "menu_quit\n"); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Quit ", "menu_quit\n"); y += 20;
#endif #endif
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32); mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32);

View file

@ -151,7 +151,7 @@ qboolean ApplySetupMenu (union menuoption_s *option,struct menu_s *menu, int key
Q_snprintfz(top, sizeof(top), "0x%x", info->topcolour&0xffffff); Q_snprintfz(top, sizeof(top), "0x%x", info->topcolour&0xffffff);
else else
Q_snprintfz(top, sizeof(top), "%i", info->topcolour); Q_snprintfz(top, sizeof(top), "%i", info->topcolour);
Cbuf_AddText(va("color %s %s\n", bot, top), RESTRICT_LOCAL); Cbuf_AddText(va("color %s %s\n", top, bot), RESTRICT_LOCAL);
S_LocalSound ("misc/menu2.wav"); S_LocalSound ("misc/menu2.wav");
M_RemoveMenu(menu); M_RemoveMenu(menu);
return true; return true;

View file

@ -675,6 +675,8 @@ const char *presetexec[] =
"seta r_nolerp 1;" "seta r_nolerp 1;"
"seta r_nolightdir 1;" "seta r_nolightdir 1;"
"seta r_dynamic 0;" "seta r_dynamic 0;"
"seta r_bloom 0;"
"seta r_softwarebanding 0;"
"seta gl_polyblend 0;" "seta gl_polyblend 0;"
"seta gl_flashblend 0;" "seta gl_flashblend 0;"
"seta gl_specular 0;" "seta gl_specular 0;"
@ -730,6 +732,7 @@ const char *presetexec[] =
"cl_bob 0.02;" "cl_bob 0.02;"
//these things are perhaps a little extreme //these things are perhaps a little extreme
"r_loadlit 0;" "r_loadlit 0;"
"r_softwarebanding 1;" //ugly software banding.
"gl_texturemode nnl;" //yup, we went there. "gl_texturemode nnl;" //yup, we went there.
"gl_texturemode2d n.l;" //yeah, 2d too. "gl_texturemode2d n.l;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby! "r_part_classic_square 1;" //blocky baby!
@ -752,6 +755,7 @@ const char *presetexec[] =
"gl_load24bit 1;" "gl_load24bit 1;"
"r_replacemodels \"md3 md2\";" "r_replacemodels \"md3 md2\";"
"r_coronas 1;" "r_coronas 1;"
"r_softwarebanding 0;"
"r_lerpmuzzlehack 1;" "r_lerpmuzzlehack 1;"
"gl_texturemode ln;" "gl_texturemode ln;"
"gl_texturemode2d l;" "gl_texturemode2d l;"
@ -778,8 +782,8 @@ const char *presetexec[] =
"gl_texture_anisotropic_filtering 4;" "gl_texture_anisotropic_filtering 4;"
, // realtime options , // realtime options
// "r_bloom 1;" "r_bloom 1;"
"r_particledesc \"spikeset high tsshaft\";" "r_particledesc \"high tsshaft\";"
"r_waterstyle 3;" "r_waterstyle 3;"
"r_glsl_offsetmapping 1;" "r_glsl_offsetmapping 1;"
"r_shadow_realtime_world 1;" "r_shadow_realtime_world 1;"
@ -801,6 +805,7 @@ static void ApplyPreset (int presetnum)
{ {
Cbuf_InsertText(presetexec[i], RESTRICT_LOCAL, true); Cbuf_InsertText(presetexec[i], RESTRICT_LOCAL, true);
} }
Cbuf_InsertText("vid_reload\n", RESTRICT_LOCAL, true);
forcesaveprompt = true; forcesaveprompt = true;
} }
@ -2518,7 +2523,7 @@ void M_Menu_Video_f (void)
MB_CMD("Apply Settings", M_VideoApply, "Restart video and apply renderer, display, and 2D resolution options."), MB_CMD("Apply Settings", M_VideoApply, "Restart video and apply renderer, display, and 2D resolution options."),
MB_SPACING(4), MB_SPACING(4),
MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL), MB_SLIDER("View Size", scr_viewsize, 30, 120, 10, NULL),
MB_SLIDER("Gamma", v_gamma, 0.25, 1.5, 0.05, NULL), MB_SLIDER("Gamma", v_gamma, 1.5, 0.25, -0.05, NULL),
MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL), MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL),
MB_END() MB_END()
}; };
@ -2887,7 +2892,7 @@ static qboolean Mods_Key(struct menucustom_s *c, struct menu_s *m, int key)
man = mods->manifests[i]; man = mods->manifests[i];
mods->manifests[i] = NULL; mods->manifests[i] = NULL;
M_RemoveMenu(m); M_RemoveMenu(m);
FS_ChangeGame(man, true); FS_ChangeGame(man, true, true);
//starting to a blank state generally means that the current config settings are utterly useless and windowed by default. //starting to a blank state generally means that the current config settings are utterly useless and windowed by default.
//so generally when switching to a *real* game, we want to restart video just so things like fullscreen etc are saved+used properly. //so generally when switching to a *real* game, we want to restart video just so things like fullscreen etc are saved+used properly.
@ -2935,7 +2940,7 @@ void M_Menu_Mods_f (void)
if (mods.nummanifests == 1) if (mods.nummanifests == 1)
{ {
FS_ChangeGame(mods.manifests[0], true); FS_ChangeGame(mods.manifests[0], true, true);
Z_Free(mods.manifests); Z_Free(mods.manifests);
} }
else else
@ -2957,4 +2962,96 @@ void M_Menu_Mods_f (void)
menu->remove = Mods_Remove; menu->remove = Mods_Remove;
} }
} }
#if 0
extern ftemanifest_t *fs_manifest; //currently active manifest.
struct installermenudata
{
menuedit_t *syspath;
};
static void Installer_Remove (struct menu_s *m)
{
Cbuf_AddText("quit force\n", RESTRICT_LOCAL);
}
void FS_CreateBasedir(const char *path);
#include <process.h>
static qboolean Installer_Go(menuoption_t *opt, menu_t *menu, int key)
{
struct installermenudata *md = menu->data;
if (key == K_MOUSE1 || key == K_ENTER)
{
extern int startuppending;
vfsfile_t *f;
char path[MAX_OSPATH];
char exepath[MAX_OSPATH];
char newexepath[MAX_OSPATH];
Q_snprintfz(path, sizeof(path), "%s/", md->syspath->text);
Con_Printf("path %s\n", path);
menu->remove = NULL;
M_RemoveMenu(menu);
FS_CreateBasedir(path);
#ifdef _WIN32
GetModuleFileName(NULL, exepath, sizeof(exepath));
FS_NativePath(va("%s.exe", fs_manifest->installation), FS_ROOT, newexepath, sizeof(newexepath));
CopyFile(exepath, newexepath, FALSE);
// SetHookState(false);
Host_Shutdown ();
// CloseHandle (qwclsemaphore);
// SetHookState(false);
// _execv(newexepath, host_parms.argv);
{
PROCESS_INFORMATION childinfo;
STARTUPINFO startinfo = {sizeof(startinfo)};
CreateProcess(newexepath, va("\"%s\" +sys_register_file_associations %s", newexepath, COM_Parse(GetCommandLineA())), NULL, NULL, FALSE, 0, NULL, path, &startinfo, &childinfo);
}
exit(1);
#elif 0
#ifdef __linux__
if (readlink("/proc/self/exe", exepath, sizeof(exepath)-1) <= 0)
#endif
Q_strncpyz(exepath, host_parms.argv[0], sizeof(exepath));
int fd = creat(newexepath, S_IRWXU | S_IRGRP|S_IXGRP);
write(fd);
close(fd);
#endif
startuppending = 2;
return TRUE;
}
return FALSE;
}
void M_Menu_Installer(void)
{
menu_t *menu;
struct installermenudata *md;
Key_Dest_Add(kdm_menu);
menu = M_CreateMenu(sizeof(*md));
md = menu->data = (menu+1);
md->syspath = MC_AddEdit(menu, 0, 160, 64, "Path", "C:/Games/AfterQuake/testinstall/base");//va("c:/%s", fs_manifest->installation));
//FIXME: add path check display
MC_AddCommand (menu, 0, 160, 128, "Install", Installer_Go);
MC_AddConsoleCommand(menu, 0, 160, 136, "Cancel", "menu_quit\n");
menu->selecteditem = (menuoption_t*)md->syspath;
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 250, 0, menu->selecteditem->common.posy, NULL, false);
menu->remove = Installer_Remove;
}
#endif
#endif #endif

View file

@ -115,6 +115,7 @@ void M_Keyup (int key, int unicode);
void M_Draw (int uimenu); void M_Draw (int uimenu);
void M_ToggleMenu_f (void); void M_ToggleMenu_f (void);
void M_Menu_Mods_f (void); //used at startup if the current gamedirs look dodgy. void M_Menu_Mods_f (void); //used at startup if the current gamedirs look dodgy.
void M_Menu_Installer (void); //given an embedded manifest, this displays an install menu for said game.
mpic_t *M_CachePic (char *path); mpic_t *M_CachePic (char *path);
void M_Menu_Quit_f (void); void M_Menu_Quit_f (void);
void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel); void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2, char *m3, char *optionyes, char *optionno, char *optioncancel);

View file

@ -182,6 +182,8 @@ typedef enum uploadfmt
TF_BGR24, /*bgr byte order, no alpha channel nor pad, and regular top down*/ TF_BGR24, /*bgr byte order, no alpha channel nor pad, and regular top down*/
TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/ TF_BGR24_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/
TF_LUM8, /*8bit greyscale image*/ TF_LUM8, /*8bit greyscale image*/
TF_MIP4_LUM8, /*8bit 4-mip greyscale image*/
TF_MIP4_SOLID8, /*8bit 4-mip image*/
TF_SOLID8, /*8bit quake-palette image*/ TF_SOLID8, /*8bit quake-palette image*/
TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/ TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/
TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/ TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/

View file

@ -1495,8 +1495,10 @@ static void P_ParticleEffect_f(void)
ptype->looks.blendmode = BM_INVMODC; ptype->looks.blendmode = BM_INVMODC;
else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor")) else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor"))
ptype->looks.blendmode = BM_BLENDCOLOUR; ptype->looks.blendmode = BM_BLENDCOLOUR;
else else if (!strcmp(value, "blendalpha"))
ptype->looks.blendmode = BM_BLEND; ptype->looks.blendmode = BM_BLEND;
else
ptype->looks.blendmode = BM_BLEND; //fallback
} }
else if (!strcmp(var, "spawnmode")) else if (!strcmp(var, "spawnmode"))
{ {
@ -5321,7 +5323,22 @@ static void R_AddTSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type)
if (type->stretch) if (type->stretch < 0)
{
vec3_t movedir;
VectorNormalize2(p->vel, movedir);
VectorMA(p->org, type->stretch, movedir, o2);
VectorSubtract(r_refdef.vieworg, o2, v);
CrossProduct(v, p->vel, cr);
VectorNormalize(cr);
VectorMA(o2, -p->scale/2, cr, cl_strisvertv[cl_numstrisvert+0]);
VectorMA(o2, p->scale/2, cr, cl_strisvertv[cl_numstrisvert+1]);
VectorMA(p->org, -type->stretch, movedir, o2);
}
else if (type->stretch)
{ {
VectorMA(p->org, -type->stretch, p->vel, o2); VectorMA(p->org, -type->stretch, p->vel, o2);
VectorSubtract(r_refdef.vieworg, o2, v); VectorSubtract(r_refdef.vieworg, o2, v);

View file

@ -152,6 +152,8 @@ extern sfx_t *cl_sfx_r_exp3;
globalentity(trace_ent, "trace_ent"); /*entity written by traceline*/ \ globalentity(trace_ent, "trace_ent"); /*entity written by traceline*/ \
globalfloat(trace_surfaceflags, "trace_surfaceflags"); /*float written by traceline*/ \ globalfloat(trace_surfaceflags, "trace_surfaceflags"); /*float written by traceline*/ \
globalfloat(trace_endcontents, "trace_endcontents"); /*float written by traceline EXT_CSQC_1*/ \ globalfloat(trace_endcontents, "trace_endcontents"); /*float written by traceline EXT_CSQC_1*/ \
globalint(trace_brush_id, "trace_brush_id"); /*int written by traceline*/ \
globalint(trace_brush_faceid, "trace_brush_faceid"); /*int written by traceline*/ \
\ \
globalfloat(clientcommandframe, "clientcommandframe"); /*float the next frame that will be sent*/ \ globalfloat(clientcommandframe, "clientcommandframe"); /*float the next frame that will be sent*/ \
globalfloat(servercommandframe, "servercommandframe"); /*float the most recent frame received from the server*/ \ globalfloat(servercommandframe, "servercommandframe"); /*float the most recent frame received from the server*/ \
@ -188,6 +190,7 @@ extern sfx_t *cl_sfx_r_exp3;
typedef struct { typedef struct {
#define globalfloat(name,qcname) float *name #define globalfloat(name,qcname) float *name
#define globalint(name,qcname) int *name
#define globalvector(name,qcname) float *name #define globalvector(name,qcname) float *name
#define globalentity(name,qcname) int *name #define globalentity(name,qcname) int *name
#define globalstring(name,qcname) string_t *name #define globalstring(name,qcname) string_t *name
@ -197,6 +200,7 @@ typedef struct {
csqcglobals csqcglobals
#undef globalfloat #undef globalfloat
#undef globalint
#undef globalvector #undef globalvector
#undef globalentity #undef globalentity
#undef globalstring #undef globalstring
@ -273,6 +277,7 @@ static void CSQC_FindGlobals(void)
{ {
static float csphysicsmode = 0; static float csphysicsmode = 0;
#define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalfloat(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalint(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalvector(name,qcname) csqcg.name = (float*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalentity(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalentity(name,qcname) csqcg.name = (int*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
#define globalstring(name,qcname) csqcg.name = (string_t*)PR_FindGlobal(csqcprogs, qcname, 0, NULL); #define globalstring(name,qcname) csqcg.name = (string_t*)PR_FindGlobal(csqcprogs, qcname, 0, NULL);
@ -281,6 +286,7 @@ static void CSQC_FindGlobals(void)
csqcglobals csqcglobals
#undef globalfloat #undef globalfloat
#undef globalint
#undef globalvector #undef globalvector
#undef globalentity #undef globalentity
#undef globalstring #undef globalstring
@ -1200,6 +1206,10 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (!csqc_poly_shader) if (!csqc_poly_shader)
return; return;
nv = cl_numstrisvert-csqc_poly_startvert;
if (nv == 2)
flags |= BEF_LINES;
/*if the shader didn't change, continue with the old poly*/ /*if the shader didn't change, continue with the old poly*/
if (cl_numstris && cl_stris[cl_numstris-1].shader == csqc_poly_shader && cl_stris[cl_numstris-1].flags == flags) if (cl_numstris && cl_stris[cl_numstris-1].shader == csqc_poly_shader && cl_stris[cl_numstris-1].flags == flags)
t = &cl_stris[cl_numstris-1]; t = &cl_stris[cl_numstris-1];
@ -1219,19 +1229,38 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
t->numidx = 0; t->numidx = 0;
} }
nv = cl_numstrisvert-csqc_poly_startvert; if (flags & BEF_LINES)
if (cl_numstrisidx+(nv-2)*3 > cl_maxstrisidx)
{ {
cl_maxstrisidx=cl_numstrisidx+(nv-2)*3 + 64; nv = cl_numstrisvert-csqc_poly_startvert;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); if (cl_numstrisidx+nv > cl_maxstrisidx)
} {
cl_maxstrisidx=cl_numstrisidx+nv + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
/*build the triangle fan out of triangles*/ /*build the line list fan out of triangles*/
for (i = 2; i < nv; i++) for (i = 1; i < nv; i++)
{
cl_strisidx[cl_numstrisidx++] = t->numvert + i-1;
cl_strisidx[cl_numstrisidx++] = t->numvert + i;
}
}
else
{ {
cl_strisidx[cl_numstrisidx++] = t->numvert + 0; nv = cl_numstrisvert-csqc_poly_startvert;
cl_strisidx[cl_numstrisidx++] = t->numvert + i-1; if (cl_numstrisidx+(nv-2)*3 > cl_maxstrisidx)
cl_strisidx[cl_numstrisidx++] = t->numvert + i; {
cl_maxstrisidx=cl_numstrisidx+(nv-2)*3 + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
/*build the triangle fan out of triangles*/
for (i = 2; i < nv; i++)
{
cl_strisidx[cl_numstrisidx++] = t->numvert + 0;
cl_strisidx[cl_numstrisidx++] = t->numvert + i-1;
cl_strisidx[cl_numstrisidx++] = t->numvert + i;
}
} }
if (csqc_poly_flags & 4) if (csqc_poly_flags & 4)
@ -1389,7 +1418,7 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
switch(parametertype) switch(parametertype)
{ {
case VF_LPLAYER: case VF_ACTIVESEAT:
if (prinst == csqc_world.progs) if (prinst == csqc_world.progs)
*r = csqc_playerseat; *r = csqc_playerseat;
break; break;
@ -1538,7 +1567,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
G_FLOAT(OFS_RETURN) = 1; G_FLOAT(OFS_RETURN) = 1;
switch(parametertype) switch(parametertype)
{ {
case VF_LPLAYER: case VF_ACTIVESEAT:
if (prinst == csqc_world.progs) if (prinst == csqc_world.progs)
{ {
CSQC_ChangeLocalPlayer(*p); CSQC_ChangeLocalPlayer(*p);
@ -1895,6 +1924,10 @@ static void cs_settracevars(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
*csqcg.trace_surfaceflags = tr->surface?tr->surface->flags:0; *csqcg.trace_surfaceflags = tr->surface?tr->surface->flags:0;
if (csqcg.trace_endcontents) if (csqcg.trace_endcontents)
*csqcg.trace_endcontents = tr->contents; *csqcg.trace_endcontents = tr->contents;
if (csqcg.trace_brush_id)
*csqcg.trace_brush_id = tr->brush_id;
if (csqcg.trace_brush_faceid)
*csqcg.trace_brush_faceid = tr->brush_face;
if (tr->ent) if (tr->ent)
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent); *csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent);
else else
@ -2526,7 +2559,7 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
if (!cls.state) if (!cls.state)
return; return;
MSG_WriteByte(&cls.netchan.message, clc_qcrequest); MSG_WriteByte(&cls.netchan.message, clcfte_qcrequest);
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
{ {
if (argtypes[i] == 's') if (argtypes[i] == 's')
@ -4965,6 +4998,13 @@ static struct {
{"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 277},//void(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS)
{"terrain_edit", PF_terrain_edit, 278},//void(float action, vector pos, float radius, float quant) terrain_edit = #278 (??FTE_TERRAIN_EDIT??) {"terrain_edit", PF_terrain_edit, 278},//void(float action, vector pos, float radius, float quant) terrain_edit = #278 (??FTE_TERRAIN_EDIT??)
{"brush_get", PF_brush_get, 0},
{"brush_create", PF_brush_create, 0},
{"brush_delete", PF_brush_delete, 0},
{"brush_selected", PF_brush_selected, 0},
{"brush_getfacepoints", PF_brush_getfacepoints, 0},
{"brush_findinvolume", PF_brush_findinvolume, 0},
{"touchtriggers", PF_touchtriggers, 279},//void() touchtriggers = #279; {"touchtriggers", PF_touchtriggers, 279},//void() touchtriggers = #279;
{"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)
@ -5108,6 +5148,8 @@ static struct {
{"con_draw", PF_SubConDraw, 393}, {"con_draw", PF_SubConDraw, 393},
{"con_input", PF_SubConInput, 394}, {"con_input", PF_SubConInput, 394},
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
//400 //400
{"copyentity", PF_cs_copyentity, 400}, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) {"copyentity", PF_cs_copyentity, 400}, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
{"setcolors", PF_NoCSQC, 401}, // #401 void(entity cl, float colours) setcolors (DP_SV_SETCOLOR) (don't implement) {"setcolors", PF_NoCSQC, 401}, // #401 void(entity cl, float colours) setcolors (DP_SV_SETCOLOR) (don't implement)
@ -6834,9 +6876,9 @@ void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd)
//this protocol allows up to 32767 edicts. //this protocol allows up to 32767 edicts.
#ifdef PEXT_CSQC #ifdef PEXT_CSQC
static void CSQC_EntityCheck(int entnum) static void CSQC_EntityCheck(unsigned int entnum)
{ {
int newmax; unsigned int newmax;
if (entnum >= maxcsqcentities) if (entnum >= maxcsqcentities)
{ {
@ -6905,7 +6947,7 @@ void CSQC_GetEntityOrigin(unsigned int csqcent, float *out)
void CSQC_ParseEntities(void) void CSQC_ParseEntities(void)
{ {
csqcedict_t *ent; csqcedict_t *ent;
unsigned short entnum; unsigned int entnum;
void *pr_globals; void *pr_globals;
int packetsize; int packetsize;
int packetstart; int packetstart;
@ -6944,7 +6986,7 @@ void CSQC_ParseEntities(void)
//replacement deltas now also includes 22bit entity num indicies. //replacement deltas now also includes 22bit entity num indicies.
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{ {
entnum = MSG_ReadShort(); entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000); removeflag = !!(entnum & 0x8000);
if (entnum & 0x4000) if (entnum & 0x4000)
entnum = (entnum & 0x3fff) | (MSG_ReadByte()<<14); entnum = (entnum & 0x3fff) | (MSG_ReadByte()<<14);
@ -6953,7 +6995,7 @@ void CSQC_ParseEntities(void)
} }
else else
{ {
entnum = MSG_ReadShort(); entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000); removeflag = !!(entnum & 0x8000);
entnum &= ~0x8000; entnum &= ~0x8000;
} }

View file

@ -904,9 +904,9 @@ void QCBUILTIN PF_SubConGetSet (pubprogfuncs_t *prinst, struct globalvars_s *pr_
} }
else if (!strcmp(field, "hidden")) else if (!strcmp(field, "hidden"))
{ {
RETURN_TSTRING((con->flags & CON_HIDDEN)?"1":"0"); RETURN_TSTRING((con->flags & CONF_HIDDEN)?"1":"0");
if (value) if (value)
con->flags = (con->flags & ~CON_HIDDEN) | (atoi(value)?CON_HIDDEN:0); con->flags = (con->flags & ~CONF_HIDDEN) | (atoi(value)?CONF_HIDDEN:0);
} }
else if (!strcmp(field, "linecount")) else if (!strcmp(field, "linecount"))
{ {
@ -943,7 +943,7 @@ void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
fontsize *= world->g.drawfontscale[1]; fontsize *= world->g.drawfontscale[1];
} }
Con_DrawOneConsole(con, PR_CL_ChooseFont(world->g.drawfont, fontsize, fontsize), pos[0], pos[1], size[0], size[1]); Con_DrawOneConsole(con, con->flags & CONF_KEYFOCUSED, PR_CL_ChooseFont(world->g.drawfont, fontsize, fontsize), pos[0], pos[1], size[0], size[1]);
} }
qboolean Key_Console (console_t *con, unsigned int unicode, int key); qboolean Key_Console (console_t *con, unsigned int unicode, int key);
void Key_ConsoleRelease (console_t *con, unsigned int unicode, int key); void Key_ConsoleRelease (console_t *con, unsigned int unicode, int key);
@ -1184,7 +1184,10 @@ void QCBUILTIN PF_isdemo (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
//float clientstate(void) = #62; //float clientstate(void) = #62;
void QCBUILTIN PF_clientstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_clientstate (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
G_FLOAT(OFS_RETURN) = cls.state >= ca_connected ? 2 : 1; //fit in with netquake (we never run a menu.dat dedicated) if (isDedicated)
G_FLOAT(OFS_RETURN) = 0;
else
G_FLOAT(OFS_RETURN) = cls.state >= ca_connected ? 2 : 1; //fit in with netquake (we never run a menu.dat dedicated)
} }
//too specific to the prinst's builtins. //too specific to the prinst's builtins.
@ -1646,6 +1649,11 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
model_t *mod = Mod_ForName(modelname, MLV_WARN); model_t *mod = Mod_ForName(modelname, MLV_WARN);
if (modelval) if (modelval)
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough. modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
if (mod)
while(mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (mod && minsval) if (mod && minsval)
VectorCopy(mod->mins, minsval->_vector); VectorCopy(mod->mins, minsval->_vector);
if (mod && maxsval) if (mod && maxsval)
@ -1960,6 +1968,7 @@ static struct {
{"con_printf", PF_SubConPrintf, 392}, {"con_printf", PF_SubConPrintf, 392},
{"con_draw", PF_SubConDraw, 393}, {"con_draw", PF_SubConDraw, 393},
{"con_input", PF_SubConInput, 394}, {"con_input", PF_SubConInput, 394},
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
//gap //gap
{"buf_create", PF_buf_create, 440}, {"buf_create", PF_buf_create, 440},
{"buf_del", PF_buf_del, 441}, {"buf_del", PF_buf_del, 441},

View file

@ -230,9 +230,10 @@ int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_lis
typedef struct quakeparms_s typedef struct quakeparms_s
{ {
char *basedir; //working directory char *basedir; //working directory
char *binarydir; //exe directory char *binarydir; //exe directory
int argc; const char *manifest; //linked manifest data (for installer functionality etc)
int argc;
const char **argv; const char **argv;
} quakeparms_t; } quakeparms_t;

View file

@ -725,10 +725,18 @@ void R2D_Font_AddFontLink(char *buffer, int buffersize, char *fontname)
#endif #endif
void R2D_Font_Changed(void) void R2D_Font_Changed(void)
{ {
float tsize;
if (!con_textsize.modified) if (!con_textsize.modified)
return; return;
con_textsize.modified = false; con_textsize.modified = false;
if (con_textsize.value < 0)
tsize = (-con_textsize.value * vid.height) / vid.pixelheight;
else
tsize = con_textsize.value;
if (!tsize)
tsize = 8;
if (font_console == font_default) if (font_console == font_default)
font_console = NULL; font_console = NULL;
if (font_console) if (font_console)
@ -763,8 +771,8 @@ void R2D_Font_Changed(void)
CHOOSEFONTA cf = {sizeof(cf)}; CHOOSEFONTA cf = {sizeof(cf)};
extern HWND mainwindow; extern HWND mainwindow;
font_default = Font_LoadFont(8, ""); font_default = Font_LoadFont(8, "");
if (con_textsize.ival != 8 && con_textsize.ival >= 1) if (tsize != 8)
font_console = Font_LoadFont(con_textsize.ival, ""); font_console = Font_LoadFont(tsize, "");
if (!font_console) if (!font_console)
font_console = font_default; font_console = font_default;
@ -805,11 +813,11 @@ void R2D_Font_Changed(void)
if (!font_default && *gl_font.string) if (!font_default && *gl_font.string)
font_default = Font_LoadFont(8, ""); font_default = Font_LoadFont(8, "");
if (con_textsize.ival != 8 && con_textsize.ival >= 1) if (tsize != 8)
{ {
font_console = Font_LoadFont(con_textsize.ival, gl_font.string); font_console = Font_LoadFont(tsize, gl_font.string);
if (!font_console) if (!font_console)
font_console = Font_LoadFont(con_textsize.ival, ""); font_console = Font_LoadFont(tsize, "");
} }
if (!font_console) if (!font_console)
font_console = font_default; font_console = font_default;
@ -977,6 +985,8 @@ void R2D_BrightenScreen (void)
//don't go crazy with brightness. that makes it unusable and is thus unsafe - and worse, lots of people assume its based around 1 (like gamma and contrast are). cap to 0.5 //don't go crazy with brightness. that makes it unusable and is thus unsafe - and worse, lots of people assume its based around 1 (like gamma and contrast are). cap to 0.5
if (v_brightness.value > 0.5) if (v_brightness.value > 0.5)
v_brightness.value = 0.5; v_brightness.value = 0.5;
if (v_contrast.value < 0.5)
v_contrast.value = 0.5;
if (r2d_canhwgamma) if (r2d_canhwgamma)
return; return;

View file

@ -1582,7 +1582,7 @@ char *particle_set_high =
"randomvel 1000\n" "randomvel 1000\n"
"friction 0.01\n" "friction 0.01\n"
"gravity 100\n" "gravity 100\n"
"stretchfactor 5\n" "stretchfactor -80\n"
"}\n" "}\n"
//hide lights in explosions. //hide lights in explosions.
@ -1633,6 +1633,8 @@ char *particle_set_high =
"shader\n" "shader\n"
"{\n" "{\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"glslprogram\n" "glslprogram\n"
"{\n" "{\n"
"varying vec2 tcoord;\n" "varying vec2 tcoord;\n"

View file

@ -1,30 +1,9 @@
/*
WARNING: THIS FILE IS GENERATED BY 'generatebuiltin.c'.
YOU SHOULD NOT EDIT THIS FILE BY HAND
*/
extern char *particle_set_spikeset; extern char *particle_set_spikeset;
#define R_PARTSET_BUILTINS_spikeset {"spikeset", &particle_set_spikeset},
extern char *particle_set_faithful; extern char *particle_set_faithful;
#define R_PARTSET_BUILTINS_faithful {"faithful", &particle_set_faithful},
extern char *particle_set_highfps; extern char *particle_set_highfps;
#define R_PARTSET_BUILTINS_highfps {"highfps", &particle_set_highfps},
extern char *particle_set_high; extern char *particle_set_high;
#define R_PARTSET_BUILTINS_high {"high", &particle_set_high},
extern char *particle_set_minimal; extern char *particle_set_minimal;
#define R_PARTSET_BUILTINS_minimal {"minimal", &particle_set_minimal},
#ifdef HEXEN2
extern char *particle_set_h2part; extern char *particle_set_h2part;
#define R_PARTSET_BUILTINS_h2part {"h2part", &particle_set_h2part},
#else
#define R_PARTSET_BUILTINS_h2part
#endif
#ifdef Q2CLIENT
extern char *particle_set_q2part; extern char *particle_set_q2part;
#define R_PARTSET_BUILTINS_q2part {"q2part", &particle_set_q2part},
#else
#define R_PARTSET_BUILTINS_q2part
#endif
extern char *particle_set_tsshaft; extern char *particle_set_tsshaft;
#define R_PARTSET_BUILTINS_tsshaft {"tsshaft", &particle_set_tsshaft}, #define R_PARTSET_BUILTINS {"spikeset", &particle_set_spikeset},{"faithful", &particle_set_faithful},{"highfps", &particle_set_highfps},{"high", &particle_set_high},{"minimal", &particle_set_minimal},{"h2part", &particle_set_h2part},{"q2part", &particle_set_q2part},{"tsshaft", &particle_set_tsshaft},
#define R_PARTSET_BUILTINS R_PARTSET_BUILTINS_spikeset R_PARTSET_BUILTINS_faithful R_PARTSET_BUILTINS_highfps R_PARTSET_BUILTINS_high R_PARTSET_BUILTINS_minimal R_PARTSET_BUILTINS_h2part R_PARTSET_BUILTINS_q2part R_PARTSET_BUILTINS_tsshaft

View file

@ -280,7 +280,7 @@ void R_LightArraysByte_BGR(const entity_t *entity, vecV_t *coords, byte_vec4_t *
void R_LightArrays(const entity_t *entity, vecV_t *coords, vec4_t *colours, int vertcount, vec3_t *normals, float scale); void R_LightArrays(const entity_t *entity, vecV_t *coords, vec4_t *colours, int vertcount, vec3_t *normals, float scale);
void R_DrawSkyChain (struct batch_s *batch); /*called from the backend, and calls back into it*/ void R_DrawSkyChain (struct batch_s *batch); /*called from the backend, and calls back into it*/
void R_InitSky (struct texnums_s *ret, struct texture_s *mt, qbyte *src); /*generate q1 sky texnums*/ void R_InitSky (struct texnums_s *tn, const char *skyname, qbyte *src, unsigned int width, unsigned int height); /*generate q1 sky texnums*/
void R_Clutter_Emit(struct batch_s **batches); void R_Clutter_Emit(struct batch_s **batches);
void R_Clutter_Purge(void); void R_Clutter_Purge(void);
@ -303,7 +303,7 @@ void Surf_BuildModelLightmaps (struct model_s *m); //rebuild lightmaps for a sin
void Surf_RenderDynamicLightmaps (struct msurface_s *fa); void Surf_RenderDynamicLightmaps (struct msurface_s *fa);
void Surf_RenderAmbientLightmaps (struct msurface_s *fa, int ambient); void Surf_RenderAmbientLightmaps (struct msurface_s *fa, int ambient);
int Surf_LightmapShift (struct model_s *model); int Surf_LightmapShift (struct model_s *model);
#define LMBLOCK_SIZE_MAX 1024 //single axis #define LMBLOCK_SIZE_MAX 2048 //single axis
typedef struct glRect_s { typedef struct glRect_s {
unsigned short l,t,w,h; unsigned short l,t,w,h;
} glRect_t; } glRect_t;
@ -371,13 +371,15 @@ enum imageflags
IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/ IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<10, IF_MIPCAP = 1<<10,
IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha IF_PREMULTIPLYALPHA = 1<<12, //rgb *= alpha
IF_LOADNOW = 1<<25, IF_HIGHPRIORITY = 1<<23,
IF_LOWPRIORITY = 1<<24,
IF_LOADNOW = 1<<25, /*hit the disk now, and delay the gl load until its actually needed. this is used only so that the width+height are known in advance*/
IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/ IF_NOPCX = 1<<26, /*block pcx format. meaning qw skins can use team colours and cropping*/
IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/ IF_TRYBUMP = 1<<27, /*attempt to load _bump if the specified _norm texture wasn't found*/
IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/ IF_RENDERTARGET = 1<<28, /*never loaded from disk, loading can't fail*/
IF_EXACTEXTENSION = 1<<29, /*don't mangle extensions, use what is specified and ONLY that*/ IF_EXACTEXTENSION = 1<<29, /*don't mangle extensions, use what is specified and ONLY that*/
IF_NOREPLACE = 1<<30, /*don't load a replacement, for some reason*/ IF_NOREPLACE = 1<<30, /*don't load a replacement, for some reason*/
IF_NOWORKER = 1u<<31 /*don't pass the work to a loader thread. this gives synchronous loading.*/ IF_NOWORKER = 1u<<31 /*don't pass the work to a loader thread. this gives fully synchronous loading. only valid from the main thread.*/
}; };
#define R_LoadTexture8(id,w,h,d,f,t) Image_GetTexture(id, NULL, f, d, NULL, w, h, t?TF_TRANS8:TF_SOLID8) #define R_LoadTexture8(id,w,h,d,f,t) Image_GetTexture(id, NULL, f, d, NULL, w, h, t?TF_TRANS8:TF_SOLID8)
@ -455,8 +457,14 @@ void Mod_UnRegisterAllModelFormats(void *module);
void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b); void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b);
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
void LightFace (int surfnum); struct relight_ctx_s;
void LightLoadEntities(char *entstring); struct llightinfo_s;
void LightFace (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, int surfnum); //version that is aware of bsp trees
void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, qbyte surf_styles[4], qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale); //special version that doesn't know what a face is or anything.
struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, struct model_s *model, qboolean shadows);
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring);
void LightShutdown(struct relight_ctx_s *ctx, struct model_s *mod);
extern const size_t lightthreadctxsize;
#endif #endif
@ -505,6 +513,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, qboolean *
qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height); qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height);
qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *name); qbyte *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *name);
qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out); qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out);
void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight);
void BoostGamma(qbyte *rgba, int width, int height); void BoostGamma(qbyte *rgba, int width, int height);
void SaturateR8G8B8(qbyte *data, int size, float sat); void SaturateR8G8B8(qbyte *data, int size, float sat);
@ -566,6 +575,7 @@ extern cvar_t r_coronas, r_flashblend, r_flashblendscale;
extern cvar_t r_lightstylesmooth; extern cvar_t r_lightstylesmooth;
extern cvar_t r_lightstylesmooth_limit; extern cvar_t r_lightstylesmooth_limit;
extern cvar_t r_lightstylespeed; extern cvar_t r_lightstylespeed;
extern cvar_t r_lightstylescale;
extern cvar_t gl_nocolors; extern cvar_t gl_nocolors;
extern cvar_t gl_load24bit; extern cvar_t gl_load24bit;
extern cvar_t gl_finish; extern cvar_t gl_finish;
@ -626,13 +636,13 @@ extern int rquant[RQUANT_MAX];
#define RSpeedRemark() #define RSpeedRemark()
#define RSpeedEnd(spt) #define RSpeedEnd(spt)
#else #else
#define RSpeedLocals() int rsp #define RSpeedLocals() double rsp
#define RSpeedMark() int rsp = (r_speeds.ival>1)?Sys_DoubleTime()*1000000:0 #define RSpeedMark() double rsp = (r_speeds.ival>1)?Sys_DoubleTime()*1000000:0
#define RSpeedRemark() rsp = (r_speeds.ival>1)?Sys_DoubleTime()*1000000:0 #define RSpeedRemark() rsp = (r_speeds.ival>1)?Sys_DoubleTime()*1000000:0
#if defined(_WIN32) && defined(GLQUAKE) #if defined(_WIN32) && defined(GLQUAKE)
extern void (_stdcall *qglFinish) (void); extern void (_stdcall *qglFinish) (void);
#define RSpeedEnd(spt) do {if(r_speeds.ival > 1){if(r_speeds.ival > 2 && qglFinish)qglFinish(); rspeeds[spt] += (int)(Sys_DoubleTime()*1000000) - rsp;}}while (0) #define RSpeedEnd(spt) do {if(r_speeds.ival > 1){if(r_speeds.ival > 2 && qglFinish)qglFinish(); rspeeds[spt] += (double)(Sys_DoubleTime()*1000000) - rsp;}}while (0)
#else #else
#define RSpeedEnd(spt) rspeeds[spt] += (r_speeds.ival>1)?Sys_DoubleTime()*1000000 - rsp:0 #define RSpeedEnd(spt) rspeeds[spt] += (r_speeds.ival>1)?Sys_DoubleTime()*1000000 - rsp:0
#endif #endif

View file

@ -103,8 +103,8 @@ cvar_t r_flashblendscale = SCVARF ("gl_flashblendscale", "0.35",
CVAR_ARCHIVE); CVAR_ARCHIVE);
cvar_t r_floorcolour = CVARAF ("r_floorcolour", "64 64 128", cvar_t r_floorcolour = CVARAF ("r_floorcolour", "64 64 128",
"r_floorcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); "r_floorcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
cvar_t r_floortexture = SCVARF ("r_floortexture", "", //cvar_t r_floortexture = SCVARF ("r_floortexture", "",
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); // CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
cvar_t r_fullbright = CVARFD ("r_fullbright", "0", cvar_t r_fullbright = CVARFD ("r_fullbright", "0",
CVAR_CHEAT|CVAR_SHADERSYSTEM, "Ignore world lightmaps, drawing everything fully lit."); CVAR_CHEAT|CVAR_SHADERSYSTEM, "Ignore world lightmaps, drawing everything fully lit.");
cvar_t r_fullbrightSkins = SCVARF ("r_fullbrightSkins", "0.8", /*don't default to 1, as it looks a little ugly (too bright), but don't default to 0 either because then you're handicapped in the dark*/ cvar_t r_fullbrightSkins = SCVARF ("r_fullbrightSkins", "0.8", /*don't default to 1, as it looks a little ugly (too bright), but don't default to 0 either because then you're handicapped in the dark*/
@ -113,6 +113,7 @@ cvar_t r_lightmap_saturation = SCVAR ("r_lightmap_saturation", "1");
cvar_t r_lightstylesmooth = CVARF ("r_lightstylesmooth", "0", CVAR_ARCHIVE); cvar_t r_lightstylesmooth = CVARF ("r_lightstylesmooth", "0", CVAR_ARCHIVE);
cvar_t r_lightstylesmooth_limit = SCVAR ("r_lightstylesmooth_limit", "2"); cvar_t r_lightstylesmooth_limit = SCVAR ("r_lightstylesmooth_limit", "2");
cvar_t r_lightstylespeed = SCVAR ("r_lightstylespeed", "10"); cvar_t r_lightstylespeed = SCVAR ("r_lightstylespeed", "10");
cvar_t r_lightstylescale = SCVAR ("r_lightstylescale", "1");
cvar_t r_loadlits = CVARF ("r_loadlit", "1", CVAR_ARCHIVE); cvar_t r_loadlits = CVARF ("r_loadlit", "1", CVAR_ARCHIVE);
cvar_t r_menutint = SCVARF ("r_menutint", "0.68 0.4 0.13", cvar_t r_menutint = SCVARF ("r_menutint", "0.68 0.4 0.13",
CVAR_RENDERERCALLBACK); CVAR_RENDERERCALLBACK);
@ -127,7 +128,7 @@ cvar_t r_part_rain = CVARFD ("r_part_rain", "0",
"Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects."); "Enable particle effects to emit off of surfaces. Mainly used for weather or lava/slime effects.");
cvar_t r_skyboxname = SCVARF ("r_skybox", "", cvar_t r_skyboxname = SCVARF ("r_skybox", "",
CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM); CVAR_RENDERERCALLBACK | CVAR_SHADERSYSTEM);
cvar_t r_softwarebanding = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM | CVAR_RENDERERLATCH, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well)."); cvar_t r_softwarebanding = CVARFD ("r_softwarebanding", "0", CVAR_SHADERSYSTEM, "Utilise the Quake colormap in order to emulate 8bit software rendering. This results in banding as well as other artifacts that some believe adds character. Also forces nearest sampling on affected surfaces (palette indicies do not interpolate well).");
cvar_t r_speeds = SCVAR ("r_speeds", "0"); cvar_t r_speeds = SCVAR ("r_speeds", "0");
cvar_t r_stainfadeammount = SCVAR ("r_stainfadeammount", "1"); cvar_t r_stainfadeammount = SCVAR ("r_stainfadeammount", "1");
cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1"); cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1");
@ -137,8 +138,8 @@ cvar_t r_stains = CVARFC("r_stains", IFMINIMAL("0","0.75"),
cvar_t r_postprocshader = CVARD("r_postprocshader", "", "Specifies a shader to use as a post-processing shader"); cvar_t r_postprocshader = CVARD("r_postprocshader", "", "Specifies a shader to use as a post-processing shader");
cvar_t r_wallcolour = CVARAF ("r_wallcolour", "128 128 128", cvar_t r_wallcolour = CVARAF ("r_wallcolour", "128 128 128",
"r_wallcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);//FIXME: broken "r_wallcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);//FIXME: broken
cvar_t r_walltexture = CVARF ("r_walltexture", "", //cvar_t r_walltexture = CVARF ("r_walltexture", "",
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); //FIXME: broken // CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); //FIXME: broken
cvar_t r_wateralpha = CVARF ("r_wateralpha", "1", cvar_t r_wateralpha = CVARF ("r_wateralpha", "1",
CVAR_ARCHIVE | CVAR_SHADERSYSTEM); CVAR_ARCHIVE | CVAR_SHADERSYSTEM);
cvar_t r_lavaalpha = CVARF ("r_lavaalpha", "", cvar_t r_lavaalpha = CVARF ("r_lavaalpha", "",
@ -170,7 +171,7 @@ cvar_t scr_conspeed = CVAR ("scr_conspeed", "2000");
cvar_t scr_fov = CVARFDC("fov", "90", cvar_t scr_fov = CVARFDC("fov", "90",
CVAR_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108.", CVAR_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108.",
SCR_Fov_Callback); SCR_Fov_Callback);
cvar_t scr_printspeed = SCVAR ("scr_printspeed", "8"); cvar_t scr_printspeed = SCVAR ("scr_printspeed", "16");
cvar_t scr_showpause = SCVAR ("showpause", "1"); cvar_t scr_showpause = SCVAR ("showpause", "1");
cvar_t scr_showturtle = SCVAR ("showturtle", "0"); cvar_t scr_showturtle = SCVAR ("showturtle", "0");
cvar_t scr_turtlefps = SCVAR ("scr_turtlefps", "10"); cvar_t scr_turtlefps = SCVAR ("scr_turtlefps", "10");
@ -298,8 +299,6 @@ cvar_t gl_load24bit = SCVARF ("gl_load24bit", "1",
cvar_t r_clear = CVARAF("r_clear","0", cvar_t r_clear = CVARAF("r_clear","0",
"gl_clear", 0); "gl_clear", 0);
cvar_t gl_max_size = CVARFD ("gl_max_size", "8192", CVAR_RENDERERLATCH, "Specifies the maximum texture size that the engine may use. Textures larger than this will be downsized. Clamped by the value the driver supports."); cvar_t gl_max_size = CVARFD ("gl_max_size", "8192", CVAR_RENDERERLATCH, "Specifies the maximum texture size that the engine may use. Textures larger than this will be downsized. Clamped by the value the driver supports.");
cvar_t gl_maxshadowlights = SCVARF ("gl_maxshadowlights", "2",
CVAR_ARCHIVE);
cvar_t gl_menutint_shader = CVARD ("gl_menutint_shader", "1", "Controls the use of GLSL to desaturate the background when drawing the menu, like quake's dos software renderer used to do before the ugly dithering of winquake."); cvar_t gl_menutint_shader = CVARD ("gl_menutint_shader", "1", "Controls the use of GLSL to desaturate the background when drawing the menu, like quake's dos software renderer used to do before the ugly dithering of winquake.");
//by setting to 64 or something, you can use this as a wallhack //by setting to 64 or something, you can use this as a wallhack
@ -333,10 +332,10 @@ cvar_t gl_specular_fallbackexp = CVARF ("gl_specular_fallbackexp", "1", CVAR
cvar_t gl_texture_anisotropic_filtering = CVARFC("gl_texture_anisotropic_filtering", "0", cvar_t gl_texture_anisotropic_filtering = CVARFC("gl_texture_anisotropic_filtering", "0",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
Image_TextureMode_Callback); Image_TextureMode_Callback);
cvar_t gl_texturemode = CVARFDC("gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", cvar_t gl_texturemode = CVARFDC("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK | CVAR_SAVE, CVAR_ARCHIVE | CVAR_RENDERERCALLBACK | CVAR_SAVE,
"Specifies how world/model textures appear. Typically 3 letters eg lln.\nFirst letter can be l(inear) or n(earest) and says how to sample from the mip (when downsampling).\nThe middle letter can . to disable mipmaps, or l or n to describe whether to blend between mipmaps.\nThe third letter says what to do when the texture is too low resolution and is thus the most noticable with low resolution textures, a n will make it look like lego, while an l will keep it smooth.", Image_TextureMode_Callback); "Specifies how world/model textures appear. Typically 3 letters eg lln.\nFirst letter can be l(inear) or n(earest) and says how to sample from the mip (when downsampling).\nThe middle letter can . to disable mipmaps, or l or n to describe whether to blend between mipmaps.\nThe third letter says what to do when the texture is too low resolution and is thus the most noticable with low resolution textures, a n will make it look like lego, while an l will keep it smooth.", Image_TextureMode_Callback);
cvar_t gl_mipcap = CVARFC("d_mipcap", "0 1000", cvar_t gl_mipcap = CVARAFC("d_mipcap", "0 1000", "gl_miptexLevel",
CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, CVAR_ARCHIVE | CVAR_RENDERERCALLBACK,
Image_TextureMode_Callback); Image_TextureMode_Callback);
cvar_t gl_texturemode2d = CVARFDC("gl_texturemode2d", "GL_LINEAR", cvar_t gl_texturemode2d = CVARFDC("gl_texturemode2d", "GL_LINEAR",
@ -362,7 +361,7 @@ cvar_t r_shadow_heightscale_bumpmap = CVARD ("r_shadow_heightscale_bumpmap",
cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures."); cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures.");
cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04");
cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer. r_glsl_offsetmapping must be set."); cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer, but noticably more expensive at high resolutions. r_glsl_offsetmapping must be set.");
cvar_t r_glsl_turbscale = CVARFD ("r_glsl_turbscale", "1", CVAR_ARCHIVE, "Controls the strength of water ripples (used by the altwater glsl code)."); cvar_t r_glsl_turbscale = CVARFD ("r_glsl_turbscale", "1", CVAR_ARCHIVE, "Controls the strength of water ripples (used by the altwater glsl code).");
cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.\n"); cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.\n");
@ -431,7 +430,6 @@ void GLRenderer_Init(void)
Cvar_Register (&r_portaldrawplanes, GLRENDEREROPTIONS); Cvar_Register (&r_portaldrawplanes, GLRENDEREROPTIONS);
Cvar_Register (&r_portalonly, GLRENDEREROPTIONS); Cvar_Register (&r_portalonly, GLRENDEREROPTIONS);
Cvar_Register (&r_noaliasshadows, GLRENDEREROPTIONS); Cvar_Register (&r_noaliasshadows, GLRENDEREROPTIONS);
Cvar_Register (&gl_maxshadowlights, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS); Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS); Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_heightscale_basetexture, GLRENDEREROPTIONS); Cvar_Register (&r_shadow_heightscale_basetexture, GLRENDEREROPTIONS);
@ -478,8 +476,8 @@ void GLRenderer_Init(void)
Cvar_Register (&r_wallcolour, GLRENDEREROPTIONS); Cvar_Register (&r_wallcolour, GLRENDEREROPTIONS);
Cvar_Register (&r_floorcolour, GLRENDEREROPTIONS); Cvar_Register (&r_floorcolour, GLRENDEREROPTIONS);
Cvar_Register (&r_walltexture, GLRENDEREROPTIONS); // Cvar_Register (&r_walltexture, GLRENDEREROPTIONS);
Cvar_Register (&r_floortexture, GLRENDEREROPTIONS); // Cvar_Register (&r_floortexture, GLRENDEREROPTIONS);
Cvar_Register (&r_vertexdlights, GLRENDEREROPTIONS); Cvar_Register (&r_vertexdlights, GLRENDEREROPTIONS);
@ -630,6 +628,7 @@ void Renderer_Init(void)
Cvar_Register(&r_lightstylesmooth, GRAPHICALNICETIES); Cvar_Register(&r_lightstylesmooth, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylesmooth_limit, GRAPHICALNICETIES); Cvar_Register(&r_lightstylesmooth_limit, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylespeed, GRAPHICALNICETIES); Cvar_Register(&r_lightstylespeed, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylescale, GRAPHICALNICETIES);
Cvar_Register(&r_stains, GRAPHICALNICETIES); Cvar_Register(&r_stains, GRAPHICALNICETIES);
Cvar_Register(&r_stainfadetime, GRAPHICALNICETIES); Cvar_Register(&r_stainfadetime, GRAPHICALNICETIES);
@ -1430,6 +1429,13 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
newr->stereo = (r_stereo_method.ival == 1); newr->stereo = (r_stereo_method.ival == 1);
newr->srgb = vid_srgb.ival; newr->srgb = vid_srgb.ival;
if (com_installer)
{
newr->fullscreen = false;
newr->width = 640;
newr->height = 480;
}
if (!*vid_vsync.string || vid_vsync.value < 0) if (!*vid_vsync.string || vid_vsync.value < 0)
newr->wait = -1; newr->wait = -1;
else else

View file

@ -141,6 +141,13 @@ int Sbar_PlayerNum(playerview_t *pv)
int Sbar_TopColour(player_info_t *p) int Sbar_TopColour(player_info_t *p)
{ {
if (cl.teamfortress)
{
if (!Q_strcasecmp(p->team, "red"))
return 4;
if (!Q_strcasecmp(p->team, "blue"))
return 13;
}
if (scr_scoreboard_forcecolors.ival) if (scr_scoreboard_forcecolors.ival)
return p->ttopcolor; return p->ttopcolor;
else else
@ -149,6 +156,13 @@ int Sbar_TopColour(player_info_t *p)
int Sbar_BottomColour(player_info_t *p) int Sbar_BottomColour(player_info_t *p)
{ {
if (cl.teamfortress)
{
if (!Q_strcasecmp(p->team, "red"))
return 4;
if (!Q_strcasecmp(p->team, "blue"))
return 13;
}
if (scr_scoreboard_forcecolors.ival) if (scr_scoreboard_forcecolors.ival)
return p->tbottomcolor; return p->tbottomcolor;
else else
@ -1205,9 +1219,10 @@ int Sbar_itoa (int num, char *buf)
num = -num; num = -num;
} }
for (pow10 = 10 ; num >= pow10 ; pow10 *= 10) for (pow10 = 10 ; num >= pow10 && pow10>=10; pow10 *= 10)
; ;
if (pow10 > 0)
do do
{ {
pow10 /= 10; pow10 /= 10;
@ -1229,7 +1244,7 @@ Sbar_DrawNum
*/ */
void Sbar_DrawNum (float x, float y, int num, int digits, int color) void Sbar_DrawNum (float x, float y, int num, int digits, int color)
{ {
char str[12]; char str[16];
char *ptr; char *ptr;
int l, frame; int l, frame;
#undef small #undef small

View file

@ -97,7 +97,8 @@ void SCR_SetLoadingFile(char *str);
/*fonts*/ /*fonts*/
void Font_Init(void); void Font_Init(void);
void Font_Shutdown(void); void Font_Shutdown(void);
struct font_s *Font_LoadFont(int height, const char *fontfilename); int Font_RegisterTrackerImage(const char *image); //returns a unicode char value that can be used to embed the char within a line of text.
struct font_s *Font_LoadFont(float height, const char *fontfilename);
void Font_Free(struct font_s *f); void Font_Free(struct font_s *f);
void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py);
void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/

View file

@ -83,7 +83,7 @@ cvar_t snd_show = CVARAF( "s_show", "0",
"snd_show", 0); "snd_show", 0);
cvar_t snd_khz = CVARAFD( "s_khz", "48", cvar_t snd_khz = CVARAFD( "s_khz", "48",
"snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz."); "snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "0", cvar_t snd_inactive = CVARAFD( "s_inactive", "1",
"snd_inactive", 0, "snd_inactive", 0,
"Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed." "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.
@ -754,7 +754,7 @@ void S_Voip_RTP_Parse(unsigned short sequence, char *codec, unsigned char *data,
if (!strcmp(codec, "speex@11025")) if (!strcmp(codec, "speex@11025"))
S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_OLD, 0, sequence, datalen, data); //very much non-standard rtp S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_OLD, 0, sequence, datalen, data); //very much non-standard rtp
if (!strcmp(codec, "speex@16000")) if (!strcmp(codec, "speex@16000"))
S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_WIDE, 0, sequence, datalen, data); S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_WIDE, 0, sequence&0xff, datalen, data);
if (!strcmp(codec, "speex@32000")) if (!strcmp(codec, "speex@32000"))
S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_ULTRAWIDE, 0, sequence, datalen, data); S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_ULTRAWIDE, 0, sequence, datalen, data);
if (!strcmp(codec, "opus")) if (!strcmp(codec, "opus"))
@ -2450,6 +2450,8 @@ void S_StopAllSounds(qboolean clear)
{ {
s = sc->channel[i].sfx; s = sc->channel[i].sfx;
sc->channel[i].sfx = NULL; sc->channel[i].sfx = NULL;
if (s->loadstate == SLS_LOADING)
COM_WorkerPartialSync(s, &s->loadstate, SLS_LOADING);
if (s->decoder.ended) if (s->decoder.ended)
if (!S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly. if (!S_IsPlayingSomewhere(s)) //if we aint playing it elsewhere, free it compleatly.
{ {

View file

@ -756,6 +756,9 @@ qboolean S_RegisterSoundInputPlugin(S_LoadSound_t loadfnc)
return false; return false;
} }
void S_Wakeup (void *ctx, void *ctxdata, size_t a, size_t b)
{
}
/* /*
============== ==============
S_LoadSound S_LoadSound
@ -765,7 +768,7 @@ S_LoadSound
qboolean S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b) qboolean S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
{ {
sfx_t *s = ctx; sfx_t *s = ctx;
char namebuffer[256]; char namebuffer[256];
qbyte *data; qbyte *data;
int i; int i;
size_t result; size_t result;
@ -863,6 +866,8 @@ qboolean S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
if (AudioInputPlugins[i](s, data, filesize, snd_speed)) if (AudioInputPlugins[i](s, data, filesize, snd_speed))
{ {
s->loadstate = SLS_LOADED; s->loadstate = SLS_LOADED;
//wake up the main thread in case it decided to wait for us.
COM_AddWork(0, S_Wakeup, s, NULL, 0, 0);
BZ_Free(data); BZ_Free(data);
return true; return true;
} }
@ -898,83 +903,85 @@ WAV loading
=============================================================================== ===============================================================================
*/ */
char *wavname; typedef struct
qbyte *data_p; {
qbyte *iff_end; char *wavname;
qbyte *last_chunk; qbyte *data_p;
qbyte *iff_data; qbyte *iff_end;
int iff_chunk_len; qbyte *last_chunk;
qbyte *iff_data;
int iff_chunk_len;
} wavctx_t;
short GetLittleShort(wavctx_t *ctx)
short GetLittleShort(void)
{ {
short val = 0; short val = 0;
val = *data_p; val = *ctx->data_p;
val = val + (*(data_p+1)<<8); val = val + (*(ctx->data_p+1)<<8);
data_p += 2; ctx->data_p += 2;
return val; return val;
} }
int GetLittleLong(void) int GetLittleLong(wavctx_t *ctx)
{ {
int val = 0; int val = 0;
val = *data_p; val = *ctx->data_p;
val = val + (*(data_p+1)<<8); val = val + (*(ctx->data_p+1)<<8);
val = val + (*(data_p+2)<<16); val = val + (*(ctx->data_p+2)<<16);
val = val + (*(data_p+3)<<24); val = val + (*(ctx->data_p+3)<<24);
data_p += 4; ctx->data_p += 4;
return val; return val;
} }
unsigned int FindNextChunk(char *name) unsigned int FindNextChunk(wavctx_t *ctx, char *name)
{ {
unsigned int dataleft; unsigned int dataleft;
while (1) while (1)
{ {
dataleft = iff_end - last_chunk; dataleft = ctx->iff_end - ctx->last_chunk;
if (dataleft < 8) if (dataleft < 8)
{ // didn't find the chunk { // didn't find the chunk
data_p = NULL; ctx->data_p = NULL;
return 0; return 0;
} }
data_p=last_chunk; ctx->data_p=ctx->last_chunk;
data_p += 4; ctx->data_p += 4;
dataleft-= 8; dataleft-= 8;
iff_chunk_len = GetLittleLong(); ctx->iff_chunk_len = GetLittleLong(ctx);
if (iff_chunk_len < 0) if (ctx->iff_chunk_len < 0)
{ {
data_p = NULL; ctx->data_p = NULL;
return 0; return 0;
} }
if (iff_chunk_len > dataleft) if (ctx->iff_chunk_len > dataleft)
{ {
Con_DPrintf ("\"%s\" seems truncated by %i bytes\n", wavname, iff_chunk_len-dataleft); Con_DPrintf ("\"%s\" seems truncated by %i bytes\n", ctx->wavname, ctx->iff_chunk_len-dataleft);
#if 1 #if 1
iff_chunk_len = dataleft; ctx->iff_chunk_len = dataleft;
#else #else
data_p = NULL; ctx->data_p = NULL;
return 0; return 0;
#endif #endif
} }
dataleft-= iff_chunk_len; dataleft-= ctx->iff_chunk_len;
// if (iff_chunk_len > 1024*1024) // if (iff_chunk_len > 1024*1024)
// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
data_p -= 8; ctx->data_p -= 8;
last_chunk = data_p + 8 + iff_chunk_len; ctx->last_chunk = ctx->data_p + 8 + ctx->iff_chunk_len;
if ((iff_chunk_len&1) && dataleft) if ((ctx->iff_chunk_len&1) && dataleft)
last_chunk++; ctx->last_chunk++;
if (!Q_strncmp(data_p, name, 4)) if (!Q_strncmp(ctx->data_p, name, 4))
return iff_chunk_len; return ctx->iff_chunk_len;
} }
} }
unsigned int FindChunk(char *name) unsigned int FindChunk(wavctx_t *ctx, char *name)
{ {
last_chunk = iff_data; ctx->last_chunk = ctx->iff_data;
return FindNextChunk (name); return FindNextChunk (ctx, name);
} }
@ -1004,67 +1011,72 @@ GetWavinfo
wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
{ {
wavinfo_t info; wavinfo_t info;
int i; int i;
int format; int format;
int samples; int samples;
int chunklen; int chunklen;
wavctx_t ctx;
memset (&info, 0, sizeof(info)); memset (&info, 0, sizeof(info));
if (!wav) if (!wav)
return info; return info;
iff_data = wav; ctx.data_p = NULL;
iff_end = wav + wavlength; ctx.last_chunk = NULL;
wavname = name; ctx.iff_chunk_len = 0;
ctx.iff_data = wav;
ctx.iff_end = wav + wavlength;
ctx.wavname = name;
// find "RIFF" chunk // find "RIFF" chunk
chunklen = FindChunk("RIFF"); chunklen = FindChunk(&ctx, "RIFF");
if (chunklen < 4 || Q_strncmp(data_p+8, "WAVE", 4)) if (chunklen < 4 || Q_strncmp(ctx.data_p+8, "WAVE", 4))
{ {
Con_Printf("Missing RIFF/WAVE chunks in %s\n", name); Con_Printf("Missing RIFF/WAVE chunks in %s\n", name);
return info; return info;
} }
// get "fmt " chunk // get "fmt " chunk
iff_data = data_p + 12; ctx.iff_data = ctx.data_p + 12;
// DumpChunks (); // DumpChunks ();
chunklen = FindChunk("fmt "); chunklen = FindChunk(&ctx, "fmt ");
if (chunklen < 24-8) if (chunklen < 24-8)
{ {
Con_Printf("Missing/truncated fmt chunk\n"); Con_Printf("Missing/truncated fmt chunk\n");
return info; return info;
} }
data_p += 8; ctx.data_p += 8;
format = GetLittleShort(); format = GetLittleShort(&ctx);
if (format != 1) if (format != 1)
{ {
Con_Printf("Microsoft PCM format only\n"); Con_Printf("Microsoft PCM format only\n");
return info; return info;
} }
info.numchannels = GetLittleShort(); info.numchannels = GetLittleShort(&ctx);
info.rate = GetLittleLong(); info.rate = GetLittleLong(&ctx);
data_p += 4+2; ctx.data_p += 4+2;
info.width = GetLittleShort() / 8; info.width = GetLittleShort(&ctx) / 8;
// get cue chunk // get cue chunk
chunklen = FindChunk("cue "); chunklen = FindChunk(&ctx, "cue ");
if (chunklen >= 36-8) if (chunklen >= 36-8)
{ {
data_p += 32; ctx.data_p += 32;
info.loopstart = GetLittleLong(); info.loopstart = GetLittleLong(&ctx);
// Con_Printf("loopstart=%d\n", sfx->loopstart); // Con_Printf("loopstart=%d\n", sfx->loopstart);
// if the next chunk is a LIST chunk, look for a cue length marker // if the next chunk is a LIST chunk, look for a cue length marker
chunklen = FindNextChunk ("LIST"); chunklen = FindNextChunk (&ctx, "LIST");
if (chunklen >= 32-8) if (chunklen >= 32-8)
{ {
if (!strncmp (data_p + 28, "mark", 4)) if (!strncmp (ctx.data_p + 28, "mark", 4))
{ // this is not a proper parse, but it works with cooledit... { // this is not a proper parse, but it works with cooledit...
data_p += 24; ctx.data_p += 24;
i = GetLittleLong (); // samples in loop i = GetLittleLong (&ctx); // samples in loop
info.samples = info.loopstart + i; info.samples = info.loopstart + i;
// Con_Printf("looped length: %i\n", i); // Con_Printf("looped length: %i\n", i);
} }
@ -1074,14 +1086,14 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
info.loopstart = -1; info.loopstart = -1;
// find data chunk // find data chunk
chunklen = FindChunk("data"); chunklen = FindChunk(&ctx, "data");
if (!chunklen) if (!ctx.data_p)
{ {
Con_Printf("Missing data chunk in %s\n", name); Con_Printf("Missing data chunk in %s\n", name);
return info; return info;
} }
data_p += 8; ctx.data_p += 8;
samples = chunklen / info.width /info.numchannels; samples = chunklen / info.width /info.numchannels;
if (info.samples) if (info.samples)
@ -1101,7 +1113,7 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
info.loopstart = info.samples; info.loopstart = info.samples;
} }
info.dataofs = data_p - wav; info.dataofs = ctx.data_p - wav;
return info; return info;
} }

View file

@ -45,17 +45,19 @@ typedef struct {
void *buf; void *buf;
} sfxdecode_t; } sfxdecode_t;
enum
{
SLS_NOTLOADED, //not tried to load it
SLS_LOADING, //loading it on a worker thread.
SLS_LOADED, //currently in memory and usable.
SLS_FAILED //already tried to load it. it won't work. not found, invalid format, etc
};
typedef struct sfx_s typedef struct sfx_s
{ {
char name[MAX_OSPATH]; char name[MAX_OSPATH];
sfxdecode_t decoder; sfxdecode_t decoder;
enum { int loadstate; //no more super-spammy
SLS_NOTLOADED, //not tried to load it
SLS_LOADING, //loading it on a worker thread.
SLS_LOADED, //currently in memory and usable.
SLS_FAILED //already tried to load it. it won't work. not found, invalid format, etc
} loadstate; //no more super-spammy
qboolean touched:1; //if the sound is still relevent qboolean touched:1; //if the sound is still relevent
#ifdef AVAIL_OPENAL #ifdef AVAIL_OPENAL

View file

@ -82,6 +82,9 @@ void INS_Move(float *movements, int pnum)
void INS_Commands(void) void INS_Commands(void)
{ {
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
}
void INS_Init(void) void INS_Init(void)
{ {
} }

View file

@ -252,7 +252,8 @@ void Sys_Printf (char *fmt, ...)
void Sys_Quit (void) void Sys_Quit (void)
{ {
Host_Shutdown(); Host_Shutdown();
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); if (!noconinput)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
#ifdef USE_LIBTOOL #ifdef USE_LIBTOOL
lt_dlexit(); lt_dlexit();
@ -273,7 +274,8 @@ void Sys_Error (const char *error, ...)
char string[1024]; char string[1024];
// change stdin to non blocking // change stdin to non blocking
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); if (!noconinput)
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
va_start (argptr,error); va_start (argptr,error);
vsnprintf (string,sizeof(string)-1, error,argptr); vsnprintf (string,sizeof(string)-1, error,argptr);
@ -703,6 +705,9 @@ char *Sys_ConsoleInput(void)
static char text[256]; static char text[256];
int len; int len;
if (noconinput)
return NULL;
// if (!qrenderer) // if (!qrenderer)
{ {
len = read (0, text, sizeof(text)); len = read (0, text, sizeof(text));

View file

@ -123,7 +123,7 @@ double Sys_DoubleTime (void)
void Sys_Quit (void) void Sys_Quit (void)
{ {
Host_Shutdown (); Host_Shutdown ();
exit(1); exit(0);
} }
void Sys_mkdir (char *path) void Sys_mkdir (char *path)
@ -291,7 +291,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(
#else #else
#if defined(GLQUAKE) #if defined(GLQUAKE)
//#define PRINTGLARRAYS #define PRINTGLARRAYS
#endif #endif
#if defined(_DEBUG) || defined(DEBUG) #if defined(_DEBUG) || defined(DEBUG)
@ -606,7 +606,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI
} }
#ifdef PRINTGLARRAYS #ifdef PRINTGLARRAYS
if (!iswatchdog && qrenderer == QR_OPENGL) if (!iswatchdog && qrenderer == QR_OPENGL && Sys_IsMainThread())
DumpGLState(); DumpGLState();
#endif #endif
@ -2841,7 +2841,7 @@ void Sys_SetAutoUpdateSetting(int newval)
Update_Check(); Update_Check();
} }
qboolean Sys_CheckUpdated(void) qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize)
{ {
int ffe = COM_CheckParm("--fromfrontend"); int ffe = COM_CheckParm("--fromfrontend");
PROCESS_INFORMATION childinfo; PROCESS_INFORMATION childinfo;
@ -2924,7 +2924,12 @@ qboolean Sys_CheckUpdated(void)
return true; return true;
} }
if (com_argv[ffe+2]) if (com_argv[ffe+2])
{
com_argv[0] = com_argv[ffe+2]; com_argv[0] = com_argv[ffe+2];
Q_strncpyz(bindir, com_argv[0], bindirsize);
*COM_SkipPath(bindir) = 0;
}
} }
return false; return false;
} }
@ -2936,7 +2941,7 @@ int Sys_GetAutoUpdateSetting(void)
void Sys_SetAutoUpdateSetting(int newval) void Sys_SetAutoUpdateSetting(int newval)
{ {
} }
qboolean Sys_CheckUpdated(void) qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize)
{ {
return false; return false;
} }
@ -3024,6 +3029,7 @@ void Sys_DoFileAssociations(qboolean elevated)
Q_snprintfz(command, sizeof(command), DISTRIBUTION"_BSPFile.1"); Q_snprintfz(command, sizeof(command), DISTRIBUTION"_BSPFile.1");
ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\FileAssociations", ".bsp", REG_SZ, command, strlen(command)); ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\FileAssociations", ".bsp", REG_SZ, command, strlen(command));
ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\FileAssociations", ".map", REG_SZ, command, strlen(command));
// ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\FileAssociations", ".fmf", REG_SZ, DISTRIBUTION"_ManifestFile", strlen(DISTRIBUTION"_ManifestFile")); // ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\FileAssociations", ".fmf", REG_SZ, DISTRIBUTION"_ManifestFile", strlen(DISTRIBUTION"_ManifestFile"));
// ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\MIMEAssociations", "application/x-ftemanifest", REG_SZ, DISTRIBUTION"_ManifestFile", strlen(DISTRIBUTION"_ManifestFile")); // ok = ok & MyRegSetValue(root, "Software\\"FULLENGINENAME"\\Capabilities\\MIMEAssociations", "application/x-ftemanifest", REG_SZ, DISTRIBUTION"_ManifestFile", strlen(DISTRIBUTION"_ManifestFile"));
@ -3172,6 +3178,593 @@ static int Sys_ProcessCommandline(char **argv, int maxargc, char *argv0)
return i; return i;
} }
//using this like posix' access function, but with much more code, microsoftisms, and no errno codes/info
//no, I don't really have a clue why it needs to be so long.
#include <svrapi.h>
BOOL microsoft_access(LPCSTR pszFolder, DWORD dwAccessDesired)
{
HANDLE hToken;
PRIVILEGE_SET PrivilegeSet;
DWORD dwPrivSetSize;
DWORD dwAccessGranted;
BOOL fAccessGranted = FALSE;
GENERIC_MAPPING GenericMapping;
SECURITY_INFORMATION si = (SECURITY_INFORMATION)( OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION);
PSECURITY_DESCRIPTOR psdSD = NULL;
DWORD dwNeeded;
wchar_t wpath[MAX_OSPATH];
widen(wpath, sizeof(wpath), pszFolder);
GetFileSecurity(pszFolder,si,NULL,0,&dwNeeded);
psdSD = malloc(dwNeeded);
GetFileSecurity(pszFolder,si,psdSD,dwNeeded,&dwNeeded);
ImpersonateSelf(SecurityImpersonation);
OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hToken);
memset(&GenericMapping, 0xff, sizeof(GENERIC_MAPPING));
GenericMapping.GenericRead = ACCESS_READ;
GenericMapping.GenericWrite = ACCESS_WRITE;
GenericMapping.GenericExecute = 0;
GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
MapGenericMask(&dwAccessDesired, &GenericMapping);
dwPrivSetSize = sizeof(PRIVILEGE_SET);
AccessCheck(psdSD, hToken, dwAccessDesired, &GenericMapping, &PrivilegeSet, &dwPrivSetSize, &dwAccessGranted, &fAccessGranted);
free(psdSD);
return fAccessGranted;
}
int MessageBoxU(HWND hWnd, char *lpText, char *lpCaption, UINT uType)
{
wchar_t widecaption[256];
wchar_t widetext[2048];
widen(widetext, sizeof(widetext), lpText);
widen(widecaption, sizeof(widecaption), lpCaption);
return MessageBoxW(hWnd, widetext, widecaption, uType);
}
static WNDPROC omgwtfwhyohwhy;
LRESULT CALLBACK stoopidstoopidstoopid(HWND w, UINT m, WPARAM wp, LPARAM lp)
{
switch (m)
{
case WM_NOTIFY:
switch (((LPNMHDR)lp)->code)
{
case TVN_ENDLABELEDITW:
{
LRESULT r;
NMTVDISPINFOW *fu = (NMTVDISPINFOW*)lp;
NMTREEVIEWW gah;
gah.action = TVC_UNKNOWN;
gah.itemOld = fu->item;
gah.itemNew = fu->item;
gah.ptDrag.x = gah.ptDrag.y = 0;
gah.hdr = fu->hdr;
gah.hdr.code = TVN_SELCHANGEDW;
r = CallWindowProc(omgwtfwhyohwhy,w,m,wp,lp);
CallWindowProc(omgwtfwhyohwhy,w,WM_NOTIFY,wp,(LPARAM)&gah);
return r;
}
break;
case TVN_ENDLABELEDITA:
{
LRESULT r;
NMTVDISPINFOA *fu = (NMTVDISPINFOA*)lp;
NMTREEVIEWA gah;
gah.action = TVC_UNKNOWN;
gah.itemOld = fu->item;
gah.itemNew = fu->item;
gah.ptDrag.x = gah.ptDrag.y = 0;
gah.hdr = fu->hdr;
gah.hdr.code = TVN_SELCHANGEDA;
r = CallWindowProc(omgwtfwhyohwhy,w,m,wp,lp);
CallWindowProc(omgwtfwhyohwhy,w,WM_NOTIFY,wp,(LPARAM)&gah);
return r;
}
break;
case TVN_SELCHANGEDA:
case TVN_SELCHANGEDW:
break;
}
break;
}
return CallWindowProc(omgwtfwhyohwhy,w,m,wp,lp);
}
struct egadsthisisretarded
{
char title[MAX_OSPATH];
char subdir[MAX_OSPATH];
char parentdir[MAX_OSPATH];
char statustext[MAX_OSPATH];
};
static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pDatafoo)
{ //'stolen' from microsoft's knowledge base.
//required to work around microsoft being annoying.
struct egadsthisisretarded *pData = (struct egadsthisisretarded*)pDatafoo;
TCHAR szDir[MAX_PATH];
// char *foo;
HWND edit = FindWindowEx(hwnd, NULL, "EDIT", NULL);
HWND list;
extern qboolean com_homepathenabled;
// OutputDebugString(va("got %u (%u)\n", uMsg, lp));
switch(uMsg)
{
case BFFM_INITIALIZED:
OutputDebugString("initialised\n");
//combat windows putting new windows behind everything else if it takes a while for UAC prompts to go away
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
//combat windows bug where renaming something doesn't update the dialog's path
list = FindWindowEx(hwnd, NULL, "SHBROWSEFORFOLDER SHELLNAMESPACE CONTROL", NULL);
if (list)
omgwtfwhyohwhy = (WNDPROC)SetWindowLongPtr(list, GWLP_WNDPROC, (LONG_PTR)stoopidstoopidstoopid);
#ifndef _DEBUG
//the standard location iiuc
if (com_homepathenabled && SHGetSpecialFolderPath(NULL, szDir, CSIDL_PROGRAM_FILES, TRUE) && microsoft_access(szDir, ACCESS_READ | ACCESS_WRITE))
;
else if (microsoft_access("C:\\Games\\", ACCESS_READ | ACCESS_WRITE))
Q_strncpyz(szDir, "C:\\Games\\", sizeof(szDir));
else if (microsoft_access("C:\\", ACCESS_READ | ACCESS_WRITE))
Q_strncpyz(szDir, "C:\\", sizeof(szDir));
//if we're not an admin, install it somewhere else.
else if (SHGetSpecialFolderPath(NULL, szDir, CSIDL_LOCAL_APPDATA, TRUE) && microsoft_access(szDir, ACCESS_READ | ACCESS_WRITE))
;
else
#endif
if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir) && microsoft_access(szDir, ACCESS_READ | ACCESS_WRITE))
;
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir);
// SendMessage(hwnd, BFFM_SETEXPANDED, TRUE, (LPARAM)szDir);
SendMessageW(hwnd, BFFM_SETOKTEXT, TRUE, (LPARAM)L"Install");
break;
case BFFM_VALIDATEFAILEDA:
if (!microsoft_access(pData->parentdir, ACCESS_READ | ACCESS_WRITE))
return 1;
if (edit)
GetWindowText(edit, pData->subdir, sizeof(pData->subdir));
if (microsoft_access(va("%s\\%s", pData->parentdir, pData->subdir), ACCESS_READ))
return MessageBoxU(hwnd, va("%s\\%s already exists!\nThis installer will (generally) not overwrite.\nIf you want to re-install, you must manually uninstall it first.\n\nContinue?", pData->parentdir, pData->subdir), fs_gamename.string, MB_ICONWARNING|MB_OKCANCEL|MB_TOPMOST) == IDCANCEL;
else
return MessageBoxU(hwnd, va("Install to %s\\%s ?", pData->parentdir, pData->subdir), fs_gamename.string, MB_OKCANCEL) == IDCANCEL;
case BFFM_VALIDATEFAILEDW:
return 1;//!microsoft_access("C:\\Games\\", ACCESS_READ | ACCESS_WRITE))
case BFFM_SELCHANGED:
OutputDebugString("selchanged\n");
if (SHGetPathFromIDList((LPITEMIDLIST)lp, pData->parentdir))
{
// OutputDebugString(va("selchanged: %s\n", szDir));
// while(foo = strchr(pData->parentdir, '\\'))
// *foo = '/';
//fixme: verify that id1 is a subdir perhaps?
if (edit)
{
SetWindowText(edit, fs_gamename.string);
SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)va("%s", pData->parentdir));
}
else
SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)va("%s/%s", pData->parentdir, fs_gamename.string));
}
break;
case BFFM_IUNKNOWN:
break;
}
return 0;
}
LRESULT CALLBACK NoCloseWindowProc(HWND w, UINT m, WPARAM wp, LPARAM lp)
{
if (m == WM_CLOSE)
return 0;
return DefWindowProc(w, m, wp, lp);
}
void FS_CreateBasedir(const char *path);
qboolean Sys_DoInstall(void)
{
extern ftemanifest_t *fs_manifest;
char exepath[MAX_OSPATH];
char newexepath[MAX_OSPATH];
char resultpath[MAX_PATH];
BROWSEINFO bi;
LPITEMIDLIST il;
struct egadsthisisretarded diediedie;
if (fs_manifest && fs_manifest->eula)
{
if (MessageBoxU(NULL, fs_manifest->eula, fs_gamename.string, MB_OKCANCEL|MB_TOPMOST|MB_DEFBUTTON2) != IDOK)
return TRUE;
}
memset(&bi, 0, sizeof(bi));
bi.hwndOwner = mainwindow; //note that this is usually still null
bi.pidlRoot = NULL;
GetCurrentDirectory(sizeof(resultpath)-1, resultpath);
bi.pszDisplayName = resultpath;
Q_snprintfz(diediedie.title, sizeof(diediedie.title), "Where would you like to install %s to?", fs_gamename.string);
bi.lpszTitle = diediedie.title;
bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT | BIF_EDITBOX|BIF_NEWDIALOGSTYLE|BIF_VALIDATE;
bi.lpfn = StupidBrowseCallbackProc;
bi.lParam = (LPARAM)&diediedie;
bi.iImage = 0;
Q_strncpyz(diediedie.subdir, fs_gamename.string, sizeof(diediedie.subdir));
il = SHBrowseForFolder(&bi);
if (il)
{
SHGetPathFromIDList(il, resultpath);
CoTaskMemFree(il);
}
else
return true;
Q_strncatz(resultpath, "/", sizeof(resultpath));
if (*diediedie.subdir)
{
Q_strncatz(resultpath, diediedie.subdir, sizeof(resultpath));
Q_strncatz(resultpath, "/", sizeof(resultpath));
}
FS_CreateBasedir(resultpath);
GetModuleFileName(NULL, exepath, sizeof(exepath));
FS_NativePath(va("%s.exe", fs_gamename.string), FS_ROOT, newexepath, sizeof(newexepath));
CopyFile(exepath, newexepath, FALSE);
/*the game can now be run (using regular autoupdate stuff), but most installers are expected to install the data instead of just more downloaders, so lets do that with a 'nice' progress box*/
{
HINSTANCE hInstance = NULL;
HWND progress, label, wnd;
WNDCLASS wc;
RECT ca;
int sh;
int pct = -100;
char fname[MAX_OSPATH];
memset(&wc, 0, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = NoCloseWindowProc;//Progress_Wnd;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
wc.hbrBackground = (void *)COLOR_WINDOW;
wc.lpszClassName = "FTEPROG";
RegisterClass(&wc);
ca.right = GetSystemMetrics(SM_CXSCREEN);
ca.bottom = GetSystemMetrics(SM_CYSCREEN);
mainwindow = wnd = CreateWindowEx(0, wc.lpszClassName, va("%s Installer", fs_gamename.string), 0, (ca.right-320)/2, (ca.bottom-100)/2, 320, 100, NULL, NULL, hInstance, NULL);
GetClientRect(wnd, &ca);
sh = GetSystemMetrics(SM_CYVSCROLL);
InitCommonControls();
label = CreateWindow("STATIC","", WS_CHILD | WS_VISIBLE | SS_PATHELLIPSIS, sh, ((ca.bottom-ca.top-sh)/3), ca.right-ca.left-2*sh, sh, wnd, NULL, hInstance, NULL);
progress = CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, sh, ((ca.bottom-ca.top-sh)/3)*2, ca.right-ca.left-2*sh, sh, wnd, NULL, hInstance, NULL);
ShowWindow(wnd, SW_NORMAL);
SetWindowPos(wnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
SendMessage(progress, PBM_SETRANGE32, 0, 10000);
*fname = 0;
HTTP_CL_Think();
while(FS_DownloadingPackage())
{
MSG msg;
char *cur = cls.download?COM_SkipPath(cls.download->localname):"Please Wait";
int newpct = cls.download?cls.download->percent*100:0;
if (cls.download && cls.download->sizeunknown)
{
//marquee needs manifest bollocks in order to work. so lets just not bother.
float time = Sys_DoubleTime();
newpct = 10000 * (time - (int)time);
if ((int)time & 1)
newpct = 10000 - newpct;
}
if (Q_strcmp(fname, cur))
{
Q_strncpyz(fname, cur, sizeof(fname));
SetWindowText(label, fname);
}
if (pct != newpct)
{
SendMessage(progress, PBM_SETPOS, pct, 0);
pct = newpct;
}
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessage (&msg);
Sleep(10);
HTTP_CL_Think();
}
DestroyWindow(progress);
DestroyWindow(wnd);
UnregisterClass("FTEPROG", hInstance);
mainwindow = NULL;
}
/*create startmenu icon*/
if (MessageBoxU(NULL, va("Create Startmenu icon for %s?", fs_gamename.string), fs_gamename.string, MB_YESNO|MB_ICONQUESTION|MB_TOPMOST) == IDYES)
{
HRESULT hres;
IShellLinkW *psl;
hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
char startmenu[MAX_OSPATH];
WCHAR wsz[MAX_PATH];
IPersistFile *ppf;
widen(wsz, sizeof(wsz), newexepath);
psl->lpVtbl->SetPath(psl, wsz);
widen(wsz, sizeof(wsz), resultpath);
psl->lpVtbl->SetWorkingDirectory(psl, wsz);
hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres) && SHGetSpecialFolderPath(NULL, startmenu, CSIDL_COMMON_PROGRAMS, TRUE))
{
WCHAR wsz[MAX_PATH];
widen(wsz, sizeof(wsz), va("%s/%s.lnk", startmenu, fs_gamename.string));
hres = ppf->lpVtbl->Save(ppf, wsz, TRUE);
if (hres == E_ACCESSDENIED && SHGetSpecialFolderPath(NULL, startmenu, CSIDL_PROGRAMS, TRUE))
{
widen(wsz, sizeof(wsz), va("%s/%s.lnk", startmenu, fs_gamename.string));
hres = ppf->lpVtbl->Save(ppf, wsz, TRUE);
}
ppf->lpVtbl->Release(ppf);
}
psl->lpVtbl->Release(psl);
}
}
//now start it up properly.
ShellExecute(mainwindow, "open", newexepath, Q_strcasecmp(fs_manifest->installation, "quake")?"":"+sys_register_file_associations", resultpath, SW_SHOWNORMAL);
return true;
}
qboolean Sys_RunInstaller(void)
{
HINSTANCE ch;
char exepath[MAX_OSPATH];
if (COM_CheckParm("-doinstall"))
return Sys_DoInstall();
if (!com_installer)
return false;
if (MessageBoxU(NULL, va("%s is not installed. Install now?", fs_gamename.string), fs_gamename.string, MB_OKCANCEL|MB_ICONQUESTION|MB_TOPMOST) == IDOK)
{
GetModuleFileName(NULL, exepath, sizeof(exepath));
ch = ShellExecute(mainwindow, "runas", com_argv[0], va("%s -doinstall", COM_Parse(GetCommandLine())), NULL, SW_SHOWNORMAL);
if ((intptr_t)ch > 32)
return true; //succeeded. should quit out.
return Sys_DoInstall(); //if it failed, try doing it with the current privileges
}
return true;
}
#include "fs.h"
#define RESLANG MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)
static const char *Sys_FindManifest(void)
{
HRSRC hdl = FindResource(NULL, MAKEINTRESOURCE(1), RT_RCDATA);
HGLOBAL hgl = LoadResource(NULL, hdl);
return LockResource(hgl);
}
//size info that microsoft recommends
static const struct
{
int width;
int height;
int bpp;
} icosizes[] = {
// {96, 96, 32},
{48, 48, 32},
{32, 32, 32},
{16, 16, 32},
// {16, 16, 4},
// {48, 48, 4},
// {32, 32, 4},
// {16, 16, 1},
// {48, 48, 1},
// {32, 32, 1},
{256, 256, 32} //vista!
};
//dates back to 16bit windows. bah.
#pragma pack(push)
#pragma pack(2)
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD nId;
} idEntries[sizeof(icosizes)/sizeof(icosizes[0])];
} icon_group_t;
#pragma pack(pop)
static void Sys_MakeInstaller(const char *name)
{
vfsfile_t *filehandle;
qbyte *filedata;
unsigned int filelen;
char *error = NULL;
HANDLE bin;
char ourname[MAX_OSPATH];
char newname[MAX_OSPATH];
char tmpname[MAX_OSPATH];
Q_snprintfz(newname, sizeof(newname), "%s.exe", name);
Q_snprintfz(tmpname, sizeof(tmpname), "tmp.exe");
GetModuleFileName(NULL, ourname, sizeof(ourname));
if (!CopyFile(ourname, tmpname, FALSE))
error = va("\"%s\" already exists or cannot be written", tmpname);
if (!(bin = BeginUpdateResource(tmpname, FALSE)))
error = "BeginUpdateResource failed";
else
{
//nuke existing icons.
UpdateResource(bin, RT_GROUP_ICON, MAKEINTRESOURCE(1), RESLANG, NULL, 0);
UpdateResource(bin, RT_GROUP_ICON, MAKEINTRESOURCE(2), RESLANG, NULL, 0);
// UpdateResource(bin, RT_GROUP_ICON, MAKEINTRESOURCE(3), RESLANG, NULL, 0);
filehandle = VFSOS_Open(va("%s.png", name), "rb");
if (filehandle)
{
icon_group_t icondata;
qbyte *rgbadata;
int imgwidth, imgheight;
int iconid = 1;
qboolean hasalpha;
memset(&icondata, 0, sizeof(icondata));
icondata.idType = 1;
filelen = VFS_GETLEN(filehandle);
filedata = BZ_Malloc(filelen);
VFS_READ(filehandle, filedata, filelen);
VFS_CLOSE(filehandle);
rgbadata = Read32BitImageFile(filedata, filelen, &imgwidth, &imgheight, &hasalpha, va("%s.png", name));
if (!rgbadata)
error = "unable to read icon image";
else
{
void *data = NULL;
unsigned int datalen = 0;
unsigned int i;
extern cvar_t gl_lerpimages;
gl_lerpimages.ival = 1;
for (i = 0; i < sizeof(icosizes)/sizeof(icosizes[0]); i++)
{
unsigned int x,y;
unsigned int pixels;
if (icosizes[i].width > imgwidth || icosizes[i].height > imgheight)
continue; //ignore icons if they're bigger than the original icon.
if (icosizes[i].bpp == 32 && icosizes[i].width >= 128 && icosizes[i].height >= 128 && icosizes[i].width == imgwidth && icosizes[i].height == imgheight)
{ //png compression. oh look. we originally loaded a png!
data = filedata;
datalen = filelen;
}
else
{
//generate the bitmap info
BITMAPV4HEADER *bi;
qbyte *out, *outmask;
qbyte *in, *inrow;
unsigned int outidx;
pixels = icosizes[i].width * icosizes[i].height;
bi = data = Z_Malloc(sizeof(*bi) + icosizes[i].width * icosizes[i].height * 5 + icosizes[i].height*4);
memset(bi,0, sizeof(BITMAPINFOHEADER));
bi->bV4Size = sizeof(BITMAPINFOHEADER);
bi->bV4Width = icosizes[i].width;
bi->bV4Height = icosizes[i].height * 2;
bi->bV4Planes = 1;
bi->bV4BitCount = icosizes[i].bpp;
bi->bV4V4Compression = BI_RGB;
bi->bV4ClrUsed = (icosizes[i].bpp>=32?0:(1u<<icosizes[i].bpp));
datalen = bi->bV4Size;
out = (qbyte*)data + datalen;
datalen += ((icosizes[i].width*icosizes[i].bpp/8+3)&~3) * icosizes[i].height;
outmask = (qbyte*)data + datalen;
datalen += ((icosizes[i].width+31)&~31)/8 * icosizes[i].height;
in = malloc(pixels*4);
Image_ResampleTexture((unsigned int*)rgbadata, imgwidth, imgheight, (unsigned int*)in, icosizes[i].width, icosizes[i].height);
inrow = in;
outidx = 0;
if (icosizes[i].bpp == 32)
{
for (y = 0; y < icosizes[i].height; y++)
{
inrow = in + 4*icosizes[i].width*(icosizes[i].height-1-y);
for (x = 0; x < icosizes[i].width; x++)
{
if (inrow[3] == 0) //transparent
outmask[outidx>>3] |= 1u<<(outidx&7);
else
{
out[0] = inrow[2];
out[1] = inrow[1];
out[2] = inrow[0];
}
out += 4;
outidx++;
inrow += 4;
}
if (x & 3)
out += 4 - (x&3);
outidx = (outidx + 31)&~31;
}
}
}
if (!error && !UpdateResource(bin, RT_ICON, MAKEINTRESOURCE(iconid), 0, data, datalen))
error = "UpdateResource failed (icon data)";
//and make a copy of it in the icon list
icondata.idEntries[icondata.idCount].bWidth = (icosizes[i].width<256)?icosizes[i].width:0;
icondata.idEntries[icondata.idCount].bHeight = (icosizes[i].height<256)?icosizes[i].height:0;
icondata.idEntries[icondata.idCount].wBitCount = icosizes[i].bpp;
icondata.idEntries[icondata.idCount].wPlanes = 1;
icondata.idEntries[icondata.idCount].bColorCount = (icosizes[i].bpp>=8)?0:(1u<<icosizes[i].bpp);
icondata.idEntries[icondata.idCount].dwBytesInRes = datalen;
icondata.idEntries[icondata.idCount].nId = iconid++;
icondata.idCount++;
}
}
if (!error && !UpdateResource(bin, RT_GROUP_ICON, MAKEINTRESOURCE(IDI_ICON1), RESLANG, &icondata, (qbyte*)&icondata.idEntries[icondata.idCount] - (qbyte*)&icondata))
error = "UpdateResource failed (icon group)";
BZ_Free(filedata);
}
else
error = va("%s.ico not found", name);
filehandle = VFSOS_Open(va("%s.fmf", name), "rb");
if (filehandle)
{
filelen = VFS_GETLEN(filehandle);
filedata = BZ_Malloc(filelen+1);
filedata[filelen] = 0;
VFS_READ(filehandle, filedata, filelen);
VFS_CLOSE(filehandle);
if (!error && !UpdateResource(bin, RT_RCDATA, MAKEINTRESOURCE(1), 0, filedata, filelen+1))
error = "UpdateResource failed (manicfest)";
BZ_Free(filedata);
}
else
error = va("%s.fmf not found in working directory", name);
if (!EndUpdateResource(bin, !!error) && !error)
error = "EndUpdateResource failed. Check access permissions.";
DeleteFile(newname);
MoveFile(tmpname, newname);
}
if (error)
Sys_Error("%s", error);
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{ {
// MSG msg; // MSG msg;
@ -3234,8 +3827,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
MessageBox(NULL, "This is an SSE2 optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0); MessageBox(NULL, "This is an SSE2 optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0);
else else
#endif #endif
if (!(idedx&(1<<25))) if (!(idedx&(1<<25)))
MessageBox(NULL, "This is an SSE optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0); MessageBox(NULL, "This is an SSE optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0);
} }
#endif #endif
#endif #endif
@ -3297,7 +3890,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
isPlugin = 0; isPlugin = 0;
} }
if (Sys_CheckUpdated()) if (Sys_CheckUpdated(bindir, sizeof(bindir)))
return true; return true;
if (COM_CheckParm("-register_types")) if (COM_CheckParm("-register_types"))
@ -3349,6 +3942,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (!GetCurrentDirectoryA (sizeof(cwd), cwd)) if (!GetCurrentDirectoryA (sizeof(cwd), cwd))
Sys_Error ("Couldn't determine current directory"); Sys_Error ("Couldn't determine current directory");
} }
c = COM_CheckParm("-makeinstaller");
if (c)
{
Sys_MakeInstaller(parms.argv[c+1]);
return true;
}
parms.manifest = Sys_FindManifest();
if (parms.argc >= 2) if (parms.argc >= 2)
{ {
if (*parms.argv[1] != '-' && *parms.argv[1] != '+') if (*parms.argv[1] != '-' && *parms.argv[1] != '+')
@ -3380,7 +3982,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
} }
else else
{ {
MessageBox(NULL, "Expected one argument, got multiple", "Blocking potential remote exploit", 0); MessageBox(NULL, va("Invalid commandline:\n%s", lpCmdLine), FULLENGINENAME, 0);
return 0; return 0;
} }
@ -3408,8 +4010,10 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
TL_InitLanguages(); TL_InitLanguages();
//tprints are now allowed //tprints are now allowed
if (*cwd && cwd[strlen(cwd)-1] != '\\' && cwd[strlen(cwd)-1] != '/')
Q_strncatz(cwd, "/", sizeof(cwd));
parms.basedir = cwd; parms.basedir = cwd;
parms.binarydir = bindir;
parms.argc = com_argc; parms.argc = com_argc;
parms.argv = com_argv; parms.argv = com_argv;
@ -3545,8 +4149,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
#endif #endif
#endif #endif
/* return success of application */ /* return success of application */
return TRUE; return TRUE;
} }
int __cdecl main(void) int __cdecl main(void)

View file

@ -532,7 +532,7 @@ void Validation_Apply_Ruleset(void)
#endif #endif
Validation_DelatchRulesets(); //make sure there's no old one Validation_DelatchRulesets(); //make sure there's no old one
if (!*ruleset.string || !strcmp(ruleset.string, "none")) if (!*ruleset.string || !strcmp(ruleset.string, "none") || !strcmp(ruleset.string, "default"))
return; //no ruleset is set return; //no ruleset is set
for (rs = rulesets; rs->rulesetname; rs++) for (rs = rulesets; rs->rulesetname; rs++)

View file

@ -51,6 +51,8 @@ void W_CleanupName (const char *in, char *out)
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
c += ('a' - 'A'); c += ('a' - 'A');
if (c == '*') //not a valid filesystem char
c = '#';
out[i] = c; out[i] = c;
} }
@ -253,9 +255,9 @@ int numwadtextures;
static texwadlump_t texwadlump[TEXWAD_MAXIMAGES]; static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
typedef struct wadfile_s { typedef struct wadfile_s {
char name[64];
vfsfile_t *file; vfsfile_t *file;
struct wadfile_s *next; struct wadfile_s *next;
char name[1];
} wadfile_t; } wadfile_t;
wadfile_t *openwadfiles; wadfile_t *openwadfiles;
@ -345,6 +347,12 @@ void W_LoadTextureWadFile (char *filename, int complain)
} }
} }
// leaves the file open // leaves the file open
wf = BZ_Malloc(sizeof(*wf) + strlen(filename));
strcpy(wf->name, filename);
wf->file = file;
wf->next = openwadfiles;
openwadfiles = wf;
} }
/* /*
@ -384,6 +392,9 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *hei
else if (!strncmp(tex->name, "window", 6) || !strncmp(tex->name, "glass", 5)) else if (!strncmp(tex->name, "window", 6) || !strncmp(tex->name, "glass", 5))
alpha = 2; alpha = 2;
if (tex->width > 0x10000 || tex->height > 0x10000)
return NULL;
//use malloc here if you want, but you'll have to free it again... NUR! //use malloc here if you want, but you'll have to free it again... NUR!
data = out = BZ_Malloc(tex->width * tex->height * 4); data = out = BZ_Malloc(tex->width * tex->height * 4);
@ -394,10 +405,17 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *hei
*width = tex->width; *width = tex->width;
*height = tex->height; *height = tex->height;
pal = in + (((tex->width * tex->height) * 85) >> 6);
pal += 2; //halflife wads have palettes embedded in them. but make sure everything else is packed because some quake wads are weird.
if (pal+768 - (qbyte*)tex > lumpsize) if (tex->offsets[0] == sizeof(*tex) &&
tex->offsets[1] == tex->offsets[0] + (tex->width)*(tex->height) &&
tex->offsets[2] == tex->offsets[1] + (tex->width>>1)*(tex->height>>1) &&
tex->offsets[3] == tex->offsets[2] + (tex->width>>2)*(tex->height>>2) &&
lumpsize == tex->offsets[3] + (tex->width>>3)*(tex->height>>3) + 2 + 768)
pal = (qbyte *)tex + tex->offsets[3] + (tex->width>>3)*(tex->height>>3) + 2;
else
pal = host_basepal; pal = host_basepal;
for (d = 0;d < tex->width * tex->height;d++) for (d = 0;d < tex->width * tex->height;d++)
{ {
p = *in++; p = *in++;
@ -482,6 +500,39 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp
return NULL; return NULL;
} }
miptex_t *W_GetMipTex(const char *name)
{
char texname[17];
int i, j;
vfsfile_t *file;
miptex_t *tex;
texname[16] = 0;
W_CleanupName (name, texname);
for (i = 0;i < numwadtextures;i++)
{
if (!strcmp(texname, texwadlump[i].name)) // found it
{
file = texwadlump[i].file;
if (!VFS_SEEK(file, texwadlump[i].position))
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
tex = BZ_Malloc(texwadlump[i].size); //temp buffer for disk info (was hunk_tempalloc, but that wiped loading maps and the like
if (!tex)
return NULL;
if (VFS_READ(file, tex, texwadlump[i].size) < texwadlump[i].size)
{Con_Printf("W_GetTexture: corrupt WAD3 file");return NULL;}
tex->width = LittleLong(tex->width);
tex->height = LittleLong(tex->height);
for (j = 0;j < MIPLEVELS;j++)
tex->offsets[j] = LittleLong(tex->offsets[j]);
return tex;
}
}
return NULL;
}
typedef struct mapgroup_s { typedef struct mapgroup_s {
char *mapname; char *mapname;
char *skyname; char *skyname;

View file

@ -116,3 +116,4 @@ qbyte *W_ConvertWAD3Texture(miptex_t *tex, size_t lumpsize, int *width, int *hei
void Mod_ParseInfoFromEntityLump(struct model_s *wmodel); void Mod_ParseInfoFromEntityLump(struct model_s *wmodel);
qboolean Wad_NextDownload (void); qboolean Wad_NextDownload (void);
qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalpha); qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalpha);
miptex_t *W_GetMipTex(const char *name);

View file

@ -79,8 +79,8 @@ void TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue);
TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \ TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \
TP_CVAR(tp_forceTriggers, "0"); \ TP_CVAR(tp_forceTriggers, "0"); \
TP_CVAR(tp_loadlocs, "1"); \ TP_CVAR(tp_loadlocs, "1"); \
TP_CVARC(cl_teamskin, "", TP_SkinCvar_Callback); \ TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARC(cl_enemyskin, "", TP_SkinCvar_Callback); \ TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVAR(tp_soundtrigger, "~"); \ TP_CVAR(tp_soundtrigger, "~"); \
\ \
TP_CVAR(tp_name_none, ""); \ TP_CVAR(tp_name_none, ""); \
@ -165,9 +165,11 @@ void TP_SkinCvar_Callback(struct cvar_s *var, char *oldvalue);
//create the globals for all the TP cvars. //create the globals for all the TP cvars.
#define TP_CVAR(name,def) cvar_t name = CVAR(#name, def) #define TP_CVAR(name,def) cvar_t name = CVAR(#name, def)
#define TP_CVARC(name,def,call) cvar_t name = CVARC(#name, def, call) #define TP_CVARC(name,def,call) cvar_t name = CVARC(#name, def, call)
#define TP_CVARAC(name,def,name2,call) cvar_t name = CVARAFC(#name, def, #name2, 0, call)
TP_CVARS; TP_CVARS;
#undef TP_CVAR #undef TP_CVAR
#undef TP_CVARC #undef TP_CVARC
#undef TP_CVARAC
extern cvar_t host_mapname; extern cvar_t host_mapname;
@ -2092,57 +2094,118 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
player_info_t *player; player_info_t *player;
char *name; char *name;
*offset = 0;
*plr = NULL;
flags = TPM_UNKNOWN; flags = TPM_UNKNOWN;
msglen = strlen(s); msglen = strlen(s);
if (!msglen) if (!msglen)
return TPM_UNKNOWN; return TPM_UNKNOWN;
*offset = 0; if ((s[0] == '^' && s[1] == '[') || (s[0] == '(' && s[1] == '^' && s[2] == '['))
*plr = NULL;
for (i=0, player=cl.players ; i < cl.allocated_client_slots ; i++, player++)
{ {
name = player->name; char *end, *info;
if (!(*name)) i = 0;
continue; for(info = s; *info; )
len = strlen(name); {
// check messagemode1 if (info[0] == '^' && info[1] == ']')
if (len+2 <= msglen && s[len] == ':' && s[len+1] == ' ' && break;
!strncmp(name, s, len)) if (*info == '\\')
break;
if (info[0] == '^' && info[1] == '^')
info+=2;
else
info++;
}
for(end = info; *end; )
{
if (end[0] == '^' && end[1] == ']')
{
*end = 0;
info = Info_ValueForKey(info, "player");
if (*info)
i = atoi(info)+1;
*end = '^';
break;
}
if (end[0] == '^' && end[1] == '^')
end+=2;
else
end++;
}
if (!*end || i < 1 || i > cl.allocated_client_slots)
return TPM_UNKNOWN;
if (*s == '(')
{
if (end[2] != ')')
return TPM_UNKNOWN;
end+=3;
}
else
end+=2;
if (*end++ != ':')
return TPM_UNKNOWN;
if (*end++ != ' ')
return TPM_UNKNOWN;
*plr = player = &cl.players[i-1];
*offset = end - s;
if (*s == '(')
flags = TPM_TEAM;
else
{ {
if (player->spectator) if (player->spectator)
flags |= TPM_SPECTATOR; flags |= TPM_SPECTATOR;
else else
flags |= TPM_NORMAL; flags |= TPM_NORMAL;
*offset = len + 2;
*plr = player;
} }
// check messagemode2 }
else if (s[0] == '(' && len+4 <= msglen && else
!strncmp(s+len+1, "): ", 3) && {
!strncmp(name, s+1, len)) for (i=0, player=cl.players ; i < cl.allocated_client_slots ; i++, player++)
{ {
// no team messages in teamplay 0, except for our own name = player->name;
if (cl.spectator) if (!(*name))
continue;
len = strlen(name);
// check messagemode1
if (len+2 <= msglen && s[len] == ':' && s[len+1] == ' ' &&
!strncmp(name, s, len))
{ {
unsigned int track = Cam_TrackNum(&cl.playerview[SP]); if (player->spectator)
if (i == track || ( cl.teamplay && flags |= TPM_SPECTATOR;
!strcmp(cl.players[track].team, player->team)) ) else
{ flags |= TPM_NORMAL;
flags |= TPM_OBSERVEDTEAM; *offset = len + 2;
} *plr = player;
} }
else // check messagemode2
else if (s[0] == '(' && len+4 <= msglen &&
!strncmp(s+len+1, "): ", 3) &&
!strncmp(name, s+1, len))
{ {
if (i == cl.playerview[SP].playernum || ( cl.teamplay && // no team messages in teamplay 0, except for our own
!strcmp(cl.players[cl.playerview[SP].playernum].team, player->team)) ) if (cl.spectator)
{ {
flags |= TPM_TEAM; unsigned int track = Cam_TrackNum(&cl.playerview[SP]);
if (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) )
{
flags |= TPM_OBSERVEDTEAM;
}
}
else
{
if (i == cl.playerview[SP].playernum || ( cl.teamplay &&
!strcmp(cl.players[cl.playerview[SP].playernum].team, player->team)) )
{
flags |= TPM_TEAM;
}
} }
}
*offset = len + 4; *offset = len + 4;
*plr = player; *plr = player;
}
} }
} }
@ -3390,9 +3453,11 @@ void TP_Init (void)
//register all the TeamPlay cvars. //register all the TeamPlay cvars.
#define TP_CVAR(name,def) Cvar_Register (&name, TEAMPLAYVARS); #define TP_CVAR(name,def) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARC(name,def,callback) Cvar_Register (&name, TEAMPLAYVARS); #define TP_CVARC(name,def,callback) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARAC(name,def,name2,callback) Cvar_Register (&name, TEAMPLAYVARS);
TP_CVARS; TP_CVARS;
#undef TP_CVAR #undef TP_CVAR
#undef TP_CVARC #undef TP_CVARC
#undef TP_CVARAC
Cmd_AddCommand ("loadloc", TP_LoadLocFile_f); Cmd_AddCommand ("loadloc", TP_LoadLocFile_f);
Cmd_AddCommand ("filter", TP_MsgFilter_f); Cmd_AddCommand ("filter", TP_MsgFilter_f);
@ -3429,7 +3494,7 @@ qboolean TP_SuppressMessage(char *buf) {
return false; return false;
} }
void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags); void CL_PrintChat(player_info_t *plr, char *msg, int plrflags);
void CL_Say (qboolean team, char *extra) void CL_Say (qboolean team, char *extra)
{ {
@ -3509,7 +3574,7 @@ void CL_Say (qboolean team, char *extra)
if (team) if (team)
plrflags |= 2; plrflags |= 2;
CL_PrintChat(&cl.players[cl.playerview[SP].playernum], NULL, text, plrflags); CL_PrintChat(&cl.players[cl.playerview[SP].playernum], text, plrflags);
} }
//strip out the extra markup //strip out the extra markup

View file

@ -149,7 +149,7 @@ struct {
sizebuf_t buf; sizebuf_t buf;
int noclear; int noclear;
double waitattime; double waitattime;
} cmd_text[RESTRICT_MAX+1+MAX_SPLITS]; //max is local. } cmd_text[RESTRICT_MAX+3+MAX_SPLITS]; //max is local.
//RESTRICT_MAX+1 is the from sever buffer (max+2 is for second player...) //RESTRICT_MAX+1 is the from sever buffer (max+2 is for second player...)
/* /*

View file

@ -88,6 +88,7 @@ qboolean Cmd_AddCommandD (char *cmd_name, xcommand_t function, char *description
// as a clc_stringcmd instead of executed locally // as a clc_stringcmd instead of executed locally
qboolean Cmd_Exists (const char *cmd_name); qboolean Cmd_Exists (const char *cmd_name);
char *Cmd_AliasExist(const char *name, int restrictionlevel);
// 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_Describe (char *cmd_name);

View file

@ -2336,7 +2336,10 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
line = COM_ParseOut(line, tok, sizeof(tok)); line = COM_ParseOut(line, tok, sizeof(tok));
frames[count].fps = atof(tok); frames[count].fps = atof(tok);
line = COM_ParseOut(line, tok, sizeof(tok)); line = COM_ParseOut(line, tok, sizeof(tok));
frames[count].loop = !!atoi(tok); if (!strcmp(tok, "true") || !strcmp(tok, "yes") || !strcmp(tok, "on"))
frames[count].loop = true;
else
frames[count].loop = !!atoi(tok);
line = COM_ParseOut(line, frames[count].name, sizeof(frames[count].name)); line = COM_ParseOut(line, frames[count].name, sizeof(frames[count].name));
if (frames[count].posecount>0 && frames[count].fps) if (frames[count].posecount>0 && frames[count].fps)
count++; count++;
@ -3150,6 +3153,40 @@ static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, u
} }
#endif #endif
void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
{
unsigned int numanims, a, p, n, g, oldnumanims = galias->numanimations, targpose;
galiasanimation_t *o, *oldanims = galias->ofsanimations, *frame;
frameinfo_t *framegroups = ParseFrameInfo(mod->name, &numanims);
if (framegroups)
{
galias->ofsanimations = o = ZG_Malloc(&mod->memgroup, sizeof(*galias->ofsanimations) * numanims);
for (a = 0; a < numanims; a++, o++)
{
o->poseofs = ZG_Malloc(&mod->memgroup, sizeof(*o->poseofs) * framegroups[a].posecount);
for (p = 0; p < framegroups[a].posecount; p++)
{
targpose = framegroups[a].firstpose + p;
for (n = 0, g = 0, frame = oldanims; g < oldnumanims; g++, frame++)
{
if (targpose < frame->numposes)
break;
targpose -= frame->numposes;
}
if (g == oldnumanims)
break;
o->poseofs[p] = frame->poseofs[targpose];
}
o->numposes = p;
o->rate = framegroups[a].fps;
o->loop = framegroups[a].loop;
Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name));
}
galias->numanimations = numanims;
free(framegroups);
}
}
qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize) qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
@ -3440,6 +3477,8 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
mod->type = mod_alias; mod->type = mod_alias;
Mod_ClampModelSize(mod); Mod_ClampModelSize(mod);
Mesh_HandleFramegroupsFile(mod, galias);
mod->meshinfo = galias; mod->meshinfo = galias;
mod->funcs.NativeTrace = Mod_Trace; mod->funcs.NativeTrace = Mod_Trace;

View file

@ -350,7 +350,11 @@ int Q_strncasecmp (const char *s1, const char *s2, int n)
if (c2 >= 'a' && c2 <= 'z') if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A'); c2 -= ('a' - 'A');
if (c1 != c2) if (c1 != c2)
return -1; // strings not equal { // strings not equal
if (c1 > c2)
return 1; // strings not equal
return -1;
}
} }
if (!c1) if (!c1)
return 0; // strings are equal return 0; // strings are equal
@ -1174,7 +1178,7 @@ void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
MSG_WriteByte (buf, cmd->buttons); MSG_WriteByte (buf, cmd->buttons);
if (bits & CM_IMPULSE) if (bits & CM_IMPULSE)
MSG_WriteByte (buf, cmd->impulse); MSG_WriteByte (buf, cmd->impulse);
MSG_WriteByte (buf, cmd->msec); MSG_WriteByte (buf, cmd->msec&0xff);
} }
} }
@ -2993,7 +2997,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t
else if (*str == '^' && !(flags & PFS_NOMARKUP)) else if (*str == '^' && !(flags & PFS_NOMARKUP))
{ {
if (str[1] >= '0' && str[1] <= '9') if (str[1] >= '0' && str[1] <= '9')
{ { //q3 colour codes
if (ext & CON_RICHFORECOLOUR) if (ext & CON_RICHFORECOLOUR)
ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR)); ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR));
ext = q3codemasks[str[1]-'0'] | (ext&~CON_Q3MASK); //change colour only. ext = q3codemasks[str[1]-'0'] | (ext&~CON_Q3MASK); //change colour only.
@ -3344,7 +3348,7 @@ messedup:
} }
else else
{ {
if (uc == '\n' || uc == '\r' || uc == '\t' || uc == ' ') if (uc == '\n' || uc == '\r' || uc == '\t' || uc == '\v' || uc == ' ')
*out++ = uc | ext; *out++ = uc | ext;
else if (uc >= 32 && uc < 127) else if (uc >= 32 && uc < 127)
*out++ = uc | ext; *out++ = uc | ext;
@ -4693,10 +4697,11 @@ void COM_ErrorMe_f(void)
#ifdef LOADERTHREAD #ifdef LOADERTHREAD
#define WORKERTHREADS (1+1+4)
/*multithreading worker thread stuff*/ /*multithreading worker thread stuff*/
static void *com_workercondition[2]; static void *com_workercondition[WORKERTHREADS];
static qboolean com_workerdone[2]; static qboolean com_workerdone[WORKERTHREADS];
static void *com_workerthread; static void *com_workerthread[WORKERTHREADS];
static unsigned int mainthreadid; static unsigned int mainthreadid;
qboolean com_fatalerror; qboolean com_fatalerror;
static struct com_work_s static struct com_work_s
@ -4707,7 +4712,7 @@ static struct com_work_s
void *data; void *data;
size_t a; size_t a;
size_t b; size_t b;
} *com_work_head[2], *com_work_tail[2]; } *com_work_head[WORKERTHREADS], *com_work_tail[WORKERTHREADS];
static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b) static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b)
{ {
Sys_Error(data); Sys_Error(data);
@ -4719,6 +4724,9 @@ void COM_WorkerAbort(char *message)
if (Sys_IsMainThread()) if (Sys_IsMainThread())
return; return;
if (!com_workercondition[0])
return; //Sys_IsMainThread was probably called too early...
work.func = Sys_ErrorThread; work.func = Sys_ErrorThread;
work.ctx = NULL; work.ctx = NULL;
work.data = message; work.data = message;
@ -4743,22 +4751,34 @@ void COM_WorkerAbort(char *message)
//return if there's *any* loading that needs to be done anywhere. //return if there's *any* loading that needs to be done anywhere.
qboolean COM_HasWork(void) qboolean COM_HasWork(void)
{ {
return com_work_head[0] || com_work_head[1]; unsigned int i;
for (i = 0; i < WORKERTHREADS-1; i++)
{
if (com_work_head[i])
return true;
}
return false;
} }
//thread==0 is main thread, thread==1 is a worker thread //thread==0 is main thread, thread==1 is a worker thread
void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b) void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t b), void *ctx, void *data, size_t a, size_t b)
{ {
struct com_work_s *work;
//no worker there, just do it immediately on this thread instead of pushing it to the worker.
if (thread && (!com_workerthread[thread] || com_fatalerror))
{
func(ctx, data, a, b);
return;
}
//build the work //build the work
struct com_work_s *work = Z_Malloc(sizeof(*work)); work = Z_Malloc(sizeof(*work));
work->func = func; work->func = func;
work->ctx = ctx; work->ctx = ctx;
work->data = data; work->data = data;
work->a = a; work->a = a;
work->b = b; work->b = b;
if (!com_workerthread || com_fatalerror)
thread = 0;
//queue it (fifo) //queue it (fifo)
Sys_LockConditional(com_workercondition[thread]); Sys_LockConditional(com_workercondition[thread]);
if (com_work_tail[thread]) if (com_work_tail[thread])
@ -4774,9 +4794,9 @@ void COM_AddWork(int thread, void(*func)(void *ctx, void *data, size_t a, size_t
Sys_ConditionSignal(com_workercondition[thread]); Sys_ConditionSignal(com_workercondition[thread]);
Sys_UnlockConditional(com_workercondition[thread]); Sys_UnlockConditional(com_workercondition[thread]);
if (!com_workerthread) // if (!com_workerthread[thread])
while(COM_DoWork(0, false)) // while(COM_DoWork(thread, false))
; // ;
} }
//leavelocked = false == poll mode. //leavelocked = false == poll mode.
//leavelocked = true == safe sleeping //leavelocked = true == safe sleeping
@ -4816,9 +4836,20 @@ qboolean COM_DoWork(int thread, qboolean leavelocked)
//nothing going on, if leavelocked then noone can add anything until we sleep. //nothing going on, if leavelocked then noone can add anything until we sleep.
return false; return false;
} }
static void COM_WorkerSync_StopWorker(void *ctx, void *data, size_t a, size_t b)
{
com_workerdone[a] = true;
}
static void COM_WorkerSync_SignalMain(void *ctx, void *data, size_t a, size_t b)
{
Sys_LockConditional(com_workercondition[a]);
com_workerdone[a] = true;
Sys_ConditionSignal(com_workercondition[a]);
Sys_UnlockConditional(com_workercondition[a]);
}
static int COM_WorkerThread(void *arg) static int COM_WorkerThread(void *arg)
{ {
int thread = *(int*)arg; int thread = (void**)arg - com_workerthread;
Sys_LockConditional(com_workercondition[thread]); Sys_LockConditional(com_workercondition[thread]);
do do
{ {
@ -4828,15 +4859,14 @@ static int COM_WorkerThread(void *arg)
break; break;
} while (Sys_ConditionWait(com_workercondition[thread])); } while (Sys_ConditionWait(com_workercondition[thread]));
Sys_UnlockConditional(com_workercondition[thread]); Sys_UnlockConditional(com_workercondition[thread]);
//no more work please...
*(void**)arg = NULL;
//and wake up main thread
COM_WorkerSync_SignalMain(NULL, NULL, 0, 0);
return 0; return 0;
} }
static void COM_WorkerSync_Stop(void *ctx, void *data, size_t a, size_t b)
{
Sys_LockConditional(com_workercondition[a]);
com_workerdone[a] = true;
Sys_ConditionSignal(com_workercondition[a]);
Sys_UnlockConditional(com_workercondition[a]);
}
#ifndef COM_AssertMainThread #ifndef COM_AssertMainThread
void COM_AssertMainThread(const char *msg) void COM_AssertMainThread(const char *msg)
{ {
@ -4848,22 +4878,45 @@ void COM_AssertMainThread(const char *msg)
#endif #endif
void COM_DestroyWorkerThread(void) void COM_DestroyWorkerThread(void)
{ {
int i;
com_fatalerror = false; com_fatalerror = false;
if (com_workerthread) for (i = 0; i < WORKERTHREADS; i++)
{ {
//send it the terminate message if (com_workerthread[i])
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 1, 0); {
Sys_WaitOnThread(com_workerthread); void *thread = com_workerthread[i];
com_workerthread = NULL; com_workerdone[0] = false;
//send it the terminate message
COM_AddWork(i, COM_WorkerSync_StopWorker, NULL, NULL, i, 0);
//wait for the response while servicing anything that it might be waiting for.
Sys_LockConditional(com_workercondition[0]);
do
{
if (com_fatalerror)
break;
while(COM_DoWork(0, true))
;
if (com_workerdone[0])
break;
} while (Sys_ConditionWait(com_workercondition[0]));
Sys_UnlockConditional(com_workercondition[0]);
//and now that we know its going down and will not wait any more, we can block for its final moments
Sys_WaitOnThread(thread);
//finish any work that got posted to it that it neglected to finish.
while(COM_DoWork(i, true))
;
}
} }
if (com_workercondition[0]) for (i = 0; i < WORKERTHREADS; i++)
Sys_DestroyConditional(com_workercondition[0]); {
com_workercondition[0] = NULL; if (com_workercondition[i])
Sys_DestroyConditional(com_workercondition[i]);
if (com_workercondition[1]) com_workercondition[i] = NULL;
Sys_DestroyConditional(com_workercondition[1]); }
com_workercondition[1] = NULL;
if (com_resourcemutex) if (com_resourcemutex)
Sys_DestroyMutex(com_resourcemutex); Sys_DestroyMutex(com_resourcemutex);
@ -4874,33 +4927,38 @@ void COM_DestroyWorkerThread(void)
void COM_WorkerFullSync(void) void COM_WorkerFullSync(void)
{ {
qboolean repeat; qboolean repeat;
if (!com_workerthread) int i;
return;
//main thread asks worker thread to set main thread's 'done' flag. for (i = 1; i < WORKERTHREADS; i++)
//the worker might be posting work to the main thread and back (shaders with texures) so make sure that the only work we do before the reply is the reply itself.
do
{ {
int cmds = 0; if (!com_workerthread[i])
com_workerdone[0] = false; continue;
repeat = COM_HasWork();
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 0, 0); //main thread asks worker thread to set main thread's 'done' flag.
Sys_LockConditional(com_workercondition[0]); //the worker might be posting work to the main thread and back (shaders with texures) so make sure that the only work we do before the reply is the reply itself.
do do
{ {
int cmds = 0;
com_workerdone[0] = false;
repeat = COM_HasWork();
COM_AddWork(i, COM_WorkerSync_SignalMain, NULL, NULL, 0, 0);
Sys_LockConditional(com_workercondition[0]);
do
{
if (com_fatalerror)
break;
while(COM_DoWork(0, true))
cmds++;
if (com_workerdone[0])
break;
} while (Sys_ConditionWait(com_workercondition[0]));
Sys_UnlockConditional(com_workercondition[0]);
if (com_fatalerror) if (com_fatalerror)
break; break;
while(COM_DoWork(0, true)) if (cmds > 1)
cmds++; repeat = true;
if (com_workerdone[0]) } while (COM_DoWork(0, false) || repeat); //outer loop ensures there isn't anything pingponging between
break; }
} while (Sys_ConditionWait(com_workercondition[0]));
Sys_UnlockConditional(com_workercondition[0]);
if (com_fatalerror)
break;
if (cmds > 1)
repeat = true;
} while (COM_DoWork(0, false) || repeat); //outer loop ensures there isn't anything pingponging between
} }
//main thread wants a specific object to be prioritised. //main thread wants a specific object to be prioritised.
@ -4912,7 +4970,6 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
{ {
struct com_work_s **link, *work, *prev; struct com_work_s **link, *work, *prev;
double time1 = Sys_DoubleTime(); double time1 = Sys_DoubleTime();
int thread = 1;
// Con_Printf("waiting for %p %s\n", priorityctx, priorityctx); // Con_Printf("waiting for %p %s\n", priorityctx, priorityctx);
@ -4922,32 +4979,36 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
//main thread is meant to do all loadstate value changes anyway, ensuring that we're woken up properly in this case. //main thread is meant to do all loadstate value changes anyway, ensuring that we're woken up properly in this case.
if (priorityctx) if (priorityctx)
{ {
unsigned int thread;
qboolean found = false; qboolean found = false;
Sys_LockConditional(com_workercondition[thread]); for (thread = 1; thread < WORKERTHREADS && !found; thread++)
for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
{ {
prev = work; Sys_LockConditional(com_workercondition[thread]);
work = *link; for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
if (work->ctx == priorityctx) {
{ //unlink it prev = work;
work = *link;
if (work->ctx == priorityctx)
{ //unlink it
*link = work->next; *link = work->next;
if (!work->next) if (!work->next)
com_work_tail[thread] = prev; com_work_tail[thread] = prev;
//link it in at the head, so its the next thing seen. //link it in at the head, so its the next thing seen.
work->next = com_work_head[thread]; work->next = com_work_head[thread];
com_work_head[thread] = work; com_work_head[thread] = work;
if (!work->next) if (!work->next)
com_work_tail[thread] = work; com_work_tail[thread] = work;
found = true; found = true;
break; //found it, nothing else to do. break; //found it, nothing else to do.
}
} }
//we've not actually added any work, so no need to signal
Sys_UnlockConditional(com_workercondition[thread]);
} }
if (!found) if (!found)
Con_DPrintf("Might be in for a long wait for %s\n", priorityctx); Con_DPrintf("Might be in for a long wait for %s\n", priorityctx);
//we've not actually added any work, so no need to signal
Sys_UnlockConditional(com_workercondition[thread]);
} }
Sys_LockConditional(com_workercondition[0]); Sys_LockConditional(com_workercondition[0]);
@ -4974,7 +5035,7 @@ static void COM_WorkerPing(void *ctx, void *data, size_t a, size_t b)
{ {
double *timestamp = data; double *timestamp = data;
if (!b) if (!b)
COM_AddWork(0, COM_WorkerPing, ctx, data , 0, 1); COM_AddWork(0, COM_WorkerPing, ctx, data, 0, 1);
else else
{ {
Con_Printf("Ping: %g\n", Sys_DoubleTime() - *timestamp); Con_Printf("Ping: %g\n", Sys_DoubleTime() - *timestamp);
@ -4996,14 +5057,21 @@ static void COM_WorkerTest_f(void)
cvar_t worker_flush = CVARD("worker_flush", "1", "Is set, process the entire load queue, loading stuff faster but at the risk of stalling."); cvar_t worker_flush = CVARD("worker_flush", "1", "Is set, process the entire load queue, loading stuff faster but at the risk of stalling.");
static void COM_InitWorkerThread(void) static void COM_InitWorkerThread(void)
{ {
static int tid = 1; int i;
//in theory, we could run multiple workers, signalling a different one in turn for each bit of work. //in theory, we could run multiple workers, signalling a different one in turn for each bit of work.
com_resourcemutex = Sys_CreateMutex(); com_resourcemutex = Sys_CreateMutex();
com_workercondition[0] = Sys_CreateConditional(); for (i = 0; i < WORKERTHREADS; i++)
com_workercondition[1] = Sys_CreateConditional(); {
com_workercondition[i] = Sys_CreateConditional();
}
if (!COM_CheckParm("-noworker")) if (!COM_CheckParm("-noworker"))
com_workerthread = Sys_CreateThread("loadworker", COM_WorkerThread, &tid, 0, 256*1024); {
for (i = 1; i < WORKERTHREADS; i++)
{
com_workerthread[i] = Sys_CreateThread(va("loadworker_%i", i), COM_WorkerThread, &com_workerthread[i], 0, 256*1024);
}
}
Cmd_AddCommand ("worker_test", COM_WorkerTest_f); Cmd_AddCommand ("worker_test", COM_WorkerTest_f);
Cvar_Register(&worker_flush, NULL); Cvar_Register(&worker_flush, NULL);
@ -5753,8 +5821,10 @@ void Info_Print (char *s, char *lineprefix)
void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags) void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags)
{ {
const char *quotedvalue;
char buffer[1024];
char *command; char *command;
char *value; char *value, t;
cvar_t *var; cvar_t *var;
while(*info == '\\') while(*info == '\\')
@ -5779,7 +5849,11 @@ void Info_WriteToFile(vfsfile_t *f, char *info, char *commandname, int cvarflags
VFS_WRITE(f, " ", 1); VFS_WRITE(f, " ", 1);
VFS_WRITE(f, command, value-command); VFS_WRITE(f, command, value-command);
VFS_WRITE(f, " ", 1); VFS_WRITE(f, " ", 1);
VFS_WRITE(f, value+1, info-(value+1)); t = *info;
*info = 0;
quotedvalue = COM_QuotedString(value+1, buffer, sizeof(buffer), false);
VFS_WRITE(f, quotedvalue, strlen(quotedvalue));
*info = t;
VFS_WRITE(f, "\n", 1); VFS_WRITE(f, "\n", 1);
} }
} }

View file

@ -477,10 +477,18 @@ void COM_FlushFSCache(qboolean purge, qboolean domutex); //a file was written us
void COM_RefreshFSCache_f(void); void COM_RefreshFSCache_f(void);
qboolean FS_Restarted(unsigned int *since); qboolean FS_Restarted(unsigned int *since);
enum manifestdeptype_e
{
mdt_invalid,
mdt_singlepackage, //regular package, versioned.
mdt_installation //allowed to install to the root.
};
typedef struct typedef struct
{ {
qboolean blockupdate; //set to block the updateurl from being used this session. this avoids recursive updates when manifests contain the same update url. qboolean blockupdate; //set to block the updateurl from being used this session. this avoids recursive updates when manifests contain the same update url.
qboolean doinstall; //manifest was embedded in the engine. don't assume its already installed, but ask to install it (also, enable some extra permissions for writing dlls)
int parsever;
int minver; //if the engine svn revision is lower than this, the manifest will not be used as an 'upgrade'. int minver; //if the engine svn revision is lower than this, the manifest will not be used as an 'upgrade'.
int maxver; //if not 0, the manifest will not be used int maxver; //if not 0, the manifest will not be used
qboolean disablehomedir; qboolean disablehomedir;
@ -490,13 +498,15 @@ typedef struct
char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise. char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise.
char *protocolname; //the name used for purposes of dpmaster char *protocolname; //the name used for purposes of dpmaster
char *defaultexec; //execed after cvars are reset, to give game-specific defaults. char *defaultexec; //execed after cvars are reset, to give game-specific defaults.
char *eula; //when running as an installer, the user will be presented with this as a prompt
struct struct
{ {
qboolean base; qboolean base;
char *path; char *path;
} gamepath[8]; } gamepath[8];
struct struct manpack_s
{ {
int type;
char *path; //the 'pure' name char *path; //the 'pure' name
qboolean crcknown; //if the crc was specified qboolean crcknown; //if the crc was specified
unsigned int crc; //the public crc unsigned int crc; //the public crc
@ -509,7 +519,8 @@ void FS_Manifest_Free(ftemanifest_t *man);
ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data); ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data);
void COM_InitFilesystem (void); //does not set up any gamedirs. void COM_InitFilesystem (void); //does not set up any gamedirs.
qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs); qboolean FS_DownloadingPackage(void);
qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs, qboolean allowbasedirchange);
void FS_Shutdown(void); void FS_Shutdown(void);
void COM_Gamedir (const char *dir); void COM_Gamedir (const char *dir);
char *FS_GetGamedir(qboolean publicpathonly); char *FS_GetGamedir(qboolean publicpathonly);
@ -529,6 +540,7 @@ void COM_FlushTempoaryPacks(void);
void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm); void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm);
extern qboolean com_installer; //says that the engine is running in an 'installer' mode, and that the correct basedir is not yet known.
extern struct cvar_s registered; extern struct cvar_s registered;
extern qboolean standard_quake; //fixme: remove extern qboolean standard_quake; //fixme: remove

View file

@ -106,23 +106,40 @@ typedef struct conline_s {
float time; float time;
} conline_t; } conline_t;
//majority of these are mututally exclusive. the bits allow multiple.
#define CB_NONE 0
#define CB_SCROLL 1
#define CB_COPY 2
#define CB_CLOSE 3
#define CB_MOVE 4
#define CB_SIZELEFT (1u<<29)
#define CB_SIZERIGHT (1u<<30)
#define CB_SIZEBOTTOM (1u<<31)
#define CONF_HIDDEN 1 /*do not show in the console list (unless active)*/ #define CONF_HIDDEN 1 /*do not show in the console list (unless active)*/
#define CONF_NOTIFY 2 /*text printed to console also appears as notify lines*/ #define CONF_NOTIFY 2 /*text printed to console also appears as notify lines*/
#define CONF_NOTIFY_BOTTOM 4 /*align the bottom*/ #define CONF_NOTIFY_BOTTOM 4 /*align the bottom*/
#define CONF_NOTIMES 8 #define CONF_NOTIFY_RIGHT 8
#define CONF_KEYFOCUSED 16 #define CONF_NOTIMES 16
#define CONF_KEYFOCUSED 32
#define CONF_ISWINDOW 64
typedef struct console_s typedef struct console_s
{ {
int id; int id;
int nextlineid; //the current line being written to. so we can rewrite links etc. int nextlineid; //the current line being written to. so we can rewrite links etc.
char name[64]; char name[128];
char title[64]; char title[128];
float wnd_x;
float wnd_y;
float wnd_w;
float wnd_h;
int linecount; int linecount;
unsigned int flags; unsigned int flags;
int notif_x; float notif_x;
int notif_y; float notif_y;
int notif_w; float notif_w;
int notif_l; int notif_l;
float notif_fade; // will be transparent for this long when fading
int maxlines;
float notif_t; float notif_t;
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
@ -135,7 +152,7 @@ typedef struct console_s
unsigned parseflags; unsigned parseflags;
conchar_t defaultcharbits; conchar_t defaultcharbits;
int commandcompletion; //allows tab completion of quake console commands int commandcompletion; //allows tab completion of quake console commands
void (*linebuffered) (struct console_s *con, char *line); //if present, called on enter, causes the standard console input to appear. int (*linebuffered) (struct console_s *con, char *line); //if present, called on enter, causes the standard console input to appear. return 2 to not save the line in history.
void (*redirect) (struct console_s *con, int key); //if present, called every character. void (*redirect) (struct console_s *con, int key); //if present, called every character.
void *userdata; void *userdata;
@ -143,14 +160,16 @@ typedef struct console_s
conline_t *footerline; //temp text at the bottom of the console conline_t *footerline; //temp text at the bottom of the console
conline_t *selstartline, *selendline; conline_t *selstartline, *selendline;
unsigned int selstartoffset, selendoffset; unsigned int selstartoffset, selendoffset;
int mousedown[3]; //x,y,buttons int mousedown[2]; //x,y position that the current buttons were clicked.
unsigned int buttonsdown;
int mousecursor[2]; //x,y int mousecursor[2]; //x,y
struct console_s *next; struct console_s *next;
} console_t; } console_t;
extern console_t con_main; extern console_t con_main;
extern console_t *con_current; // point to either con_main or con_chat extern console_t *con_curwindow; // refers to a windowed console
extern console_t *con_current; // point to either con_main or con_chat
extern console_t *con_mouseover; extern console_t *con_mouseover;
extern console_t *con_chat; extern console_t *con_chat;
@ -178,23 +197,23 @@ void Con_Shutdown (void);
void Con_History_Save(void); void Con_History_Save(void);
void Con_History_Load(void); void Con_History_Load(void);
struct font_s; struct font_s;
void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy, float fsx, float fsy); void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, float fx, float fy, float fsx, float fsy);
void Con_DrawConsole (int lines, qboolean noback); void Con_DrawConsole (int lines, qboolean noback);
char *Con_CopyConsole(qboolean nomarkup, qboolean onlyiflink); char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink);
void Con_Print (char *txt); void Con_Print (char *txt);
void Con_PrintFlags(char *text, unsigned int setflags, unsigned int clearflags); void Con_PrintFlags(char *text, unsigned int setflags, unsigned int clearflags);
void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1); void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_TPrintf (translation_t text, ...); void VARGS Con_TPrintf (translation_t text, ...);
void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1); void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_SafePrintf (char *fmt, ...) LIKEPRINTF(1); void VARGS Con_SafePrintf (char *fmt, ...) LIKEPRINTF(1);
void Con_Footerf(qboolean append, char *fmt, ...) LIKEPRINTF(2); void Con_Footerf(console_t *con, qboolean append, char *fmt, ...) LIKEPRINTF(3);
void Con_Clear_f (void); void Con_Clear_f (void);
void Con_DrawNotify (void); void Con_DrawNotify (void);
void Con_ClearNotify (void); void Con_ClearNotify (void);
void Con_ToggleConsole_f (void);//note: allows csqc to intercept the toggleconsole void Con_ToggleConsole_f (void);//note: allows csqc to intercept the toggleconsole
void Con_ToggleConsole_Force(void); void Con_ToggleConsole_Force(void);
void Con_ExecuteLine(console_t *con, char *line); //takes normal console commands int Con_ExecuteLine(console_t *con, char *line); //takes normal console commands
void Con_CycleConsole (void); void Con_CycleConsole (void);

File diff suppressed because it is too large Load diff

View file

@ -3,15 +3,16 @@
#include "winquake.h" #include "winquake.h"
//outlen is the size of out in _BYTES_. //outlen is the size of out in _BYTES_.
wchar_t *widen(wchar_t *out, size_t outlen, const char *utf8) wchar_t *widen(wchar_t *out, size_t outbytes, const char *utf8)
{ {
size_t outlen;
wchar_t *ret = out; wchar_t *ret = out;
//utf-8 to utf-16, not ucs-2. //utf-8 to utf-16, not ucs-2.
unsigned int codepoint; unsigned int codepoint;
int error; int error;
outlen = outbytes/sizeof(wchar_t);
if (!outlen) if (!outlen)
return L""; return L"";
outlen /= sizeof(wchar_t);
outlen--; outlen--;
while (*utf8) while (*utf8)
{ {
@ -304,7 +305,7 @@ static vfsfile_t *QDECL VFSW32_OpenInternal(vfsw32path_t *handle, const char *qu
file->offset = 0; file->offset = 0;
file->length = fsize; file->length = fsize;
return (vfsfile_t*)file; return &file->funcs;
} }
vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode) vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode)

View file

@ -232,6 +232,228 @@ vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile)
return temp; return temp;
} }
//returns an unseekable write-only file that will decompress any data that is written to it.
//decompressed data will be written to the output
typedef struct
{
vfsfile_t vf;
vfsfile_t *outfile;
qboolean autoclosefile;
//gzip header handling
qboolean headerparsed;
qbyte in[65536];
int inlen;
qbyte out[65536];
z_stream strm;
} vf_gz_dec_t;
static qboolean QDECL FS_GZ_Dec_Close(vfsfile_t *f)
{
vf_gz_dec_t *n = (vf_gz_dec_t*)f;
if (n->autoclosefile)
VFS_CLOSE(n->outfile);
qinflateEnd(&n->strm);
Z_Free(n);
return true;
}
static int QDECL FS_GZ_Dec_Write(vfsfile_t *f, const void *buffer, int len)
{
int ret;
vf_gz_dec_t *n = (vf_gz_dec_t*)f;
if (n->headerparsed != 1)
{
qofs_t ofs = 0;
gzheader_t *header;
int chunk;
if (len > sizeof(n->in) - n->inlen)
chunk = sizeof(n->in) - n->inlen;
else
chunk = len;
memmove(n->in, buffer, chunk);
n->inlen += chunk;
if (n->headerparsed == 2)
{
if (n->inlen >= 8)
{
unsigned int crc = (n->in[0]<<0) | (n->in[1]<<8) | (n->in[2]<<16) | (n->in[3]<<24);
unsigned int isize = (n->in[4]<<0) | (n->in[5]<<8) | (n->in[6]<<16) | (n->in[7]<<24);
if (n->strm.total_out != isize)
return -1; //the file we just received decoded to a different length (yay, concat...).
//FIXME: validate the decoded crc
n->headerparsed = false;
n->strm.total_in = 0;
n->strm.total_out = 0;
len = n->inlen - 8;
n->inlen = 0;
if (FS_GZ_Dec_Write(f, n->in + 8, len) != len)
return -1; //FIXME: make non-fatal somehow
return chunk;
}
return chunk;
}
header = (gzheader_t*)n->in;
ofs += sizeofgzheader_t; if (ofs > n->inlen) goto noheader;
if (header->ident1 != 0x1f || header->ident2 != 0x8b || header->cm != 8 || header->flags & GZ_RESERVED)
return -1; //ERROR
if (header->flags & GZ_FEXTRA)
{
unsigned short ex;
if (ofs+2 > n->inlen) goto noheader;
ex = (n->in[ofs]<<0) | (n->in[ofs+1]<<8); //read little endian
ofs += 2+ex; if (ofs > n->inlen) goto noheader;
}
if (header->flags & GZ_FNAME)
{
char ch;
// Con_Printf("gzipped file name: ");
do {
if (ofs+1 > n->inlen) goto noheader;
ch = n->in[ofs++];
// Con_Printf("%c", ch);
} while(ch);
// Con_Printf("\n");
}
if (header->flags & GZ_FCOMMENT)
{
char ch;
// Con_Printf("gzipped file comment: ");
do {
if (ofs+1 > n->inlen) goto noheader;
ch = n->in[ofs++];
// Con_Printf("%c", ch);
} while(ch);
// Con_Printf("\n");
}
if (header->flags & GZ_FHCRC)
{
ofs += 2; if (ofs > n->inlen) goto noheader;
}
//if we got here then the header is now complete.
//tail-recurse it.
n->headerparsed = true;
chunk = n->inlen - ofs;
if (FS_GZ_Dec_Write(f, n->in + ofs, chunk) != chunk)
return -1; //FIXME: make non-fatal somehow
return len;
noheader:
if (n->inlen == sizeof(n->in))
return -1; //we filled our buffer. if we didn't get past the header yet then someone fucked up.
return len;
}
n->strm.next_in = buffer;
n->strm.avail_in = len;
while(n->strm.avail_in)
{
ret = qinflate(&n->strm, Z_SYNC_FLUSH);
if (!n->strm.avail_out)
{
if (VFS_WRITE(n->outfile, n->out, n->strm.next_out-n->out) != n->strm.next_out-n->out)
return -1;
n->strm.next_out = n->out;
n->strm.avail_out = sizeof(n->out);
}
if (ret == Z_OK)
continue;
//flush it
if (VFS_WRITE(n->outfile, n->out, n->strm.next_out-n->out) != n->strm.next_out-n->out)
return -1;
n->strm.next_out = n->out;
n->strm.avail_out = sizeof(n->out);
if (ret == Z_STREAM_END) //allow concat
{
int l = n->strm.avail_in;
n->headerparsed = 2;
n->inlen = 0;
if (l != FS_GZ_Dec_Write(f, n->strm.next_in, n->strm.avail_in))
return -1;
return len;
}
switch (ret)
{
case Z_NEED_DICT:
Con_Printf("Z_NEED_DICT\n");
break;
case Z_ERRNO:
Con_Printf("Z_ERRNO\n");
break;
case Z_STREAM_ERROR:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_BUF_ERROR:
case Z_VERSION_ERROR:
Con_Printf("File is corrupt\n");
break;
default:
Con_Printf("Bug!\n");
break;
}
return -1;
}
return len;
}
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile)
{
vf_gz_dec_t *n = Z_Malloc(sizeof(*n));
n->outfile = outfile;
n->autoclosefile = autoclosefile;
n->strm.next_in = NULL;
n->strm.avail_in = 0;
n->strm.total_in = 0;
n->strm.next_out = n->out;
n->strm.avail_out = sizeof(n->out);
n->strm.total_out = 0;
n->vf.Flush = NULL;
n->vf.GetLen = NULL;
n->vf.ReadBytes = NULL;
n->vf.Seek = NULL;
n->vf.Tell = NULL;
n->vf.Close = FS_GZ_Dec_Close;
n->vf.WriteBytes = FS_GZ_Dec_Write;
n->vf.seekingisabadplan = true;
qinflateInit2(&n->strm, -MAX_WBITS);
return &n->vf;
}
#endif #endif

View file

@ -141,8 +141,8 @@ void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
void ClearBounds (vec3_t mins, vec3_t maxs) void ClearBounds (vec3_t mins, vec3_t maxs)
{ {
mins[0] = mins[1] = mins[2] = 999999999; mins[0] = mins[1] = mins[2] = FLT_MAX;
maxs[0] = maxs[1] = maxs[2] = -999999999; maxs[0] = maxs[1] = maxs[2] = -FLT_MAX;
} }
@ -1215,7 +1215,7 @@ texture_t *Mod_LoadWall(model_t *loadmodel, char *mapname, char *texname, char *
image_t *base; image_t *base;
Q_snprintfz (name, sizeof(name), "textures/%s.wal", texname); Q_snprintfz (name, sizeof(name), "textures/%s.wal", texname);
wal = (void *)FS_LoadMallocFile (texname, NULL); wal = (void *)FS_LoadMallocFile (name, NULL);
if (!wal) if (!wal)
{ {
wal = &replacementwal; wal = &replacementwal;
@ -1263,11 +1263,31 @@ texture_t *Mod_LoadWall(model_t *loadmodel, char *mapname, char *texname, char *
tex->width = base->width; tex->width = base->width;
tex->height = base->height; tex->height = base->height;
} }
else
Con_Printf("Unable to load textures/%s.wal\n", wal->name);
} }
} }
else else
{
unsigned int size =
(wal->width>>0)*(wal->height>>0) +
(wal->width>>1)*(wal->height>>1) +
(wal->width>>2)*(wal->height>>2) +
(wal->width>>3)*(wal->height>>3);
tex->mips[0] = BZ_Malloc(size);
tex->palette = host_basepal;
tex->mips[1] = tex->mips[0] + (wal->width>>0)*(wal->height>>0);
tex->mips[2] = tex->mips[1] + (wal->width>>1)*(wal->height>>1);
tex->mips[3] = tex->mips[2] + (wal->width>>2)*(wal->height>>2);
memcpy(tex->mips[0], (qbyte *)wal + wal->offsets[0], (wal->width>>0)*(wal->height>>0));
memcpy(tex->mips[1], (qbyte *)wal + wal->offsets[1], (wal->width>>1)*(wal->height>>1));
memcpy(tex->mips[2], (qbyte *)wal + wal->offsets[2], (wal->width>>2)*(wal->height>>2));
memcpy(tex->mips[3], (qbyte *)wal + wal->offsets[3], (wal->width>>3)*(wal->height>>3));
BZ_Free(wal); BZ_Free(wal);
}
return tex; return tex;
} }
@ -3933,7 +3953,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
if (header.lumps[i].filelen && header.lumps[i].fileofs + header.lumps[i].filelen > filelen) if (header.lumps[i].filelen && header.lumps[i].fileofs + header.lumps[i].filelen > filelen)
{ {
Con_Printf (CON_ERROR "WARNING: q3bsp %s truncated (lump %i, %i+%i > %i)\n", mod->name, i, header.lumps[i].fileofs, header.lumps[i].filelen, filelen); Con_Printf (CON_ERROR "WARNING: q3bsp %s truncated (lump %i, %i+%i > %u)\n", mod->name, i, header.lumps[i].fileofs, header.lumps[i].filelen, (unsigned int)filelen);
header.lumps[i].filelen = filelen - header.lumps[i].fileofs; header.lumps[i].filelen = filelen - header.lumps[i].fileofs;
if (header.lumps[i].filelen < 0) if (header.lumps[i].filelen < 0)
header.lumps[i].filelen = 0; header.lumps[i].filelen = 0;
@ -5128,6 +5148,7 @@ static void Mod_Trace_Trisoup_(vecV_t *posedata, index_t *indexes, size_t numind
} }
} }
/*
static void CM_ClipBoxToMesh (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, mesh_t *mesh) static void CM_ClipBoxToMesh (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, mesh_t *mesh)
{ {
trace_truefraction = trace->truefraction; trace_truefraction = trace->truefraction;
@ -5136,6 +5157,7 @@ static void CM_ClipBoxToMesh (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, tr
trace->truefraction = trace_truefraction; trace->truefraction = trace_truefraction;
trace->fraction = trace_nearfraction; trace->fraction = trace_nearfraction;
} }
*/
static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
trace_t *trace, q2cbrush_t *brush) trace_t *trace, q2cbrush_t *brush)

View file

@ -184,7 +184,7 @@ qboolean NET_RTP_Transmit(unsigned int sequence, unsigned int timestamp, const c
built = true; built = true;
MSG_WriteByte(&buf, (2u<<6) | (0u<<5) | (0u<<4) | (0<<0)); //v2_p1_x1_cc4 MSG_WriteByte(&buf, (2u<<6) | (0u<<5) | (0u<<4) | (0<<0)); //v2_p1_x1_cc4
MSG_WriteByte(&buf, (0u<<7) | ((i+96)<<0)); //m1_pt7 MSG_WriteByte(&buf, (0u<<7) | ((i+96)<<0)); //m1_pt7
MSG_WriteShort(&buf, BigShort(sequence)); //seq MSG_WriteShort(&buf, BigShort(sequence)&0xffff); //seq
MSG_WriteLong(&buf, BigLong(timestamp)); //timestamp MSG_WriteLong(&buf, BigLong(timestamp)); //timestamp
MSG_WriteLong(&buf, BigLong(0)); //ssrc MSG_WriteLong(&buf, BigLong(0)); //ssrc
SZ_Write(&buf, cdata, clength); SZ_Write(&buf, cdata, clength);

View file

@ -76,9 +76,10 @@ qboolean SSL_Inited(void)
struct sslbuf struct sslbuf
{ {
char data[8192]; size_t datasize;
int avail; char *data;
int newd; size_t avail;
size_t newd;
}; };
typedef struct { typedef struct {
@ -113,13 +114,20 @@ typedef struct {
static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes) static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes)
{ {
if (bytes > sizeof(buf->data) - buf->avail) if (bytes > buf->datasize - buf->avail)
bytes = sizeof(buf->data) - buf->avail; bytes = buf->datasize - buf->avail;
memcpy(buf->data + buf->avail, data, bytes); memcpy(buf->data + buf->avail, data, bytes);
buf->avail += bytes; buf->avail += bytes;
return bytes; return bytes;
} }
static int SSPI_ExpandBuffer(struct sslbuf *buf, size_t bytes)
{
if (bytes < buf->datasize)
return buf->datasize;
Z_ReallocElements(&buf->data, &buf->datasize, bytes, 1);
return bytes;
}
static void SSPI_Error(sslfile_t *f, char *error) static void SSPI_Error(sslfile_t *f, char *error)
{ {
@ -153,7 +161,7 @@ static int SSPI_CheckNewInCrypt(sslfile_t *f)
int newd; int newd;
if (!f->stream) if (!f->stream)
return -1; return -1;
newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, sizeof(f->incrypt.data) - f->incrypt.avail); newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, f->incrypt.datasize - f->incrypt.avail);
if (newd < 0) if (newd < 0)
return newd; return newd;
else else
@ -193,7 +201,11 @@ static void SSPI_Decode(sslfile_t *f)
if (ss < 0) if (ss < 0)
{ {
if (ss == SEC_E_INCOMPLETE_MESSAGE) if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return; //no error if its incomplete, we can just get more data later on. return; //no error if its incomplete, we can just get more data later on.
}
switch(ss) switch(ss)
{ {
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "DecryptMessage failed: SEC_E_INVALID_HANDLE\n"); break; case SEC_E_INVALID_HANDLE: SSPI_Error(f, "DecryptMessage failed: SEC_E_INVALID_HANDLE\n"); break;
@ -296,15 +308,17 @@ static void SSPI_Encode(sslfile_t *f)
} }
//these are known sites that use self-signed certificates, or are special enough that we don't trust corporate networks to hack in their own certificate authority for a proxy/mitm //these are known sites that use self-signed certificates, or are special enough that we don't trust corporate networks to hack in their own certificate authority for a proxy/mitm
static const qbyte triptohell_certdata[] = "\x30\x82\x03\xa1\x30\x82\x02\x89\xa0\x03\x02\x01\x02\x02\x09\x00\x8b\xd0\x05\x63\x62\xd1\x6a\xe3\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x34\x32\x32\x34\x32\x34\x37\x5a\x17\x0d\x32\x34\x31\x32\x32\x31\x32\x32\x34\x32\x34\x37\x5a\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xaf\x10\x33\xfa\x39\xf5\xae\x2c\x91\x0e\x20\xe6\x3c\x5c\x7c\x1e\xeb\x16\x50\x2f\x05\x30\xfe\x67\xee\xa9\x00\x54\xd9\x4a\x86\xe6\xba\x80\xfb\x1a\x80\x08\x7e\x7b\x13\xe5\x1a\x18\xc9\xd4\x70\xbd\x5d\xc4\x38\xef\x64\xf1\x90\x2c\x53\x49\x93\x24\x36\x3e\x11\x59\x69\xa6\xdf\x37\xb2\x54\x82\x28\x3e\xdd\x30\x75\xa0\x18\xd8\xe1\xf5\x52\x73\x12\x5b\x37\x68\x1c\x59\xbd\x8c\x73\x66\x47\xbc\xcb\x9c\xfe\x38\x92\x8f\x74\xe9\xd1\x2f\x96\xd2\x5d\x6d\x11\x59\xb2\xdc\xbd\x8c\x37\x5b\x22\x76\x98\xe7\xbe\x08\xef\x1e\x99\xc4\xa9\x77\x2c\x9c\x0e\x08\x3c\x8e\xab\x97\x0c\x6a\xd7\x03\xab\xfd\x4a\x1e\x95\xb2\xc2\x9c\x3a\x16\x65\xd7\xaf\x45\x5f\x6e\xe7\xce\x51\xba\xa0\x60\x43\x0e\x07\xc5\x0b\x0a\x82\x05\x26\xc4\x92\x0a\x27\x5b\xfc\x57\x6c\xdf\xe2\x54\x8a\xef\x38\xf1\xf8\xc4\xf8\x51\x16\x27\x1f\x78\x89\x7c\x5b\xd7\x53\xcd\x9b\x54\x2a\xe6\x71\xee\xe4\x56\x2e\xa4\x09\x1a\x61\xf7\x0f\x97\x22\x94\xd7\xef\x21\x6c\xe6\x81\xfb\x54\x5f\x09\x92\xac\xd2\x7c\xab\xd5\xa9\x81\xf4\xc9\xb7\xd6\xbf\x68\xf8\x4f\xdc\xf3\x60\xa3\x3b\x29\x92\x9e\xdd\xa2\xa3\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x62\xa7\x26\xeb\xd4\x03\x29\x9c\x09\x33\x69\x7a\x9c\x65\x68\xec\x4c\xb9\x06\xeb\x1e\x51\x6f\x78\x20\xdc\xf6\x44\x5e\x06\x6e\x53\x87\x73\xe6\x14\x15\xb9\x17\x74\x67\xe0\x4e\x48\x38\xbc\x1c\xbd\xd0\xad\xd6\xbd\x8c\xf0\x3a\xe0\x13\x73\x19\xad\x8b\x79\x68\x67\x65\x9b\x7a\x4c\x81\xfb\xd9\x92\x77\x89\xb5\xb0\x53\xb0\xa5\xf7\x2d\x8e\x29\x60\x31\xd1\x9b\x2f\x63\x8a\x5f\x64\xc1\x61\xd5\xb7\xdf\x70\x3b\x2b\xf6\x1a\x96\xb9\xa7\x08\xca\x87\xa6\x8c\x60\xca\x6e\xd7\xee\xba\xef\x89\x0b\x93\xd5\xfd\xfc\x14\xba\xef\x27\xba\x90\x11\x90\xf7\x25\x70\xe7\x4e\xf4\x9c\x13\x27\xc1\xa7\x8e\xd9\x66\x43\x72\x20\x5b\xe1\x5c\x73\x74\xf5\x33\xf2\xa5\xf6\xe1\xd5\xac\xf3\x67\x5c\xe7\xd4\x0a\x8d\x91\x73\x03\x3e\x9d\xbc\x96\xc3\x0c\xdb\xd5\x77\x6e\x76\x44\x69\xaf\x24\x0f\x4f\x8b\x47\x36\x8b\xc3\xd6\x36\xdd\x26\x5a\x9c\xdd\x9c\x43\xee\x29\x43\xdd\x75\x2f\x19\x52\xfc\x1d\x24\x9c\x13\x29\x99\xa0\x6d\x7a\x95\xcc\xa0\x58\x86\xd8\xc5\xb9\xa3\xc2\x3d\x64\x1d\x85\x8a\xca\x53\x55\x8e\x9a\x6d\xc9\x91\x73\xf4\xe1\xe1\xa4\x9b\x76\xfc\x7f\x63\xc2\xb9\x23";
static struct static struct
{ {
wchar_t *hostname; wchar_t *hostname;
unsigned int datasize; unsigned int datasize;
qbyte *data; const qbyte *data;
//FIXME: include expiry information //FIXME: include expiry information
//FIXME: add alternative when one is about to expire //FIXME: add alternative when one is about to expire
} knowncerts[] = { } knowncerts[] = {
{L"triptohell.info", 933, "\x30\x82\x03\xa1\x30\x82\x02\x89\xa0\x03\x02\x01\x02\x02\x09\x00\x8b\xd0\x05\x63\x62\xd1\x6a\xe3\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x1e\x17\x0d\x31\x34\x31\x32\x32\x34\x32\x32\x34\x32\x34\x37\x5a\x17\x0d\x32\x34\x31\x32\x32\x31\x32\x32\x34\x32\x34\x37\x5a\x30\x67\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42\x44\x31\x0c\x30\x0a\x06\x03\x55\x04\x08\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x07\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0a\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x0b\x0c\x03\x42\x61\x64\x31\x0c\x30\x0a\x06\x03\x55\x04\x03\x0c\x03\x42\x61\x64\x31\x12\x30\x10\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01\x16\x03\x42\x61\x64\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xaf\x10\x33\xfa\x39\xf5\xae\x2c\x91\x0e\x20\xe6\x3c\x5c\x7c\x1e\xeb\x16\x50\x2f\x05\x30\xfe\x67\xee\xa9\x00\x54\xd9\x4a\x86\xe6\xba\x80\xfb\x1a\x80\x08\x7e\x7b\x13\xe5\x1a\x18\xc9\xd4\x70\xbd\x5d\xc4\x38\xef\x64\xf1\x90\x2c\x53\x49\x93\x24\x36\x3e\x11\x59\x69\xa6\xdf\x37\xb2\x54\x82\x28\x3e\xdd\x30\x75\xa0\x18\xd8\xe1\xf5\x52\x73\x12\x5b\x37\x68\x1c\x59\xbd\x8c\x73\x66\x47\xbc\xcb\x9c\xfe\x38\x92\x8f\x74\xe9\xd1\x2f\x96\xd2\x5d\x6d\x11\x59\xb2\xdc\xbd\x8c\x37\x5b\x22\x76\x98\xe7\xbe\x08\xef\x1e\x99\xc4\xa9\x77\x2c\x9c\x0e\x08\x3c\x8e\xab\x97\x0c\x6a\xd7\x03\xab\xfd\x4a\x1e\x95\xb2\xc2\x9c\x3a\x16\x65\xd7\xaf\x45\x5f\x6e\xe7\xce\x51\xba\xa0\x60\x43\x0e\x07\xc5\x0b\x0a\x82\x05\x26\xc4\x92\x0a\x27\x5b\xfc\x57\x6c\xdf\xe2\x54\x8a\xef\x38\xf1\xf8\xc4\xf8\x51\x16\x27\x1f\x78\x89\x7c\x5b\xd7\x53\xcd\x9b\x54\x2a\xe6\x71\xee\xe4\x56\x2e\xa4\x09\x1a\x61\xf7\x0f\x97\x22\x94\xd7\xef\x21\x6c\xe6\x81\xfb\x54\x5f\x09\x92\xac\xd2\x7c\xab\xd5\xa9\x81\xf4\xc9\xb7\xd6\xbf\x68\xf8\x4f\xdc\xf3\x60\xa3\x3b\x29\x92\x9e\xdd\xa2\xa3\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x19\xed\xd0\x7b\x16\xaf\xb5\x0c\x9a\xe8\xd3\x46\x2e\x3c\x64\x29\xb6\xc1\x73\x5a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00\x62\xa7\x26\xeb\xd4\x03\x29\x9c\x09\x33\x69\x7a\x9c\x65\x68\xec\x4c\xb9\x06\xeb\x1e\x51\x6f\x78\x20\xdc\xf6\x44\x5e\x06\x6e\x53\x87\x73\xe6\x14\x15\xb9\x17\x74\x67\xe0\x4e\x48\x38\xbc\x1c\xbd\xd0\xad\xd6\xbd\x8c\xf0\x3a\xe0\x13\x73\x19\xad\x8b\x79\x68\x67\x65\x9b\x7a\x4c\x81\xfb\xd9\x92\x77\x89\xb5\xb0\x53\xb0\xa5\xf7\x2d\x8e\x29\x60\x31\xd1\x9b\x2f\x63\x8a\x5f\x64\xc1\x61\xd5\xb7\xdf\x70\x3b\x2b\xf6\x1a\x96\xb9\xa7\x08\xca\x87\xa6\x8c\x60\xca\x6e\xd7\xee\xba\xef\x89\x0b\x93\xd5\xfd\xfc\x14\xba\xef\x27\xba\x90\x11\x90\xf7\x25\x70\xe7\x4e\xf4\x9c\x13\x27\xc1\xa7\x8e\xd9\x66\x43\x72\x20\x5b\xe1\x5c\x73\x74\xf5\x33\xf2\xa5\xf6\xe1\xd5\xac\xf3\x67\x5c\xe7\xd4\x0a\x8d\x91\x73\x03\x3e\x9d\xbc\x96\xc3\x0c\xdb\xd5\x77\x6e\x76\x44\x69\xaf\x24\x0f\x4f\x8b\x47\x36\x8b\xc3\xd6\x36\xdd\x26\x5a\x9c\xdd\x9c\x43\xee\x29\x43\xdd\x75\x2f\x19\x52\xfc\x1d\x24\x9c\x13\x29\x99\xa0\x6d\x7a\x95\xcc\xa0\x58\x86\xd8\xc5\xb9\xa3\xc2\x3d\x64\x1d\x85\x8a\xca\x53\x55\x8e\x9a\x6d\xc9\x91\x73\xf4\xe1\xe1\xa4\x9b\x76\xfc\x7f\x63\xc2\xb9\x23"}, {L"triptohell.info", 933, triptohell_certdata},
{L"fte.triptohell.info", 933, triptohell_certdata},
{NULL} {NULL}
}; };
@ -543,7 +557,7 @@ static void SSPI_Handshake (sslfile_t *f)
OutBuffDesc.cBuffers = 1; OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff; OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.cbBuffer = sizeof(f->outcrypt.data) - f->outcrypt.avail; OutSecBuff.cbBuffer = f->outcrypt.datasize - f->outcrypt.avail;
OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = f->outcrypt.data + f->outcrypt.avail; OutSecBuff.pvBuffer = f->outcrypt.data + f->outcrypt.avail;
@ -589,7 +603,11 @@ static void SSPI_Handshake (sslfile_t *f)
ss = secur.pInitializeSecurityContextA (&f->cred, &f->sechnd, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime); ss = secur.pInitializeSecurityContextA (&f->cred, &f->sechnd, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
if (ss == SEC_E_INCOMPLETE_MESSAGE) if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return; return;
}
//any extra data should still remain for the next time around. this might be more handshake data or payload data. //any extra data should still remain for the next time around. this might be more handshake data or payload data.
if (InSecBuff[1].BufferType == SECBUFFER_EXTRA) if (InSecBuff[1].BufferType == SECBUFFER_EXTRA)
@ -620,7 +638,11 @@ static void SSPI_Handshake (sslfile_t *f)
ss = secur.pAcceptSecurityContext(&f->cred, (f->handshaking==HS_SERVER)?&f->sechnd:NULL, &InBuffDesc, ASC_REQ_ALLOCATE_MEMORY|ASC_REQ_STREAM|ASC_REQ_CONFIDENTIALITY, SECURITY_NATIVE_DREP, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime); ss = secur.pAcceptSecurityContext(&f->cred, (f->handshaking==HS_SERVER)?&f->sechnd:NULL, &InBuffDesc, ASC_REQ_ALLOCATE_MEMORY|ASC_REQ_STREAM|ASC_REQ_CONFIDENTIALITY, SECURITY_NATIVE_DREP, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
if (ss == SEC_E_INCOMPLETE_MESSAGE) if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return; return;
}
f->handshaking = HS_SERVER; f->handshaking = HS_SERVER;
//any extra data should still remain for the next time around. this might be more handshake data or payload data. //any extra data should still remain for the next time around. this might be more handshake data or payload data.
@ -776,6 +798,12 @@ static qboolean QDECL SSPI_Close (struct vfsfile_s *file)
sslfile_t *f = (sslfile_t *)file; sslfile_t *f = (sslfile_t *)file;
qboolean success = f->stream != NULL; qboolean success = f->stream != NULL;
SSPI_Error(f, ""); SSPI_Error(f, "");
Z_Free(f->outraw.data);
Z_Free(f->outcrypt.data);
Z_Free(f->inraw.data);
Z_Free(f->incrypt.data);
Z_Free(f); Z_Free(f);
return success; return success;
} }
@ -834,6 +862,11 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server)
newf->funcs.WriteBytes = SSPI_WriteBytes; newf->funcs.WriteBytes = SSPI_WriteBytes;
newf->funcs.seekingisabadplan = true; newf->funcs.seekingisabadplan = true;
SSPI_ExpandBuffer(&newf->outraw, 8192);
SSPI_ExpandBuffer(&newf->outcrypt, 8192);
SSPI_ExpandBuffer(&newf->inraw, 8192);
SSPI_ExpandBuffer(&newf->incrypt, 8192);
if (server) if (server)
SSPI_GenServerCredentials(newf); SSPI_GenServerCredentials(newf);

View file

@ -2544,7 +2544,11 @@ qboolean FTENET_Generic_SendPacket(ftenet_generic_connection_t *con, int length,
Con_DPrintf("NET_SendPacket Warning: %i\n", ecode); Con_DPrintf("NET_SendPacket Warning: %i\n", ecode);
else else
#endif #endif
#ifdef _WIN32
Con_TPrintf ("NET_SendPacket ERROR: %i\n", ecode); Con_TPrintf ("NET_SendPacket ERROR: %i\n", ecode);
#else
Con_TPrintf ("NET_SendPacket ERROR: %s\n", strerror(ecode));
#endif
} }
return true; return true;
#endif #endif
@ -2807,6 +2811,82 @@ void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen)
*out = 0; *out = 0;
} }
qboolean FTENET_TCPConnect_WebSocket_Splurge(ftenet_tcpconnect_stream_t *st, qbyte packettype, const qbyte *data, unsigned int length)
{
/*as a server, we don't need the mask stuff*/
unsigned short ctrl = 0x8000 | (packettype<<8);
unsigned int paylen = 0;
unsigned int payoffs = st->outlen;
int i;
switch((ctrl>>8) & 0xf)
{
case 1:
for (i = 0; i < length; i++)
{
paylen += (((char*)data)[i] == 0 || ((unsigned char*)data)[i] >= 0x80)?2:1;
}
break;
default:
paylen = length;
break;
}
if (paylen >= 126)
ctrl |= 126;
else
ctrl |= paylen;
if (payoffs + 4 + paylen > sizeof(st->outbuffer))
return false;
st->outbuffer[payoffs++] = ctrl>>8;
st->outbuffer[payoffs++] = ctrl&0xff;
if ((ctrl&0x7f) == 126)
{
st->outbuffer[payoffs++] = paylen>>8;
st->outbuffer[payoffs++] = paylen&0xff;
}
switch((ctrl>>8) & 0xf)
{
case 1:/*utf8ify the data*/
for (i = 0; i < length; i++)
{
if (!((unsigned char*)data)[i])
{ /*0 is encoded as 0x100 to avoid safety checks*/
st->outbuffer[payoffs++] = 0xc0 | (0x100>>6);
st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f);
}
else if (((unsigned char*)data)[i] >= 0x80)
{ /*larger bytes require markup*/
st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6);
st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f);
}
else
{ /*lower 7 bits are as-is*/
st->outbuffer[payoffs++] = ((char*)data)[i];
}
}
break;
default: //raw data
memcpy(st->outbuffer+payoffs, data, length);
payoffs += length;
break;
}
st->outlen = payoffs;
if (st->outlen)
{ /*try and flush the old data*/
int done;
done = VFS_WRITE(st->clientstream, st->outbuffer, st->outlen);
if (done > 0)
{
memmove(st->outbuffer, st->outbuffer + done, st->outlen - done);
st->outlen -= done;
}
}
return true;
}
#include "fs.h" #include "fs.h"
qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
{ {
@ -3218,35 +3298,47 @@ handshakeerror:
unsigned int payoffs = 2; unsigned int payoffs = 2;
unsigned int mask = 0; unsigned int mask = 0;
st->inbuffer[st->inlen]=0; st->inbuffer[st->inlen]=0;
if (ctrl & 0x7000)
{
Con_Printf ("%s: reserved bits set\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
}
if ((ctrl & 0x7f) == 127) if ((ctrl & 0x7f) == 127)
{ {
unsigned long long ullpaylen;
//as a payload is not allowed to be encoded as too large a type, and quakeworld never used packets larger than 1450 bytes anyway, this code isn't needed (65k is the max even without this) //as a payload is not allowed to be encoded as too large a type, and quakeworld never used packets larger than 1450 bytes anyway, this code isn't needed (65k is the max even without this)
// if (sizeof(paylen) < 8) if (sizeof(ullpaylen) < 8)
{ {
Con_Printf ("%s: payload frame too large\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_Printf ("%s: payload frame too large\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
} }
/* else else
{ {
if (payoffs + 8 > st->inlen) if (payoffs + 8 > st->inlen)
break; break;
paylen = ullpaylen =
((unsigned char*)st->inbuffer)[payoffs+0]<<56 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+0]<<56ull |
((unsigned char*)st->inbuffer)[payoffs+1]<<48 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+1]<<48ull |
((unsigned char*)st->inbuffer)[payoffs+2]<<40 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+2]<<40ull |
((unsigned char*)st->inbuffer)[payoffs+3]<<32 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+3]<<32ull |
((unsigned char*)st->inbuffer)[payoffs+4]<<24 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+4]<<24ull |
((unsigned char*)st->inbuffer)[payoffs+5]<<16 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+5]<<16ull |
((unsigned char*)st->inbuffer)[payoffs+6]<<8 | (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+6]<< 8ull |
((unsigned char*)st->inbuffer)[payoffs+7]<<0; (unsigned long long)((unsigned char*)st->inbuffer)[payoffs+7]<< 0ull;
if (paylen < 0x10000) if (ullpaylen < 0x10000)
{ {
Con_Printf ("%s: payload size encoded badly\n", NET_AdrToString (st->remoteaddr, sizeof(st->remoteaddr), net_from)); Con_Printf ("%s: payload size (%llu) encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream; goto closesvstream;
} }
if (ullpaylen > 0x10000)
{
Con_Printf ("%s: payload size (%llu) is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), st->inbuffer, ullpaylen);
goto closesvstream;
}
paylen = ullpaylen;
payoffs += 8; payoffs += 8;
} }
*/ } }
else if ((ctrl & 0x7f) == 126) else if ((ctrl & 0x7f) == 126)
{ {
if (payoffs + 2 > st->inlen) if (payoffs + 2 > st->inlen)
@ -3293,10 +3385,10 @@ handshakeerror:
switch((ctrl>>8) & 0xf) switch((ctrl>>8) & 0xf)
{ {
case 0: /*continuation*/ case 0x0: /*continuation*/
Con_Printf ("websocket continuation frame from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_Printf ("websocket continuation frame from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
case 1: /*text frame*/ case 0x1: /*text frame*/
// Con_Printf ("websocket text frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); // Con_Printf ("websocket text frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
{ {
/*text frames are pure utf-8 chars, no dodgy encodings or anything, all pre-checked... /*text frames are pure utf-8 chars, no dodgy encodings or anything, all pre-checked...
@ -3330,8 +3422,8 @@ handshakeerror:
net_message.cursize = out - net_message_buffer; net_message.cursize = out - net_message_buffer;
} }
break; break;
case 2: /*binary frame*/ case 0x2: /*binary frame*/
// Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr)); Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
net_message.cursize = paylen; net_message.cursize = paylen;
if (net_message.cursize+8 >= sizeof(net_message_buffer) ) if (net_message.cursize+8 >= sizeof(net_message_buffer) )
{ {
@ -3350,13 +3442,15 @@ handshakeerror:
else else
memcpy(net_message_buffer, st->inbuffer+payoffs, paylen); memcpy(net_message_buffer, st->inbuffer+payoffs, paylen);
break; break;
case 8: /*connection close*/ case 0x8: /*connection close*/
Con_Printf ("websocket closure %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_Printf ("websocket closure %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
case 9: /*ping*/ case 0x9: /*ping*/
Con_Printf ("websocket ping from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_Printf ("websocket ping from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; if (!FTENET_TCPConnect_WebSocket_Splurge(st, 0xa, st->inbuffer+payoffs, paylen))
case 10: /*pong*/ goto closesvstream;
break;
case 0xa: /*pong*/
Con_Printf ("websocket pong from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_Printf ("websocket pong from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
default: default:
@ -3479,67 +3573,7 @@ qboolean FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
//fallthrough //fallthrough
case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETB:
{ FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length);
/*as a server, we don't need the mask stuff*/
unsigned short ctrl = (st->clienttype==TCPC_WEBSOCKETU)?0x8100:0x8200;
unsigned int paylen = 0;
unsigned int payoffs = 2;
int i;
switch((ctrl>>8) & 0xf)
{
case 1:
for (i = 0; i < length; i++)
{
paylen += (((char*)data)[i] == 0 || ((unsigned char*)data)[i] >= 0x80)?2:1;
}
break;
default:
paylen = length;
break;
}
if (paylen >= 126)
{
ctrl |= 126;
payoffs += 2;
}
else
ctrl |= paylen;
st->outbuffer[0] = ctrl>>8;
st->outbuffer[1] = ctrl&0xff;
if (paylen >= 126)
{
st->outbuffer[2] = paylen>>8;
st->outbuffer[3] = paylen&0xff;
}
switch((ctrl>>8) & 0xf)
{
case 1:/*utf8ify the data*/
for (i = 0; i < length; i++)
{
if (!((unsigned char*)data)[i])
{ /*0 is encoded as 0x100 to avoid safety checks*/
st->outbuffer[payoffs++] = 0xc0 | (0x100>>6);
st->outbuffer[payoffs++] = 0x80 | (0x100&0x3f);
}
else if (((unsigned char*)data)[i] >= 0x80)
{ /*larger bytes require markup*/
st->outbuffer[payoffs++] = 0xc0 | (((unsigned char*)data)[i]>>6);
st->outbuffer[payoffs++] = 0x80 | (((unsigned char*)data)[i]&0x3f);
}
else
{ /*lower 7 bits are as-is*/
st->outbuffer[payoffs++] = ((char*)data)[i];
}
}
break;
default: //raw data
memcpy(st->outbuffer+payoffs, data, length);
payoffs += length;
break;
}
st->outlen = payoffs;
}
break; break;
default: default:
break; break;
@ -4395,7 +4429,8 @@ static qboolean FTENET_WebSocket_SendPacket(ftenet_generic_connection_t *gcon, i
ftenet_websocket_connection_t *wsc = (void*)gcon; ftenet_websocket_connection_t *wsc = (void*)gcon;
if (NET_CompareAdr(to, &wsc->remoteadr)) if (NET_CompareAdr(to, &wsc->remoteadr))
{ {
emscriptenfte_ws_send(wsc->sock, data, length); if (emscriptenfte_ws_send(wsc->sock, data, length) < 0)
return false;
return true; return true;
} }
return false; return false;
@ -5846,8 +5881,16 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
if (tf->sock != INVALID_SOCKET) if (tf->sock != INVALID_SOCKET)
{ {
trying = sizeof(tf->readbuffer) - tf->readbuffered; trying = sizeof(tf->readbuffer) - tf->readbuffered;
if (trying > 1500) if (bytestoread > 1500)
trying = 1500; {
if (trying > bytestoread)
trying = bytestoread;
}
else
{
if (trying > 1500)
trying = 1500;
}
len = recv(tf->sock, tf->readbuffer + tf->readbuffered, trying, 0); len = recv(tf->sock, tf->readbuffer + tf->readbuffered, trying, 0);
if (len == -1) if (len == -1)
{ {
@ -5924,7 +5967,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
timeout.tv_usec = 0; timeout.tv_usec = 0;
FD_ZERO(&fd); FD_ZERO(&fd);
FD_SET(tf->sock, &fd); FD_SET(tf->sock, &fd);
if (!select((int)tf->sock+1, NULL, &fd, NULL, &timeout)) if (!select((int)tf->sock+1, NULL, &fd, &fd, &timeout))
return 0; return 0;
tf->conpending = false; tf->conpending = false;
} }
@ -5939,7 +5982,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
return 0; //nothing available yet. return 0; //nothing available yet.
case NET_ENOTCONN: case NET_ENOTCONN:
Con_Printf("connection to \"%s\" failed\n", tf->peer); Con_Printf("connection to \"%s\" failed\n", tf->peer);
break; return -1; //don't bother trying to read if we never connected.
default: default:
Sys_Printf("tcp socket error %i (%s)\n", e, tf->peer); Sys_Printf("tcp socket error %i (%s)\n", e, tf->peer);
break; break;

View file

@ -77,7 +77,7 @@ typedef struct plugin_s {
struct plugin_s *next; struct plugin_s *next;
} plugin_t; } plugin_t;
void Plug_SubConsoleCommand(console_t *con, char *line); int Plug_SubConsoleCommand(console_t *con, char *line);
plugin_t *currentplug; plugin_t *currentplug;
@ -262,6 +262,8 @@ plugin_t *Plug_Load(const char *file, int type)
newplug->name = (char*)(newplug+1); newplug->name = (char*)(newplug+1);
strcpy(newplug->name, file); strcpy(newplug->name, file);
if (!newplug->vm && (type & PLUG_NATIVE))
newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL);
if (!newplug->vm && (type & PLUG_NATIVE)) if (!newplug->vm && (type & PLUG_NATIVE))
newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL); newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL);
if (!newplug->vm && (type & PLUG_QVM)) if (!newplug->vm && (type & PLUG_QVM))
@ -334,6 +336,9 @@ static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, time_t mtim
if (dot) if (dot)
*dot = 0; *dot = 0;
} }
len = strlen(vmname);
if (len > 0 && vmname[len-1] == '_')
vmname[len-1] = 0;
if (!Plug_Load(vmname, PLUG_NATIVE)) if (!Plug_Load(vmname, PLUG_NATIVE))
Con_Printf("Couldn't load plugin %s\n", vmname); Con_Printf("Couldn't load plugin %s\n", vmname);
@ -1538,16 +1543,18 @@ qboolean Plug_ConsoleLink(char *text, char *info)
return result; return result;
} }
void Plug_SubConsoleCommand(console_t *con, char *line) int Plug_SubConsoleCommand(console_t *con, char *line)
{ {
int ret;
char buffer[2048]; char buffer[2048];
plugin_t *oldplug = currentplug; //shouldn't really be needed, but oh well plugin_t *oldplug = currentplug; //shouldn't really be needed, but oh well
currentplug = con->userdata; currentplug = con->userdata;
Q_strncpyz(buffer, va("\"%s\" %s", con->name, line), sizeof(buffer)); Q_strncpyz(buffer, va("\"%s\" %s", con->name, line), sizeof(buffer));
Cmd_TokenizeString(buffer, false, false); Cmd_TokenizeString(buffer, false, false);
VM_Call(currentplug->vm, currentplug->conexecutecommand, 0); ret = VM_Call(currentplug->vm, currentplug->conexecutecommand, 0);
currentplug = oldplug; currentplug = oldplug;
return ret;
} }
void Plug_SpellCheckMaskedText(unsigned int *maskedstring, int maskedchars, int x, int y, int cs, int firstc, int charlimit) void Plug_SpellCheckMaskedText(unsigned int *maskedstring, int maskedchars, int x, int y, int cs, int firstc, int charlimit)

View file

@ -295,9 +295,9 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int
debuggerinstance = prinst; debuggerinstance = prinst;
debuggerfile = filename; debuggerfile = filename;
if (reason) if (reason)
Con_Footerf(false, "^bDebugging: %s", reason); Con_Footerf(NULL, false, "^bDebugging: %s", reason);
else else
Con_Footerf(false, "^bDebugging"); Con_Footerf(NULL, false, "^bDebugging");
while(debuggerresume == -1 && !wantquit) while(debuggerresume == -1 && !wantquit)
{ {
Sleep(10); Sleep(10);
@ -1015,7 +1015,16 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
wedict_t *ent = (wedict_t*)PROG_TO_EDICT(prinst, *w->g.self); wedict_t *ent = ((prinst->callargc>0)?G_WEDICT(prinst, OFS_PARM0):PROG_TO_WEDICT(prinst, *w->g.self));
if (prinst->callargc > 1)
{
if (ent->readonly)
{
Con_Printf("setorigin on readonly entity %i\n", ent->entnum);
return;
}
VectorCopy(G_VECTOR(OFS_PARM1), ent->v->origin);
}
World_LinkEdict (w, ent, true); World_LinkEdict (w, ent, true);
} }
@ -1231,6 +1240,11 @@ void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
} }
void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = Cvar_UnsavedArchive();
}
//string(string cvarname) cvar_defstring //string(string cvarname) cvar_defstring
void QCBUILTIN PF_cvar_defstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_cvar_defstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
@ -1438,8 +1452,6 @@ void QCBUILTIN PF_memptradd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
//memory stuff //memory stuff
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
//hash table stuff //hash table stuff
#define MAX_QC_HASHTABLES 256
typedef struct typedef struct
{ {
pubprogfuncs_t *prinst; pubprogfuncs_t *prinst;
@ -1458,12 +1470,16 @@ typedef struct
char *stringdata; char *stringdata;
}; };
} pf_hashentry_t; } pf_hashentry_t;
pf_hashtab_t pf_hashtab[MAX_QC_HASHTABLES]; pf_hashtab_t *pf_hashtab;
size_t pf_hash_maxtables;
pf_hashtab_t pf_peristanthashtab; //persists over map changes. pf_hashtab_t pf_peristanthashtab; //persists over map changes.
pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts. pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts.
static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx) static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
{ {
if (!idx) idx -= 1;
if (idx >= 0 && (unsigned)idx < pf_hash_maxtables && pf_hashtab[idx].prinst)
return &pf_hashtab[idx];
else if (idx == -1)
{ {
if (!pf_peristanthashtab.tab.numbuckets) if (!pf_peristanthashtab.tab.numbuckets)
{ {
@ -1475,9 +1491,6 @@ static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
} }
return &pf_peristanthashtab; return &pf_peristanthashtab;
} }
idx -= 1;
if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst)
return &pf_hashtab[idx];
else else
PR_BIError(prinst, "PF_hash_findtab: invalid hash table\n"); PR_BIError(prinst, "PF_hash_findtab: invalid hash table\n");
return NULL; return NULL;
@ -1585,7 +1598,7 @@ void QCBUILTIN PF_hash_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{ {
if (!type) if (!type)
type = tab->defaulttype; type = tab->defaulttype;
if (flags & 256) if (!(flags & 512) || (flags & 256))
{ {
ent = Hash_Get(&tab->tab, name); ent = Hash_Get(&tab->tab, name);
if (ent) if (ent)
@ -1635,6 +1648,7 @@ void QCBUILTIN PF_hash_destroytab (pubprogfuncs_t *prinst, struct globalvars_s *
} }
void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
//FIXME: these need to be managed by the qcvm for garbage collection
int i; int i;
int numbuckets = G_FLOAT(OFS_PARM0); int numbuckets = G_FLOAT(OFS_PARM0);
// qboolean dupestrings = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):false; // qboolean dupestrings = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):false;
@ -1643,20 +1657,27 @@ void QCBUILTIN PF_hash_createtab (pubprogfuncs_t *prinst, struct globalvars_s *p
type = ev_vector; type = ev_vector;
if (numbuckets < 4) if (numbuckets < 4)
numbuckets = 64; numbuckets = 64;
for (i = 0; i < MAX_QC_HASHTABLES; i++)
{ for (i = 0; i < pf_hash_maxtables; i++)
{ //look for an empty slot
if (!pf_hashtab[i].prinst) if (!pf_hashtab[i].prinst)
break;
}
if (i == pf_hash_maxtables)
{ //all slots taken, expand list
if (!ZF_ReallocElements(&pf_hashtab, &pf_hash_maxtables, pf_hash_maxtables+64, sizeof(*pf_hashtab)))
{ {
pf_hashtab[i].defaulttype = type; G_FLOAT(OFS_RETURN) = 0;
pf_hashtab[i].prinst = prinst;
pf_hashtab[i].bucketmem = Z_Malloc(Hash_BytesForBuckets(numbuckets));
Hash_InitTable(&pf_hashtab[i].tab, numbuckets, pf_hashtab[i].bucketmem);
G_FLOAT(OFS_RETURN) = i + 1;
return; return;
} }
} }
G_FLOAT(OFS_RETURN) = 0;
return; //fill it in
pf_hashtab[i].defaulttype = type;
pf_hashtab[i].prinst = prinst;
pf_hashtab[i].bucketmem = Z_Malloc(Hash_BytesForBuckets(numbuckets));
Hash_InitTable(&pf_hashtab[i].tab, numbuckets, pf_hashtab[i].bucketmem);
G_FLOAT(OFS_RETURN) = i + 1;
} }
void pf_hash_savegame(void) //write the persistant table to a saved game. void pf_hash_savegame(void) //write the persistant table to a saved game.
@ -4847,6 +4868,11 @@ void QCBUILTIN PF_localcmd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
char *str; char *str;
str = PF_VarString(prinst, 0, pr_globals); str = PF_VarString(prinst, 0, pr_globals);
if (developer.ival)
{
PR_StackTrace(prinst, false);
Con_Printf("localcmd: %s\n", str);
}
if (!strcmp(str, "host_framerate 0\n")) if (!strcmp(str, "host_framerate 0\n"))
Cbuf_AddText ("sv_mintic 0\n", RESTRICT_INSECURE); //hmm... do this better... Cbuf_AddText ("sv_mintic 0\n", RESTRICT_INSECURE); //hmm... do this better...
else else

View file

@ -269,11 +269,19 @@ void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr
void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_getfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_brush_findinvolume(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
//pr_cmds.c builtins that need to be moved to a common. //pr_cmds.c builtins that need to be moved to a common.
void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...) LIKEPRINTF(2); void VARGS PR_BIError(pubprogfuncs_t *progfuncs, char *format, ...) LIKEPRINTF(2);
void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvar_setf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_cvar_setf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_ArgC (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_ArgC (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -621,7 +629,7 @@ typedef enum
//33-36 used by DP... //33-36 used by DP...
VF_PERSPECTIVE = 200, VF_PERSPECTIVE = 200,
//201 used by DP... WTF? CLEARSCREEN //201 used by DP... WTF? CLEARSCREEN
VF_LPLAYER = 202, VF_ACTIVESEAT = 202,
VF_AFOV = 203, //aproximate fov (match what the engine would normally use for the fov cvar). p0=fov, p1=zoom VF_AFOV = 203, //aproximate fov (match what the engine would normally use for the fov cvar). p0=fov, p1=zoom
VF_SCREENVSIZE = 204, VF_SCREENVSIZE = 204,
VF_SCREENPSIZE = 205, VF_SCREENPSIZE = 205,

View file

@ -282,6 +282,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define svcfte_voicechat 84 #define svcfte_voicechat 84
#define svcfte_setangledelta 85 // [angle3] add this to the current viewangles #define svcfte_setangledelta 85 // [angle3] add this to the current viewangles
#define svcfte_updateentities 86 #define svcfte_updateentities 86
#define svcfte_brushedit 87 // networked brush editing, paired with clcfte_brushedit.
//fitz svcs //fitz svcs
@ -413,14 +414,15 @@ enum clcq2_ops_e
#define clc_stringcmd 4 // [string] message #define clc_stringcmd 4 // [string] message
#define clc_delta 5 // [qbyte] sequence number, requests delta compression of message #define clc_delta 5 // [qbyte] sequence number, requests delta compression of message
#define clc_tmove 6 // teleport request, spectator only #define clc_tmove 6 // teleport request, spectator only
#define clc_upload 7 // teleport request, spectator only #define clc_upload 7 //
#define clcdp_ackframe 50 #define clcdp_ackframe 50
#define clcdp_ackdownloaddata 51 #define clcdp_ackdownloaddata 51
#define clc_qcrequest 81 #define clcfte_qcrequest 81
#define clc_prydoncursor 82 #define clcfte_prydoncursor 82
#define clc_voicechat 83 #define clcfte_voicechat 83
#define clcfte_brushedit 84
//============================================== //==============================================

View file

@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void Sys_mkdir (char *path); //not all pre-unix systems have directories (including dos 1) void Sys_mkdir (char *path); //not all pre-unix systems have directories (including dos 1)
qboolean Sys_remove (char *path); qboolean Sys_remove (char *path);
qboolean Sys_Rename (char *oldfname, char *newfname); qboolean Sys_Rename (char *oldfname, char *newfname);
qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *basepath, int basepathlen); qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *basepath, int basepathlen, qboolean allowprompts);
// //
// memory protection // memory protection
@ -49,6 +49,7 @@ void Sys_Warn (char *fmt, ...) LIKEPRINTF(1);
void Sys_Quit (void); void Sys_Quit (void);
void Sys_RecentServer(char *command, char *target, char *title, char *desc); void Sys_RecentServer(char *command, char *target, char *title, char *desc);
qboolean Sys_RunInstaller(void);
typedef struct { typedef struct {
void **funcptr; void **funcptr;

View file

@ -72,6 +72,8 @@ typedef struct trace_s
qboolean inopen, inwater; qboolean inopen, inwater;
float truefraction; //can be negative, also has floating point precision issues, etc. float truefraction; //can be negative, also has floating point precision issues, etc.
int brush_id;
int brush_face;
} trace_t; } trace_t;
typedef struct q2trace_s typedef struct q2trace_s

View file

@ -322,6 +322,34 @@ void VARGS Z_FreeTags(int tag)
} }
} }
//close enough
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif
qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize)
{
void *n;
size_t oldsize;
size_t newsize;
//protect against malicious overflows
if (newelements > SIZE_MAX / elementsize)
return false;
oldsize = *elements * elementsize;
newsize = newelements * elementsize;
n = BZ_Realloc(*ptr, newsize);
if (!n)
return false;
if (newsize > oldsize)
memset((char*)n+oldsize, 0, newsize - oldsize);
*elements = newelements;
*ptr = n;
return true;
}
/* /*
void *Z_Realloc(void *data, int newsize) void *Z_Realloc(void *data, int newsize)
{ {

View file

@ -95,7 +95,8 @@ void *ZF_MallocNamed (int size, char *file, int line); // allowed to fail
void *VARGS Z_TagMalloc (int size, int tag); void *VARGS Z_TagMalloc (int size, int tag);
void VARGS Z_TagFree(void *ptr); void VARGS Z_TagFree(void *ptr);
void VARGS Z_FreeTags(int tag); void VARGS Z_FreeTags(int tag);
//void *Z_Realloc (void *ptr, int size); qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize); //returns false on error
#define Z_ReallocElements(ptr,elements,newelements,elementsize) do{if (!ZF_ReallocElements(ptr,elements,newelements,elementsize))Sys_Error("Z_ReallocElements failed (%s %i)\n", __FILE__, __LINE__);}while(0) //returns false on error
//Big Zone: allowed to fail, doesn't clear. The expectation is a large file, rather than sensitive data structures. //Big Zone: allowed to fail, doesn't clear. The expectation is a large file, rather than sensitive data structures.
//(this is a nicer name for malloc) //(this is a nicer name for malloc)

View file

@ -759,9 +759,9 @@ static void (D3D9_VID_DeInit) (void)
mainwindow = NULL; mainwindow = NULL;
} }
Cvar_Unhook(&v_gamma); // Cvar_Unhook(&v_gamma);
Cvar_Unhook(&v_contrast); // Cvar_Unhook(&v_contrast);
Cvar_Unhook(&v_brightness); // Cvar_Unhook(&v_brightness);
} }
qboolean D3D9_VID_ApplyGammaRamps (unsigned short *ramps) qboolean D3D9_VID_ApplyGammaRamps (unsigned short *ramps)

View file

@ -2,9 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005 # Visual Studio 2005
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}" Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{82285268-9C3B-44AD-BBE7-40670F9D2628} = {82285268-9C3B-44AD-BBE7-40670F9D2628}
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{72269FEE-293D-40BC-A7AE-E429F4496869} = {72269FEE-293D-40BC-A7AE-E429F4496869} {72269FEE-293D-40BC-A7AE-E429F4496869} = {72269FEE-293D-40BC-A7AE-E429F4496869}
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{82285268-9C3B-44AD-BBE7-40670F9D2628} = {82285268-9C3B-44AD-BBE7-40670F9D2628}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}"
@ -33,6 +33,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpserver", "..\http\https
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080}
EndProjectSection EndProjectSection
EndProject EndProject
@ -351,6 +352,7 @@ Global
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.ActiveCfg = Debug|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|x64.ActiveCfg = Debug|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.ActiveCfg = Debug|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.Build.0 = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|x64.ActiveCfg = Debug|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|x64.ActiveCfg = Debug|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.ActiveCfg = Release|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|x64.ActiveCfg = Release|Win32 {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|x64.ActiveCfg = Release|Win32

View file

@ -26099,6 +26099,10 @@
RelativePath="..\common\fs_win32.c" RelativePath="..\common\fs_win32.c"
> >
</File> </File>
<File
RelativePath="..\common\fs_xz.c"
>
</File>
<File <File
RelativePath="..\common\fs_zip.c" RelativePath="..\common\fs_zip.c"
> >

View file

@ -742,6 +742,7 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
cm->texnum.specular = r_nulltex; cm->texnum.specular = r_nulltex;
cm->texnum.loweroverlay = r_nulltex; cm->texnum.loweroverlay = r_nulltex;
cm->texnum.upperoverlay = r_nulltex; cm->texnum.upperoverlay = r_nulltex;
cm->texnum.paletted = r_nulltex;
//q2 has no surfaces in its player models, so don't crash from that //q2 has no surfaces in its player models, so don't crash from that
//note that q2 should also always have a custom skin set. its not our problem (here) if it doesn't. //note that q2 should also always have a custom skin set. its not our problem (here) if it doesn't.

View file

@ -3531,6 +3531,12 @@ void GLBE_SelectMode(backendmode_t mode)
shaderstate.crepskyshader = R_RegisterShader("crepuscular_sky", SUF_NONE, shaderstate.crepskyshader = R_RegisterShader("crepuscular_sky", SUF_NONE,
"{\n" "{\n"
"program crepuscular_sky\n" "program crepuscular_sky\n"
"{\n"
"map $diffuse\n"
"}\n"
"{\n"
"map $fullbright\n"
"}\n"
"}\n" "}\n"
); );
} }
@ -3988,7 +3994,7 @@ static void DrawMeshes(void)
{ {
GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex);
} }
BE_SendPassBlendDepthMask((shaderstate.curshader->passes[0].shaderbits & ~SBITS_BLEND_BITS) | SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | SBITS_MISC_NODEPTHTEST); BE_SendPassBlendDepthMask((shaderstate.curshader->passes[0].shaderbits & ~SBITS_BLEND_BITS) | SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA | ((r_wireframe.ival == 1)?SBITS_MISC_NODEPTHTEST:0));
BE_EnableShaderAttributes((1u<<VATTR_LEG_VERTEX) | (1u<<VATTR_LEG_COLOUR), 0); BE_EnableShaderAttributes((1u<<VATTR_LEG_VERTEX) | (1u<<VATTR_LEG_COLOUR), 0);
BE_SubmitMeshChain(false); BE_SubmitMeshChain(false);
@ -4629,6 +4635,7 @@ static void BE_UpdateLightmaps(void)
lightmapinfo_t *lm; lightmapinfo_t *lm;
int lmidx; int lmidx;
int glformat, gltype; int glformat, gltype;
int internalformat = GL_RGBA;
switch (lightmap_bytes) switch (lightmap_bytes)
{ {
case 4: case 4:
@ -4644,6 +4651,9 @@ static void BE_UpdateLightmaps(void)
gltype = GL_UNSIGNED_BYTE; gltype = GL_UNSIGNED_BYTE;
break; break;
} }
if (gl_config.gles)
internalformat = glformat;
for (lmidx = 0; lmidx < numlightmaps; lmidx++) for (lmidx = 0; lmidx < numlightmaps; lmidx++)
{ {
lm = lightmap[lmidx]; lm = lightmap[lmidx];
@ -4660,7 +4670,7 @@ static void BE_UpdateLightmaps(void)
GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture); GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, qglTexImage2D(GL_TEXTURE_2D, 0, internalformat,
lm->width, lm->height, 0, glformat, gltype, lm->width, lm->height, 0, glformat, gltype,
lm->lightmaps); lm->lightmaps);
} }

View file

@ -45,7 +45,7 @@ http://prideout.net/archive/bloom/ contains some sample code
#include "shader.h" #include "shader.h"
#include "glquake.h" #include "glquake.h"
cvar_t r_bloom = CVARAFD("r_bloom", "0", "gl_bloom", CVAR_ARCHIVE, "Enables bloom (light bleeding from bright objects). Fractional values reduce the amount shown."); cvar_t r_bloom = CVARAFD("r_bloom", "0", "gl_bloom", CVAR_ARCHIVE, "Enables bloom (light bleeding from bright objects). Fractional values reduce the amount shown.");
cvar_t r_bloom_filter = CVARD("r_bloom_filter", "0.5 0.5 0.5", "Controls how bright the image must get before it will bloom (3 separate values, in RGB order)."); cvar_t r_bloom_filter = CVARD("r_bloom_filter", "0.7 0.7 0.7", "Controls how bright the image must get before it will bloom (3 separate values, in RGB order).");
cvar_t r_bloom_scale = CVARD("r_bloom_scale", "0.5", "Controls the initial downscale size. Smaller values will bloom further but be more random."); cvar_t r_bloom_scale = CVARD("r_bloom_scale", "0.5", "Controls the initial downscale size. Smaller values will bloom further but be more random.");
static shader_t *bloomfilter; static shader_t *bloomfilter;
static shader_t *bloomrescale; static shader_t *bloomrescale;

View file

@ -233,7 +233,7 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
} }
else else
{ {
if ((filter[1]))// && !(flags & IF_NEAREST)) || (flags & IF_LINEAR)) if ((filter[1] && !(flags & IF_NEAREST)) || (flags & IF_LINEAR))
{ {
if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR)) if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR))
min = GL_LINEAR_MIPMAP_LINEAR; min = GL_LINEAR_MIPMAP_LINEAR;
@ -242,7 +242,7 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
} }
else else
{ {
if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR)) if ((filter[0] && !(flags & IF_NEAREST)) || (flags & IF_LINEAR))
min = GL_LINEAR_MIPMAP_NEAREST; min = GL_LINEAR_MIPMAP_NEAREST;
else else
min = GL_NEAREST_MIPMAP_NEAREST; min = GL_NEAREST_MIPMAP_NEAREST;
@ -324,6 +324,7 @@ qboolean GL_LoadTextureMips(texid_t tex, struct pendingtextureinfo *mips)
//make sure the texture is complete even if the mips are not. //make sure the texture is complete even if the mips are not.
//note that some drivers will just ignore levels that are not valid. //note that some drivers will just ignore levels that are not valid.
//this means that we can't make this setting dynamic, so we might as well let the drivers know BEFORE we do the uploads, to be kind to those that are buggy.. //this means that we can't make this setting dynamic, so we might as well let the drivers know BEFORE we do the uploads, to be kind to those that are buggy..
//this is available in gles3
if (!gl_config.gles) if (!gl_config.gles)
{ {
if (targ != GL_TEXTURE_CUBE_MAP_ARB && (tex->flags & IF_MIPCAP)) if (targ != GL_TEXTURE_CUBE_MAP_ARB && (tex->flags & IF_MIPCAP))

View file

@ -10,7 +10,7 @@
void Font_Init(void); void Font_Init(void);
void Font_Shutdown(void); void Font_Shutdown(void);
struct font_s *Font_LoadFont(int height, const char *fontfilename); struct font_s *Font_LoadFont(float height, const char *fontfilename);
void Font_Free(struct font_s *f); void Font_Free(struct font_s *f);
void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py); void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py);
void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py); /*avoid using*/
@ -161,6 +161,7 @@ static const char *imgs[] =
#define BITMAPPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-2) #define BITMAPPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-2)
#define DEFAULTPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-3) #define DEFAULTPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-3)
#define SINGLEPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-4) #define SINGLEPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-4)
#define TRACKERIMAGE ((1<<(8*sizeof(PLANEIDXTYPE)))-5)
#define PLANEWIDTH (1<<8) #define PLANEWIDTH (1<<8)
#define PLANEHEIGHT PLANEWIDTH #define PLANEHEIGHT PLANEWIDTH
@ -226,6 +227,7 @@ typedef struct font_s
typedef struct { typedef struct {
texid_t texnum[FONTPLANES]; texid_t texnum[FONTPLANES];
texid_t defaultfont; texid_t defaultfont;
texid_t trackerimage;
unsigned char plane[PLANEWIDTH*PLANEHEIGHT][4]; //tracks the current plane unsigned char plane[PLANEWIDTH*PLANEHEIGHT][4]; //tracks the current plane
PLANEIDXTYPE activeplane; PLANEIDXTYPE activeplane;
@ -259,12 +261,56 @@ static struct font_s *curfont;
static float curfont_scale[2]; static float curfont_scale[2];
static qboolean curfont_scaled; static qboolean curfont_scaled;
//^Ue2XX
static struct
{
image_t *image;
char name[64];
} trackerimages[256];
static int numtrackerimages;
#define TRACKERFIRST 0xe200
int Font_RegisterTrackerImage(const char *image)
{
int i;
for (i = 0; i < numtrackerimages; i++)
{
if (!strcmp(trackerimages[i].name, image))
return TRACKERFIRST + i;
}
if (numtrackerimages == 256)
return 0;
trackerimages[i].image = NULL; //actually load it elsewhere, because we're lazy.
Q_strncpyz(trackerimages[i].name, image, sizeof(trackerimages[i].name));
numtrackerimages++;
return TRACKERFIRST + i;
}
//called from the font display code for tracker images
static image_t *Font_GetTrackerImage(unsigned int imid)
{
if (!trackerimages[imid].image)
{
if (!*trackerimages[imid].name)
return NULL;
trackerimages[imid].image = Image_GetTexture(trackerimages[imid].name, NULL, 0, NULL, NULL, 0, 0, TF_INVALID);
}
if (!trackerimages[imid].image)
return NULL;
if (trackerimages[imid].image->status != TEX_LOADED)
return NULL;
return trackerimages[imid].image;
}
//called at load time - initalises font buffers //called at load time - initalises font buffers
void Font_Init(void) void Font_Init(void)
{ {
int i; int i;
TEXASSIGN(fontplanes.defaultfont, r_nulltex); TEXASSIGN(fontplanes.defaultfont, r_nulltex);
//clear tracker images, just in case they were still set for the previous renderer context
for (i = 0; i < sizeof(trackerimages)/sizeof(trackerimages[0]); i++)
trackerimages[i].image = NULL;
font_foremesh.indexes = font_indicies; font_foremesh.indexes = font_indicies;
font_foremesh.xyz_array = font_coord; font_foremesh.xyz_array = font_coord;
font_foremesh.st_array = font_texcoord; font_foremesh.st_array = font_texcoord;
@ -658,6 +704,17 @@ static struct charcache_s *Font_GetChar(font_t *f, CHARIDXTYPE charidx)
struct charcache_s *c = &f->chars[charidx]; struct charcache_s *c = &f->chars[charidx];
if (c->texplane == INVALIDPLANE) if (c->texplane == INVALIDPLANE)
{ {
if (charidx >= TRACKERFIRST && charidx < TRACKERFIRST+100)
{
static struct charcache_s tc;
tc.texplane = TRACKERIMAGE;
fontplanes.trackerimage = Font_GetTrackerImage(charidx-TRACKERFIRST);
if (!fontplanes.trackerimage)
return Font_GetChar(f, '?');
tc.advance = fontplanes.trackerimage->width * ((float)f->charheight / fontplanes.trackerimage->height);
return &tc;
}
//not cached, can't get. //not cached, can't get.
c = Font_TryLoadGlyph(f, charidx); c = Font_TryLoadGlyph(f, charidx);
@ -1079,14 +1136,14 @@ void Doom_ExpandPatch(doompatch_t *p, unsigned char *b, int stride)
//creates a new font object from the given file, with each text row with the given height. //creates a new font object from the given file, with each text row with the given height.
//width is implicit and scales with height and choice of font. //width is implicit and scales with height and choice of font.
struct font_s *Font_LoadFont(int vheight, const char *fontfilename) struct font_s *Font_LoadFont(float vheight, const char *fontfilename)
{ {
struct font_s *f; struct font_s *f;
int i = 0; int i = 0;
int defaultplane; int defaultplane;
char *aname; char *aname;
char *parms; char *parms;
int height = (vheight * vid.rotpixelheight)/vid.height; int height = ((vheight * vid.rotpixelheight)/vid.height) + 0.5;
char facename[MAX_QPATH]; char facename[MAX_QPATH];
Q_strncpy(facename, fontfilename, sizeof(facename)); Q_strncpy(facename, fontfilename, sizeof(facename));
@ -1572,7 +1629,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
// scan the width of the line // scan the width of the line
for (px=0, l=0 ; px <= maxpixelwidth; ) for (px=0, l=0 ; px <= maxpixelwidth; )
{ {
if (start+l >= end || (start[l]&(CON_CHARMASK|CON_HIDDEN)) == '\n') if (start+l >= end || (start[l]&(CON_CHARMASK|CON_HIDDEN)) == '\n' || (start[l]&(CON_CHARMASK|CON_HIDDEN)) == '\v')
break; break;
px = Font_CharEndCoord(font, px, start[l]); px = Font_CharEndCoord(font, px, start[l]);
l++; l++;
@ -1600,7 +1657,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
if (start == end) if (start == end)
break; break;
if ((*start&(CON_CHARMASK|CON_HIDDEN)) == '\n') if ((*start&(CON_CHARMASK|CON_HIDDEN)) == '\n' || (*start&(CON_CHARMASK|CON_HIDDEN)) == '\v')
start++; // skip the \n start++; // skip the \n
} }
@ -1707,16 +1764,16 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
if ((charcode & CON_CHARMASK) == ' ') if ((charcode & CON_CHARMASK) == ' ')
return nextx; return nextx;
if (charcode & CON_BLINKTEXT) /* if (charcode & CON_BLINKTEXT)
{ {
if (!cl_noblink.ival) if (!cl_noblink.ival)
if ((int)(realtime*3) & 1) if ((int)(realtime*3) & 1)
return nextx; return nextx;
} }
*/
if (charcode & CON_RICHFORECOLOUR) if (charcode & CON_RICHFORECOLOUR)
{ {
col = charcode & (CON_2NDCHARSETTEXT|CON_RICHFORECOLOUR|(0xfff<<CON_RICHBSHIFT)); col = charcode & (CON_2NDCHARSETTEXT|CON_BLINKTEXT|CON_RICHFORECOLOUR|(0xfff<<CON_RICHBSHIFT));
if (col != font_colourmask) if (col != font_colourmask)
{ {
vec4_t rgba; vec4_t rgba;
@ -1749,6 +1806,11 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
rgba[1] *= font_foretint[1]; rgba[1] *= font_foretint[1];
rgba[2] *= font_foretint[2]; rgba[2] *= font_foretint[2];
rgba[3] *= font_foretint[3]; rgba[3] *= font_foretint[3];
if (charcode & CON_BLINKTEXT)
{
float a = (sin(realtime*3)+1)*0.4 + 0.2;
rgba[3] *= a;
}
font_forecolour[0] = min(rgba[0], 255); font_forecolour[0] = min(rgba[0], 255);
font_forecolour[1] = min(rgba[1], 255); font_forecolour[1] = min(rgba[1], 255);
font_forecolour[2] = min(rgba[2], 255); font_forecolour[2] = min(rgba[2], 255);
@ -1757,7 +1819,7 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
} }
else else
{ {
col = charcode & (CON_2NDCHARSETTEXT|CON_NONCLEARBG|CON_BGMASK|CON_FGMASK|CON_HALFALPHA); col = charcode & (CON_2NDCHARSETTEXT|CON_NONCLEARBG|CON_BGMASK|CON_FGMASK|CON_HALFALPHA|CON_BLINKTEXT);
if (col != font_colourmask) if (col != font_colourmask)
{ {
vec4_t rgba; vec4_t rgba;
@ -1793,6 +1855,11 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
rgba[1] *= font_foretint[1]; rgba[1] *= font_foretint[1];
rgba[2] *= font_foretint[2]; rgba[2] *= font_foretint[2];
rgba[3] *= font_foretint[3]; rgba[3] *= font_foretint[3];
if (charcode & CON_BLINKTEXT)
{
float a = (sin(realtime*3)+1)*0.4 + 0.2;
rgba[3] *= a;
}
font_forecolour[0] = min(rgba[0], 255); font_forecolour[0] = min(rgba[0], 255);
font_forecolour[1] = min(rgba[1], 255); font_forecolour[1] = min(rgba[1], 255);
font_forecolour[2] = min(rgba[2], 255); font_forecolour[2] = min(rgba[2], 255);
@ -1807,6 +1874,15 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
switch(c->texplane) switch(c->texplane)
{ {
case TRACKERIMAGE:
s0 = t0 = 0;
s1 = t1 = 1;
sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth;
sy = ((py+c->top + dxbias)*(int)vid.height) / (float)vid.rotpixelheight;
sw = (c->advance*vid.width) / (float)vid.rotpixelwidth;
sh = (font->charheight*vid.height) / (float)vid.rotpixelheight;
v = Font_BeginChar(fontplanes.trackerimage);
break;
case DEFAULTPLANE: case DEFAULTPLANE:
sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth; sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth;
sy = ((py+c->top + dxbias)*(int)vid.height) / (float)vid.rotpixelheight; sy = ((py+c->top + dxbias)*(int)vid.height) / (float)vid.rotpixelheight;

File diff suppressed because it is too large Load diff

View file

@ -83,6 +83,7 @@ void Mod_LoadAliasShaders(model_t *mod);
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
model_t *lightmodel; model_t *lightmodel;
struct relight_ctx_s *lightcontext;
int numlightdata; int numlightdata;
qboolean writelitfile; qboolean writelitfile;
@ -254,6 +255,7 @@ volatile qboolean wantrelight;
int RelightThread(void *arg) int RelightThread(void *arg)
{ {
int surf; int surf;
void *threadctx = malloc(lightthreadctxsize);
while (wantrelight) while (wantrelight)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -265,9 +267,10 @@ int RelightThread(void *arg)
#endif #endif
if (surf >= lightmodel->numsurfaces) if (surf >= lightmodel->numsurfaces)
break; break;
LightFace(surf); LightFace(lightcontext, threadctx, surf);
lightmodel->surfaces[surf].cached_dlight = -1; lightmodel->surfaces[surf].cached_dlight = -1;
} }
free(threadctx);
return 0; return 0;
} }
#endif #endif
@ -312,7 +315,7 @@ void Mod_Think (void)
return; return;
} }
#else #else
LightFace(relitsurface); LightFace(lightcontext, relitsurface);
Mod_UpdateLightmap(relitsurface); Mod_UpdateLightmap(relitsurface);
relitsurface++; relitsurface++;
@ -337,6 +340,9 @@ void Mod_Think (void)
} }
#endif #endif
LightShutdown(lightcontext, lightmodel);
lightcontext = NULL;
if (lightmodel->deluxdata) if (lightmodel->deluxdata)
{ {
COM_StripExtension(lightmodel->name, filename, sizeof(filename)); COM_StripExtension(lightmodel->name, filename, sizeof(filename));
@ -1180,31 +1186,94 @@ model_t *Mod_ForName (const char *name, enum mlverbosity_e verbosity)
=============================================================================== ===============================================================================
*/ */
static const struct
{
const char *oldname;
unsigned int chksum; //xor-compacted md4
const char *newname;
} buggytextures[] =
{
//FIXME: we should load this table from disk or something.
//old sum new
{"metal5_2", 0x45d110ec, "metal5_2_arc"},
{"metal5_2", 0x0d275f87, "metal5_2_x"},
{"metal5_4", 0xf8e27da8, "metal5_4_arc"},
{"metal5_4", 0xa301c52e, "metal5_4_double"},
{"metal5_8", 0xfaa8bf77, "metal5_8_back"},
{"metal5_8", 0x88792923, "metal5_8_rune"},
{"plat_top1", 0xfe4f9f5a, "plat_top1_bolt"},
{"plat_top1", 0x9ac3fccf, "plat_top1_cable"},
{"sky4", 0xde688b77, "sky1"},
// {"sky4", 0x8a010dc0, "sky4"},
// {"window03", ?, "window03_?"},
// {"window03", ?, "window03_?"},
//FIXME: hexen2 has the same issue.
};
static const char *Mod_RemapBuggyTexture(const char *name, const qbyte *data, unsigned int datalen)
{
unsigned int i;
for (i = 0; i < sizeof(buggytextures)/sizeof(buggytextures[0]); i++)
{
if (!strcmp(name, buggytextures[i].oldname))
{
unsigned int sum = Com_BlockChecksum(data, datalen);
for (; i < sizeof(buggytextures)/sizeof(buggytextures[0]); i++)
{
if (strcmp(name, buggytextures[i].oldname))
break;
if (sum == buggytextures[i].chksum)
return buggytextures[i].newname;
}
break;
}
}
return NULL;
}
void Mod_FinishTexture(texture_t *tx, const char *loadname) void Mod_FinishTexture(texture_t *tx, const char *loadname)
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
extern cvar_t gl_shadeq1_name; extern cvar_t gl_shadeq1_name;
char altname[MAX_QPATH]; char altname[MAX_QPATH];
char *star; char *star;
const char *origname = NULL;
const char *shadername = tx->name;
/*skies? just replace with the override sky*/ /*skies? just replace with the override sky*/
if (!strncmp(tx->name, "sky", 3) && *cl.skyname) if (!strncmp(tx->name, "sky", 3) && *cl.skyname)
tx->shader = R_RegisterCustom (va("skybox_%s", cl.skyname), SUF_NONE, Shader_DefaultSkybox, NULL); //just load the regular name. tx->shader = R_RegisterCustom (va("skybox_%s", cl.skyname), SUF_NONE, Shader_DefaultSkybox, NULL); //just load the regular name.
//find the *
else if (!*gl_shadeq1_name.string || !strcmp(gl_shadeq1_name.string, "*"))
tx->shader = R_RegisterCustom (tx->name, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL); //just load the regular name.
else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(tx->name)+1>=sizeof(altname))) //it's got to fit.
tx->shader = R_RegisterCustom (gl_shadeq1_name.string, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
else else
{ {
strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left //remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
altname[star-gl_shadeq1_name.string] = '\0'; shadername = Mod_RemapBuggyTexture(shadername, tx->mips[0], tx->width*tx->height);
strcat(altname, tx->name); //insert the * if (shadername)
strcat(altname, star+1); //add any final text. origname = tx->name;
tx->shader = R_RegisterCustom (altname, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL); else
shadername = tx->name;
//find the *
if (!*gl_shadeq1_name.string || !strcmp(gl_shadeq1_name.string, "*"))
;
else if (!(star = strchr(gl_shadeq1_name.string, '*')) || (strlen(gl_shadeq1_name.string)+strlen(tx->name)+1>=sizeof(altname))) //it's got to fit.
shadername = gl_shadeq1_name.string;
else
{
strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left
altname[star-gl_shadeq1_name.string] = '\0';
strcat(altname, shadername); //insert the *
strcat(altname, star+1); //add any final text.
shadername = altname;
}
tx->shader = R_RegisterCustom (shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
} }
if (!strncmp(tx->name, "sky", 3)) if (!strncmp(tx->name, "sky", 3))
R_InitSky (&tx->shader->defaulttextures, tx, tx->mips[0]); R_InitSky (&tx->shader->defaulttextures, shadername, tx->mips[0], tx->width, tx->height);
else else
{ {
unsigned int maps = 0; unsigned int maps = 0;
@ -1216,53 +1285,42 @@ void Mod_FinishTexture(texture_t *tx, const char *loadname)
maps |= SHADER_HASNORMALMAP; maps |= SHADER_HASNORMALMAP;
if (gl_specular.ival) if (gl_specular.ival)
maps |= SHADER_HASGLOSS; maps |= SHADER_HASGLOSS;
R_BuildLegacyTexnums(tx->shader, loadname, maps, ((*tx->name=='{')?TF_TRANS8:TF_SOLID8), tx->width, tx->height, tx->mips, host_basepal); R_BuildLegacyTexnums(tx->shader, origname, loadname, maps, ((*tx->name=='{')?TF_TRANS8:TF_MIP4_SOLID8), tx->width, tx->height, tx->mips, tx->palette);
} }
BZ_Free(tx->mips[0]); BZ_Free(tx->mips[0]);
#endif #endif
} }
#ifndef SERVERONLY
static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt) static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt)
{ {
#ifndef SERVERONLY unsigned int size =
qbyte *base; (mt->width>>0)*(mt->height>>0) +
qboolean alphaed; (mt->width>>1)*(mt->height>>1) +
int pixels = mt->width*mt->height/64*85; (mt->width>>2)*(mt->height>>2) +
(mt->width>>3)*(mt->height>>3);
base = (qbyte *)(mt+1);
if (loadmodel->fromgame == fg_halflife) if (loadmodel->fromgame == fg_halflife)
{//external textures have already been filtered. { //mostly identical, just a specific palette hidden at the end. handle fences elsewhere.
tx->mips[0] = BZ_Malloc(size + 768);
//size is not directly known. tx->palette = tx->mips[0] + size;
//we might be able to infer based upon neighbours, but that seems like too much hassle memcpy(tx->palette, (qbyte *)mt + mt->offsets[3] + (mt->width>>3)*(mt->height>>3) + 2, 768);
base = W_ConvertWAD3Texture(mt, 0xffffffff, &mt->width, &mt->height, &alphaed); //convert texture to 32 bit.
// tx->texnums.base = R_LoadReplacementTexture(mt->name, loadname, alphaed?0:IF_NOALPHA, base, tx->width, tx->height, alphaed?TF_RGBA32:TF_RGBX32);
BZ_Free(base);
} }
else else
{ {
qbyte *mipbase; tx->mips[0] = BZ_Malloc(size);
unsigned int mipwidth, mipheight; tx->palette = host_basepal;
extern cvar_t gl_miptexLevel;
if ((unsigned int)gl_miptexLevel.ival < 4 && mt->offsets[gl_miptexLevel.ival])
{
mipbase = (qbyte*)mt + mt->offsets[gl_miptexLevel.ival];
mipwidth = tx->width>>gl_miptexLevel.ival;
mipheight = tx->height>>gl_miptexLevel.ival;
}
else
{
mipbase = base;
mipwidth = tx->width;
mipheight = tx->height;
}
tx->mips[0] = BZ_Malloc(mipwidth*mipheight);
memcpy(tx->mips[0], mipbase, mipwidth*mipheight);
} }
#endif
tx->mips[1] = tx->mips[0] + (mt->width>>0)*(mt->height>>0);
tx->mips[2] = tx->mips[1] + (mt->width>>1)*(mt->height>>1);
tx->mips[3] = tx->mips[2] + (mt->width>>2)*(mt->height>>2);
memcpy(tx->mips[0], (qbyte *)mt + mt->offsets[0], (mt->width>>0)*(mt->height>>0));
memcpy(tx->mips[1], (qbyte *)mt + mt->offsets[1], (mt->width>>1)*(mt->height>>1));
memcpy(tx->mips[2], (qbyte *)mt + mt->offsets[2], (mt->width>>2)*(mt->height>>2));
memcpy(tx->mips[3], (qbyte *)mt + mt->offsets[3], (mt->width>>3)*(mt->height>>3));
} }
#endif
/* /*
================= =================
@ -1346,7 +1404,9 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
continue; continue;
} }
#ifndef SERVERONLY
Mod_LoadMiptex(loadmodel, tx, mt); Mod_LoadMiptex(loadmodel, tx, mt);
#endif
} }
// //
// sequence the animations // sequence the animations
@ -1562,6 +1622,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
{ //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous. { //the map util has a '-scalecos X' parameter. use 0 if you're going to use only just lux. without lux scalecos 0 is hideous.
char luxname[MAX_QPATH]; char luxname[MAX_QPATH];
size_t luxsz = 0; size_t luxsz = 0;
*luxname = 0;
if (!luxdata) if (!luxdata)
{ {
Q_strncpyz(luxname, loadmodel->name, sizeof(luxname)); Q_strncpyz(luxname, loadmodel->name, sizeof(luxname));
@ -1586,6 +1647,12 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz); luxdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, luxname, &luxsz);
luxtmp = false; luxtmp = false;
} }
//make sure the .lux has the correct size
if (luxdata && l->filelen && l->filelen != (luxsz-8)/3)
{
Con_Printf("deluxmap \"%s\" doesn't match level. Ignored.\n", luxname);
luxdata=NULL;
}
if (!luxdata) if (!luxdata)
{ {
int size; int size;
@ -1594,20 +1661,12 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
luxdata = NULL; luxdata = NULL;
luxtmp = true; luxtmp = true;
} }
else if (luxdata) else
{ {
if (l->filelen && l->filelen != (luxsz-8)/3) if (luxdata[0] == 'Q' && luxdata[1] == 'L' && luxdata[2] == 'I' && luxdata[3] == 'T')
{
Con_Printf("deluxmap \"%s\" doesn't match level. Ignored.\n", luxname);
luxdata=NULL;
}
else if (luxdata[0] == 'Q' && luxdata[1] == 'L' && luxdata[2] == 'I' && luxdata[3] == 'T')
{ {
if (LittleLong(*(int *)&luxdata[4]) == 1) if (LittleLong(*(int *)&luxdata[4]) == 1)
{
luxdata+=8; luxdata+=8;
loadmodel->deluxdata = luxdata;
}
else else
{ {
Con_Printf("\"%s\" isn't a version 1 deluxmap\n", luxname); Con_Printf("\"%s\" isn't a version 1 deluxmap\n", luxname);
@ -1647,23 +1706,17 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
if (depthmaps <= depthlits) if (depthmaps <= depthlits)
litname = litnamemaps; //maps has priority over lits litname = litnamemaps; //maps has priority over lits
else else
{
litname = litnamelits; litname = litnamelits;
}
litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize); litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize);
littmp = false; if (litdata)
if (!litdata) { //validate it, if we loaded one.
{ if (litdata[0] != 'Q' || litdata[1] != 'L' || litdata[2] != 'I' || litdata[3] != 'T')
int size; {
litdata = Q1BSPX_FindLump("RGBLIGHTING", &size);
if (size != samples*3)
litdata = NULL; litdata = NULL;
littmp = true; Con_Printf("lit \"%s\" isn't a lit\n", litname);
} }
else if (litdata[0] == 'Q' && litdata[1] == 'L' && litdata[2] == 'I' && litdata[3] == 'T') else if (LittleLong(*(int *)&litdata[4]) == 1 && l->filelen && samples*3 != (litsize-8))
{
if (LittleLong(*(int *)&litdata[4]) == 1 && l->filelen && samples*3 != (litsize-8))
{ {
litdata = NULL; litdata = NULL;
Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname); Con_Printf("lit \"%s\" doesn't match level. Ignored.\n", litname);
@ -1673,7 +1726,20 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
Con_Printf("lit \"%s\" isn't version 1.\n", litname); Con_Printf("lit \"%s\" isn't version 1.\n", litname);
litdata = NULL; litdata = NULL;
} }
else if (lumdata) }
littmp = false;
if (!litdata)
{
int size;
litdata = Q1BSPX_FindLump("RGBLIGHTING", &size);
if (size != samples*3)
litdata = NULL;
littmp = true;
}
else
{
if (lumdata)
{ {
float prop; float prop;
int i; int i;
@ -1711,13 +1777,6 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
//end anti-cheat //end anti-cheat
} }
} }
else if (litdata)
{
Con_Printf("lit \"%s\" isn't a lit\n", litname);
litdata = NULL;
}
// else
//failed to find
} }
#endif #endif
@ -1850,7 +1909,7 @@ char *Mod_ParseWorldspawnKey(const char *ents, const char *key, char *buffer, si
{ {
char keyname[64]; char keyname[64];
char value[1024]; char value[1024];
while(*ents) while(ents && *ents)
{ {
ents = COM_ParseOut(ents, keyname, sizeof(keyname)); ents = COM_ParseOut(ents, keyname, sizeof(keyname));
if (*keyname == '{') //an entity if (*keyname == '{') //an entity
@ -2731,28 +2790,20 @@ static void Mod_Batches_Generate(model_t *mod)
} }
} }
typedef struct void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height, int firstlm)
{
int allocated[LMBLOCK_SIZE_MAX];
int lmnum;
unsigned int width;
unsigned int height;
qboolean deluxe;
} lmalloc_t;
#define LM_FIRST 0x50
static void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height)
{ {
memset(lmallocator, 0, sizeof(*lmallocator)); memset(lmallocator, 0, sizeof(*lmallocator));
lmallocator->deluxe = hasdeluxe; lmallocator->deluxe = hasdeluxe;
lmallocator->lmnum = LM_FIRST; lmallocator->lmnum = firstlm;
lmallocator->firstlm = firstlm;
lmallocator->width = width; lmallocator->width = width;
lmallocator->height = height; lmallocator->height = height;
} }
static void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod) void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod)
{ {
mod->lightmaps.first = LM_FIRST; mod->lightmaps.first = lmallocator->firstlm;
mod->lightmaps.count = (lmallocator->lmnum - LM_FIRST); mod->lightmaps.count = (lmallocator->lmnum - lmallocator->firstlm);
if (lmallocator->allocated[0]) if (lmallocator->allocated[0])
mod->lightmaps.count++; mod->lightmaps.count++;
@ -2765,7 +2816,7 @@ static void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod)
else else
mod->lightmaps.deluxemapping = false; mod->lightmaps.deluxemapping = false;
} }
static void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short *x, unsigned short *y, int *tnum) void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short *x, unsigned short *y, int *tnum)
{ {
int best, best2; int best, best2;
int i, j; int i, j;
@ -2920,6 +2971,8 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
} }
samps /= 4; samps /= 4;
samps = sqrt(samps); samps = sqrt(samps);
if (j > 128)
samps *= 2;
mod->lightmaps.width = bound(j, samps, LMBLOCK_SIZE_MAX); mod->lightmaps.width = bound(j, samps, LMBLOCK_SIZE_MAX);
mod->lightmaps.height = bound(j, samps, LMBLOCK_SIZE_MAX); mod->lightmaps.height = bound(j, samps, LMBLOCK_SIZE_MAX);
for (i = 0; (1<<i) < mod->lightmaps.width; i++); for (i = 0; (1<<i) < mod->lightmaps.width; i++);
@ -2929,7 +2982,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
mod->lightmaps.width = bound(64, mod->lightmaps.width, sh_config.texture_maxsize); mod->lightmaps.width = bound(64, mod->lightmaps.width, sh_config.texture_maxsize);
mod->lightmaps.height = bound(64, mod->lightmaps.height, sh_config.texture_maxsize); mod->lightmaps.height = bound(64, mod->lightmaps.height, sh_config.texture_maxsize);
Mod_LightmapAllocInit(&lmallocator, mod->deluxdata != NULL, mod->lightmaps.width, mod->lightmaps.height); Mod_LightmapAllocInit(&lmallocator, mod->deluxdata != NULL, mod->lightmaps.width, mod->lightmaps.height, 0x50);
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = mod->batches[sortid]; batch != NULL; batch = batch->next) for (batch = mod->batches[sortid]; batch != NULL; batch = batch->next)
@ -2982,7 +3035,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift); extern void Surf_CreateSurfaceLightmap (msurface_t *surf, int shift);
//if build is NULL, uses q1/q2 surf generation, and allocates lightmaps //if build is NULL, uses q1/q2 surf generation, and allocates lightmaps
void Mod_Batches_Build(model_t *mod, builddata_t *bd) static void Mod_Batches_Build(model_t *mod, builddata_t *bd)
{ {
int i; int i;
int numverts = 0, numindicies=0; int numverts = 0, numindicies=0;
@ -4099,6 +4152,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
{ {
#ifndef SERVERONLY #ifndef SERVERONLY
model_t *mod = ctx; model_t *mod = ctx;
char loadname[MAX_QPATH];
if (!a) if (!a)
{ //submodels share textures, so only do this if 'a' is 0 (inline index, 0 = world). { //submodels share textures, so only do this if 'a' is 0 (inline index, 0 = world).
@ -4128,15 +4182,26 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
} }
else if (mod->fromgame == fg_quake2) else if (mod->fromgame == fg_quake2)
{ {
COM_FileBase (mod->name, loadname, sizeof(loadname));
for(a = 0; a < mod->numtextures; a++) for(a = 0; a < mod->numtextures; a++)
{ {
unsigned int maps = 0;
mod->textures[a]->shader = R_RegisterCustom (mod->textures[a]->name, SUF_LIGHTMAP, Shader_DefaultBSPQ2, NULL); mod->textures[a]->shader = R_RegisterCustom (mod->textures[a]->name, SUF_LIGHTMAP, Shader_DefaultBSPQ2, NULL);
R_BuildDefaultTexnums(NULL, mod->textures[a]->shader);
maps |= SHADER_HASPALETTED;
maps |= SHADER_HASDIFFUSE;
if (r_fb_bmodels.ival)
maps |= SHADER_HASFULLBRIGHT;
// if (r_loadbumpmapping || (r_waterstyle.ival > 1 && *tx->name == '*'))
// maps |= SHADER_HASNORMALMAP;
if (gl_specular.ival)
maps |= SHADER_HASGLOSS;
R_BuildLegacyTexnums(mod->textures[a]->shader, mod->textures[a]->name, loadname, maps, TF_MIP4_SOLID8, mod->textures[a]->width, mod->textures[a]->height, mod->textures[a]->mips, mod->textures[a]->palette);
BZ_Free(mod->textures[a]->mips[0]);
} }
} }
else else
{ {
char loadname[MAX_QPATH];
COM_FileBase (mod->name, loadname, sizeof(loadname)); COM_FileBase (mod->name, loadname, sizeof(loadname));
if (!strncmp(loadname, "b_", 2)) if (!strncmp(loadname, "b_", 2))
Q_strncpyz(loadname, "bmodels", sizeof(loadname)); Q_strncpyz(loadname, "bmodels", sizeof(loadname));
@ -4168,11 +4233,14 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
int *lenptr, len; int *lenptr, len;
int ofs; int ofs;
qbyte *file; qbyte *file;
char *mapname;
memset(patch, 0, sizeof(*patch)); memset(patch, 0, sizeof(*patch));
if (!mod_external_vis.ival) if (!mod_external_vis.ival)
return; return;
mapname = COM_SkipPath(mod->name);
COM_StripExtension(mod->name, patchname, sizeof(patchname)); COM_StripExtension(mod->name, patchname, sizeof(patchname));
Q_strncatz(patchname, ".vis", sizeof(patchname)); Q_strncatz(patchname, ".vis", sizeof(patchname));
@ -4184,6 +4252,7 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
patch->filelen = FS_LoadFile(patchname, &patch->fileptr); patch->filelen = FS_LoadFile(patchname, &patch->fileptr);
if (!patch->fileptr) if (!patch->fileptr)
return; return;
ofs = 0; ofs = 0;
while (ofs+36 <= patch->filelen) while (ofs+36 <= patch->filelen)
{ {
@ -4198,7 +4267,7 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
if (ofs+36+len > patch->filelen) if (ofs+36+len > patch->filelen)
break; break;
// if (!Q_strcasecmp(patchname, "foo")) if (!Q_strcasecmp(patchname, mapname))
{ {
lenptr = (int*)file; lenptr = (int*)file;
patch->vislen = LittleLong(*lenptr); patch->vislen = LittleLong(*lenptr);
@ -4214,10 +4283,11 @@ static void Mod_FindVisPatch(struct vispatch_s *patch, model_t *mod, size_t leaf
if (sizeof(int)*2 + patch->vislen + patch->leaflen != len || patch->leaflen != leaflumpsize) if (sizeof(int)*2 + patch->vislen + patch->leaflen != len || patch->leaflen != leaflumpsize)
{ {
Con_Printf("Vis patch is unsuitable\n");
patch->visptr = NULL; patch->visptr = NULL;
patch->leafptr = NULL; patch->leafptr = NULL;
} }
else
break;
} }
ofs += 36+len; ofs += 36+len;
} }
@ -4494,7 +4564,10 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__));
if (lightmodel == mod) if (lightmodel == mod)
LightLoadEntities(lightmodel->entities); {
lightcontext = LightStartup(NULL, lightmodel, true);
LightReloadEntities(lightcontext, lightmodel->entities);
}
#endif #endif
TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__));
if (!isDedicated) if (!isDedicated)

View file

@ -51,7 +51,11 @@ typedef enum {
} shadersort_t; } shadersort_t;
#define MAX_BONES 256 #define MAX_BONES 256
#ifdef FTE_TARGET_WEB
#define MAX_GPU_BONES 32 //ATI drivers bug out and start to crash if you put this at 128. FIXME: make dynamic.
#else
#define MAX_GPU_BONES 64 //ATI drivers bug out and start to crash if you put this at 128. FIXME: make dynamic. #define MAX_GPU_BONES 64 //ATI drivers bug out and start to crash if you put this at 128. FIXME: make dynamic.
#endif
struct doll_s; struct doll_s;
void rag_flushdolls(qboolean force); void rag_flushdolls(qboolean force);
void rag_freedoll(struct doll_s *doll); void rag_freedoll(struct doll_s *doll);
@ -292,6 +296,7 @@ typedef struct texture_s
struct texture_s *alternate_anims; // bmodels in frmae 1 use these struct texture_s *alternate_anims; // bmodels in frmae 1 use these
qbyte *mips[4]; //the different mipmap levels. qbyte *mips[4]; //the different mipmap levels.
qbyte *palette; //host_basepal or halflife per-texture palette
} texture_t; } texture_t;
/* /*
typedef struct typedef struct
@ -999,6 +1004,9 @@ unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org)
struct fragmentdecal_s; struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model); void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);
qboolean Terr_DownloadedSection(char *fname); qboolean Terr_DownloadedSection(char *fname);
void CL_Parse_BrushEdit(void);
qboolean SV_Parse_BrushEdit(void);
#endif #endif

View file

@ -100,6 +100,7 @@ void R_NetGraph (void)
int lost; int lost;
char st[80]; char st[80];
unsigned ngraph_pixels[NET_GRAPHHEIGHT][NET_TIMINGS]; unsigned ngraph_pixels[NET_GRAPHHEIGHT][NET_TIMINGS];
float pi, po, bi, bo;
x = 0; x = 0;
if (r_netgraph.value < 0) if (r_netgraph.value < 0)
@ -130,15 +131,22 @@ void R_NetGraph (void)
x = ((vid.width - 320)>>1); x = ((vid.width - 320)>>1);
x=-x; x=-x;
y = vid.height - sb_lines - 24 - NET_GRAPHHEIGHT - 1; y = vid.height - sb_lines - 24 - NET_GRAPHHEIGHT - 2*8;
M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8 + 1); M_DrawTextBox (x, y, NET_TIMINGS/8, NET_GRAPHHEIGHT/8 + 3);
y += 8; y += 8;
sprintf(st, "%3i%% packet loss", lost); sprintf(st, "%3i%% packet loss", lost);
Draw_FunString(8, y, st); Draw_FunString(8, y, st);
y += 8; y += 8;
if (NET_GetRates(cls.sockets, &pi, &po, &bi, &bo))
{
Draw_FunString(8, y+0, va("in: %g %g\n", pi, bi)); //not relevent as a limit.
Draw_FunString(8, y+8, va("out: %g %g\n", po, bo)); //not relevent as a limit.
}
y += 16;
Image_Upload(netgraphtexture, TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP); Image_Upload(netgraphtexture, TF_RGBA32, ngraph_pixels, NULL, NET_TIMINGS, NET_GRAPHHEIGHT, IF_UIPIC|IF_NOMIPMAP|IF_NOPICMIP);
x=8; x=8;
R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader); R2D_Image(x, y, NET_TIMINGS, NET_GRAPHHEIGHT, 0, 0, 1, 1, netgraphshader);

View file

@ -59,6 +59,9 @@ void R_AnimateLight (void)
{ {
int i,j; int i,j;
float f; float f;
//if (r_lightstylescale.value > 2)
//r_lightstylescale.value = 2;
// //
// light animations // light animations
@ -74,13 +77,13 @@ void R_AnimateLight (void)
int v1, v2, vd; int v1, v2, vd;
if (!cl_lightstyle[j].length) if (!cl_lightstyle[j].length)
{ {
d_lightstylevalue[j] = ('m'-'a')*22; d_lightstylevalue[j] = ('m'-'a')*22 * r_lightstylescale.value;
continue; continue;
} }
if (cl_lightstyle[j].map[0] == '=') if (cl_lightstyle[j].map[0] == '=')
{ {
d_lightstylevalue[j] = atof(cl_lightstyle[j].map+1)*256; d_lightstylevalue[j] = atof(cl_lightstyle[j].map+1)*256*r_lightstylescale.value;
continue; continue;
} }
@ -92,9 +95,9 @@ void R_AnimateLight (void)
vd = v1 - v2; vd = v1 - v2;
if (!r_lightstylesmooth.ival || vd < -r_lightstylesmooth_limit.ival || vd > r_lightstylesmooth_limit.ival) if (!r_lightstylesmooth.ival || vd < -r_lightstylesmooth_limit.ival || vd > r_lightstylesmooth_limit.ival)
d_lightstylevalue[j] = v1*22; d_lightstylevalue[j] = v1*22*r_lightstylescale.value;
else else
d_lightstylevalue[j] = (v1*(1-f) + v2*(f))*22; d_lightstylevalue[j] = (v1*(1-f) + v2*(f))*22*r_lightstylescale.value;
} }
} }

View file

@ -870,6 +870,9 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2],
if (r_refdef.recurse >= R_MAX_RECURSE-1) if (r_refdef.recurse >= R_MAX_RECURSE-1)
return; return;
if (!mesh->xyz_array)
return;
if (!mesh->normals_array) if (!mesh->normals_array)
{ {
VectorSet(plane.normal, 0, 0, 1); VectorSet(plane.normal, 0, 0, 1);

View file

@ -446,7 +446,6 @@ extern cvar_t r_stains, r_stainfadetime, r_stainfadeammount;
extern cvar_t gl_font; extern cvar_t gl_font;
extern cvar_t vid_conautoscale, vid_conheight, vid_conwidth; extern cvar_t vid_conautoscale, vid_conheight, vid_conwidth;
extern cvar_t crosshair, crosshairimage, crosshaircolor, r_skyboxname; extern cvar_t crosshair, crosshairimage, crosshaircolor, r_skyboxname;
extern cvar_t r_floorcolour, r_wallcolour, r_floortexture, r_walltexture;
extern cvar_t r_fastskycolour; extern cvar_t r_fastskycolour;
void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue); void GLV_Gamma_Callback(struct cvar_s *var, char *oldvalue);
@ -460,12 +459,9 @@ void GLR_DeInit (void)
Cvar_Unhook(&vid_conautoscale); Cvar_Unhook(&vid_conautoscale);
Cvar_Unhook(&vid_conheight); Cvar_Unhook(&vid_conheight);
Cvar_Unhook(&vid_conwidth); Cvar_Unhook(&vid_conwidth);
Cvar_Unhook(&r_walltexture); // Cvar_Unhook(&v_gamma);
Cvar_Unhook(&r_floortexture); // Cvar_Unhook(&v_contrast);
Cvar_Unhook(&r_drawflat); // Cvar_Unhook(&v_brightness);
Cvar_Unhook(&v_gamma);
Cvar_Unhook(&v_contrast);
Cvar_Unhook(&v_brightness);
Surf_DeInit(); Surf_DeInit();
@ -478,10 +474,6 @@ void GLR_Init (void)
// Cmd_AddCommand ("makewad", R_MakeTexWad_f); // Cmd_AddCommand ("makewad", R_MakeTexWad_f);
// Cvar_Hook(&r_floortexture, GLR_Floortexture_Callback);
// Cvar_Hook(&r_walltexture, GLR_Walltexture_Callback);
// Cvar_Hook(&r_drawflat, GLR_Drawflat_Callback);
GLR_ReInit(); GLR_ReInit();
} }

View file

@ -657,10 +657,18 @@ static int Shader_SetImageFlags(shader_t *shader, shaderpass_t *pass, char **nam
texid_t R_LoadColourmapImage(void) texid_t R_LoadColourmapImage(void)
{ {
unsigned int w = 256, h = VID_GRADES-1; unsigned int w = 256, h = VID_GRADES;
unsigned int x; unsigned int x;
unsigned int data[256*(VID_GRADES-1)]; unsigned int data[256*(VID_GRADES)];
qbyte *colourmappal = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", NULL); qbyte *colourmappal = (qbyte *)FS_LoadMallocFile ("gfx/colormap.lmp", NULL);
if (!colourmappal)
{
size_t sz;
qbyte *pcx = FS_LoadMallocFile("pics/colormap.pcx", &sz);
colourmappal = Z_Malloc(256*VID_GRADES);
ReadPCXData(pcx, sz, 256, VID_GRADES, colourmappal);
BZ_Free(pcx);
}
if (colourmappal) if (colourmappal)
{ {
for (x = 0; x < sizeof(data)/sizeof(data[0]); x++) for (x = 0; x < sizeof(data)/sizeof(data[0]); x++)
@ -726,6 +734,12 @@ static void Shader_NoMipMaps ( shader_t *shader, shaderpass_t *pass, char **ptr
shader->flags |= (SHADER_NOMIPMAPS|SHADER_NOPICMIP); shader->flags |= (SHADER_NOMIPMAPS|SHADER_NOPICMIP);
} }
static void Shader_Affine ( shader_t *shader, shaderpass_t *pass, char **ptr )
{
shader->flags |= SBITS_AFFINE;
}
static void Shader_NoPicMip ( shader_t *shader, shaderpass_t *pass, char **ptr ) static void Shader_NoPicMip ( shader_t *shader, shaderpass_t *pass, char **ptr )
{ {
shader->flags |= SHADER_NOPICMIP; shader->flags |= SHADER_NOPICMIP;
@ -2056,6 +2070,7 @@ static shaderkey_t shaderkeys[] =
{"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d {"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d
{"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d {"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d
{"param", Shader_ProgramParam, "fte"}, //legacy {"param", Shader_ProgramParam, "fte"}, //legacy
{"affine", Shader_Affine, "fte"}, //some hardware is horribly slow, and can benefit from certain hints.
{"bemode", Shader_BEMode, "fte"}, {"bemode", Shader_BEMode, "fte"},
@ -4134,6 +4149,7 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
char *h; char *h;
char imagename[MAX_QPATH]; char imagename[MAX_QPATH];
char *subpath = NULL; char *subpath = NULL;
unsigned int imageflags = 0;
strcpy(imagename, shader->name); strcpy(imagename, shader->name);
h = strchr(imagename, '#'); h = strchr(imagename, '#');
if (h) if (h)
@ -4172,6 +4188,8 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
TEXASSIGN(shader->defaulttextures.paletted, tn->paletted); TEXASSIGN(shader->defaulttextures.paletted, tn->paletted);
} }
imageflags |= IF_LOWPRIORITY;
COM_StripExtension(imagename, imagename, sizeof(imagename)); COM_StripExtension(imagename, imagename, sizeof(imagename));
if (!TEXVALID(shader->defaulttextures.bump)) if (!TEXVALID(shader->defaulttextures.bump))
@ -4179,9 +4197,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if (r_loadbumpmapping || (shader->flags & SHADER_HASNORMALMAP)) if (r_loadbumpmapping || (shader->flags & SHADER_HASNORMALMAP))
{ {
if (!TEXVALID(tn->bump) && *shader->mapname && (shader->flags & SHADER_HASNORMALMAP)) if (!TEXVALID(tn->bump) && *shader->mapname && (shader->flags & SHADER_HASNORMALMAP))
tn->bump = R_LoadHiResTexture(va("%s_norm", shader->mapname), NULL, IF_TRYBUMP); tn->bump = R_LoadHiResTexture(va("%s_norm", shader->mapname), NULL, imageflags|IF_TRYBUMP);
if (!TEXVALID(tn->bump)) if (!TEXVALID(tn->bump))
tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, IF_TRYBUMP); tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), subpath, imageflags|IF_TRYBUMP);
} }
TEXASSIGN(shader->defaulttextures.bump, tn->bump); TEXASSIGN(shader->defaulttextures.bump, tn->bump);
} }
@ -4191,9 +4209,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if (shader->flags & SHADER_HASTOPBOTTOM) if (shader->flags & SHADER_HASTOPBOTTOM)
{ {
if (!TEXVALID(tn->loweroverlay) && *shader->mapname) if (!TEXVALID(tn->loweroverlay) && *shader->mapname)
tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->mapname), NULL, 0); tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->mapname), NULL, imageflags);
if (!TEXVALID(tn->loweroverlay)) if (!TEXVALID(tn->loweroverlay))
tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", imagename), subpath, 0); /*how rude*/ tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", imagename), subpath, imageflags); /*how rude*/
} }
TEXASSIGN(shader->defaulttextures.loweroverlay, tn->loweroverlay); TEXASSIGN(shader->defaulttextures.loweroverlay, tn->loweroverlay);
} }
@ -4203,9 +4221,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if (shader->flags & SHADER_HASTOPBOTTOM) if (shader->flags & SHADER_HASTOPBOTTOM)
{ {
if (!TEXVALID(tn->upperoverlay) && *shader->mapname) if (!TEXVALID(tn->upperoverlay) && *shader->mapname)
tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->mapname), NULL, 0); tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->mapname), NULL, imageflags);
if (!TEXVALID(tn->upperoverlay)) if (!TEXVALID(tn->upperoverlay))
tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", imagename), subpath, 0); tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", imagename), subpath, imageflags);
} }
TEXASSIGN(shader->defaulttextures.upperoverlay, tn->upperoverlay); TEXASSIGN(shader->defaulttextures.upperoverlay, tn->upperoverlay);
} }
@ -4216,9 +4234,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if ((shader->flags & SHADER_HASGLOSS) && gl_specular.value && gl_load24bit.value) if ((shader->flags & SHADER_HASGLOSS) && gl_specular.value && gl_load24bit.value)
{ {
if (!TEXVALID(tn->specular) && *shader->mapname) if (!TEXVALID(tn->specular) && *shader->mapname)
tn->specular = R_LoadHiResTexture(va("%s_gloss", shader->mapname), NULL, 0); tn->specular = R_LoadHiResTexture(va("%s_gloss", shader->mapname), NULL, imageflags);
if (!TEXVALID(tn->specular)) if (!TEXVALID(tn->specular))
tn->specular = R_LoadHiResTexture(va("%s_gloss", imagename), subpath, 0); tn->specular = R_LoadHiResTexture(va("%s_gloss", imagename), subpath, imageflags);
} }
TEXASSIGN(shader->defaulttextures.specular, tn->specular); TEXASSIGN(shader->defaulttextures.specular, tn->specular);
} }
@ -4229,24 +4247,37 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if ((shader->flags & SHADER_HASFULLBRIGHT) && r_fb_bmodels.value && gl_load24bit.value) if ((shader->flags & SHADER_HASFULLBRIGHT) && r_fb_bmodels.value && gl_load24bit.value)
{ {
if (!TEXVALID(tn->fullbright) && *shader->mapname) if (!TEXVALID(tn->fullbright) && *shader->mapname)
tn->fullbright = R_LoadHiResTexture(va("%s_luma", shader->mapname), NULL, 0); tn->fullbright = R_LoadHiResTexture(va("%s_luma", shader->mapname), NULL, imageflags);
if (!TEXVALID(tn->fullbright)) if (!TEXVALID(tn->fullbright))
tn->fullbright = R_LoadHiResTexture(va("%s_luma", imagename), subpath, 0); tn->fullbright = R_LoadHiResTexture(va("%s_luma", imagename), subpath, imageflags);
} }
TEXASSIGN(shader->defaulttextures.fullbright, tn->fullbright); TEXASSIGN(shader->defaulttextures.fullbright, tn->fullbright);
} }
} }
//call this with some fallback textures to directly load some textures //call this with some fallback textures to directly load some textures
void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned int loadflags, uploadfmt_t basefmt, size_t width, size_t height, qbyte *mipdata[4], qbyte *palette) void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, const char *subpath, unsigned int loadflags, uploadfmt_t basefmt, size_t width, size_t height, qbyte *mipdata[4], qbyte *palette)
{ {
char *h; char *h;
char imagename[MAX_QPATH]; char imagename[MAX_QPATH];
//extern cvar_t gl_miptexLevel;
texnums_t *tex = &shader->defaulttextures; texnums_t *tex = &shader->defaulttextures;
unsigned int imageflags; unsigned int imageflags;
qbyte *dontcrashme[4] = {NULL}; qbyte *dontcrashme[4] = {NULL};
if (!mipdata) if (!mipdata)
mipdata = dontcrashme; mipdata = dontcrashme;
/*else if (gl_miptexLevel.ival)
{
unsigned int miplevel = 0, i;
for (i = 0; i < 3 && i < gl_miptexLevel.ival && mipdata[i]; i++)
miplevel = i;
for (i = 0; i < 3; i++)
dontcrashme[i] = (miplevel+i)>3?NULL:mipdata[miplevel+i];
width >>= miplevel;
height >>= miplevel;
mipdata = dontcrashme;
}
*/
strcpy(imagename, shader->name); strcpy(imagename, shader->name);
h = strchr(imagename, '#'); h = strchr(imagename, '#');
if (h) if (h)
@ -4263,8 +4294,11 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned
if (shader->generator == Shader_DefaultSkin) if (shader->generator == Shader_DefaultSkin)
subpath = shader->genargs; subpath = shader->genargs;
if (basefmt == TF_MIP4_SOLID8 && (!mipdata[0] || !mipdata[1] || !mipdata[2] || !mipdata[3]))
basefmt = TF_SOLID8;
//make sure the noalpha thing is set properly. //make sure the noalpha thing is set properly.
imageflags = (basefmt==TF_SOLID8)?IF_NOALPHA:0; imageflags = (basefmt==TF_SOLID8 || basefmt == TF_MIP4_SOLID8)?IF_NOALPHA:0;
imageflags |= IF_MIPCAP; imageflags |= IF_MIPCAP;
COM_StripExtension(imagename, imagename, sizeof(imagename)); COM_StripExtension(imagename, imagename, sizeof(imagename));
@ -4274,7 +4308,22 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned
{ {
if (!TEXVALID(tex->base) && *shader->mapname) if (!TEXVALID(tex->base) && *shader->mapname)
tex->base = R_LoadHiResTexture(shader->mapname, NULL, imageflags); tex->base = R_LoadHiResTexture(shader->mapname, NULL, imageflags);
if (!TEXVALID(tex->base)) if (!TEXVALID(tex->base) && fallbackname)
{
if (gl_load24bit.ival)
{
tex->base = Image_GetTexture(imagename, subpath, imageflags|IF_NOWORKER, NULL, NULL, width, height, basefmt);
if (!TEXLOADED(tex->base))
{
tex->base = Image_GetTexture(fallbackname, subpath, imageflags|IF_NOWORKER, NULL, NULL, width, height, basefmt);
if (TEXLOADED(tex->base))
Q_strncpyz(imagename, fallbackname, sizeof(imagename));
}
}
if (!TEXLOADED(tex->base))
tex->base = Image_GetTexture(imagename, subpath, imageflags, mipdata[0], palette, width, height, basefmt);
}
else if (!TEXVALID(tex->base))
tex->base = Image_GetTexture(imagename, subpath, imageflags, mipdata[0], palette, width, height, basefmt); tex->base = Image_GetTexture(imagename, subpath, imageflags, mipdata[0], palette, width, height, basefmt);
} }
@ -4283,9 +4332,10 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned
if (!TEXVALID(tex->paletted) && *shader->mapname) if (!TEXVALID(tex->paletted) && *shader->mapname)
tex->paletted = R_LoadHiResTexture(va("%s_pal", shader->mapname), NULL, imageflags|IF_NEAREST); tex->paletted = R_LoadHiResTexture(va("%s_pal", shader->mapname), NULL, imageflags|IF_NEAREST);
if (!TEXVALID(tex->paletted)) if (!TEXVALID(tex->paletted))
tex->paletted = Image_GetTexture(va("%s_pal", imagename), subpath, imageflags|IF_NEAREST, mipdata[0], palette, width, height, TF_LUM8); tex->paletted = Image_GetTexture(va("%s_pal", imagename), subpath, imageflags|IF_NEAREST, mipdata[0], palette, width, height, (basefmt==TF_MIP4_SOLID8)?TF_MIP4_LUM8:TF_LUM8);
} }
imageflags |= IF_LOWPRIORITY;
//all the rest need/want an alpha channel in some form. //all the rest need/want an alpha channel in some form.
imageflags &= ~IF_NOALPHA; imageflags &= ~IF_NOALPHA;
imageflags |= IF_NOGAMMA; imageflags |= IF_NOGAMMA;
@ -4667,6 +4717,7 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args)
Shader_DefaultScript(shortname, s, Shader_DefaultBSPWater(s, shortname)); Shader_DefaultScript(shortname, s, Shader_DefaultBSPWater(s, shortname));
} }
else if (!strncmp(shortname, "trans/", 6)) else if (!strncmp(shortname, "trans/", 6))
{
Shader_DefaultScript(shortname, s, Shader_DefaultScript(shortname, s,
"{\n" "{\n"
"{\n" "{\n"
@ -4676,6 +4727,19 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args)
"}\n" "}\n"
"}\n" "}\n"
); );
}
else if (r_softwarebanding.ival)
{
/*alpha bended*/
Shader_DefaultScript(shortname, s,
"{\n"
"program defaultwall#EIGHTBIT\n"
"{\n"
"map $colourmap\n"
"}\n"
"}\n"
);
}
else else
Shader_DefaultBSPLM(shortname, s, args); Shader_DefaultBSPLM(shortname, s, args);
} }

View file

@ -3201,13 +3201,17 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
"}\n" "}\n"
); );
crepuscular_texture_id = Image_CreateTexture("***crepusculartexture***", NULL, 0); crepuscular_texture_id = Image_CreateTexture("***crepusculartexture***", NULL, IF_LINEAR|IF_NOMIPMAP|IF_CLAMP|IF_NOGAMMA);
Image_Upload(crepuscular_texture_id, TF_RGBA32, NULL, NULL, vid.pixelwidth, vid.pixelheight, IF_LINEAR|IF_NOMIPMAP|IF_CLAMP|IF_NOGAMMA); Image_Upload(crepuscular_texture_id, TF_RGBA32, NULL, NULL, vid.pixelwidth, vid.pixelheight, IF_LINEAR|IF_NOMIPMAP|IF_CLAMP|IF_NOGAMMA);
} }
BE_Scissor(NULL); BE_Scissor(NULL);
oldfbo = GLBE_FBO_Update(&crepuscular_fbo, 0, &crepuscular_texture_id, 1, r_nulltex, vid.pixelwidth, vid.pixelheight); oldfbo = GLBE_FBO_Update(&crepuscular_fbo, FBO_RB_DEPTH, &crepuscular_texture_id, 1, r_nulltex, vid.pixelwidth, vid.pixelheight);
GL_ForceDepthWritable();
// qglClearColor(0, 0, 0, 1);
qglClear(GL_DEPTH_BUFFER_BIT);
BE_SelectMode(BEM_CREPUSCULAR); BE_SelectMode(BEM_CREPUSCULAR);
BE_SelectDLight(dl, colours, dl->axis, LSHADER_STANDARD); BE_SelectDLight(dl, colours, dl->axis, LSHADER_STANDARD);
@ -3217,6 +3221,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
oldsrccol = NULL;//shaderstate.tex_sourcecol; oldsrccol = NULL;//shaderstate.tex_sourcecol;
GLBE_FBO_Sources(crepuscular_texture_id, NULL); GLBE_FBO_Sources(crepuscular_texture_id, NULL);
// crepuscular_shader->defaulttextures.base = crepuscular_texture_id;
//shaderstate.tex_sourcecol = oldsrccol; //shaderstate.tex_sourcecol = oldsrccol;
BE_SelectMode(BEM_STANDARD); BE_SelectMode(BEM_STANDARD);
@ -3448,6 +3453,12 @@ void Sh_DrawLights(qbyte *vis)
colour[1] *= cl_lightstyle[dl->style-1].colours[1] * d_lightstylevalue[dl->style-1]/255.0f; colour[1] *= cl_lightstyle[dl->style-1].colours[1] * d_lightstylevalue[dl->style-1]/255.0f;
colour[2] *= cl_lightstyle[dl->style-1].colours[2] * d_lightstylevalue[dl->style-1]/255.0f; colour[2] *= cl_lightstyle[dl->style-1].colours[2] * d_lightstylevalue[dl->style-1]/255.0f;
} }
else
{
colour[0] *= r_lightstylescale.value;
colour[1] *= r_lightstylescale.value;
colour[2] *= r_lightstylescale.value;
}
if (colour[0] < 0.001 && colour[1] < 0.001 && colour[2] < 0.001) if (colour[0] < 0.001 && colour[1] < 0.001 && colour[2] < 0.001)
continue; //just switch these off. continue; //just switch these off.

View file

@ -1062,6 +1062,23 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
qglDebugMessageCallbackARB = (void *)getglext("glDebugMessageCallbackARB"); qglDebugMessageCallbackARB = (void *)getglext("glDebugMessageCallbackARB");
qglGetDebugMessageLogARB = (void *)getglext("glGetDebugMessageLogARB"); qglGetDebugMessageLogARB = (void *)getglext("glGetDebugMessageLogARB");
} }
else if (GL_CheckExtension("GL_KHR_debug"))
{
if (gl_config_gles)
{
qglDebugMessageControlARB = (void *)getglext("glDebugMessageControlKHR");
qglDebugMessageInsertARB = (void *)getglext("glDebugMessageInsertKHR");
qglDebugMessageCallbackARB = (void *)getglext("glDebugMessageCallbackKHR");
qglGetDebugMessageLogARB = (void *)getglext("glGetDebugMessageLogKHR");
}
else
{
qglDebugMessageControlARB = (void *)getglext("glDebugMessageControl");
qglDebugMessageInsertARB = (void *)getglext("glDebugMessageInsert");
qglDebugMessageCallbackARB = (void *)getglext("glDebugMessageCallback");
qglGetDebugMessageLogARB = (void *)getglext("glGetDebugMessageLog");
}
}
else else
{ {
qglDebugMessageControlARB = NULL; qglDebugMessageControlARB = NULL;
@ -1640,7 +1657,13 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
strings++; strings++;
if (gl_config.gles) if (gl_config.gles)
{ {
prstrings[strings] = "precision mediump float;\n"; prstrings[strings] =
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float;\n"
"#else\n"
"precision mediump float;\n"
"#endif\n"
;
length[strings] = strlen(prstrings[strings]); length[strings] = strlen(prstrings[strings]);
strings++; strings++;
} }
@ -2612,13 +2635,22 @@ void DumpGLState(void)
// if (qglGetVertexAttribiv) // if (qglGetVertexAttribiv)
{ {
qglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &rval); if (qglBindVertexArray)
Sys_Printf("VERTEX_ARRAY_BINDING: %i\n", rval); {
qglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval); qglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &rval);
Sys_Printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval); Sys_Printf("VERTEX_ARRAY_BINDING: %i\n", rval);
}
if (qglBindBufferARB)
{
qglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval);
Sys_Printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval);
}
if (qglIsEnabled(GL_COLOR_ARRAY)) if (qglIsEnabled(GL_COLOR_ARRAY))
{ {
qglGetIntegerv(GL_COLOR_ARRAY_BUFFER_BINDING, &rval); if (qglBindBufferARB)
qglGetIntegerv(GL_COLOR_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
qglGetPointerv(GL_COLOR_ARRAY_POINTER, &ptr); qglGetPointerv(GL_COLOR_ARRAY_POINTER, &ptr);
Sys_Printf("GL_COLOR_ARRAY: %s %i:%p\n", qglIsEnabled(GL_COLOR_ARRAY)?"en":"dis", rval, ptr); Sys_Printf("GL_COLOR_ARRAY: %s %i:%p\n", qglIsEnabled(GL_COLOR_ARRAY)?"en":"dis", rval, ptr);
} }
@ -2629,7 +2661,10 @@ void DumpGLState(void)
// } // }
// if (qglIsEnabled(GL_INDEX_ARRAY)) // if (qglIsEnabled(GL_INDEX_ARRAY))
{ {
qglGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &rval); if (qglBindBufferARB)
qglGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
#ifndef GL_INDEX_ARRAY_POINTER #ifndef GL_INDEX_ARRAY_POINTER
Sys_Printf("GL_ELEMENT_ARRAY_BUFFER_BINDING: %i:%p\n", rval, (void*)0); Sys_Printf("GL_ELEMENT_ARRAY_BUFFER_BINDING: %i:%p\n", rval, (void*)0);
#else #else
@ -2639,7 +2674,10 @@ void DumpGLState(void)
} }
if (qglIsEnabled(GL_NORMAL_ARRAY)) if (qglIsEnabled(GL_NORMAL_ARRAY))
{ {
qglGetIntegerv(GL_NORMAL_ARRAY_BUFFER_BINDING, &rval); if (qglBindBufferARB)
qglGetIntegerv(GL_NORMAL_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
qglGetPointerv(GL_NORMAL_ARRAY_POINTER, &ptr); qglGetPointerv(GL_NORMAL_ARRAY_POINTER, &ptr);
Sys_Printf("GL_NORMAL_ARRAY: %s %i:%p\n", qglIsEnabled(GL_NORMAL_ARRAY)?"en":"dis", rval, ptr); Sys_Printf("GL_NORMAL_ARRAY: %s %i:%p\n", qglIsEnabled(GL_NORMAL_ARRAY)?"en":"dis", rval, ptr);
} }
@ -2650,14 +2688,20 @@ void DumpGLState(void)
qglClientActiveTextureARB(mtexid0 + i); qglClientActiveTextureARB(mtexid0 + i);
if (qglIsEnabled(GL_TEXTURE_COORD_ARRAY)) if (qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
{ {
qglGetIntegerv(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &rval); if (qglBindBufferARB)
qglGetIntegerv(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
qglGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &ptr); qglGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &ptr);
Sys_Printf("GL_TEXTURE_COORD_ARRAY %i: %s %i:%p\n", i, qglIsEnabled(GL_TEXTURE_COORD_ARRAY)?"en":"dis", rval, ptr); Sys_Printf("GL_TEXTURE_COORD_ARRAY %i: %s %i:%p\n", i, qglIsEnabled(GL_TEXTURE_COORD_ARRAY)?"en":"dis", rval, ptr);
} }
} }
if (qglIsEnabled(GL_VERTEX_ARRAY)) if (qglIsEnabled(GL_VERTEX_ARRAY))
{ {
qglGetIntegerv(GL_VERTEX_ARRAY_BUFFER_BINDING, &rval); if (qglBindBufferARB)
qglGetIntegerv(GL_VERTEX_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
qglGetPointerv(GL_VERTEX_ARRAY_POINTER, &ptr); qglGetPointerv(GL_VERTEX_ARRAY_POINTER, &ptr);
Sys_Printf("GL_VERTEX_ARRAY: %s %i:%p\n", qglIsEnabled(GL_VERTEX_ARRAY)?"en":"dis", rval, ptr); Sys_Printf("GL_VERTEX_ARRAY: %s %i:%p\n", qglIsEnabled(GL_VERTEX_ARRAY)?"en":"dis", rval, ptr);
} }
@ -2670,7 +2714,10 @@ void DumpGLState(void)
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &en); qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &en);
if (!en) if (!en)
continue; continue;
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &bo); if (qglBindBufferARB)
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &bo);
else
bo = 0;
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &as); qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &as);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &st); qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &st);
qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &ty); qglGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &ty);
@ -2680,8 +2727,11 @@ void DumpGLState(void)
Sys_Printf("attrib%i: %s sz:%i st:%i ty:%0x %s%i:%p\n", i, en?"en":"dis", as, st,ty,no?"norm ":"", bo, ptr); Sys_Printf("attrib%i: %s sz:%i st:%i ty:%0x %s%i:%p\n", i, en?"en":"dis", as, st,ty,no?"norm ":"", bo, ptr);
} }
qglGetIntegerv(GL_CURRENT_PROGRAM, &glint); if (qglUseProgramObjectARB)
Sys_Printf("GL_CURRENT_PROGRAM: %i\n", glint); {
qglGetIntegerv(GL_CURRENT_PROGRAM, &glint);
Sys_Printf("GL_CURRENT_PROGRAM: %i\n", glint);
}
qglGetIntegerv(GL_BLEND, &glint); qglGetIntegerv(GL_BLEND, &glint);
Sys_Printf("GL_BLEND: %i\n", glint); Sys_Printf("GL_BLEND: %i\n", glint);

View file

@ -2009,6 +2009,9 @@ void INS_ReInit(void)
void INS_Shutdown(void) void INS_Shutdown(void)
{ {
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
}
void GLVID_SetCaption(char *text) void GLVID_SetCaption(char *text)
{ {

View file

@ -205,6 +205,9 @@ void INS_Shutdown (void)
void INS_Commands (void) void INS_Commands (void)
{ {
} }
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, char *type, char *devicename, int *qdevid))
{
}
void INS_Move (float *movements, int pnum) void INS_Move (float *movements, int pnum)
{ {
} }

View file

@ -578,7 +578,6 @@ RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int pa
return r; return r;
} }
void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight);
void *WIN_CreateCursor(char *filename, float hotx, float hoty, float scale) void *WIN_CreateCursor(char *filename, float hotx, float hoty, float scale)
{ {
int width, height; int width, height;
@ -2157,6 +2156,10 @@ LONG WINAPI GLMainWndProc (
INS_TranslateKeyEvent(wParam, lParam, false, 0, false); INS_TranslateKeyEvent(wParam, lParam, false, 0, false);
break; break;
case WM_MOUSEACTIVATE:
lRet = MA_ACTIVATEANDEAT;
break;
// this is complicated because Win32 seems to pack multiple mouse events into // this is complicated because Win32 seems to pack multiple mouse events into
// one update sometimes, so we always check all states and look for events // one update sometimes, so we always check all states and look for events
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:

View file

@ -352,6 +352,8 @@ static void R_CalcSkyChainBounds (batch_t *batch)
for (m = batch->firstmesh; m < batch->meshes; m++) for (m = batch->firstmesh; m < batch->meshes; m++)
{ {
mesh = batch->mesh[m]; mesh = batch->mesh[m];
if (!mesh->xyz_array)
continue;
//triangulate //triangulate
for (i=2 ; i<mesh->numvertexes ; i++) for (i=2 ; i<mesh->numvertexes ; i++)
{ {
@ -742,7 +744,7 @@ R_InitSky
A sky texture is 256*128, with the right side being a masked overlay A sky texture is 256*128, with the right side being a masked overlay
============== ==============
*/ */
void R_InitSky (struct texnums_s *tn, texture_t *mt, qbyte *src) void R_InitSky (struct texnums_s *tn, const char *skyname, qbyte *src, unsigned int width, unsigned int height)
{ {
int i, j, p; int i, j, p;
unsigned trans[128*128]; unsigned trans[128*128];
@ -751,45 +753,51 @@ void R_InitSky (struct texnums_s *tn, texture_t *mt, qbyte *src)
unsigned *rgba; unsigned *rgba;
char name[MAX_QPATH]; char name[MAX_QPATH];
unsigned int stride = width;
width /= 2;
memset(tn, 0, sizeof(*tn)); memset(tn, 0, sizeof(*tn));
if (width < 1 || height < 1 || stride != width*2)
return;
// make an average value for the back to avoid // make an average value for the back to avoid
// a fringe on the top level // a fringe on the top level
r = g = b = 0; r = g = b = 0;
for (i=0 ; i<128 ; i++) for (i=0 ; i<height ; i++)
for (j=0 ; j<128 ; j++) for (j=0 ; j<width ; j++)
{ {
p = src[i*256 + j + 128]; p = src[i*stride + j + width];
rgba = &d_8to24rgbtable[p]; rgba = &d_8to24rgbtable[p];
trans[(i*128) + j] = *rgba; trans[(i*width) + j] = *rgba;
r += ((qbyte *)rgba)[0]; r += ((qbyte *)rgba)[0];
g += ((qbyte *)rgba)[1]; g += ((qbyte *)rgba)[1];
b += ((qbyte *)rgba)[2]; b += ((qbyte *)rgba)[2];
} }
Q_snprintfz(name, sizeof(name), "%s_solid", mt->name); Q_snprintfz(name, sizeof(name), "%s_solid", skyname);
Q_strlwr(name); Q_strlwr(name);
tn->base = R_LoadReplacementTexture(name, NULL, IF_NOALPHA, trans, 128, 128, TF_RGBX32); tn->base = R_LoadReplacementTexture(name, NULL, IF_NOALPHA, trans, width, height, TF_RGBX32);
((qbyte *)&transpix)[0] = r/(128*128); ((qbyte *)&transpix)[0] = r/(width*height);
((qbyte *)&transpix)[1] = g/(128*128); ((qbyte *)&transpix)[1] = g/(width*height);
((qbyte *)&transpix)[2] = b/(128*128); ((qbyte *)&transpix)[2] = b/(width*height);
((qbyte *)&transpix)[3] = 0; ((qbyte *)&transpix)[3] = 0;
alphamask = LittleLong(0x7fffffff); alphamask = LittleLong(0x7fffffff);
for (i=0 ; i<128 ; i++) for (i=0 ; i<height ; i++)
for (j=0 ; j<128 ; j++) for (j=0 ; j<width ; j++)
{ {
p = src[i*256 + j]; p = src[i*stride + j];
if (p == 0) if (p == 0)
trans[(i*128) + j] = transpix; trans[(i*width) + j] = transpix;
else else
trans[(i*128) + j] = d_8to24rgbtable[p] & alphamask; trans[(i*width) + j] = d_8to24rgbtable[p] & alphamask;
} }
//FIXME: support _trans //FIXME: support _trans
Q_snprintfz(name, sizeof(name), "%s_alpha", mt->name); Q_snprintfz(name, sizeof(name), "%s_alpha", skyname);
Q_strlwr(name); Q_strlwr(name);
tn->fullbright = R_LoadReplacementTexture(name, NULL, 0, trans, 128, 128, TF_RGBA32); tn->fullbright = R_LoadReplacementTexture(name, NULL, 0, trans, width, height, TF_RGBA32);
} }
#endif #endif

View file

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

View file

@ -1,34 +1,6 @@
#include "quakedef.h" #include "quakedef.h"
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
#ifndef UTILITY
extern model_t *lightmodel;
#define bsptexinfo(i) (*i)
#define dsurfedges lightmodel->surfedges
#define dvertexes lightmodel->vertexes
#define dedges lightmodel->edges
#define texinfo_t mtexinfo_t
#define Q_PI M_PI
#define Error Host_Error
#define byte qbyte
#define dfaces lightmodel->surfaces
#define dplanes lightmodel->planes
#define dface_t msurface_t
#define dvertex_t mvertex_t
#define point position
#define side flags & SURF_PLANEBACK
#define scaledist 1
#define rangescale 0.5
#define extrasamples 1
#define scalecos 0.5
typedef struct mentity_s { typedef struct mentity_s {
vec3_t origin; vec3_t origin;
@ -41,11 +13,40 @@ typedef struct mentity_s {
char target[64]; char target[64];
char targetname[64]; char targetname[64];
struct mentity_s *targetent; int targetentnum;
} mentity_t; } mentity_t;
static mentity_t entities[8192]; struct relight_ctx_s
static int num_entities; {
unsigned int nummodels;
model_t *models[2048];
qboolean shadows;
mentity_t *entities;
unsigned int num_entities;
unsigned int max_entities;
};
#define bsptexinfo(i) (*i)
#define dsurfedges lightmodel->surfedges
#define dvertexes lightmodel->vertexes
#define dedges lightmodel->edges
#define texinfo_t mtexinfo_t
#define Q_PI M_PI
#define dfaces lightmodel->surfaces
#define dplanes lightmodel->planes
#define dface_t msurface_t
#define dvertex_t mvertex_t
#define side flags & SURF_PLANEBACK
#define scaledist 1
#define rangescale 0.5
#define extrasamples 0
#define scalecos 0.5
#define bsp_origin vec3_origin #define bsp_origin vec3_origin
@ -56,14 +57,17 @@ CastRay
Returns the distance between the points, or -1 if blocked Returns the distance between the points, or -1 if blocked
============= =============
*/ */
vec_t CastRay (vec3_t p1, vec3_t p2) static vec_t CastRay (struct relight_ctx_s *ctx, vec3_t p1, vec3_t p2)
{ {
trace_t trace; trace_t trace;
vec3_t move; vec3_t move;
lightmodel->funcs.NativeTrace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &trace); if (ctx->shadows)
if (trace.fraction < 1) {
return -1; ctx->models[0]->funcs.NativeTrace (ctx->models[0], 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &trace);
if (trace.fraction < 1)
return -1;
}
VectorSubtract(p1, p2, move); VectorSubtract(p1, p2, move);
return VectorLength(move); return VectorLength(move);
@ -114,7 +118,33 @@ static void ParseEpair (mentity_t *mapent, char *key, char *value)
} }
} }
void LightLoadEntities(char *entstring) void LightShutdown(struct relight_ctx_s *ctx, model_t *mod)
{
qboolean stillheld = false;
unsigned int i;
for (i = 0; i < ctx->nummodels; i++)
{
if (ctx->models[i] == mod)
ctx->models[i] = NULL;
if (ctx->models[i])
stillheld = true;
}
if (stillheld)
return;
Z_Free(ctx->entities);
Z_Free(ctx);
}
struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, model_t *model, qboolean shadows)
{
if (!ctx)
{
ctx = Z_Malloc(sizeof(*ctx));
ctx->shadows = shadows;
}
ctx->models[ctx->nummodels++] = model;
return ctx;
}
void LightReloadEntities(struct relight_ctx_s *ctx, char *entstring)
{ {
#define DEFAULTLIGHTLEVEL 300 #define DEFAULTLIGHTLEVEL 300
mentity_t *mapent; mentity_t *mapent;
@ -122,7 +152,7 @@ void LightLoadEntities(char *entstring)
char value[1024]; char value[1024];
int i; int i;
int switchedstyle=32; int switchedstyle=32;
num_entities = 0; ctx->num_entities = 0;
while(1) while(1)
{ {
@ -135,11 +165,18 @@ void LightLoadEntities(char *entstring)
break; break;
} }
mapent = &entities[num_entities]; if (ctx->num_entities == ctx->max_entities)
{
ctx->max_entities = ctx->max_entities + 128;
ctx->entities = BZ_Realloc(ctx->entities, sizeof(*ctx->entities) * ctx->max_entities);
}
mapent = &ctx->entities[ctx->num_entities];
memset(mapent, 0, sizeof(*mapent)); memset(mapent, 0, sizeof(*mapent));
mapent->colour[0] = 0; mapent->colour[0] = 0;
mapent->colour[1] = 0; mapent->colour[1] = 0;
mapent->colour[2] = 0; mapent->colour[2] = 0;
mapent->targetentnum = -1;
while(1) while(1)
{ {
entstring = COM_ParseOut(entstring, key, sizeof(key)); entstring = COM_ParseOut(entstring, key, sizeof(key));
@ -158,7 +195,7 @@ void LightLoadEntities(char *entstring)
for (i = 0; i < 256; i+=16) for (i = 0; i < 256; i+=16)
{ {
v[2] = mapent->origin[2]-i; v[2] = mapent->origin[2]-i;
cont = lightmodel->funcs.PointContents (lightmodel, NULL, v); cont = ctx->models[0]->funcs.PointContents (ctx->models[0], NULL, v);
if (cont & (FTECONTENTS_LAVA | FTECONTENTS_SLIME | FTECONTENTS_SOLID)) if (cont & (FTECONTENTS_LAVA | FTECONTENTS_SLIME | FTECONTENTS_SOLID))
break; break;
} }
@ -204,35 +241,35 @@ void LightLoadEntities(char *entstring)
if (*mapent->targetname && !mapent->style && !strcmp(mapent->classname, "light")) if (*mapent->targetname && !mapent->style && !strcmp(mapent->classname, "light"))
{ {
for (i = 0; i <= num_entities; i++) for (i = 0; i <= ctx->num_entities; i++)
{ {
if (entities[i].style >= 32 && !strcmp(entities[i].targetname, mapent->targetname)) if (ctx->entities[i].style >= 32 && !strcmp(ctx->entities[i].targetname, mapent->targetname))
{ {
mapent->style = entities[i].style; mapent->style = ctx->entities[i].style;
break; break;
} }
} }
if (i == num_entities) if (i == ctx->num_entities)
mapent->style = switchedstyle++; mapent->style = switchedstyle++;
} }
num_entities++; ctx->num_entities++;
} }
for (mapent = entities; mapent < &entities[num_entities]; mapent++) for (mapent = ctx->entities; mapent < &ctx->entities[ctx->num_entities]; mapent++)
{ {
if (*mapent->target) if (*mapent->target)
{ {
for (i = 0; i < num_entities; i++) for (i = 0; i < ctx->num_entities; i++)
{ {
if (mapent == &entities[i]) if (mapent == &ctx->entities[i])
continue; continue;
if (!strcmp(mapent->target, entities[i].targetname)) if (!strcmp(mapent->target, ctx->entities[i].targetname))
{ {
mapent->targetent = &entities[i]; mapent->targetentnum = i;
break; break;
} }
} }
@ -240,43 +277,6 @@ void LightLoadEntities(char *entstring)
} }
} }
#else
#define mentity_t entity_t
#define UTILITY
#include "light.h"
#define bsptexinfo(i) texinfo[i]
/*
============
CastRay
Returns the distance between the points, or -1 if blocked
=============
*/
vec_t CastRay (vec3_t p1, vec3_t p2)
{
int i;
vec_t t;
qboolean trace;
trace = TestLine (p1, p2);
if (!trace)
return -1; // ray was blocked
t = 0;
for (i=0 ; i< 3 ; i++)
t += (p2[i]-p1[i]) * (p2[i]-p1[i]);
if (t < 1)
t = 1; // don't blow up...
return sqrt(t);
}
#endif
/* /*
=============================================================================== ===============================================================================
@ -298,10 +298,13 @@ towards the center until it is valid.
=============================================================================== ===============================================================================
*/ */
#define SINGLEMAP (18*18*4) #define MAXIMUMEXTENT 128
#define SINGLEMAP (MAXIMUMEXTENT*MAXIMUMEXTENT*4)
typedef struct typedef struct llightinfo_s
{ {
struct relight_ctx_s *ctx; //relight context, shared between threads.
vec3_t lightmaps[MAXQ1LIGHTMAPS][SINGLEMAP]; vec3_t lightmaps[MAXQ1LIGHTMAPS][SINGLEMAP];
vec3_t lightnorm[MAXQ1LIGHTMAPS][SINGLEMAP]; vec3_t lightnorm[MAXQ1LIGHTMAPS][SINGLEMAP];
int numlightstyles; int numlightstyles;
@ -319,11 +322,11 @@ typedef struct
vec_t exactmins[2], exactmaxs[2]; vec_t exactmins[2], exactmaxs[2];
int texmins[2], texsize[2]; int texmins[2], texsize[2];
int lightstyles[256]; int lightstyles[MAXQ1LIGHTMAPS];
int surfnum;
dface_t *face;
} llightinfo_t; } llightinfo_t;
const size_t lightthreadctxsize = sizeof(llightinfo_t);
/* /*
================ ================
@ -332,35 +335,36 @@ CalcFaceVectors
Fills in texorg, worldtotex. and textoworld Fills in texorg, worldtotex. and textoworld
================ ================
*/ */
static void LightCalcFaceVectors (llightinfo_t *l) static void LightCalcFaceVectors (llightinfo_t *l, vec4_t surf_texplanes[2])
{ {
texinfo_t *tex;
int i, j; int i, j;
vec3_t texnormal; vec3_t texnormal;
float distscale; float distscale;
vec_t dist, len; vec_t dist, len;
tex = &bsptexinfo(l->face->texinfo);
// convert from float to vec_t // convert from float to vec_t
for (i=0 ; i<2 ; i++) for (i=0 ; i<2 ; i++)
for (j=0 ; j<3 ; j++) for (j=0 ; j<3 ; j++)
l->worldtotex[i][j] = tex->vecs[i][j]; l->worldtotex[i][j] = surf_texplanes[i][j];
// calculate a normal to the texture axis. points can be moved along this // calculate a normal to the texture axis. points can be moved along this
// without changing their S/T // without changing their S/T
texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] texnormal[0] = surf_texplanes[1][1]*surf_texplanes[0][2]
- tex->vecs[1][2]*tex->vecs[0][1]; - surf_texplanes[1][2]*surf_texplanes[0][1];
texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] texnormal[1] = surf_texplanes[1][2]*surf_texplanes[0][0]
- tex->vecs[1][0]*tex->vecs[0][2]; - surf_texplanes[1][0]*surf_texplanes[0][2];
texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] texnormal[2] = surf_texplanes[1][0]*surf_texplanes[0][1]
- tex->vecs[1][1]*tex->vecs[0][0]; - surf_texplanes[1][1]*surf_texplanes[0][0];
VectorNormalize (texnormal); VectorNormalize (texnormal);
// flip it towards plane normal // flip it towards plane normal
distscale = DotProduct (texnormal, l->facenormal); distscale = DotProduct (texnormal, l->facenormal);
if (!distscale) if (!distscale)
Error ("Texture axis perpendicular to face"); {
VectorCopy(l->facenormal, texnormal);
distscale = 1;
Con_Printf ("Texture axis perpendicular to face\n");
}
if (distscale < 0) if (distscale < 0)
{ {
distscale = -distscale; distscale = -distscale;
@ -383,7 +387,7 @@ static void LightCalcFaceVectors (llightinfo_t *l)
// calculate texorg on the texture plane // calculate texorg on the texture plane
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; l->texorg[i] = -surf_texplanes[0][3]* l->textoworld[0][i] - surf_texplanes[1][3] * l->textoworld[1][i];
// project back to the face plane // project back to the face plane
dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
@ -400,18 +404,15 @@ Fills in s->texmins[] and s->texsize[]
also sets exactmins[] and exactmaxs[] also sets exactmins[] and exactmaxs[]
================ ================
*/ */
static void LightCalcFaceExtents (llightinfo_t *l) static void LightCalcFaceExtents (model_t *lightmodel, dface_t *s, vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2])
{ {
dface_t *s;
vec_t mins[2], maxs[2], val; vec_t mins[2], maxs[2], val;
int i,j, e; int i,j, e;
dvertex_t *v; dvertex_t *v;
texinfo_t *tex; texinfo_t *tex;
s = l->face;
mins[0] = mins[1] = 999999; mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -99999; maxs[0] = maxs[1] = -999999;
tex = &bsptexinfo(s->texinfo); tex = &bsptexinfo(s->texinfo);
@ -425,9 +426,9 @@ static void LightCalcFaceExtents (llightinfo_t *l)
for (j=0 ; j<2 ; j++) for (j=0 ; j<2 ; j++)
{ {
val = v->point[0] * tex->vecs[j][0] + val = v->position[0] * tex->vecs[j][0] +
v->point[1] * tex->vecs[j][1] + v->position[1] * tex->vecs[j][1] +
v->point[2] * tex->vecs[j][2] + v->position[2] * tex->vecs[j][2] +
tex->vecs[j][3]; tex->vecs[j][3];
if (val < mins[j]) if (val < mins[j])
mins[j] = val; mins[j] = val;
@ -438,17 +439,17 @@ static void LightCalcFaceExtents (llightinfo_t *l)
for (i=0 ; i<2 ; i++) for (i=0 ; i<2 ; i++)
{ {
l->exactmins[i] = mins[i]; exactmins[i] = mins[i];
l->exactmaxs[i] = maxs[i]; exactmaxs[i] = maxs[i];
mins[i] = floor(mins[i]/(1<<s->lmshift)); mins[i] = floor(mins[i]/(1<<s->lmshift));
maxs[i] = ceil(maxs[i]/(1<<s->lmshift)); maxs[i] = ceil(maxs[i]/(1<<s->lmshift));
l->texmins[i] = mins[i]; texmins[i] = mins[i];
l->texsize[i] = maxs[i] - mins[i]; texsize[i] = maxs[i] - mins[i];
if (l->texsize[i] > 17) if (texsize[i] > MAXIMUMEXTENT-1)
{ {
l->texsize[i] = 17; texsize[i] = MAXIMUMEXTENT-1;
Con_Printf("Bad surface extents"); Con_Printf("Bad surface extents");
} }
} }
@ -462,12 +463,12 @@ For each texture aligned grid point, back project onto the plane
to get the world xyz value of the sample point to get the world xyz value of the sample point
================= =================
*/ */
static int c_bad; static void LightCalcPoints (llightinfo_t *l, float lmscale)
static void LightCalcPoints (llightinfo_t *l)
{ {
int i; int i;
int s, t, j; int s, t, j;
int w, h, step; int w, h;
vec_t step;
vec_t starts, startt, us, ut; vec_t starts, startt, us, ut;
vec_t *surf; vec_t *surf;
vec_t mids, midt; vec_t mids, midt;
@ -489,17 +490,17 @@ static void LightCalcPoints (llightinfo_t *l)
{ // extra filtering { // extra filtering
h = (l->texsize[1]+1)*2; h = (l->texsize[1]+1)*2;
w = (l->texsize[0]+1)*2; w = (l->texsize[0]+1)*2;
starts = (l->texmins[0]-0.5)*16; starts = (l->texmins[0]-0.5)*lmscale;
startt = (l->texmins[1]-0.5)*16; startt = (l->texmins[1]-0.5)*lmscale;
step = 8; step = 0.5 * lmscale;
} }
else else
{ {
h = l->texsize[1]+1; h = l->texsize[1]+1;
w = l->texsize[0]+1; w = l->texsize[0]+1;
starts = l->texmins[0]*16; starts = l->texmins[0]*lmscale;
startt = l->texmins[1]*16; startt = l->texmins[1]*lmscale;
step = 16; step = lmscale;
} }
l->numsurfpt = w * h; l->numsurfpt = w * h;
@ -518,19 +519,19 @@ static void LightCalcPoints (llightinfo_t *l)
surf[j] = l->texorg[j] + l->textoworld[0][j]*us surf[j] = l->texorg[j] + l->textoworld[0][j]*us
+ l->textoworld[1][j]*ut; + l->textoworld[1][j]*ut;
if (CastRay (facemid, surf) != -1) if (CastRay (l->ctx, facemid, surf) != -1)
break; // got it break; // got it
if (i & 1) if (i & 1)
{ {
if (us > mids) if (us > mids)
{ {
us -= 8; us -= lmscale*0.5;
if (us < mids) if (us < mids)
us = mids; us = mids;
} }
else else
{ {
us += 8; us += lmscale*0.5;
if (us > mids) if (us > mids)
us = mids; us = mids;
} }
@ -539,13 +540,13 @@ static void LightCalcPoints (llightinfo_t *l)
{ {
if (ut > midt) if (ut > midt)
{ {
ut -= 8; ut -= lmscale*0.5;
if (ut < midt) if (ut < midt)
ut = midt; ut = midt;
} }
else else
{ {
ut += 8; ut += lmscale*0.5;
if (ut > midt) if (ut > midt)
ut = midt; ut = midt;
} }
@ -555,9 +556,9 @@ static void LightCalcPoints (llightinfo_t *l)
VectorSubtract (facemid, surf, move); VectorSubtract (facemid, surf, move);
VectorNormalize (move); VectorNormalize (move);
VectorMA (surf, 8, move, surf); VectorMA (surf, 8, move, surf);
P_RunParticleEffectType(surf, NULL, 1, pt_wizspike);
} }
if (i == 2)
c_bad++;
} }
} }
@ -572,8 +573,6 @@ FACE LIGHTING
=============================================================================== ===============================================================================
*/ */
int c_culldistplane, c_proper;
/* /*
================ ================
SingleLightFace SingleLightFace
@ -588,8 +587,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
vec_t *surf; vec_t *surf;
qboolean hit; qboolean hit;
int mapnum; int mapnum;
int size; int c;
int c, i;
vec3_t rel; vec3_t rel;
vec3_t spotvec; vec3_t spotvec;
vec_t falloff; vec_t falloff;
@ -605,14 +603,11 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
// don't bother with light too far away // don't bother with light too far away
if (dist > light->light) if (dist > light->light)
{
c_culldistplane++;
return; return;
}
if (light->targetent) if (light->targetentnum>=0)
{ {
VectorSubtract (light->targetent->origin, light->origin, spotvec); VectorSubtract (l->ctx->entities[light->targetentnum].origin, light->origin, spotvec);
VectorNormalize (spotvec); VectorNormalize (spotvec);
if (!light->angle) if (!light->angle)
falloff = -cos(20*Q_PI/180); falloff = -cos(20*Q_PI/180);
@ -631,6 +626,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
norms = l->lightnorm[mapnum]; norms = l->lightnorm[mapnum];
if (mapnum == l->numlightstyles) if (mapnum == l->numlightstyles)
{ // init a new light map { // init a new light map
#ifdef UTILITY
if (mapnum == MAXQ1LIGHTMAPS) if (mapnum == MAXQ1LIGHTMAPS)
{ {
printf ("WARNING: Too many light styles on a face\n"); printf ("WARNING: Too many light styles on a face\n");
@ -646,24 +642,26 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
norms[i][1] = 0; norms[i][1] = 0;
norms[i][2] = 0; norms[i][2] = 0;
} }
#else
return; //can't light a surface with a lightstyle that did not previously exist, due to lightmap space limits.
#endif
} }
// //
// check it for real // check it for real
// //
hit = false; hit = false;
c_proper++;
surf = l->surfpt[0]; surf = l->surfpt[0];
for (c=0 ; c<l->numsurfpt ; c++, surf+=3) for (c=0 ; c<l->numsurfpt ; c++, surf+=3)
{ {
dist = CastRay(light->origin, surf)*scaledist; dist = CastRay(l->ctx, light->origin, surf)*scaledist;
if (dist < 0) if (dist < 0)
continue; // light doesn't reach continue; // light doesn't reach
VectorSubtract (light->origin, surf, incoming); VectorSubtract (light->origin, surf, incoming);
VectorNormalize (incoming); VectorNormalize (incoming);
if (light->targetent) if (light->targetentnum >= 0)
{ // spotlight cutoff { // spotlight cutoff
if (DotProduct (spotvec, incoming) > falloff) if (DotProduct (spotvec, incoming) > falloff)
continue; continue;
@ -680,14 +678,14 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
lightsamp[c][1] += add*light->colour[1]; lightsamp[c][1] += add*light->colour[1];
lightsamp[c][2] += add*light->colour[2]; lightsamp[c][2] += add*light->colour[2];
norms[c][0] += add * incoming[0]; //Quake doesn't make sence some times. norms[c][0] += add * incoming[0];
norms[c][1] += add * incoming[1]; norms[c][1] += add * incoming[1];
norms[c][2] += add * incoming[2]; norms[c][2] += add * incoming[2];
if (add > 1) // ignore real tiny lights if (add > 1) // ignore real tiny lights
hit = true; hit = true;
} }
if (mapnum == l->numlightstyles && hit) if (mapnum == l->numlightstyles && hit)
{ {
l->lightstyles[mapnum] = light->style; l->lightstyles[mapnum] = light->style;
@ -749,12 +747,10 @@ static void FixMinlight (llightinfo_t *l)
LightFace LightFace
============ ============
*/ */
void LightFace (int surfnum) void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *l, qbyte surf_styles[4], qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale)
{ {
dface_t *f;
llightinfo_t l;
int s, t; int s, t;
int i,j,c,ch; int i,c,ch;
vec_t total, mean; vec_t total, mean;
int size; int size;
int lightmapwidth; int lightmapwidth;
@ -762,82 +758,62 @@ void LightFace (int surfnum)
int lightmapsize; int lightmapsize;
byte *out; byte *out;
#endif #endif
byte *rgbout; qbyte *rgbout;
byte *dulout; qbyte *dulout;
vec3_t *light, *norm; vec3_t *light, *norm;
vec3_t wnorm, temp, svector, tvector; vec3_t wnorm, temp, svector, tvector;
int w; int w;
f = dfaces + surfnum;
// //
// some surfaces don't need lightmaps // some surfaces don't need lightmaps
// //
#ifdef UTILITY if (!surf_rgbsamples)
for (j=0 ; j<MAXLIGHTMAPS ; j++)
f->styles[j] = 255;
#endif
if ( bsptexinfo(f->texinfo).flags & TEX_SPECIAL)
{ // non-lit texture
#ifdef UTILITY
f->lightofs = -1;
#endif
return; return;
}
#ifndef UTILITY memset (l, 0, sizeof(*l));
if (!f->samples) l->ctx = ctx;
return;
#endif
memset (&l, 0, sizeof(l));
l.surfnum = surfnum;
l.face = f;
// //
// rotate plane // rotate plane
// //
#ifndef UTILITY VectorCopy (surf_plane, l->facenormal);
VectorCopy (f->plane->normal, l.facenormal); l->facedist = surf_plane[3];
l.facedist = f->plane->dist;
#else
VectorCopy (dplanes[f->planenum].normal, l.facenormal);
l.facedist = dplanes[f->planenum].dist;
#endif
if (f->side)
{
VectorNegate (l.facenormal, l.facenormal);
l.facedist = -l.facedist;
}
LightCalcFaceVectors (l, surf_texplanes);
LightCalcFaceVectors (&l); Vector2Copy(exactmins, l->exactmins);
LightCalcFaceExtents (&l); Vector2Copy(exactmaxs, l->exactmaxs);
LightCalcPoints (&l); Vector2Copy(texmins, l->texmins);
Vector2Copy(texsize, l->texsize);
LightCalcPoints (l, lmscale);
lightmapwidth = l.texsize[0]+1; lightmapwidth = l->texsize[0]+1;
size = lightmapwidth*(l.texsize[1]+1); size = lightmapwidth*(l->texsize[1]+1);
if (size > SINGLEMAP) if (size > SINGLEMAP)
Error ("Bad lightmap size"); Host_Error ("Bad lightmap size");
for (i=0 ; i<MAXQ1LIGHTMAPS ; i++) i = 0;
l.lightstyles[i] = 255; #ifndef UTILITY
for (; surf_styles[i] != 255 && i < 4; i++)
l->lightstyles[i] = surf_styles[i];
#endif
l->numlightstyles = i;
for ( ; i<MAXQ1LIGHTMAPS ; i++)
l->lightstyles[i] = 255;
// //
// cast all lights // cast all lights
// //
l.numlightstyles = 0; for (i=0 ; i<ctx->num_entities ; i++)
for (i=0 ; i<num_entities ; i++)
{ {
if (entities[i].light) if (ctx->entities[i].light)
SingleLightFace (&entities[i], &l); SingleLightFace (&ctx->entities[i], l);
} }
FixMinlight (&l); FixMinlight (l);
if (!l.numlightstyles) if (!l->numlightstyles)
{ // no light hitting it { // no light hitting it
#ifdef UTILITY #ifdef UTILITY
f->lightofs = -1; f->lightofs = -1;
@ -845,20 +821,15 @@ void LightFace (int surfnum)
return; return;
} }
#ifndef UTILITY
for (j=0 ; j<MAXQ1LIGHTMAPS ; j++)
f->styles[j] = 255;
#endif
// //
// save out the values // save out the values
// //
for (i=0 ; i <MAXQ1LIGHTMAPS ; i++) for (i=0 ; i <MAXQ1LIGHTMAPS ; i++)
f->styles[i] = l.lightstyles[i]; surf_styles[i] = l->lightstyles[i];
#ifdef UTILITY #ifdef UTILITY
lightmapsize = size*l.numlightstyles; lightmapsize = size*l->numlightstyles;
if (runningrgblightdatabase) if (runningrgblightdatabase)
{ {
out = GetFakeFileSpace(&f->lightofs, lightmapsize); out = GetFakeFileSpace(&f->lightofs, lightmapsize);
@ -873,13 +844,13 @@ void LightFace (int surfnum)
dulout = GetNormFileSpace (f->lightofs, lightmapsize); dulout = GetNormFileSpace (f->lightofs, lightmapsize);
} }
#else #else
rgbout = f->samples; rgbout = surf_rgbsamples;
if (lightmodel->deluxdata) if (l->ctx->models[0]->deluxdata)
{ {
dulout = f->samples - lightmodel->lightdata + lightmodel->deluxdata; dulout = surf_deluxesamples;
VectorCopy(bsptexinfo(f->texinfo).vecs[0], svector); VectorCopy(surf_texplanes[0], svector);
VectorNegate(bsptexinfo(f->texinfo).vecs[1], tvector); VectorNegate(surf_texplanes[1], tvector);
VectorNormalize(svector); VectorNormalize(svector);
VectorNormalize(tvector); VectorNormalize(tvector);
} }
@ -891,18 +862,20 @@ void LightFace (int surfnum)
// extra filtering // extra filtering
// h = (l.texsize[1]+1)*2; // h = (l.texsize[1]+1)*2;
w = (l.texsize[0]+1)*2; w = l->texsize[0]+1;
if (extrasamples)
w *= 2;
for (i=0 ; i< l.numlightstyles ; i++) for (i=0 ; i< l->numlightstyles ; i++)
{ {
if (l.lightstyles[i] == 0xff) if (l->lightstyles[i] == 0xff)
Error ("Wrote empty lightmap"); Host_Error ("Wrote empty lightmap");
light = l.lightmaps[i]; light = l->lightmaps[i];
norm = l.lightnorm[i]; norm = l->lightnorm[i];
c = 0; c = 0;
for (t=0 ; t<=l.texsize[1] ; t++) for (t=0 ; t<=l->texsize[1] ; t++)
{ {
for (s=0 ; s<=l.texsize[0] ; s++, c++) for (s=0 ; s<=l->texsize[0] ; s++, c++)
{ {
mean = 0; mean = 0;
@ -924,11 +897,13 @@ void LightFace (int surfnum)
} }
total *= rangescale; // scale before clamping total *= rangescale; // scale before clamping
#ifndef UTILITY #ifndef UTILITY
if (total > *rgbout) //sorry - for qw // if (total > *rgbout) //sorry - for qw
total = *rgbout; // total = *rgbout;
#endif #endif
if (total < 0) if (total < 0)
Error ("light < 0"); total = 0;
if (total > 0xff)
total = 0xff;
*rgbout++ = total; *rgbout++ = total;
mean += total; mean += total;
@ -941,15 +916,11 @@ void LightFace (int surfnum)
{ {
temp[0] = DotProduct(wnorm, svector); temp[0] = DotProduct(wnorm, svector);
temp[1] = DotProduct(wnorm, tvector); temp[1] = DotProduct(wnorm, tvector);
temp[2] = DotProduct(wnorm, l.facenormal); temp[2] = DotProduct(wnorm, l->facenormal);
if (!temp[0] && !temp[1] && !temp[2]) if (!temp[0] && !temp[1] && !temp[2])
VectorSet(temp, 0, 0, 1); VectorSet(temp, 0, 0, 1);
else else
{
VectorNormalize(temp); VectorNormalize(temp);
// temp[2] += 0.5;
VectorNormalize(temp);
}
*dulout++ = (temp[0]+1)*128; *dulout++ = (temp[0]+1)*128;
*dulout++ = (temp[1]+1)*128; *dulout++ = (temp[1]+1)*128;
*dulout++ = (temp[2]+1)*128; *dulout++ = (temp[2]+1)*128;
@ -958,5 +929,27 @@ void LightFace (int surfnum)
} }
} }
} }
void LightFace (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, int facenum)
{
dface_t *f = ctx->models[0]->surfaces + facenum;
vec4_t plane;
vec2_t exactmins;
vec2_t exactmaxs;
int texmins[2], texsize[2];
VectorCopy (f->plane->normal, plane);
plane[3] = f->plane->dist;
if (f->flags & SURF_PLANEBACK)
{
VectorNegate (plane, plane);
plane[3] = -plane[3];
}
//no lighting on these.
if (f->texinfo->flags & TEX_SPECIAL)
return;
LightCalcFaceExtents(ctx->models[0], f, exactmins, exactmaxs, texmins, texsize);
LightPlane(ctx, threadctx, f->styles, f->samples, f->samples - ctx->models[0]->lightdata + ctx->models[0]->deluxdata, plane, f->texinfo->vecs, exactmins, exactmaxs, texmins, texsize, 1<<f->lmshift);
}
#endif #endif

View file

@ -1691,8 +1691,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#define r_glsl_pcf 9\n" "#define r_glsl_pcf 9\n"
"#endif\n" "#endif\n"
"#if 0 && defined(GL_ARB_texture_gather) && defined(PCF) \n"
//texturegather is a gl4 feature, but these shaders are gl2.0 or something
"#if #include \"cvar/texgather\" && defined(GL_ARB_texture_gather) && defined(PCF) \n"
"#extension GL_ARB_texture_gather : enable\n" "#extension GL_ARB_texture_gather : enable\n"
"#define DOTEXTUREGATHER\n"
"#endif\n" "#endif\n"
"#ifdef UPPERLOWER\n" "#ifdef UPPERLOWER\n"
@ -1851,7 +1854,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"{\n" "{\n"
"vec3 shadowcoord = ShadowmapCoord();\n" "vec3 shadowcoord = ShadowmapCoord();\n"
"#if 0//def GL_ARB_texture_gather\n" "#ifdef DOTEXTUREGATHER\n"
"vec2 ipart, fpart;\n" "vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(s_t4, ipart.xy, vec2(x,y)))\n" "#define dosamp(x,y) textureGatherOffset(s_t4, ipart.xy, vec2(x,y)))\n"
"vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n" "vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n"

View file

@ -595,7 +595,7 @@ shader_t *QDECL R_RegisterSkin (const char *shadername, const char *modname);
shader_t *R_RegisterCustom (const char *name, unsigned int usageflags, shader_gen_t *defaultgen, const void *args); shader_t *R_RegisterCustom (const char *name, unsigned int usageflags, shader_gen_t *defaultgen, const void *args);
//once loaded, most shaders should have one of the following two calls used upon it //once loaded, most shaders should have one of the following two calls used upon it
void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader); void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader);
void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned int loadflags, uploadfmt_t basefmt, size_t width, size_t height, qbyte *mipdata[4], qbyte *palette); void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, const char *subpath, unsigned int loadflags, uploadfmt_t basefmt, size_t width, size_t height, qbyte *mipdata[4], qbyte *palette);
void R_RemapShader(const char *sourcename, const char *destname, float timeoffset); void R_RemapShader(const char *sourcename, const char *destname, float timeoffset);
cin_t *R_ShaderGetCinematic(shader_t *s); cin_t *R_ShaderGetCinematic(shader_t *s);

View file

@ -5,6 +5,8 @@
#include "netinc.h" #include "netinc.h"
#include "fs.h" #include "fs.h"
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
#if defined(WEBCLIENT) #if defined(WEBCLIENT)
#if defined(FTE_TARGET_WEB) #if defined(FTE_TARGET_WEB)
@ -287,20 +289,20 @@ struct http_dl_ctx_s {
char *buffer; char *buffer;
int bufferused; size_t bufferused;
int bufferlen; size_t bufferlen;
int totalreceived; //useful when we're just dumping to a file. size_t totalreceived; //useful when we're just dumping to a file.
struct vfsfile_s *file; //if gzipping, this is a temporary file. we'll write to the real file from this after the transfer is complete. struct vfsfile_s *file; //if gzipping, this is a temporary file. we'll write to the real file from this after the transfer is complete.
qboolean gzip; qboolean gzip;
qboolean chunking; qboolean chunking;
int chunksize; size_t chunksize;
int chunked; size_t chunked;
enum {HC_REQUESTING, HC_GETTINGHEADER, HC_GETTING} state; enum {HC_REQUESTING, HC_GETTINGHEADER, HC_GETTING} state;
int contentlength; size_t contentlength;
}; };
void HTTP_Cleanup(struct dl_download *dl) void HTTP_Cleanup(struct dl_download *dl)
@ -400,7 +402,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
msg = con->buffer; msg = con->buffer;
con->chunking = false; con->chunking = false;
con->contentlength = 0; con->contentlength = -1;
con->gzip = false; con->gzip = false;
*mimetype = 0; *mimetype = 0;
*Location = 0; *Location = 0;
@ -567,7 +569,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
if (con->gzip) if (con->gzip)
{ {
#if !defined(NPFTE) && defined(AVAIL_ZLIB) #if !defined(NPFTE) && defined(AVAIL_ZLIB)
#if 1
con->file = FS_GZ_DecompressWriteFilter(dl->file, false);
#else
con->file = FS_OpenTemp(); con->file = FS_OpenTemp();
#endif
#else #else
Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname); Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname);
dl->status = DL_FAILED; dl->status = DL_FAILED;
@ -659,7 +665,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
} }
else else
{ {
con->totalreceived+=ammount; con->totalreceived+=con->bufferused;
if (con->file) //we've got a chunk in the buffer if (con->file) //we've got a chunk in the buffer
{ //write it { //write it
if (VFS_WRITE(con->file, con->buffer, con->bufferused) != con->bufferused) if (VFS_WRITE(con->file, con->buffer, con->bufferused) != con->bufferused)
@ -669,6 +675,8 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
} }
con->bufferused = 0; con->bufferused = 0;
} }
if (con->totalreceived == con->contentlength)
ammount = 0;
} }
if (!ammount) if (!ammount)
@ -678,6 +686,13 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
else else
{ {
#if !defined(NPFTE) && defined(AVAIL_ZLIB) #if !defined(NPFTE) && defined(AVAIL_ZLIB)
#if 1
if (con->gzip && con->file)
{
VFS_CLOSE(con->file);
con->file = NULL;
}
#else
if (con->gzip && con->file) if (con->gzip && con->file)
{ {
VFS_SEEK(con->file, 0); VFS_SEEK(con->file, 0);
@ -685,7 +700,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
con->file = NULL; con->file = NULL;
} }
#endif #endif
dl->status = (dl->replycode == 200)?DL_FINISHED:DL_FAILED; #endif
if (con->contentlength != -1 && con->totalreceived != con->contentlength)
dl->status = DL_FAILED; //file was truncated
else
dl->status = (dl->replycode == 200)?DL_FINISHED:DL_FAILED;
} }
return false; return false;
} }

View file

@ -82,28 +82,41 @@ char *authedusername;
char *autheduserpassword; char *autheduserpassword;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int httpport = 80;
int arg = 1;
WSADATA pointlesscrap; WSADATA pointlesscrap;
WSAStartup(2, &pointlesscrap); WSAStartup(2, &pointlesscrap);
if (argc == 3) if (arg < argc && atoi(argv[arg]))
{ httpport = atoi(argv[arg++]);
authedusername = argv[1]; if (arg < argc)
autheduserpassword = argv[2]; authedusername = argv[arg++];
if (arg < argc)
autheduserpassword = argv[arg++];
printf("http port %i\n", httpport);
if (authedusername || autheduserpassword)
printf("Username = \"%s\"\nPassword = \"%s\"\n", authedusername, autheduserpassword); printf("Username = \"%s\"\nPassword = \"%s\"\n", authedusername, autheduserpassword);
}
else else
printf("Server is read only\n"); printf("Server is read only\n");
while(1) while(1)
{ {
// FTP_ServerRun(1, 21); // FTP_ServerRun(1, 21);
HTTP_ServerPoll(1, 80); if (httpport)
HTTP_ServerPoll(1, httpport);
Sleep(1); Sleep(1);
} }
} }
static time_t Sys_FileTimeToTime(FILETIME ft)
void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *f), void *parm) {
ULARGE_INTEGER ull;
ull.LowPart = ft.dwLowDateTime;
ull.HighPart = ft.dwHighDateTime;
return ull.QuadPart / 10000000ULL - 11644473600ULL;
}
void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *f), void *parm)
{ {
HANDLE r; HANDLE r;
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;
@ -132,19 +145,19 @@ void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, vo
else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory else if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //is a directory
{ {
sprintf(file, "%s%s/", apath, fd.cFileName); sprintf(file, "%s%s/", apath, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm, NULL); go = func(file, fd.nFileSizeLow, Sys_FileTimeToTime(fd.ftLastWriteTime), parm, NULL);
} }
else else
{ {
sprintf(file, "%s%s", apath, fd.cFileName); sprintf(file, "%s%s", apath, fd.cFileName);
go = func(file, fd.nFileSizeLow, parm, NULL); go = func(file, fd.nFileSizeLow, Sys_FileTimeToTime(fd.ftLastWriteTime), parm, NULL);
} }
} }
while(FindNextFile(r, &fd) && go); while(FindNextFile(r, &fd) && go);
FindClose(r); FindClose(r);
} }
char *COM_ParseOut (const char *data, char *out, int outlen) char *COM_ParseType (const char *data, char *out, int outlen, com_tokentype_t *toktype)
{ {
int c; int c;
int len; int len;

View file

@ -284,7 +284,7 @@ r_part +te_explosion
randomvel 1000 randomvel 1000
friction 0.01 friction 0.01
gravity 100 gravity 100
stretchfactor 5 stretchfactor -80
} }
//hide lights in explosions. //hide lights in explosions.

View file

@ -1950,8 +1950,8 @@ void NPP_QWWriteByte(int dest, qbyte data) //replacement write func (nq to qw)
protocollen = 6; protocollen = 6;
break; break;
case svc_updateuserinfo: case svc_updateuserinfo:
protocollen = 6;
nullterms = 1; nullterms = 1;
protocollen = 6+nullterms;
break; break;
case svcqw_updatestatlong: case svcqw_updatestatlong:
protocollen = 6; protocollen = 6;

View file

@ -87,6 +87,7 @@ cvar_t pr_ssqc_coreonerror = CVAR("pr_coreonerror", "1");
cvar_t sv_gameplayfix_honest_tracelines = CVAR("sv_gameplayfix_honest_tracelines", "1"); cvar_t sv_gameplayfix_honest_tracelines = CVAR("sv_gameplayfix_honest_tracelines", "1");
cvar_t sv_gameplayfix_setmodelrealbox = CVARD("sv_gameplayfix_setmodelrealbox", "0", "Vanilla setmodel will setsize the entity to a hardcoded size for non-bsp models. This cvar will always use the real size of the model instead, but will require that the server actually loads the model."); cvar_t sv_gameplayfix_setmodelrealbox = CVARD("sv_gameplayfix_setmodelrealbox", "0", "Vanilla setmodel will setsize the entity to a hardcoded size for non-bsp models. This cvar will always use the real size of the model instead, but will require that the server actually loads the model.");
cvar_t sv_gameplayfix_setmodelsize_qw = CVARD("sv_gameplayfix_setmodelsize_qw", "0", "The setmodel builtin will act as a setsize for QuakeWorld mods also."); cvar_t sv_gameplayfix_setmodelsize_qw = CVARD("sv_gameplayfix_setmodelsize_qw", "0", "The setmodel builtin will act as a setsize for QuakeWorld mods also.");
cvar_t dpcompat_nopreparse = CVARD("dpcompat_nopreparse", "0", "Xonotic uses svc_tempentity with unknowable lengths mixed with other data that needs to be translated. This cvar disables any attempt to translate or pre-parse network messages, including disabling nq/qw cross compatibility. NOTE: because preparsing will be disabled, messages might not get backbuffered correctly if too much reliable data is written.");
cvar_t sv_addon[MAXADDONS]; cvar_t sv_addon[MAXADDONS];
char cvargroup_progs[] = "Progs variables"; char cvargroup_progs[] = "Progs variables";
@ -1295,6 +1296,7 @@ void PR_Init(void)
Cvar_Register (&pr_ssqc_progs, cvargroup_progs); Cvar_Register (&pr_ssqc_progs, cvargroup_progs);
Cvar_Register (&pr_compatabilitytest, cvargroup_progs); Cvar_Register (&pr_compatabilitytest, cvargroup_progs);
Cvar_Register (&dpcompat_nopreparse, cvargroup_progs);
Cvar_Register (&pr_nonetaccess, cvargroup_progs); Cvar_Register (&pr_nonetaccess, cvargroup_progs);
Cvar_Register (&pr_overridebuiltins, cvargroup_progs); Cvar_Register (&pr_overridebuiltins, cvargroup_progs);
@ -2957,9 +2959,8 @@ PF_ambientsound
*/ */
void PF_ambientsound_Internal (float *pos, const char *samp, float vol, float attenuation) void PF_ambientsound_Internal (float *pos, const char *samp, float vol, float attenuation)
{ {
int i, soundnum, j; staticsound_state_t *state;
sizebuf_t *buf[3] = {&sv.signon, &sv.nqmulticast, &sv.multicast}; int soundnum;
sizebuf_t *msg;
// check to see if samp was properly precached // check to see if samp was properly precached
for (soundnum=1 ; *sv.strings.sound_precache[soundnum] ; soundnum++) for (soundnum=1 ; *sv.strings.sound_precache[soundnum] ; soundnum++)
@ -2972,25 +2973,18 @@ void PF_ambientsound_Internal (float *pos, const char *samp, float vol, float at
return; return;
} }
SV_FlushSignon(); if (sv.num_static_sounds == sv_max_staticsounds)
if (soundnum > 255)
return;
for (j = 0; j < 3; j++)
{ {
msg = buf[j]; sv_max_staticsounds += 16;
if (sv.state == ss_loading && j) sv_staticsounds = BZ_Realloc(sv_staticsounds, sizeof(*sv_staticsounds) * sv_max_staticsounds);
break;
// add an svc_spawnambient command to the level signon packet
MSG_WriteByte (msg,svc_spawnstaticsound);
for (i=0 ; i<3 ; i++)
MSG_WriteCoord(msg, pos[i]);
MSG_WriteByte (msg, soundnum);
MSG_WriteByte (msg, bound(0, (int)(vol*255), 255));
MSG_WriteByte (msg, attenuation*64);
} }
SV_Multicast(pos, MULTICAST_ALL_R);
state = &sv_staticsounds[sv.num_static_sounds++];
memset(state, 0, sizeof(*state));
VectorCopy(pos, state->position);
state->soundnum = soundnum;
state->volume = bound(0, (int)(vol*255), 255);
state->attenuation = attenuation*64;
} }
static void QCBUILTIN PF_ambientsound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_ambientsound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4212,7 +4206,7 @@ static void QCBUILTIN PF_aim (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
vec3_t start, dir, end, bestdir; vec3_t start, dir, end, bestdir;
int i, j; int i, j;
trace_t tr; trace_t tr;
float dist, bestdist; float dist, bestdist = sv_aim.value;
char *noaim; char *noaim;
ent = G_EDICT(prinst, OFS_PARM0); ent = G_EDICT(prinst, OFS_PARM0);
@ -4231,6 +4225,14 @@ static void QCBUILTIN PF_aim (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
VectorCopy (P_VEC(v_forward), G_VECTOR(OFS_RETURN)); VectorCopy (P_VEC(v_forward), G_VECTOR(OFS_RETURN));
return; return;
} }
noaim = Info_ValueForKey (svs.clients[i-1].userinfo, "aim");
if (noaim)
{
dist = atof(noaim);
if (dist > 0)
bestdist = dist;
}
} }
// try sending a trace straight // try sending a trace straight
@ -4433,7 +4435,9 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteByte(dest, val); NPP_NQWriteByte(dest, val);
return; return;
@ -4444,7 +4448,7 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteByte(dest, val); NPP_QWWriteByte(dest, val);
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4454,8 +4458,12 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
ClientReliableWrite_Byte(cl, val); ClientReliableWrite_Byte(cl, val);
} }
else else
MSG_WriteByte (QWWriteDest(dest), val); {
#endif if (progstype != PROG_QW)
MSG_WriteByte (NQWriteDest(dest), val);
else
MSG_WriteByte (QWWriteDest(dest), val);
}
} }
void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4475,7 +4483,9 @@ void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteChar(dest, val); NPP_NQWriteChar(dest, val);
return; return;
@ -4486,7 +4496,7 @@ void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteChar(dest, val); NPP_QWWriteChar(dest, val);
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4496,8 +4506,12 @@ void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
ClientReliableWrite_Char(cl, val); ClientReliableWrite_Char(cl, val);
} }
else else
MSG_WriteChar (QWWriteDest(dest), val); {
#endif if (progstype != PROG_QW)
MSG_WriteChar (NQWriteDest(dest), val);
else
MSG_WriteChar (QWWriteDest(dest), val);
}
} }
void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4517,7 +4531,9 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteShort(dest, val); NPP_NQWriteShort(dest, val);
return; return;
@ -4528,8 +4544,8 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteShort(dest, val); NPP_QWWriteShort(dest, val);
return; return;
} }
#else #endif
if (desf == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
if (!cl) if (!cl)
@ -4538,8 +4554,12 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
ClientReliableWrite_Short(cl, val); ClientReliableWrite_Short(cl, val);
} }
else else
MSG_WriteShort (QWWriteDest(dest), val); {
#endif if (progstype != PROG_QW)
MSG_WriteShort (NQWriteDest(dest), val);
else
MSG_WriteShort (QWWriteDest(dest), val);
}
} }
void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4558,7 +4578,9 @@ void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteLong(dest, G_FLOAT(OFS_PARM1)); NPP_NQWriteLong(dest, G_FLOAT(OFS_PARM1));
return; return;
@ -4569,7 +4591,7 @@ void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteLong(dest, G_FLOAT(OFS_PARM1)); NPP_QWWriteLong(dest, G_FLOAT(OFS_PARM1));
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4579,8 +4601,12 @@ void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
ClientReliableWrite_Long(cl, G_FLOAT(OFS_PARM1)); ClientReliableWrite_Long(cl, G_FLOAT(OFS_PARM1));
} }
else else
MSG_WriteLong (QWWriteDest(dest), G_FLOAT(OFS_PARM1)); {
#endif if (progstype != PROG_QW)
MSG_WriteLong (NQWriteDest(dest), G_FLOAT(OFS_PARM1));
else
MSG_WriteLong (QWWriteDest(dest), G_FLOAT(OFS_PARM1));
}
} }
void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4599,7 +4625,9 @@ void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteAngle(dest, G_FLOAT(OFS_PARM1)); NPP_NQWriteAngle(dest, G_FLOAT(OFS_PARM1));
return; return;
@ -4610,7 +4638,7 @@ void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteAngle(dest, G_FLOAT(OFS_PARM1)); NPP_QWWriteAngle(dest, G_FLOAT(OFS_PARM1));
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4620,8 +4648,12 @@ void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
ClientReliableWrite_Angle(cl, G_FLOAT(OFS_PARM1)); ClientReliableWrite_Angle(cl, G_FLOAT(OFS_PARM1));
} }
else else
MSG_WriteAngle (QWWriteDest(dest), G_FLOAT(OFS_PARM1)); {
#endif if (progstype != PROG_QW)
MSG_WriteAngle (NQWriteDest(dest), G_FLOAT(OFS_PARM1));
else
MSG_WriteAngle (QWWriteDest(dest), G_FLOAT(OFS_PARM1));
}
} }
void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4640,7 +4672,9 @@ void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteCoord(dest, G_FLOAT(OFS_PARM1)); NPP_NQWriteCoord(dest, G_FLOAT(OFS_PARM1));
return; return;
@ -4651,7 +4685,7 @@ void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteCoord(dest, G_FLOAT(OFS_PARM1)); NPP_QWWriteCoord(dest, G_FLOAT(OFS_PARM1));
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4661,8 +4695,12 @@ void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
ClientReliableWrite_Coord(cl, G_FLOAT(OFS_PARM1)); ClientReliableWrite_Coord(cl, G_FLOAT(OFS_PARM1));
} }
else else
MSG_WriteCoord (QWWriteDest(dest), G_FLOAT(OFS_PARM1)); {
#endif if (progstype != PROG_QW)
MSG_WriteCoord (NQWriteDest(dest), G_FLOAT(OFS_PARM1));
else
MSG_WriteCoord (QWWriteDest(dest), G_FLOAT(OFS_PARM1));
}
} }
void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4681,7 +4719,9 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return; return;
#endif #endif
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteFloat(dest, G_FLOAT(OFS_PARM1)); NPP_NQWriteFloat(dest, G_FLOAT(OFS_PARM1));
return; return;
@ -4692,7 +4732,7 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteFloat(dest, G_FLOAT(OFS_PARM1)); NPP_QWWriteFloat(dest, G_FLOAT(OFS_PARM1));
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4702,8 +4742,12 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
ClientReliableWrite_Float(cl, G_FLOAT(OFS_PARM1)); ClientReliableWrite_Float(cl, G_FLOAT(OFS_PARM1));
} }
else else
MSG_WriteFloat (QWWriteDest(dest), G_FLOAT(OFS_PARM1)); {
#endif if (progstype != PROG_QW)
MSG_WriteFloat (NQWriteDest(dest), G_FLOAT(OFS_PARM1));
else
MSG_WriteFloat (QWWriteDest(dest), G_FLOAT(OFS_PARM1));
}
} }
void PF_WriteString_Internal (int target, const char *str) void PF_WriteString_Internal (int target, const char *str)
@ -4721,7 +4765,9 @@ void PF_WriteString_Internal (int target, const char *str)
) )
return; return;
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteString(target, str); NPP_NQWriteString(target, str);
return; return;
@ -4732,7 +4778,7 @@ void PF_WriteString_Internal (int target, const char *str)
NPP_QWWriteString(target, str); NPP_QWWriteString(target, str);
return; return;
} }
#else #endif
if (target == MSG_ONE) if (target == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4742,8 +4788,12 @@ void PF_WriteString_Internal (int target, const char *str)
ClientReliableWrite_String(cl, str); ClientReliableWrite_String(cl, str);
} }
else else
MSG_WriteString (QWWriteDest(target), str); {
#endif if (progstype != PROG_QW)
MSG_WriteString (NQWriteDest(target), str);
else
MSG_WriteString (QWWriteDest(target), str);
}
} }
static void QCBUILTIN PF_WriteString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_WriteString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -4769,7 +4819,9 @@ void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
) )
return; return;
if (progstype != PROG_QW) if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{ {
NPP_NQWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1)); NPP_NQWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1));
return; return;
@ -4780,7 +4832,7 @@ void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
NPP_QWWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1)); NPP_QWWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1));
return; return;
} }
#else #endif
if (dest == MSG_ONE) if (dest == MSG_ONE)
{ {
client_t *cl = Write_GetClient(); client_t *cl = Write_GetClient();
@ -4790,8 +4842,12 @@ void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
ClientReliableWrite_Entity(cl, G_EDICTNUM(prinst, OFS_PARM1)); ClientReliableWrite_Entity(cl, G_EDICTNUM(prinst, OFS_PARM1));
} }
else else
MSG_WriteEntity (QWWriteDest(dest), G_EDICTNUM(prinst, OFS_PARM1)); {
#endif if (progstype != PROG_QW)
MSG_WriteEntity (NQWriteDest(dest), G_EDICTNUM(prinst, OFS_PARM1));
else
MSG_WriteEntity (QWWriteDest(dest), G_EDICTNUM(prinst, OFS_PARM1));
}
} }
//small wrapper function. //small wrapper function.
@ -5029,13 +5085,10 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli
void QCBUILTIN PF_makestatic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_makestatic (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
edict_t *ent; edict_t *ent;
int mdlindex;
entity_state_t *state; entity_state_t *state;
ent = G_EDICT(prinst, OFS_PARM0); ent = G_EDICT(prinst, OFS_PARM0);
mdlindex = SV_ModelIndex(PR_GetString(prinst, ent->v->model));
if (sv.num_static_entities == sv_max_staticentities) if (sv.num_static_entities == sv_max_staticentities)
{ {
sv_max_staticentities += 16; sv_max_staticentities += 16;
@ -9519,7 +9572,30 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS) {"frameduration", PF_frameduration, 0, 0, 0, 277, D("float(float modidx, float framenum)", "Retrieves the duration (in seconds) of the specified framegroup.")},// (FTE_CSQC_SKELETONOBJECTS)
{"terrain_edit", PF_terrain_edit, 0, 0, 0, 278, D("void(float action, optional vector pos, optional float radius, optional float quant, ...)", "Realtime terrain editing. Actions are the TEREDIT_ constants.")},// (??FTE_TERRAIN_EDIT?? {"terrain_edit", PF_terrain_edit, 0, 0, 0, 278, D("void(float action, optional vector pos, optional float radius, optional float quant, ...)", "Realtime terrain editing. Actions are the TEREDIT_ constants.")},// (??FTE_TERRAIN_EDIT??
{"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void()", "Triggers a touch events between self and every entity that it is in contact with. This should typically just be the triggers touch functions.")},//
#define qcbrushface \
"typedef struct\n{\n" \
"\tstring\tshadername;\n" \
"\tvector\tplanenormal;\n" \
"\tfloat\tplanedist;\n" \
"\tvector\tsdir;\n" \
"\tfloat\tsbias;\n" \
"\tvector\ttdir;\n" \
"\tfloat\ttbias;\n" \
"} brushface_t;\n"
{"brush_get", PF_brush_get, 0, 0, 0, 0, D(qcbrushface "int(float modelidx, int brushid, brushface_t *out_faces, int maxfaces, int *out_contents)", "Queries a brush's information. You must pre-allocate the face array for the builtin to write to. Return value is the number of faces retrieved, 0 on error.")},
{"brush_create", PF_brush_create, 0, 0, 0, 0, D("int(float modelidx, brushface_t *in_faces, int numfaces, int contents)", "Inserts a new brush into the model. Return value is the new brush's id.")},
{"brush_delete", PF_brush_delete, 0, 0, 0, 0, D("void(float modelidx, int brushid)", "Destroys the specified brush.")},
{"brush_selected", PF_brush_selected, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, float selectedstate)", "Allows you to easily set transient visual properties of a brush. returns old value. selectedstate=-1 changes nothing (called for its return value).")},
{"brush_getfacepoints",PF_brush_getfacepoints,0,0, 0, 0, D("int(float modelid, int brushid, int faceid, vector *points, int maxpoints)", "Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points).")},
// {"brush_calcfacepoints",PF_brush_calcfacepoints,0,0, 0, 0, D("int(brushface_t *in_faces, int numfaces, int faceid, vector *points, int maxpoints)", "Returns the list of verticies surrounding the given face. If face is 0, returns the center of the brush (if space for 1 point) or the mins+maxs (if space for 2 points). Returns 0 if a face is degenerate.")},
{"brush_findinvolume",PF_brush_findinvolume,0, 0, 0, 0, D("int(float modelid, vector *planes, float *dists, int numplanes, int *out_brushes, int *out_faces, int maxresults)", "Allows you to easily obtain a list of brushes+faces within the given bounding region. If out_faces is not null, the same brush might be listed twice.")},
// {"brush_editplane", PF_brush_editplane, 0, 0, 0, 0, D("float(float modelid, int brushid, int faceid, in brushface *face)", "Changes a surface's texture info.")},
// {"brush_transformselected",PF_brush_transformselected,0,0,0, 0, D("int(float modelid, int brushid, float *matrix)", "Transforms selected brushes by the given transform")},
{"touchtriggers", PF_touchtriggers, 0, 0, 0, 279, D("void(optional entity ent, optional vector neworigin)", "Triggers a touch events between self and every SOLID_TRIGGER entity that it is in contact with. This should typically just be the triggers touch functions. Also optionally updates the origin of the moved entity.")},//
{"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, "void(float buf, float fl)"},// {"WriteFloat", PF_WriteFloat, 0, 0, 0, 280, "void(float buf, float fl)"},//
{"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL) {"skel_ragupdate", PF_skel_ragedit, 0, 0, 0, 281, D("float(entity skelent, string dollcmd, float animskel)", "Updates the skeletal object attached to the entity according to its origin and other properties.\nif animskel is non-zero, the ragdoll will animate towards the bone state in the animskel skeletal object, otherwise they will pick up the model's base pose which may not give nice results.\nIf dollcmd is not set, the ragdoll will update (this should be done each frame).\nIf the doll is updated without having a valid doll, the model's default .doll will be instanciated.\ncommands:\n doll foo.doll : sets up the entity to use the named doll file\n dollstring TEXT : uses the doll file directly embedded within qc, with that extra prefix.\n cleardoll : uninstanciates the doll without destroying the skeletal object.\n animate 0.5 : specifies the strength of the ragdoll as a whole \n animatebody somebody 0.5 : specifies the strength of the ragdoll on a specific body (0 will disable ragdoll animations on that body).\n enablejoint somejoint 1 : enables (or disables) a joint. Disabling joints will allow the doll to shatter.")}, // (FTE_CSQC_RAGDOLL)
{"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL) {"skel_mmap", PF_skel_mmap, 0, 0, 0, 282, D("float*(float skel)", "Map the bones in VM memory. They can then be accessed via pointers. Each bone is 12 floats, the four vectors interleaved (sadly).")},// (FTE_QC_RAGDOLL)
@ -9662,6 +9738,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"con_printf", PF_Fixme, 0, 0, 0, 392, D("void(string conname, string messagefmt, ...)", "Prints onto a named console.")}, {"con_printf", PF_Fixme, 0, 0, 0, 392, D("void(string conname, string messagefmt, ...)", "Prints onto a named console.")},
{"con_draw", PF_Fixme, 0, 0, 0, 393, D("void(string conname, vector pos, vector size, float fontsize)", "Draws the named console.")}, {"con_draw", PF_Fixme, 0, 0, 0, 393, D("void(string conname, vector pos, vector size, float fontsize)", "Draws the named console.")},
{"con_input", PF_Fixme, 0, 0, 0, 394, D("float(string conname, float inevtype, float parama, float paramb, float paramc)", "Forwards input events to the named console. Mouse updates should be absolute only.")}, {"con_input", PF_Fixme, 0, 0, 0, 394, D("float(string conname, float inevtype, float parama, float paramb, float paramc)", "Forwards input events to the named console. Mouse updates should be absolute only.")},
{"cvar_unsaved", PF_Fixme, 0, 0, 0, 0, D("float()", "Returns true if any archived cvar has an unsaved value.")},
//end fte extras //end fte extras
//DP extras //DP extras
@ -9822,7 +9899,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"cvar_type", PF_cvar_type, 0, 0, 0, 495, "float(string name)"},//DP_QC_CVAR_TYPE {"cvar_type", PF_cvar_type, 0, 0, 0, 495, "float(string name)"},//DP_QC_CVAR_TYPE
{"numentityfields", PF_numentityfields, 0, 0, 0, 496, D("float()", "Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3).")},//DP_QC_ENTITYDATA {"numentityfields", PF_numentityfields, 0, 0, 0, 496, D("float()", "Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3).")},//DP_QC_ENTITYDATA
{"findentityfield", PF_findentityfield, 0, 0, 0, 0, D("float(string fieldname)", "Find a field index by name.")}, {"findentityfield", PF_findentityfield, 0, 0, 0, 0, D("float(string fieldname)", "Find a field index by name.")},
{"entityfieldref", PF_entityfieldref, 0, 0, 0, 0, D(".__variant(float fieldnum)", "Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using.")},//DP_QC_ENTITYDATA {"entityfieldref", PF_entityfieldref, 0, 0, 0, 0, D("typedef .__variant field_t;\nfield_t(float fieldnum)", "Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using.")},//DP_QC_ENTITYDATA
{"entityfieldname", PF_entityfieldname, 0, 0, 0, 497, D("string(float fieldnum)", "Retrieves the name of the given entity field.")},//DP_QC_ENTITYDATA {"entityfieldname", PF_entityfieldname, 0, 0, 0, 497, D("string(float fieldnum)", "Retrieves the name of the given entity field.")},//DP_QC_ENTITYDATA
{"entityfieldtype", PF_entityfieldtype, 0, 0, 0, 498, D("float(float fieldnum)", "Provides information about the type of the field specified by the field num. Returns one of the EV_ values.")},//DP_QC_ENTITYDATA {"entityfieldtype", PF_entityfieldtype, 0, 0, 0, 498, D("float(float fieldnum)", "Provides information about the type of the field specified by the field num. Returns one of the EV_ values.")},//DP_QC_ENTITYDATA
{"getentityfieldstring",PF_getentityfieldstring,0,0, 0, 499, "string(float fieldnum, entity ent)"},//DP_QC_ENTITYDATA {"getentityfieldstring",PF_getentityfieldstring,0,0, 0, 499, "string(float fieldnum, entity ent)"},//DP_QC_ENTITYDATA
@ -10534,6 +10611,9 @@ void PR_DumpPlatform_f(void)
{"input_cursor_trace_endpos", "vector", CS/*|QW|NQ*/}, {"input_cursor_trace_endpos", "vector", CS/*|QW|NQ*/},
{"input_cursor_trace_entnum", "float", CS/*|QW|NQ*/}, {"input_cursor_trace_entnum", "float", CS/*|QW|NQ*/},
{"trace_brush_id", "float", QW|NQ|CS},
{"trace_brush_faceid", "float", QW|NQ|CS},
#define comfieldfloat(name,desc) {#name, ".float", FL, desc}, #define comfieldfloat(name,desc) {#name, ".float", FL, desc},
#define comfieldvector(name,desc) {#name, ".vector", FL, desc}, #define comfieldvector(name,desc) {#name, ".vector", FL, desc},
#define comfieldentity(name,desc) {#name, ".entity", FL, desc}, #define comfieldentity(name,desc) {#name, ".entity", FL, desc},
@ -10603,7 +10683,7 @@ void PR_DumpPlatform_f(void)
{"GameCommand", "noref void(string cmdtext)", CS|MENU}, {"GameCommand", "noref void(string cmdtext)", CS|MENU},
{"init", "noref void()", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget)."}, {"init", "noref void(float prevprogs)", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called as soon as a progs is loaded, called at a time when entities are not valid. This is the only time when it is safe to call addprogs without field assignment. As it is also called as part of addprogs, this also gives you a chance to hook functions in modules that are already loaded (via externget+externget)."},
{"initents", "noref void()", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules."}, {"initents", "noref void()", QW|NQ|CS, "Part of FTE_MULTIPROGS. Called after fields have been finalized. This is the first point at which it is safe to call spawn(), and is called before any entity fields have been parsed. You can use this entrypoint to send notifications to other modules."},
{"m_init", "void()", MENU}, {"m_init", "void()", MENU},
@ -10870,6 +10950,7 @@ void PR_DumpPlatform_f(void)
{"gamestate", "hashtable", ALL, "Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted).", 0}, {"gamestate", "hashtable", ALL, "Special hash table index for hash_add and hash_get. Entries in this table will persist over map changes (and doesn't need to be created/deleted).", 0},
{"HASH_REPLACE", "const float", ALL, "Used with hash_add. Attempts to remove the old value instead of adding two values for a single key.", 256}, {"HASH_REPLACE", "const float", ALL, "Used with hash_add. Attempts to remove the old value instead of adding two values for a single key.", 256},
{"HASH_ADD", "const float", ALL, "Used with hash_add. The new entry will be inserted in addition to the existing entry.", 512},
{"STAT_HEALTH", "const float", CS, "Player's health.", STAT_HEALTH}, {"STAT_HEALTH", "const float", CS, "Player's health.", STAT_HEALTH},
{"STAT_WEAPONMODELI", "const float", CS, "This is the modelindex of the current viewmodel (renamed from the original name 'STAT_WEAPON' due to confusions).", STAT_WEAPONMODELI}, {"STAT_WEAPONMODELI", "const float", CS, "This is the modelindex of the current viewmodel (renamed from the original name 'STAT_WEAPON' due to confusions).", STAT_WEAPONMODELI},
@ -10920,7 +11001,7 @@ void PR_DumpPlatform_f(void)
{"VF_CL_VIEWANGLES_Z", "const float", CS, NULL, VF_CL_VIEWANGLES_Z}, {"VF_CL_VIEWANGLES_Z", "const float", CS, NULL, VF_CL_VIEWANGLES_Z},
{"VF_PERSPECTIVE", "const float", CS|MENU, "1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport.", VF_PERSPECTIVE}, {"VF_PERSPECTIVE", "const float", CS|MENU, "1: regular rendering. Fov specifies the angle. 0: isometric-style. Fov specifies the number of Quake Units each side of the viewport.", VF_PERSPECTIVE},
{"VF_LPLAYER", "const float", CS, "The 'seat' number, used when running splitscreen.", VF_LPLAYER}, {"VF_ACTIVESEAT", "#define VF_LPLAYER VF_ACTIVESEAT\nconst float", CS, "The 'seat' number, used when running splitscreen.", VF_ACTIVESEAT},
{"VF_AFOV", "const float", CS|MENU, "Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you.", VF_AFOV}, {"VF_AFOV", "const float", CS|MENU, "Aproximate fov. Matches the 'fov' cvar. The engine handles the aspect ratio for you.", VF_AFOV},
{"VF_SCREENVSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect).", VF_SCREENVSIZE}, {"VF_SCREENVSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current virtual screen size (even if the screen is automatically scaled to retain aspect).", VF_SCREENVSIZE},
{"VF_SCREENPSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect).", VF_SCREENPSIZE}, {"VF_SCREENPSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect).", VF_SCREENPSIZE},
@ -11561,19 +11642,19 @@ void PR_DumpPlatform_f(void)
VFS_PRINTF(f, VFS_PRINTF(f,
"accessor hashtable : float\n{\n" "accessor hashtable : float\n{\n"
"\tinline get vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);};\n" "\tinline get vector v[string key] = {return hash_get(this, key, '0 0 0', EV_VECTOR);};\n"
"\tinline set vector v[string key] = {hash_add(this, key, value, 1, EV_VECTOR);};\n" "\tinline set vector v[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_VECTOR);};\n"
"\tinline get string s[string key] = {return hash_get(this, key, \"\", EV_STRING);};\n" "\tinline get string s[string key] = {return hash_get(this, key, \"\", EV_STRING);};\n"
"\tinline set string s[string key] = {hash_add(this, key, value, 1, EV_STRING);};\n" "\tinline set string s[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_STRING);};\n"
"\tinline get string f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);};\n" "\tinline get string f[string key] = {return hash_get(this, key, 0.0, EV_FLOAT);};\n"
"\tinline set string f[string key] = {hash_add(this, key, value, 1, EV_FLOAT);};\n" "\tinline set string f[string key] = {hash_add(this, key, value, HASH_REPLACE|EV_FLOAT);};\n"
"\tinline get __variant[string key] = {return hash_get(this, key, __NULL__);};\n" "\tinline get __variant[string key] = {return hash_get(this, key, __NULL__);};\n"
"\tinline set __variant[string key] = {hash_add(this, key, value, 1);};\n" "\tinline set __variant[string key] = {hash_add(this, key, value, HASH_REPLACE);};\n"
"};\n"); "};\n");
VFS_PRINTF(f, VFS_PRINTF(f,
"accessor infostring : string\n{\n" "accessor infostring : string\n{\n"
"\tget string[string] = infoget;\n" "\tget string[string] = infoget;\n"
#ifdef QCGC #ifdef QCGC
"\tinline set* string[string] = {(*this) = infoadd(*this, value);};\n" "\tinline set* string[string fld] = {(*this) = infoadd(*this, fld, value);};\n"
#endif #endif
"};\n"); "};\n");
VFS_PRINTF(f, VFS_PRINTF(f,

View file

@ -93,8 +93,18 @@ typedef struct
char fatness; char fatness;
} mvdentity_state_t; } mvdentity_state_t;
typedef struct
{
vec3_t position;
unsigned short soundnum;
qbyte volume;
qbyte attenuation;
} staticsound_state_t;
extern entity_state_t *sv_staticentities; extern entity_state_t *sv_staticentities;
extern int sv_max_staticentities; extern int sv_max_staticentities;
extern staticsound_state_t *sv_staticsounds;
extern int sv_max_staticsounds;
typedef struct typedef struct
{ {
@ -271,6 +281,7 @@ typedef struct
//end this lot... (demo playback) //end this lot... (demo playback)
int num_static_entities; int num_static_entities;
int num_static_sounds;
svcustomtents_t customtents[255]; svcustomtents_t customtents[255];
@ -354,6 +365,7 @@ enum
PRESPAWN_CUSTOMTENTS, PRESPAWN_CUSTOMTENTS,
PRESPAWN_SIGNON_BUF, PRESPAWN_SIGNON_BUF,
PRESPAWN_SPAWNSTATIC, PRESPAWN_SPAWNSTATIC,
PRESPAWN_AMBIENTSOUND,
PRESPAWN_BASELINES, PRESPAWN_BASELINES,
PRESPAWN_DONE PRESPAWN_DONE
}; };
@ -376,6 +388,8 @@ typedef struct client_s
unsigned int prespawn_stage; unsigned int prespawn_stage;
unsigned int prespawn_idx; unsigned int prespawn_idx;
qboolean prespawn_allow_modellist;
qboolean prespawn_allow_soundlist;
int spectator; // non-interactive int spectator; // non-interactive
int redirect; int redirect;

View file

@ -349,12 +349,20 @@ static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void
if (name[5] == 'b' && name[6] == '_') //skip box models if (name[5] == 'b' && name[6] == '_') //skip box models
return true; return true;
COM_StripExtension(name+5, stripped, sizeof(stripped)); COM_StripExtension(name+5, stripped, sizeof(stripped));
Con_Printf("^[%s\\map\\%s^]\n", stripped, stripped); Con_Printf("^[[%s]\\map\\%s^]\n", stripped, stripped);
return true;
}
static int QDECL ShowMapListExt (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
if (name[5] == 'b' && name[6] == '_') //skip box models
return true;
Con_Printf("^[[%s]\\map\\%s^]\n", name+5, name+5);
return true; return true;
} }
static void SV_MapList_f(void) static void SV_MapList_f(void)
{ {
COM_EnumerateFiles("maps/*.bsp", ShowMapList, NULL); COM_EnumerateFiles("maps/*.bsp", ShowMapList, NULL);
COM_EnumerateFiles("maps/*.map", ShowMapListExt, NULL);
COM_EnumerateFiles("maps/*.cm", ShowMapList, NULL); COM_EnumerateFiles("maps/*.cm", ShowMapList, NULL);
COM_EnumerateFiles("maps/*.hmp", ShowMapList, NULL); COM_EnumerateFiles("maps/*.hmp", ShowMapList, NULL);
} }
@ -413,7 +421,10 @@ void SV_Map_f (void)
if (Cmd_Argc() != 2 && Cmd_Argc() != 3) if (Cmd_Argc() != 2 && Cmd_Argc() != 3)
{ {
Con_TPrintf ("%s <levelname> <startspot>: change the level\n", Cmd_Argv(0)); if (Cmd_IsInsecure())
return;
Con_TPrintf ("Available maps:\n", Cmd_Argv(0));
SV_MapList_f();
return; return;
} }
@ -458,7 +469,7 @@ void SV_Map_f (void)
if (!strcmp(level, ".")) //restart current if (!strcmp(level, ".")) //restart current
{ {
//grab the current map name //grab the current map name
COM_StripExtension(COM_SkipPath(sv.modelname), level, sizeof(level)); Q_strncpyz(level, sv.name, sizeof(level));
isrestart = true; isrestart = true;
flushparms = false; flushparms = false;
newunit = false; newunit = false;
@ -505,7 +516,7 @@ void SV_Map_f (void)
} }
else else
{ {
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", "maps/%s.map", NULL}; char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ NULL};
int i, j; int i, j;
for (i = 0; exts[i]; i++) for (i = 0; exts[i]; i++)

View file

@ -30,6 +30,8 @@ server_t sv; // local server
entity_state_t *sv_staticentities; entity_state_t *sv_staticentities;
int sv_max_staticentities; int sv_max_staticentities;
staticsound_state_t *sv_staticsounds;
int sv_max_staticsounds;
char localinfo[MAX_LOCALINFO_STRING+1]; // local game info char localinfo[MAX_LOCALINFO_STRING+1]; // local game info
@ -937,7 +939,9 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
else else
#endif #endif
{ {
char *exts[] = {"maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", "maps/%s.map", NULL}; //.map is commented out because quite frankly, they're a bit annoying when the engine loads the gpled start.map when really you wanted to just play the damn game intead of take it apart.
//if you want to load a .map, just use 'map foo.map' instead.
char *exts[] = {"maps/%s", "maps/%s.bsp", "maps/%s.cm", "maps/%s.hmp", /*"maps/%s.map",*/ NULL};
int depth, bestdepth; int depth, bestdepth;
Q_strncpyz (sv.name, server, sizeof(sv.name)); Q_strncpyz (sv.name, server, sizeof(sv.name));
Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[0], server); Q_snprintfz (sv.modelname, sizeof(sv.modelname), exts[0], server);
@ -1004,7 +1008,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
sv.csqcchecksum = Com_BlockChecksum(file, fsz); sv.csqcchecksum = Com_BlockChecksum(file, fsz);
sprintf(text, "0x%x", sv.csqcchecksum); sprintf(text, "0x%x", sv.csqcchecksum);
Info_SetValueForStarKey(svs.info, "*csprogs", text, MAX_SERVERINFO_STRING); Info_SetValueForStarKey(svs.info, "*csprogs", text, MAX_SERVERINFO_STRING);
sprintf(text, "0x%x", fsz); sprintf(text, "0x%x", (unsigned int)fsz);
Info_SetValueForStarKey(svs.info, "*csprogssize", text, MAX_SERVERINFO_STRING); Info_SetValueForStarKey(svs.info, "*csprogssize", text, MAX_SERVERINFO_STRING);
if (strcmp(sv_csqc_progname.string, "csprogs.dat")) if (strcmp(sv_csqc_progname.string, "csprogs.dat"))
Info_SetValueForStarKey(svs.info, "*csprogsname", sv_csqc_progname.string, MAX_SERVERINFO_STRING); Info_SetValueForStarKey(svs.info, "*csprogsname", sv_csqc_progname.string, MAX_SERVERINFO_STRING);

Some files were not shown because too many files have changed in this diff Show more