1
0
Fork 0
forked from fte/fteqw

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_maxyaw = {"cl_camera_maxyaw", "30" };
static int Cam_FindSortedPlayer(int number);
int selfcam=1;
@ -524,6 +525,15 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
if (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++)
{
if (i == MAX_CLIENTS)
@ -550,6 +560,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
}
}
}
#endif
return;
}
}
@ -612,7 +623,9 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
do
{
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);
return;
@ -622,7 +635,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
// stay on same guy?
i = pv->cam_spec_track;
s = &cl.players[i];
if (s->name[0] && !s->spectator)
if (s->name[0] && !s->spectator && s->userid)
{
Cam_Lock(pv, i);
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)
{
playerview_t *pv = &cl.playerview[seat];
int slot;
int slot, sortednum;
player_info_t *s;
char *e;
if (seat >= MAX_SPLITS)
return;
@ -669,12 +717,17 @@ void Cam_TrackPlayer(int seat, char *cmdname, char *plrarg)
return;
}
// search nicks first
for (slot = 0; slot < cl.allocated_client_slots; slot++)
if (*plrarg == '#' && (slot=strtoul(plrarg+1, &e, 10)) && !*e)
slot = Cam_FindSortedPlayer(slot);
else
{
s = &cl.players[slot];
if (s->name[0] && !s->spectator && !Q_strcasecmp(s->name, plrarg))
break;
// search nicks first
for (slot = 0; slot < cl.allocated_client_slots; slot++)
{
s = &cl.players[slot];
if (s->name[0] && !s->spectator && !Q_strcasecmp(s->name, plrarg))
break;
}
}
if (slot == cl.allocated_client_slots)

View file

@ -3522,9 +3522,15 @@ void CL_LinkPacketEntities (void)
//set scale
ent->scale = state->scale/16.0;
#endif
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;
if (state->colormod[0] == 32 && state->colormod[1] == 32 && state->colormod[2] == 32)
ent->shaderRGBAf[0] = ent->shaderRGBAf[1] = ent->shaderRGBAf[2] = 1;
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;
#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;
#define IN_IMPULSECACHE 256
#define IN_IMPULSECACHE 32
int in_impulse[MAX_SPLITS][IN_IMPULSECACHE];
int in_nextimpulse[MAX_SPLITS];
int in_impulsespending[MAX_SPLITS];
@ -837,7 +837,6 @@ CL_FinishMove
void CL_FinishMove (usercmd_t *cmd, int msecs, int pnum)
{
int i;
int bits;
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_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[1] * 32767.0f);
MSG_WriteFloat(buf, cmd->cursor_start[0]);
@ -1895,7 +1894,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cls.protocol == CP_QUAKE2)
S_Voip_Transmit(clcq2_voicechat, &buf);
else
S_Voip_Transmit(clc_voicechat, &buf);
S_Voip_Transmit(clcfte_voicechat, &buf);
#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 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_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
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);
@ -718,12 +719,12 @@ void CL_CheckForResend (void)
}
else if (!strcmp(cl_loopbackprotocol.string, "q3"))
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_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_nq = CPNQ_DP7;
@ -1817,6 +1818,8 @@ void CL_CheckServerInfo(void)
cls.allow_fbskins = atof(s);
else if (cl.teamfortress)
cls.allow_fbskins = 0;
else
cls.allow_fbskins = 1;
s = Info_ValueForKey(cl.serverinfo, "*cheats");
if (cl.spectator || cls.demoplayback || !stricmp(s, "on"))
@ -2335,7 +2338,7 @@ drop to full console
void CL_Changing_f (void)
{
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;
cls.demoseeking = false; //don't seek over it
@ -2370,7 +2373,7 @@ The server is changing levels
*/
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;
#ifdef NQPROT
if (cls.protocol == CP_NETQUAKE && Cmd_FromGamecode())
@ -2528,7 +2531,7 @@ void CL_ConnectionlessPacket (void)
if (c == S2C_CHALLENGE)
{
static unsigned int lasttime = 0xdeadbeef;
netadr_t lastadr;
static netadr_t lastadr;
unsigned int curtime = Sys_Milliseconds();
unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0;
Con_TPrintf ("challenge\n");
@ -2831,6 +2834,8 @@ client_connect: //fixme: make function
cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, cls.qport);
cls.netchan.fragmentsize = connectinfo.mtu;
if (connectinfo.mtu >= 64)
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
#ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc);
#else
@ -3635,10 +3640,11 @@ void CL_Init (void)
Cvar_Register (&requiredownloads, 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_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_splitscreen, cl_controlgroup);
@ -4258,7 +4264,7 @@ void Host_DoRunFile(hrf_t *f)
// if (f->flags & HRF_DOWNLOADED)
man->blockupdate = true;
BZ_Free(fdata);
FS_ChangeGame(man, true);
FS_ChangeGame(man, true, true);
}
else
{
@ -4457,7 +4463,7 @@ Runs all active servers
extern cvar_t cl_netfps;
extern cvar_t cl_sparemsec;
qboolean startuppending;
int startuppending;
void CL_StartCinematicOrMenu(void);
int nopacketcount;
void SNDDMA_SetUnderWater(qboolean underwater);
@ -4815,6 +4821,11 @@ void CL_StartCinematicOrMenu(void)
{
COM_MainThreadWork();
if (FS_DownloadingPackage())
{
startuppending = true;
return;
}
if (cls.download)
{
startuppending = true;
@ -4822,6 +4833,8 @@ void CL_StartCinematicOrMenu(void)
}
if (startuppending)
{
if (startuppending == 2)
Cbuf_AddText("\nfs_restart\nvid_restart\n", RESTRICT_LOCAL);
startuppending = false;
Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly.
}
@ -4831,7 +4844,9 @@ void CL_StartCinematicOrMenu(void)
UI_Start();
#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).
realtime+=1;
@ -4839,6 +4854,19 @@ void CL_StartCinematicOrMenu(void)
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
#ifndef NOMEDIA
#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.
//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();
@ -5028,6 +5059,11 @@ void Host_FinishLoading(void)
"\n"
"See the GNU General Public License for more details.\n");
#ifdef _WIN32
if (Sys_RunInstaller())
Sys_Quit();
#endif
Renderer_Start();
CL_StartCinematicOrMenu();
@ -5176,6 +5212,7 @@ void Host_Shutdown(void)
CL_FreeVisEdicts();
M_Shutdown(true);
Mod_Shutdown(true);
Wads_Flush();
#ifndef CLIENTONLY
SV_Shutdown();
#else

View file

@ -27,8 +27,6 @@ void CLDP_ParseDarkPlaces5Entities(void);
void CL_SetStatInt (int pnum, int stat, int value);
static qboolean CL_CheckModelResources (char *name);
int msgflags;
char cl_dp_csqc_progsname[128];
int cl_dp_csqc_progssize;
int cl_dp_csqc_progscrc;
@ -266,7 +264,7 @@ char *svc_nqstrings[] =
"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 parsecountmod;
double parsecounttime;
@ -5082,7 +5080,7 @@ void CLQ2_ParseInventory (void)
#endif
//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;
int flags;
@ -5167,35 +5165,11 @@ char *CL_ParseChat(char *text, player_info_t **player)
}
}
msgflags = flags;
*msgflags = flags;
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
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
{
//damn spies
if (!Q_strcasecmp(plr->team, "red"))
c = 1;
else if (!Q_strcasecmp(plr->team, "blue"))
c = 5;
else
// TODO: needs some work
switch (plr->rbottomcolor)
{ //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
// 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;
char *name = NULL;
@ -5307,12 +5287,12 @@ void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags)
char fullchatmessage[2048];
fullchatmessage[0] = 0;
if (plrflags & TPM_FAKED)
/*if (plrflags & TPM_FAKED)
{
name = rawmsg; // use rawmsg pointer and msg modification to generate null-terminated string
if (msg)
*(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] == ' ')
{
@ -5540,13 +5520,63 @@ void CL_PrintStandardMessage(char *msg, int printlevel)
// print final chunk
Q_strncatz(fullmessage, msg, sizeof(fullmessage));
#ifdef CSQC_DAT
if (CSQC_ParsePrint(fullmessage, printlevel))
return;
#endif
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];
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;
Cmd_TokenizeString(stufftext+2, false, false);
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
else if (!strncmp(stufftext, "//tinfo ", 8))
@ -5916,33 +5946,7 @@ void CLQW_ParseServerMessage (void)
case svc_print:
i = MSG_ReadByte ();
s = MSG_ReadString ();
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);
}
}
CL_ParsePrint(s, i);
break;
case svc_centerprint:
@ -6060,6 +6064,12 @@ void CLQW_ParseServerMessage (void)
break;
#endif
#ifdef TERRAIN
case svcfte_brushedit:
CL_Parse_BrushEdit();
break;
#endif
case svc_updatefrags:
Sbar_Changed ();
i = MSG_ReadByte ();
@ -6448,27 +6458,7 @@ void CLQ2_ParseServerMessage (void)
i = MSG_ReadByte ();
s = MSG_ReadString ();
if (i == PRINT_CHAT)
{
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);
}
}
CL_ParsePrint(s, i);
break;
case svcq2_stufftext: //11 // [string] stuffed into client's console buffer, should be \n terminated
s = MSG_ReadString ();
@ -6721,28 +6711,11 @@ void CLNQ_ParseServerMessage (void)
s = MSG_ReadString ();
if (*s == 1 || *s == 2)
{
char *msg;
player_info_t *plr = NULL;
if ((msg = CL_ParseChat(s+1, &plr)))
{
CL_ParsePrint(s+1, PRINT_CHAT);
CL_PrintChat(plr, s+1, msg, msgflags);
}
}
CL_ParsePrint(s+1, PRINT_CHAT);
else if (CLNQ_ParseNQPrints(s))
break;
else
{
if (CLNQ_ParseNQPrints(s))
break;
#ifdef PLUGINS
if (Plug_ServerMessage(s, PRINT_HIGH))
#endif
{
CL_ParsePrint(s, PRINT_HIGH);
CL_PrintStandardMessage(s, PRINT_HIGH);
}
}
CL_ParsePrint(s, PRINT_HIGH);
break;
case svc_disconnect:
@ -7117,7 +7090,7 @@ void CLNQ_ParseServerMessage (void)
CL_ParseStatic (3);
break;
case svcfitz_spawnstaticsound2:
Host_EndGame("svcfitz_spawnstaticsound2: not implemented");
CL_ParseStaticSound(true);
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)
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;
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)
return 0;
@ -79,7 +79,7 @@ pluginimagearray_t *pluginimagearray;
#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;
@ -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);
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;
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)))
{
name = va("%s/", name);
// name = va("%s", name);
t = Image_FindTexture(name, NULL, IF_NOMIPMAP|IF_UIPIC|IF_CLAMP);
if (!TEXVALID(t))
@ -162,13 +162,13 @@ qintptr_t VARGS Plug_Draw_LoadImageData(void *offset, quintptr_t mask, const qin
}
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 *script = VM_POINTER(arg[1]);
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]);
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)
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;
int i;
@ -238,7 +238,7 @@ qintptr_t VARGS Plug_Draw_Image(void *offset, quintptr_t mask, const qintptr_t *
return 1;
}
//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
{
@ -257,7 +257,7 @@ qintptr_t VARGS Plug_Draw_Line(void *offset, quintptr_t mask, const qintptr_t *a
}
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;
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);
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;
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;
}
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;
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);
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)
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);
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);
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]));
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)
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 pnum = VM_LONG(arg[0]);
@ -383,7 +383,7 @@ typedef struct {
char team[8];
} 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;
vmplugclientinfo_t *out;
@ -427,12 +427,12 @@ qintptr_t VARGS Plug_GetPlayerInfo(void *offset, quintptr_t mask, const qintptr_
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;
}
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]);
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;
}
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 *value = VM_POINTER(arg[1]);
@ -455,7 +455,7 @@ qintptr_t VARGS Plug_SetUserInfo(void *offset, quintptr_t mask, const qintptr_t
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]);
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]);
}
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 *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;
}
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]);
console_t *con;
@ -525,7 +525,7 @@ qintptr_t VARGS Plug_Con_RenameSub(void *offset, quintptr_t mask, const qintptr_
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]);
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);
}
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]);
console_t *con;
@ -550,7 +550,7 @@ qintptr_t VARGS Plug_Con_SetActive(void *offset, quintptr_t mask, const qintptr_
Con_SetActive(con);
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]);
console_t *con;
@ -563,7 +563,7 @@ qintptr_t VARGS Plug_Con_Destroy(void *offset, quintptr_t mask, const qintptr_t
Con_Destroy(con);
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 *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);
}
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]);
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"
#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;
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;
return Mod_RegisterModelFormatMagic(module, formatname, magic, load);
}
void QDECL Plug_UnRegisterModelFormat(int idx)
static void QDECL Plug_UnRegisterModelFormat(int idx)
{
void *module = currentplug;
Mod_UnRegisterModelFormat(module, idx);
}
void QDECL Plug_UnRegisterAllModelFormats(void)
static void QDECL Plug_UnRegisterAllModelFormats(void)
{
void *module = currentplug;
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_Destroy", Plug_Con_Destroy, 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("SCR_CenterPrint", Plug_SCR_CenterPrint, PLUG_BIF_NEEDSRENDERER);

View file

@ -560,15 +560,7 @@ void CL_CalcClientTime(void)
extern float olddemotime;
cl.servertime = olddemotime;
}
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD && !(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
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)))
if (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !cls.demoplayback)) && cls.demoplayback != DPB_MVD)
{
float f;
f = cl.gametime - cl.oldgametime;

View file

@ -93,7 +93,7 @@ void RSpeedShow(void)
}
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);
}
if (r_speeds.ival > 1)
@ -245,6 +245,7 @@ void *scr_curcursor;
extern char cl_screengroup[];
void CLSCR_Init(void)
{
int i;
Cmd_AddCommand("cprint", SCR_CPrint_f);
Cvar_Register(&con_stayhidden, cl_screengroup);
@ -265,6 +266,8 @@ void CLSCR_Init(void)
memset(&key_customcursor, 0, sizeof(key_customcursor));
for (i = 0; i < kc_max; i++)
key_customcursor[i].dirty = true;
scr_curcursor = NULL;
if (rf && rf->VID_SetCursor)
rf->VID_SetCursor(scr_curcursor);
@ -417,6 +420,25 @@ void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode)
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)
{
if (Cmd_Argc() == 2)
@ -650,7 +672,7 @@ void SCR_DrawCursor(void)
return;
//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;
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].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;
oldcurs = key_customcursor[cmod].handle;
if (rf->VID_CreateCursor)
@ -1173,7 +1202,7 @@ void SCR_Init (void)
//
// 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 ("sizeup",SCR_SizeUp_f);
Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
@ -1794,7 +1823,7 @@ SCR_SetUpToDrawConsole
*/
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
//extern qboolean editoractive; //unused variable
#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))
{
//go fullscreen if we're not doing anything
if (con_curwindow && !cls.state)
{
Key_Dest_Add(kdm_cwindows);
scr_conlines = 0;
}
#ifdef VM_UI
if (UI_MenuState() || UI_OpenMenu())
else if (UI_MenuState() || UI_OpenMenu())
scr_con_current = scr_conlines = 0;
else
#endif
else
{
if (cls.state < ca_demostart)
{
if (con_stayhidden.ival)
{
extern qboolean startuppending;
extern int startuppending;
scr_conlines = 0;
if (SCR_GetLoadingStage() == LS_NONE)
{
@ -1845,7 +1879,7 @@ void SCR_SetUpToDrawConsole (void)
if (!con_stayhidden.ival && !startuppending && Key_Dest_Has(kdm_console))
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
scr_conlines = vid.height*scr_consize.value; // half screen
@ -1891,16 +1925,16 @@ SCR_DrawConsole
*/
void SCR_DrawConsole (qboolean noback)
{
if (scr_con_current)
{
Con_DrawConsole (scr_con_current, noback);
clearconsole = 0;
}
else
if (!scr_con_current)
{
if (!Key_Dest_Has(kdm_console|kdm_menu))
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 fbheight = strtoul(Cmd_Argv(3), NULL, 0);
if (Cmd_IsInsecure())
return;
if (qrenderer <= QR_HEADLESS)
{
Con_Printf("No renderer active\n");
@ -2177,7 +2214,12 @@ void SCR_ScreenShot_Mega_f(void)
rgbbuffer = VID_GetRGBInfo(0, &width, &height);
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);
}
}
@ -2452,6 +2494,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud)
{
SCR_DrawFPS ();
SCR_DrawUPS ();
SCR_DrawClock();
SCR_DrawGameClock();
}
SCR_CheckDrawCenterString ();
}

View file

@ -1475,7 +1475,7 @@ qboolean Stats_HaveKills(void);
void VARGS Stats_Message(char *msg, ...) LIKEPRINTF(1);
int qm_strcmp(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_Clear(void);

View file

@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "quakedef.h"
console_t con_main;
console_t *con_curwindow;
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_chat; // points to a chat console
@ -128,8 +129,6 @@ void Con_Destroy (console_t *con)
return;
}
con_mouseover = NULL;
for (prev = &con_main; prev->next; prev = prev->next)
{
if (prev->next == con)
@ -143,6 +142,18 @@ void Con_Destroy (console_t *con)
if (con_current == con)
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*/
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*/
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)
{
@ -186,6 +204,7 @@ void Con_SetActive (console_t *con)
Z_Free(con->footerline);
con->footerline = NULL;
}
con->buttonsdown = CB_NONE;
}
/*for enumerating consoles*/
qboolean Con_NameForNum(int num, char *buffer, int buffersize)
@ -448,6 +467,20 @@ void Con_ToggleConsole_Force(void)
void Con_ToggleConsole_f (void)
{
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
if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole"))
{
@ -457,7 +490,10 @@ void Con_ToggleConsole_f (void)
#endif
if (con_stayhidden.ival >= 3)
{
Key_Dest_Remove(kdm_cwindows);
return; //its hiding!
}
Con_ToggleConsole_Force();
}
@ -672,6 +708,12 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
conchar_t *c;
conline_t *oc;
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);
@ -690,7 +732,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
case '\n':
con->cr = false;
reuse = NULL;
while (con->linecount >= con_maxlines.ival)
while (con->linecount >= maxlines)
{
if (con->oldest == con->current)
break;
@ -714,7 +756,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
if (con->flags & CONF_NOTIMES)
con->current->time = 0;
else
con->current->time = realtime;
con->current->time = realtime + con->notif_t;
#if defined(_WIN32) && !defined(NOMEDIA) && !defined(WINRT)
if (con->current)
@ -789,7 +831,7 @@ void Con_PrintCon (console_t *con, char *txt, unsigned int parseflags)
if (con->flags & CONF_NOTIMES)
con->current->time = 0;
else
con->current->time = realtime;
con->current->time = realtime + con->notif_t;
}
void Con_Print (char *txt)
@ -811,7 +853,7 @@ void Con_CycleConsole(void)
if (!con_current)
con_current = &con_main;
if (con_current->flags & CONF_HIDDEN)
if (con_current->flags & (CONF_HIDDEN|CONF_ISWINDOW))
continue;
break;
}
@ -960,14 +1002,15 @@ void VARGS Con_DPrintf (const char *fmt, ...)
}
/*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;
char msg[MAXPRINTMSG];
conchar_t marked[MAXPRINTMSG], *markedend;
int oldlen, newlen;
conline_t *newf;
if (!con)
con = con_current;
va_start (argptr,fmt);
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;
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.
}
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)
{
conchar_t *starts[NUM_CON_TIMES], *ends[NUM_CON_TIMES];
float alphas[NUM_CON_TIMES], a;
conchar_t *c;
conline_t *l;
int lines=con->notif_l;
int line;
int x = con->notif_x, y = con->notif_y;
int w = con->notif_w;
int nx, y;
int nw;
int x;
int maxlines;
float t;
Font_BeginString(font_console, x, y, &x, &y);
Font_Transform(con->notif_w, 0, &w, NULL);
Font_BeginString(font_console, con->notif_x * vid.width, con->notif_y * vid.height, &nx, &y);
Font_Transform(con->notif_w * vid.width, 0, &nw, NULL);
if (con->notif_l < 0)
con->notif_l = 0;
@ -1222,8 +1273,8 @@ void Con_DrawNotifyOne (console_t *con)
con->notif_l = NUM_CON_TIMES;
lines = maxlines = con->notif_l;
if (x == 0 && y == 0 && con->notif_w == vid.width)
y = Con_DrawProgress(0, w, 0);
if (!con->notif_x && !con->notif_y && con->notif_w == 1)
y = Con_DrawProgress(0, nw, 0);
l = con->current;
if (!l->length)
@ -1234,21 +1285,31 @@ void Con_DrawNotifyOne (console_t *con)
if (!t)
continue; //hidden from notify
t = realtime - t;
if (t > con->notif_t)
break;
if (t > 0)
{
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)
{
lines--;
starts[lines] = NULL;
ends[lines] = NULL;
alphas[lines] = a;
}
while(line --> 0 && lines > 0)
{
lines--;
starts[lines] = starts[line];
ends[lines] = ends[line];
alphas[lines] = a;
}
if (lines == 0)
break;
@ -1265,15 +1326,24 @@ void Con_DrawNotifyOne (console_t *con)
while (lines < con->notif_l)
{
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++)
{
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();
@ -1281,6 +1351,8 @@ void Con_DrawNotifyOne (console_t *con)
}
Font_EndString(font_console);
Font_InvalidateColour();
}
void Con_ClearNotify(void)
@ -1295,20 +1367,20 @@ void Con_ClearNotify(void)
}
void Con_DrawNotify (void)
{
extern qboolean startuppending;
extern int startuppending;
console_t *con;
con_main.flags |= CONF_NOTIFY;
/*keep the main console up to date*/
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;
if (con_chat)
{
con_chat->notif_l = con_numnotifylines_chat.ival;
con_chat->notif_w = vid.width - 64;
con_chat->notif_y = vid.height - sb_lines - 8*4;
con_chat->notif_w = 1;
con_chat->notif_y = (vid.height - sb_lines - 8*4) / vid.width;
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?"+":"");
}
//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
{
@ -1568,11 +1646,9 @@ int Con_DrawAlternateConsoles(int lines)
console_t *con = &con_main, *om = con_mouseover;
conchar_t buffer[512], *end, *start;
con_mouseover = NULL;
for (con = &con_main; con; con = con->next)
{
if (!(con->flags & CONF_HIDDEN))
if (!(con->flags & (CONF_HIDDEN|CONF_ISWINDOW)))
consshown++;
}
@ -1584,7 +1660,7 @@ int Con_DrawAlternateConsoles(int lines)
h = Font_CharHeight();
for (x = 0, con = &con_main; con; con = con->next)
{
if (con->flags & CONF_HIDDEN)
if (con->flags & (CONF_HIDDEN|CONF_ISWINDOW))
continue;
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;
int i;
int x;
int charh = Font_CharHeight();
if (l != con->completionline)
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
selsy -= y;
seley -= y;
selsy /= Font_CharHeight();
seley /= Font_CharHeight();
selsy--;
seley--;
// selsy -= charh;
// seley -= charh;
//invert the selections to make sense, text-wise
if (selsy == seley)
/*if (selsy == seley)
{
//single line selected backwards
if (selex < selsx)
@ -1684,6 +1759,7 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
selsx = x;
}
}
*/
if (seley < selsy)
{ //selection goes upwards
x = selsy;
@ -1694,8 +1770,8 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
selex = selsx;
selsx = x;
}
selsy *= Font_CharHeight();
seley *= Font_CharHeight();
// selsy *= Font_CharHeight();
// seley *= Font_CharHeight();
selsy += 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");
if (*imgname)
picw = atoi(imgname);
picw = (atoi(imgname) * charh) / 8.0;
else if (pic->width)
picw = (pic->width * vid.pixelwidth) / vid.width;
else
picw = 64;
imgname = Info_ValueForKey(linkinfo, "h");
if (*imgname)
pich = atoi(imgname);
pich = (atoi(imgname) * charh) / 8.0;
else if (pic->height)
pich = (pic->height * vid.pixelheight) / vid.height;
else
@ -1773,6 +1849,9 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
pich -= texth;
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;
@ -1789,9 +1868,9 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
if (selactive)
{
if (y >= selsy)
if (y+charh >= selsy)
{
if (y <= seley)
if (y < seley)
{
int sstart;
int send;
@ -1804,7 +1883,17 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
if (send == sstart)
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;
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
con->selendoffset = 0;
}
if (y <= selsy)
if (y < selsy)
{
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
con->selstartoffset = 0;
}
if (selactive == 1)
{
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 top;
qboolean haveprogress;
console_t *w, *mouseconsole;
if (lines <= 0)
return;
con_mouseover = NULL;
//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
if (qterms)
QT_Update();
if (qterms)
QT_Update();
#endif
// draw the background
if (!noback)
R2D_ConsoleBackground (0, lines, scr_con_forcedraw);
if (!noback)
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)
con_current->display = con_current->current;
if (!con_current->display)
con_current->display = con_current->current;
x = 8;
y = lines;
x = 8;
y = lines;
con_current->mousecursor[0] = mousecursor_x;
con_current->mousecursor[1] = mousecursor_y;
con_current->selstartline = NULL;
con_current->selendline = NULL;
selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley);
con_current->mousecursor[0] = mousecursor_x;
con_current->mousecursor[1] = mousecursor_y;
con_current->selstartline = NULL;
con_current->selendline = NULL;
selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley);
Font_BeginString(font_console, x, y, &x, &y);
Font_BeginString(font_console, selsx, selsy, &selsx, &selsy);
Font_BeginString(font_console, selex, seley, &selex, &seley);
ex = Font_ScreenWidth();
sx = x;
ex -= sx;
Font_BeginString(font_console, x, y, &x, &y);
Font_BeginString(font_console, selsx, selsy, &selsx, &selsy);
Font_BeginString(font_console, selex, seley, &selex, &seley);
ex = Font_ScreenWidth();
sx = x;
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();
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);
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();
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 (con_current->selstartline)
if (mouseconsole && mouseconsole->selstartline)
{
char *mouseover = Con_CopyConsole(false, true);
char *mouseover = Con_CopyConsole(mouseconsole, false, true);
if (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 x, y, sx, sy;
@ -2018,7 +2184,7 @@ void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy,
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)
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;
conline_t *l;
conchar_t *lend;

View file

@ -53,6 +53,7 @@ typedef struct {
stat ownsuicides;
char *fullname;
char *abrev;
char *image;
char *codename;
} weapontotals[MAX_WEAPONS];
@ -75,6 +76,7 @@ typedef struct {
statmessage_t *message;
} 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;
int Stats_GetKills(int playernum)
@ -107,8 +109,149 @@ qboolean Stats_HaveKills(void)
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)
@ -126,6 +269,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
u1 = (p1 == (cl.playerview[0].playernum));
u2 = (p2 == (cl.playerview[0].playernum));
//messages are killed weapon killer
switch(mt)
{
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].ownkills++;
}
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].deaths++;
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;
case ff_suicide:
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].owndeaths++;
fragstats.weapontotals[wid].ownkills++;
Stats_Message("You are a fool\n");
}
fragstats.weapontotals[wid].suicides++;
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].suisides++;
fragstats.clienttotals[p1].deaths++;
fragstats.totalsuicides++;
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;
case ff_bonusfrag:
if (u1)
@ -160,6 +313,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].kills++;
fragstats.clienttotals[p1].kills++;
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;
case ff_tkbonus:
if (u1)
@ -173,6 +330,11 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.weapontotals[wid].teamkills++;
fragstats.clienttotals[p1].teamkills++;
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;
case ff_flagtouch:
fragstats.clienttotals[p1].grabs++;
@ -180,8 +342,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
{
Stats_Message("You grabbed the flag\n");
Stats_Message("flag grabs: %i (%i)\n", fragstats.clienttotals[p1].grabs, fragstats.totaltouches);
Stats_Message("You grabbed the flag\nflag grabs: %i (%i)\n", fragstats.clienttotals[p1].grabs, fragstats.totaltouches);
}
break;
case ff_flagcaps:
@ -190,8 +351,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
{
Stats_Message("You captured the flag\n");
Stats_Message("flag captures: %i (%i)\n", fragstats.clienttotals[p1].caps, fragstats.totalcaps);
Stats_Message("You captured the flag\nflag captures: %i (%i)\n", fragstats.clienttotals[p1].caps, fragstats.totalcaps);
}
break;
case ff_flagdrops:
@ -200,8 +360,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
{
Stats_Message("You dropped the flag\n");
Stats_Message("flag drops: %i (%i)\n", fragstats.clienttotals[p1].drops, fragstats.totaldrops);
Stats_Message("You dropped the flag\nflag drops: %i (%i)\n", fragstats.clienttotals[p1].drops, fragstats.totaldrops);
}
break;
@ -215,8 +374,7 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u1)
{
fragstats.weapontotals[wid].owndeaths++;
Stats_Message("%s killed you\n", cl.players[p2].name);
Stats_Message("%s deaths: %i (%i/%i)\n", fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].owndeaths, fragstats.weapontotals[wid].owndeaths, fragstats.totaldeaths);
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);
}
fragstats.clienttotals[p2].kills++;
@ -224,9 +382,10 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
if (u2)
{
fragstats.weapontotals[wid].ownkills++;
Stats_Message("You killed %s\n", cl.players[p1].name);
Stats_Message("%s kills: %i (%i/%i)\n", fragstats.weapontotals[wid].fullname, fragstats.clienttotals[p2].kills, fragstats.weapontotals[wid].kills, fragstats.totalkills);
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_FragMessage(p1, wid, p2, false);
break;
case ff_tkdeath:
//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.totalteamkills++;
if (u1)
fragstats.weapontotals[wid].owndeaths++;
fragstats.clienttotals[p1].teamdeaths++;
fragstats.clienttotals[p1].deaths++;
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;
case ff_tkills:
@ -266,6 +432,12 @@ void Stats_Evaluate(fragfilemsgtypes_t mt, int wid, int p1, int p2)
fragstats.totalkills++;
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;
}
}
@ -344,6 +516,7 @@ void Stats_Clear(void)
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].abrev) Z_Free(fragstats.weapontotals[i].abrev);
if (fragstats.weapontotals[i].image) Z_Free(fragstats.weapontotals[i].image);
}
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].abrev = Z_Copy(Cmd_Argv(4));
fragstats.weapontotals[wid].image = Stats_GenTrackerImageString(Cmd_Argv(5));
}
}
else if (!stricmp(tk, "obituary") ||
@ -526,7 +700,7 @@ static int Stats_ExtractName(char **line)
return bm;
}
void Stats_ParsePrintLine(char *line)
qboolean Stats_ParsePrintLine(char *line)
{
statmessage_t *ms;
int p1;
@ -536,7 +710,7 @@ void Stats_ParsePrintLine(char *line)
p1 = Stats_ExtractName(&line);
if (p1<0) //reject it.
{
return;
return false;
}
for (ms = fragstats.message; ms; ms = ms->next)
@ -552,16 +726,17 @@ void Stats_ParsePrintLine(char *line)
if (!qm_stricmp(ms->msgpart2, m2))
{
Stats_Evaluate(ms->type, ms->wid, p1, p2);
return; //done.
return true; //done.
}
}
else
{ //one player
Stats_Evaluate(ms->type, ms->wid, p1, p1);
return; //done.
return true; //done.
}
}
}
return false;
}
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)
{
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);
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)
{
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)
@ -2820,7 +2820,7 @@ static void Image_GenerateMips(struct pendingtextureinfo *mips, unsigned int fla
case PTI_RGBX8:
case PTI_BGRA8:
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].height = mips->mip[mip-1].height >> 1;
@ -3418,7 +3418,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_RGBA32F:
if (rawdata)
{
Con_Printf("R_LoadRawTexture: bad format");
Con_Printf("R_LoadRawTexture: bad format\n");
if (freedata)
BZ_Free(rawdata);
return false;
@ -3428,7 +3428,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
default:
case TF_INVALID:
Con_Printf("R_LoadRawTexture: bad format");
Con_Printf("R_LoadRawTexture: bad format\n");
if (freedata)
BZ_Free(rawdata);
return false;
@ -3444,9 +3444,78 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_BGRA32:
mips->encoding = PTI_BGRA8;
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:
mips->encoding = PTI_R8;
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:
rgbadata = BZ_Malloc(imgwidth * imgheight*4);
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 *tex;
static int seq;
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
Sys_LockMutex(com_resourcemutex);
@ -4214,16 +4286,16 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
tex->status = TEX_LOADING;
if (fallbackdata)
{
int b, pb = 0;
int b = fallbackwidth*fallbackheight, pb = 0;
switch(fallbackfmt)
{
case TF_8PAL24:
pb = 3*256;
b = 1;
b *= 1;
break;
case TF_8PAL32:
pb = 4*256;
b = 1;
b *= 1;
break;
case TF_LUM8:
case TF_SOLID8:
@ -4234,21 +4306,28 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
case TF_H2_T4A4:
case TF_HEIGHT8:
case TF_HEIGHT8PAL: //we don't care about the actual palette.
b = 1;
b *= 1;
break;
case TF_RGBX32:
case TF_RGBA32:
case TF_BGRX32:
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;
default:
Sys_Error("Image_GetTexture: bad format");
}
tex->fallbackdata = BZ_Malloc(fallbackwidth*fallbackheight*b + pb);
memcpy(tex->fallbackdata, fallbackdata, fallbackwidth*fallbackheight*b);
tex->fallbackdata = BZ_Malloc(b + pb);
memcpy(tex->fallbackdata, fallbackdata, b);
if (pb)
memcpy((qbyte*)tex->fallbackdata + fallbackwidth*fallbackheight*b, fallbackpalette, pb);
memcpy((qbyte*)tex->fallbackdata + b, fallbackpalette, pb);
tex->fallbackwidth = fallbackwidth;
tex->fallbackheight = fallbackheight;
tex->fallbackfmt = fallbackfmt;
@ -4268,7 +4347,12 @@ image_t *Image_GetTexture(const char *identifier, const char *subpath, unsigned
if (dontposttoworker)
Image_LoadHiResTextureWorker(tex, NULL, 0, 0);
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;
}
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();
}
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)
{
events_avail = 0;
@ -128,6 +166,8 @@ void IN_Init(void)
Cvar_Register (&m_slidethreshold, "input controls");
Cvar_Register (&m_touchmajoraxis, "input controls");
Cmd_AddCommand ("in_deviceids", IN_DeviceIDs_f);
INS_Init();
}

View file

@ -213,6 +213,9 @@ void INS_ProcessInputMessage(struct InputEvent *msg, qboolean consumemotion)
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)
{
}

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_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 qboolean multicursor_active[8];
POINT current_mouse_pos;
typedef struct {
union {
HANDLE rawinputhandle;
@ -534,9 +536,18 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
else
grabmouse = false;
//visiblity
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 (activeapp)
{
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
{
INS_ShowMouse();
@ -573,7 +584,7 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
#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);
@ -620,7 +631,7 @@ int INS_InitDInput (void)
if (FAILED(hr))
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.
hr = IDirectInput7_CreateDeviceEx(g_pdi7, &fGUID_SysMouse, &fIID_IDirectInputDevice7A, &g_pMouse7, NULL);
@ -678,7 +689,7 @@ int INS_InitDInput (void)
{
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.
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_JoyMove (movements, pnum);
}
else
INS_Accumulate();
}
@ -1341,8 +1354,6 @@ potentially called multiple times per frame.
*/
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)
{
#ifdef USINGRAWINPUT
@ -1350,9 +1361,9 @@ void INS_Accumulate (void)
if (!rawmicecount)
#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)
@ -1362,9 +1373,9 @@ void INS_Accumulate (void)
if (!mouseactive)
{
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;
}
}
@ -1790,6 +1801,15 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
}
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
// turning off the joystick seems too harsh for 1 read error,
// but what should be done?
@ -1994,10 +2014,29 @@ void INS_JoyMove (float *movements, int pnum)
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[] =
{
// 0 1 2 3 4 5 6 7

View file

@ -57,6 +57,7 @@ void INS_ReInit (void);
void INS_Init (void);
void INS_Shutdown (void);
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_c2spps;

View file

@ -338,9 +338,9 @@ void CompleteCommand (qboolean force)
con_commandmatch = 1;
if (desc)
Con_Footerf(false, "%s: %s", cmd, desc);
Con_Footerf(NULL, false, "%s: %s", cmd, desc);
else
Con_Footerf(false, "");
Con_Footerf(NULL, false, "");
return;
}
}
@ -374,27 +374,27 @@ void CompleteCommand (qboolean force)
if (var)
{
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
Con_Footerf(false, "%s %s", cmd, var->string);
Con_Footerf(NULL, false, "%s %s", cmd, var->string);
}
else
{
if (desc)
Con_Footerf(false, "%s: %s", cmd, desc);
Con_Footerf(NULL, false, "%s: %s", cmd, desc);
else
Con_Footerf(false, "");
Con_Footerf(NULL, false, "");
}
}
else
{
Con_Footerf(false, "");
Con_Footerf(NULL, false, "");
con_commandmatch = 1;
}
}
//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;
char deutf8[8192];
@ -413,7 +413,7 @@ void Con_ExecuteLine(console_t *con, char *line)
}
con_commandmatch=1;
Con_Footerf(false, "");
Con_Footerf(con, false, "");
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);
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
Cbuf_AddText (exec, RESTRICT_LOCAL);
@ -482,6 +482,8 @@ void Con_ExecuteLine(console_t *con, char *line)
if (cls.state == ca_disconnected)
SCR_UpdateScreen (); // force an update, because the command
// may take some time
return true;
}
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;
if (con->mousedown[2] == 1)
if (con->buttonsdown == CB_SCROLL)
{
//left-mouse.
//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];
return true;
}
else if (con->mousedown[2] == 2)
else if (con->buttonsdown == CB_COPY)
{
//right-mouse
//select. copy-to-clipboard on release.
@ -529,6 +531,43 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
}
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];
*sy = con->mousecursor[1];
*ex = con->mousecursor[0];
@ -564,7 +603,7 @@ void Key_ConsoleInsert(char *instext)
key_linepos += len;
}
void Key_DefaultLinkClicked(char *text, char *info)
void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
{
char *c;
/*the engine supports specific default links*/
@ -639,7 +678,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
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++)
{
@ -652,17 +691,17 @@ void Key_DefaultLinkClicked(char *text, char *info)
if (cl.spectator || cls.demoplayback)
{
//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
{
//we're playing.
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)
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
#ifndef CLIENTONLY
@ -670,8 +709,8 @@ void Key_DefaultLinkClicked(char *text, char *info)
#endif
))
{
Con_Footerf(true, " ^[Kick\\player\\%i\\action\\kick^]", player);
Con_Footerf(true, " ^[Ban\\player\\%i\\action\\ban^]", player);
Con_Footerf(con, true, " ^[Kick\\player\\%i\\action\\kick^]", player);
Con_Footerf(con, true, " ^[Ban\\player\\%i\\action\\ban^]", player);
}
}
else
@ -687,20 +726,20 @@ void Key_DefaultLinkClicked(char *text, char *info)
}
else
{
Con_Footerf(true, " ^[Suicide\\cmd\\kill^]");
Con_Footerf(con, true, " ^[Suicide\\cmd\\kill^]");
#ifndef CLIENTONLY
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))
#else
Con_Footerf(true, " ^[Disconnect\\cmd\\disconnect^]");
Con_Footerf(con, true, " ^[Disconnect\\cmd\\disconnect^]");
if (cls.allow_cheats)
#endif
{
Con_Footerf(true, " ^[Noclip\\cmd\\noclip^]");
Con_Footerf(true, " ^[Fly\\cmd\\fly^]");
Con_Footerf(true, " ^[God\\cmd\\god^]");
Con_Footerf(true, " ^[Give\\impulse\\9^]");
Con_Footerf(con, true, " ^[Noclip\\cmd\\noclip^]");
Con_Footerf(con, true, " ^[Fly\\cmd\\fly^]");
Con_Footerf(con, true, " ^[God\\cmd\\god^]");
Con_Footerf(con, true, " ^[Give\\impulse\\9^]");
}
}
}
@ -781,7 +820,7 @@ void Key_DefaultLinkClicked(char *text, char *info)
c = Info_ValueForKey(info, "desc");
if (*c)
{
Con_Footerf(false, "%s", c);
Con_Footerf(con, false, "%s", c);
return;
}
@ -805,13 +844,14 @@ void Key_DefaultLinkClicked(char *text, char *info)
void Key_ConsoleRelease(console_t *con, int key, int unicode)
{
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)
{
buffer = Con_CopyConsole(false, false);
Con_Footerf(false, "");
buffer = Con_CopyConsole(con, false, false);
Con_Footerf(con, false, "");
if (!buffer)
return;
if (keydown[K_SHIFT])
@ -866,7 +906,7 @@ void Key_ConsoleRelease(console_t *con, int key, int unicode)
if (!CSQC_ConsoleLink(buffer+2, info))
#endif
{
Key_DefaultLinkClicked(buffer+2, info);
Key_DefaultLinkClicked(con, buffer+2, info);
}
break;
@ -881,18 +921,27 @@ void Key_ConsoleRelease(console_t *con, int key, int unicode)
Z_Free(buffer);
}
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;
buffer = Con_CopyConsole(true, false); //don't keep markup if we're copying to the clipboard
con->buttonsdown = CB_NONE;
buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard
if (!buffer)
return;
Sys_SaveClipboard(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.
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))
{
// int xpos = (int)((con->mousecursor[0]*vid.width)/(vid.pixelwidth*8));
int ypos = (int)((con->mousecursor[1]*vid.height)/(vid.pixelheight*8));
if (con->flags & CONF_ISWINDOW)
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[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)
Con_Destroy (con_mouseover);
if (key == K_MOUSE2 && !(con->flags & CONF_ISWINDOW))
Con_Destroy (con);
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)
con->mousedown[2] = 2;
else
con->mousedown[2] = 1;
con->buttonsdown = CB_COPY;
else
{
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;
}
//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)
{ // backslash text are commands, else chat
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]);
key_lines[edit_line] = BZ_Malloc(2);
key_lines[edit_line][0] = ']';
key_lines[edit_line][1] = '\0';
key_linepos = 1;
if (con->linebuffered)
con->linebuffered(con, key_lines[oldl]+1);
con_commandmatch = 0;
return true;
}
@ -1387,7 +1467,8 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
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();
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;
}
b = Key_StringToKeynum (Cmd_Argv(1), &modifier);
@ -1726,7 +1807,7 @@ void Key_BindLevel_f (void)
if (Cmd_IsInsecure())
{
Con_Printf("Server attempted usage of bindat\n");
Con_Printf("Server attempted usage of %s\n", Cmd_Argv(0));
return;
}
@ -1812,7 +1893,7 @@ void Key_Init (void)
key_linepos = 1;
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
@ -2044,6 +2125,13 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
if (Key_Dest_Has(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))
M_ToggleMenu_f ();
}
@ -2078,11 +2166,19 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
//
if (!down)
{
if (Key_Dest_Has(kdm_console))
if (Key_Dest_Has(kdm_console|kdm_cwindows))
{
con_current->mousecursor[0] = mousecursor_x;
con_current->mousecursor[1] = mousecursor_y;
Key_ConsoleRelease(con_current, key, unicode);
console_t *con = Key_Dest_Has(kdm_console)?con_current:con_curwindow;
if (con_mouseover && key >= K_MOUSE1 && key <= K_MWHEELDOWN)
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))
M_Keyup (key, unicode);
@ -2139,12 +2235,21 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
#endif
if (conkey && Key_Dest_Has(kdm_console))
if (conkey && Key_Dest_Has(kdm_console|kdm_cwindows))
{
con_current->mousecursor[0] = mousecursor_x;
con_current->mousecursor[1] = mousecursor_y;
Key_Console (con_current, unicode, key);
return;
console_t *con = Key_Dest_Has(kdm_console)?con_current:con_curwindow;
if ((con_mouseover||!Key_Dest_Has(kdm_console)) && key >= K_MOUSE1 && key <= K_MWHEELDOWN)
con = con_mouseover;
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
if (Key_Dest_Has(kdm_editor))

View file

@ -172,11 +172,12 @@ K_MAX = 256
typedef enum //highest has priority
{
kdm_game = 1u<<0, //should always be set
kdm_message = 1u<<1,
kdm_menu = 1u<<2,
kdm_editor = 1u<<3,
kdm_console = 1u<<4,
kdm_game = 1u<<0, //should always be set
kdm_message = 1u<<1,
kdm_menu = 1u<<2,
kdm_editor = 1u<<3,
kdm_console = 1u<<4,
kdm_cwindows = 1u<<5,
} keydestmask_t;
//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)
{
range -= delta;
if (range < option->min)
range = 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;
}
else if (key == K_RIGHTARROW || key == K_MWHEELUP)
{
range += delta;
if (range > option->max)
range = option->max;
if (option->min > option->max)
range = bound(option->max, range, option->min);
else
range = bound(option->min, range, option->max);
option->current = range;
}
else if (key == K_MOUSE1 && mousecursor_x >= ix-8 && mousecursor_x < ex+8)
{
range = (mousecursor_x - ix) / (ex - ix);
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;
}
else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{
range += delta;
if (range >= option->max + delta/2)
if (range == option->max)
range = option->min;
if (range > option->max)
range = option->max;
else
{
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;
}
else
@ -2183,6 +2199,7 @@ void M_Menu_Main_f (void)
#endif
if (QBigFontWorks())
{
int y;
m_state = m_complex;
Key_Dest_Add(kdm_menu);
mainm = M_CreateMenu(0);
@ -2203,18 +2220,35 @@ void M_Menu_Main_f (void)
MC_AddCenterPicture(mainm, 4, 24, "gfx/ttl_main.lmp");
y = 32;
mainm->selecteditem = (menuoption_t *)
MC_AddConsoleCommandQBigFont (mainm, 72, 32, "Single ", "menu_single\n");
MC_AddConsoleCommandQBigFont (mainm, 72, 52, "Multiplayer ", "menu_multi\n");
MC_AddConsoleCommandQBigFont (mainm, 72, 72, "Options ", "menu_options\n");
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Single ", "menu_single\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Multiplayer ", "menu_multi\n"); y += 20;
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Options ", "menu_options\n"); y += 20;
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
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
MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Save Settings", "menu_quit\n");
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Save Settings", "menu_quit\n"); y += 20;
#else
MC_AddConsoleCommandQBigFont (mainm, 72, 112,"Quit ", "menu_quit\n");
MC_AddConsoleCommandQBigFont (mainm, 72, y, "Quit ", "menu_quit\n"); y += 20;
#endif
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);
else
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");
M_RemoveMenu(menu);
return true;

View file

@ -675,6 +675,8 @@ const char *presetexec[] =
"seta r_nolerp 1;"
"seta r_nolightdir 1;"
"seta r_dynamic 0;"
"seta r_bloom 0;"
"seta r_softwarebanding 0;"
"seta gl_polyblend 0;"
"seta gl_flashblend 0;"
"seta gl_specular 0;"
@ -730,6 +732,7 @@ const char *presetexec[] =
"cl_bob 0.02;"
//these things are perhaps a little extreme
"r_loadlit 0;"
"r_softwarebanding 1;" //ugly software banding.
"gl_texturemode nnl;" //yup, we went there.
"gl_texturemode2d n.l;" //yeah, 2d too.
"r_part_classic_square 1;" //blocky baby!
@ -752,6 +755,7 @@ const char *presetexec[] =
"gl_load24bit 1;"
"r_replacemodels \"md3 md2\";"
"r_coronas 1;"
"r_softwarebanding 0;"
"r_lerpmuzzlehack 1;"
"gl_texturemode ln;"
"gl_texturemode2d l;"
@ -778,8 +782,8 @@ const char *presetexec[] =
"gl_texture_anisotropic_filtering 4;"
, // realtime options
// "r_bloom 1;"
"r_particledesc \"spikeset high tsshaft\";"
"r_bloom 1;"
"r_particledesc \"high tsshaft\";"
"r_waterstyle 3;"
"r_glsl_offsetmapping 1;"
"r_shadow_realtime_world 1;"
@ -801,6 +805,7 @@ static void ApplyPreset (int presetnum)
{
Cbuf_InsertText(presetexec[i], RESTRICT_LOCAL, true);
}
Cbuf_InsertText("vid_reload\n", RESTRICT_LOCAL, 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_SPACING(4),
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_END()
};
@ -2887,7 +2892,7 @@ static qboolean Mods_Key(struct menucustom_s *c, struct menu_s *m, int key)
man = mods->manifests[i];
mods->manifests[i] = NULL;
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.
//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)
{
FS_ChangeGame(mods.manifests[0], true);
FS_ChangeGame(mods.manifests[0], true, true);
Z_Free(mods.manifests);
}
else
@ -2957,4 +2962,96 @@ void M_Menu_Mods_f (void)
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

View file

@ -115,6 +115,7 @@ void M_Keyup (int key, int unicode);
void M_Draw (int uimenu);
void M_ToggleMenu_f (void);
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);
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);

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_FLIP, /*bgr byte order, no alpha channel nor pad, and bottom up*/
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_TRANS8, /*8bit quake-palette image, index 255=transparent*/
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;
else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor"))
ptype->looks.blendmode = BM_BLENDCOLOUR;
else
else if (!strcmp(value, "blendalpha"))
ptype->looks.blendmode = BM_BLEND;
else
ptype->looks.blendmode = BM_BLEND; //fallback
}
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);
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*/ \
globalfloat(trace_surfaceflags, "trace_surfaceflags"); /*float written by traceline*/ \
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(servercommandframe, "servercommandframe"); /*float the most recent frame received from the server*/ \
@ -188,6 +190,7 @@ extern sfx_t *cl_sfx_r_exp3;
typedef struct {
#define globalfloat(name,qcname) float *name
#define globalint(name,qcname) int *name
#define globalvector(name,qcname) float *name
#define globalentity(name,qcname) int *name
#define globalstring(name,qcname) string_t *name
@ -197,6 +200,7 @@ typedef struct {
csqcglobals
#undef globalfloat
#undef globalint
#undef globalvector
#undef globalentity
#undef globalstring
@ -273,6 +277,7 @@ static void CSQC_FindGlobals(void)
{
static float csphysicsmode = 0;
#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 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);
@ -281,6 +286,7 @@ static void CSQC_FindGlobals(void)
csqcglobals
#undef globalfloat
#undef globalint
#undef globalvector
#undef globalentity
#undef globalstring
@ -1200,6 +1206,10 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (!csqc_poly_shader)
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 (cl_numstris && cl_stris[cl_numstris-1].shader == csqc_poly_shader && cl_stris[cl_numstris-1].flags == flags)
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;
}
nv = cl_numstrisvert-csqc_poly_startvert;
if (cl_numstrisidx+(nv-2)*3 > cl_maxstrisidx)
if (flags & BEF_LINES)
{
cl_maxstrisidx=cl_numstrisidx+(nv-2)*3 + 64;
cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx);
}
nv = cl_numstrisvert-csqc_poly_startvert;
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*/
for (i = 2; i < nv; i++)
/*build the line list fan out of triangles*/
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;
cl_strisidx[cl_numstrisidx++] = t->numvert + i-1;
cl_strisidx[cl_numstrisidx++] = t->numvert + i;
nv = cl_numstrisvert-csqc_poly_startvert;
if (cl_numstrisidx+(nv-2)*3 > cl_maxstrisidx)
{
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)
@ -1389,7 +1418,7 @@ void QCBUILTIN PF_R_GetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
switch(parametertype)
{
case VF_LPLAYER:
case VF_ACTIVESEAT:
if (prinst == csqc_world.progs)
*r = csqc_playerseat;
break;
@ -1538,7 +1567,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
G_FLOAT(OFS_RETURN) = 1;
switch(parametertype)
{
case VF_LPLAYER:
case VF_ACTIVESEAT:
if (prinst == csqc_world.progs)
{
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;
if (csqcg.trace_endcontents)
*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)
*csqcg.trace_ent = EDICT_TO_PROG(csqcprogs, (void*)tr->ent);
else
@ -2526,7 +2559,7 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
if (!cls.state)
return;
MSG_WriteByte(&cls.netchan.message, clc_qcrequest);
MSG_WriteByte(&cls.netchan.message, clcfte_qcrequest);
for (i = 0; i < 6; i++)
{
if (argtypes[i] == 's')
@ -4965,6 +4998,13 @@ static struct {
{"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??)
{"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;
{"skel_ragupdate", PF_skel_ragedit, 281},// (FTE_QC_RAGDOLL)
{"skel_mmap", PF_skel_mmap, 282},// (FTE_QC_RAGDOLL)
@ -5108,6 +5148,8 @@ static struct {
{"con_draw", PF_SubConDraw, 393},
{"con_input", PF_SubConInput, 394},
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
//400
{"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)
@ -6834,9 +6876,9 @@ void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd)
//this protocol allows up to 32767 edicts.
#ifdef PEXT_CSQC
static void CSQC_EntityCheck(int entnum)
static void CSQC_EntityCheck(unsigned int entnum)
{
int newmax;
unsigned int newmax;
if (entnum >= maxcsqcentities)
{
@ -6905,7 +6947,7 @@ void CSQC_GetEntityOrigin(unsigned int csqcent, float *out)
void CSQC_ParseEntities(void)
{
csqcedict_t *ent;
unsigned short entnum;
unsigned int entnum;
void *pr_globals;
int packetsize;
int packetstart;
@ -6944,7 +6986,7 @@ void CSQC_ParseEntities(void)
//replacement deltas now also includes 22bit entity num indicies.
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
{
entnum = MSG_ReadShort();
entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000);
if (entnum & 0x4000)
entnum = (entnum & 0x3fff) | (MSG_ReadByte()<<14);
@ -6953,7 +6995,7 @@ void CSQC_ParseEntities(void)
}
else
{
entnum = MSG_ReadShort();
entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(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"))
{
RETURN_TSTRING((con->flags & CON_HIDDEN)?"1":"0");
RETURN_TSTRING((con->flags & CONF_HIDDEN)?"1":"0");
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"))
{
@ -943,7 +943,7 @@ void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
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);
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;
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.
@ -1646,6 +1649,11 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
model_t *mod = Mod_ForName(modelname, MLV_WARN);
if (modelval)
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)
VectorCopy(mod->mins, minsval->_vector);
if (mod && maxsval)
@ -1960,6 +1968,7 @@ static struct {
{"con_printf", PF_SubConPrintf, 392},
{"con_draw", PF_SubConDraw, 393},
{"con_input", PF_SubConInput, 394},
{"cvars_haveunsaved", PF_cvars_haveunsaved, 0},
//gap
{"buf_create", PF_buf_create, 440},
{"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
{
char *basedir; //working directory
char *binarydir; //exe directory
int argc;
char *basedir; //working directory
char *binarydir; //exe directory
const char *manifest; //linked manifest data (for installer functionality etc)
int argc;
const char **argv;
} quakeparms_t;

View file

@ -725,10 +725,18 @@ void R2D_Font_AddFontLink(char *buffer, int buffersize, char *fontname)
#endif
void R2D_Font_Changed(void)
{
float tsize;
if (!con_textsize.modified)
return;
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)
font_console = NULL;
if (font_console)
@ -763,8 +771,8 @@ void R2D_Font_Changed(void)
CHOOSEFONTA cf = {sizeof(cf)};
extern HWND mainwindow;
font_default = Font_LoadFont(8, "");
if (con_textsize.ival != 8 && con_textsize.ival >= 1)
font_console = Font_LoadFont(con_textsize.ival, "");
if (tsize != 8)
font_console = Font_LoadFont(tsize, "");
if (!font_console)
font_console = font_default;
@ -805,11 +813,11 @@ void R2D_Font_Changed(void)
if (!font_default && *gl_font.string)
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)
font_console = Font_LoadFont(con_textsize.ival, "");
font_console = Font_LoadFont(tsize, "");
}
if (!font_console)
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
if (v_brightness.value > 0.5)
v_brightness.value = 0.5;
if (v_contrast.value < 0.5)
v_contrast.value = 0.5;
if (r2d_canhwgamma)
return;

View file

@ -1582,7 +1582,7 @@ char *particle_set_high =
"randomvel 1000\n"
"friction 0.01\n"
"gravity 100\n"
"stretchfactor 5\n"
"stretchfactor -80\n"
"}\n"
//hide lights in explosions.
@ -1633,6 +1633,8 @@ char *particle_set_high =
"shader\n"
"{\n"
"surfaceparm noshadows\n"
"surfaceparm nodlight\n"
"glslprogram\n"
"{\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;
#define R_PARTSET_BUILTINS_spikeset {"spikeset", &particle_set_spikeset},
extern char *particle_set_faithful;
#define R_PARTSET_BUILTINS_faithful {"faithful", &particle_set_faithful},
extern char *particle_set_highfps;
#define R_PARTSET_BUILTINS_highfps {"highfps", &particle_set_highfps},
extern char *particle_set_high;
#define R_PARTSET_BUILTINS_high {"high", &particle_set_high},
extern char *particle_set_minimal;
#define R_PARTSET_BUILTINS_minimal {"minimal", &particle_set_minimal},
#ifdef HEXEN2
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;
#define R_PARTSET_BUILTINS_q2part {"q2part", &particle_set_q2part},
#else
#define R_PARTSET_BUILTINS_q2part
#endif
extern char *particle_set_tsshaft;
#define R_PARTSET_BUILTINS_tsshaft {"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
#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},

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_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_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_RenderAmbientLightmaps (struct msurface_s *fa, int ambient);
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 {
unsigned short l,t,w,h;
} glRect_t;
@ -371,13 +371,15 @@ enum imageflags
IF_TEXTYPESHIFT = 8, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<10,
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_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_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_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)
@ -455,8 +457,14 @@ void Mod_UnRegisterAllModelFormats(void *module);
void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b);
#ifdef RUNTIMELIGHTING
void LightFace (int surfnum);
void LightLoadEntities(char *entstring);
struct relight_ctx_s;
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
@ -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 *ReadPNGFile(qbyte *buf, int length, int *width, int *height, const char *name);
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 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_limit;
extern cvar_t r_lightstylespeed;
extern cvar_t r_lightstylescale;
extern cvar_t gl_nocolors;
extern cvar_t gl_load24bit;
extern cvar_t gl_finish;
@ -626,13 +636,13 @@ extern int rquant[RQUANT_MAX];
#define RSpeedRemark()
#define RSpeedEnd(spt)
#else
#define RSpeedLocals() int rsp
#define RSpeedMark() int rsp = (r_speeds.ival>1)?Sys_DoubleTime()*1000000:0
#define RSpeedLocals() double rsp
#define RSpeedMark() double 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)
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
#define RSpeedEnd(spt) rspeeds[spt] += (r_speeds.ival>1)?Sys_DoubleTime()*1000000 - rsp:0
#endif

View file

@ -103,8 +103,8 @@ cvar_t r_flashblendscale = SCVARF ("gl_flashblendscale", "0.35",
CVAR_ARCHIVE);
cvar_t r_floorcolour = CVARAF ("r_floorcolour", "64 64 128",
"r_floorcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
cvar_t r_floortexture = SCVARF ("r_floortexture", "",
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
//cvar_t r_floortexture = SCVARF ("r_floortexture", "",
// CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);
cvar_t r_fullbright = CVARFD ("r_fullbright", "0",
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*/
@ -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_limit = SCVAR ("r_lightstylesmooth_limit", "2");
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_menutint = SCVARF ("r_menutint", "0.68 0.4 0.13",
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.");
cvar_t r_skyboxname = SCVARF ("r_skybox", "",
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_stainfadeammount = SCVAR ("r_stainfadeammount", "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_wallcolour = CVARAF ("r_wallcolour", "128 128 128",
"r_wallcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM);//FIXME: broken
cvar_t r_walltexture = CVARF ("r_walltexture", "",
CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); //FIXME: broken
//cvar_t r_walltexture = CVARF ("r_walltexture", "",
// CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); //FIXME: broken
cvar_t r_wateralpha = CVARF ("r_wateralpha", "1",
CVAR_ARCHIVE | CVAR_SHADERSYSTEM);
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_ARCHIVE, "field of vision, 1-170 degrees, standard fov is 90, nquake defaults to 108.",
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_showturtle = SCVAR ("showturtle", "0");
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",
"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_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.");
//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_ARCHIVE | CVAR_RENDERERCALLBACK,
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,
"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,
Image_TextureMode_Callback);
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_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_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_portalonly, GLRENDEREROPTIONS);
Cvar_Register (&r_noaliasshadows, GLRENDEREROPTIONS);
Cvar_Register (&gl_maxshadowlights, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_bumpscale_basetexture, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_bumpscale_bumpmap, GLRENDEREROPTIONS);
Cvar_Register (&r_shadow_heightscale_basetexture, GLRENDEREROPTIONS);
@ -478,8 +476,8 @@ void GLRenderer_Init(void)
Cvar_Register (&r_wallcolour, GLRENDEREROPTIONS);
Cvar_Register (&r_floorcolour, GLRENDEREROPTIONS);
Cvar_Register (&r_walltexture, GLRENDEREROPTIONS);
Cvar_Register (&r_floortexture, GLRENDEREROPTIONS);
// Cvar_Register (&r_walltexture, GLRENDEREROPTIONS);
// Cvar_Register (&r_floortexture, GLRENDEREROPTIONS);
Cvar_Register (&r_vertexdlights, GLRENDEREROPTIONS);
@ -630,6 +628,7 @@ void Renderer_Init(void)
Cvar_Register(&r_lightstylesmooth, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylesmooth_limit, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylespeed, GRAPHICALNICETIES);
Cvar_Register(&r_lightstylescale, GRAPHICALNICETIES);
Cvar_Register(&r_stains, 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->srgb = vid_srgb.ival;
if (com_installer)
{
newr->fullscreen = false;
newr->width = 640;
newr->height = 480;
}
if (!*vid_vsync.string || vid_vsync.value < 0)
newr->wait = -1;
else

View file

@ -141,6 +141,13 @@ int Sbar_PlayerNum(playerview_t *pv)
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)
return p->ttopcolor;
else
@ -149,6 +156,13 @@ int Sbar_TopColour(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)
return p->tbottomcolor;
else
@ -1205,9 +1219,10 @@ int Sbar_itoa (int num, char *buf)
num = -num;
}
for (pow10 = 10 ; num >= pow10 ; pow10 *= 10)
for (pow10 = 10 ; num >= pow10 && pow10>=10; pow10 *= 10)
;
if (pow10 > 0)
do
{
pow10 /= 10;
@ -1229,7 +1244,7 @@ Sbar_DrawNum
*/
void Sbar_DrawNum (float x, float y, int num, int digits, int color)
{
char str[12];
char str[16];
char *ptr;
int l, frame;
#undef small

View file

@ -97,7 +97,8 @@ void SCR_SetLoadingFile(char *str);
/*fonts*/
void Font_Init(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_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*/

View file

@ -83,7 +83,7 @@ cvar_t snd_show = CVARAF( "s_show", "0",
"snd_show", 0);
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.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "0",
cvar_t snd_inactive = CVARAFD( "s_inactive", "1",
"snd_inactive", 0,
"Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed."
); //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"))
S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_OLD, 0, sequence, datalen, data); //very much non-standard rtp
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"))
S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_ULTRAWIDE, 0, sequence, datalen, data);
if (!strcmp(codec, "opus"))
@ -2450,6 +2450,8 @@ void S_StopAllSounds(qboolean clear)
{
s = sc->channel[i].sfx;
sc->channel[i].sfx = NULL;
if (s->loadstate == SLS_LOADING)
COM_WorkerPartialSync(s, &s->loadstate, SLS_LOADING);
if (s->decoder.ended)
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;
}
void S_Wakeup (void *ctx, void *ctxdata, size_t a, size_t b)
{
}
/*
==============
S_LoadSound
@ -765,7 +768,7 @@ S_LoadSound
qboolean S_LoadSoundWorker (void *ctx, void *ctxdata, size_t a, size_t b)
{
sfx_t *s = ctx;
char namebuffer[256];
char namebuffer[256];
qbyte *data;
int i;
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))
{
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);
return true;
}
@ -898,83 +903,85 @@ WAV loading
===============================================================================
*/
char *wavname;
qbyte *data_p;
qbyte *iff_end;
qbyte *last_chunk;
qbyte *iff_data;
int iff_chunk_len;
typedef struct
{
char *wavname;
qbyte *data_p;
qbyte *iff_end;
qbyte *last_chunk;
qbyte *iff_data;
int iff_chunk_len;
} wavctx_t;
short GetLittleShort(void)
short GetLittleShort(wavctx_t *ctx)
{
short val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
data_p += 2;
val = *ctx->data_p;
val = val + (*(ctx->data_p+1)<<8);
ctx->data_p += 2;
return val;
}
int GetLittleLong(void)
int GetLittleLong(wavctx_t *ctx)
{
int val = 0;
val = *data_p;
val = val + (*(data_p+1)<<8);
val = val + (*(data_p+2)<<16);
val = val + (*(data_p+3)<<24);
data_p += 4;
val = *ctx->data_p;
val = val + (*(ctx->data_p+1)<<8);
val = val + (*(ctx->data_p+2)<<16);
val = val + (*(ctx->data_p+3)<<24);
ctx->data_p += 4;
return val;
}
unsigned int FindNextChunk(char *name)
unsigned int FindNextChunk(wavctx_t *ctx, char *name)
{
unsigned int dataleft;
while (1)
{
dataleft = iff_end - last_chunk;
dataleft = ctx->iff_end - ctx->last_chunk;
if (dataleft < 8)
{ // didn't find the chunk
data_p = NULL;
ctx->data_p = NULL;
return 0;
}
data_p=last_chunk;
data_p += 4;
ctx->data_p=ctx->last_chunk;
ctx->data_p += 4;
dataleft-= 8;
iff_chunk_len = GetLittleLong();
if (iff_chunk_len < 0)
ctx->iff_chunk_len = GetLittleLong(ctx);
if (ctx->iff_chunk_len < 0)
{
data_p = NULL;
ctx->data_p = NULL;
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
iff_chunk_len = dataleft;
ctx->iff_chunk_len = dataleft;
#else
data_p = NULL;
ctx->data_p = NULL;
return 0;
#endif
}
dataleft-= iff_chunk_len;
dataleft-= ctx->iff_chunk_len;
// if (iff_chunk_len > 1024*1024)
// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
data_p -= 8;
last_chunk = data_p + 8 + iff_chunk_len;
if ((iff_chunk_len&1) && dataleft)
last_chunk++;
if (!Q_strncmp(data_p, name, 4))
return iff_chunk_len;
ctx->data_p -= 8;
ctx->last_chunk = ctx->data_p + 8 + ctx->iff_chunk_len;
if ((ctx->iff_chunk_len&1) && dataleft)
ctx->last_chunk++;
if (!Q_strncmp(ctx->data_p, name, 4))
return ctx->iff_chunk_len;
}
}
unsigned int FindChunk(char *name)
unsigned int FindChunk(wavctx_t *ctx, char *name)
{
last_chunk = iff_data;
return FindNextChunk (name);
ctx->last_chunk = ctx->iff_data;
return FindNextChunk (ctx, name);
}
@ -1004,67 +1011,72 @@ GetWavinfo
wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
{
wavinfo_t info;
int i;
int format;
int i;
int format;
int samples;
int chunklen;
wavctx_t ctx;
memset (&info, 0, sizeof(info));
if (!wav)
return info;
iff_data = wav;
iff_end = wav + wavlength;
wavname = name;
ctx.data_p = NULL;
ctx.last_chunk = NULL;
ctx.iff_chunk_len = 0;
ctx.iff_data = wav;
ctx.iff_end = wav + wavlength;
ctx.wavname = name;
// find "RIFF" chunk
chunklen = FindChunk("RIFF");
if (chunklen < 4 || Q_strncmp(data_p+8, "WAVE", 4))
chunklen = FindChunk(&ctx, "RIFF");
if (chunklen < 4 || Q_strncmp(ctx.data_p+8, "WAVE", 4))
{
Con_Printf("Missing RIFF/WAVE chunks in %s\n", name);
return info;
}
// get "fmt " chunk
iff_data = data_p + 12;
ctx.iff_data = ctx.data_p + 12;
// DumpChunks ();
chunklen = FindChunk("fmt ");
chunklen = FindChunk(&ctx, "fmt ");
if (chunklen < 24-8)
{
Con_Printf("Missing/truncated fmt chunk\n");
return info;
}
data_p += 8;
format = GetLittleShort();
ctx.data_p += 8;
format = GetLittleShort(&ctx);
if (format != 1)
{
Con_Printf("Microsoft PCM format only\n");
return info;
}
info.numchannels = GetLittleShort();
info.rate = GetLittleLong();
data_p += 4+2;
info.width = GetLittleShort() / 8;
info.numchannels = GetLittleShort(&ctx);
info.rate = GetLittleLong(&ctx);
ctx.data_p += 4+2;
info.width = GetLittleShort(&ctx) / 8;
// get cue chunk
chunklen = FindChunk("cue ");
chunklen = FindChunk(&ctx, "cue ");
if (chunklen >= 36-8)
{
data_p += 32;
info.loopstart = GetLittleLong();
ctx.data_p += 32;
info.loopstart = GetLittleLong(&ctx);
// Con_Printf("loopstart=%d\n", sfx->loopstart);
// 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 (!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...
data_p += 24;
i = GetLittleLong (); // samples in loop
ctx.data_p += 24;
i = GetLittleLong (&ctx); // samples in loop
info.samples = info.loopstart + i;
// Con_Printf("looped length: %i\n", i);
}
@ -1074,14 +1086,14 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
info.loopstart = -1;
// find data chunk
chunklen = FindChunk("data");
if (!chunklen)
chunklen = FindChunk(&ctx, "data");
if (!ctx.data_p)
{
Con_Printf("Missing data chunk in %s\n", name);
return info;
}
data_p += 8;
ctx.data_p += 8;
samples = chunklen / info.width /info.numchannels;
if (info.samples)
@ -1101,7 +1113,7 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength)
info.loopstart = info.samples;
}
info.dataofs = data_p - wav;
info.dataofs = ctx.data_p - wav;
return info;
}

View file

@ -45,17 +45,19 @@ typedef struct {
void *buf;
} 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
{
char name[MAX_OSPATH];
sfxdecode_t decoder;
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
} loadstate; //no more super-spammy
int loadstate; //no more super-spammy
qboolean touched:1; //if the sound is still relevent
#ifdef AVAIL_OPENAL

View file

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

View file

@ -252,7 +252,8 @@ void Sys_Printf (char *fmt, ...)
void Sys_Quit (void)
{
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
lt_dlexit();
@ -273,7 +274,8 @@ void Sys_Error (const char *error, ...)
char string[1024];
// 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);
vsnprintf (string,sizeof(string)-1, error,argptr);
@ -703,6 +705,9 @@ char *Sys_ConsoleInput(void)
static char text[256];
int len;
if (noconinput)
return NULL;
// if (!qrenderer)
{
len = read (0, text, sizeof(text));

View file

@ -123,7 +123,7 @@ double Sys_DoubleTime (void)
void Sys_Quit (void)
{
Host_Shutdown ();
exit(1);
exit(0);
}
void Sys_mkdir (char *path)
@ -291,7 +291,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(
#else
#if defined(GLQUAKE)
//#define PRINTGLARRAYS
#define PRINTGLARRAYS
#endif
#if defined(_DEBUG) || defined(DEBUG)
@ -606,7 +606,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI
}
#ifdef PRINTGLARRAYS
if (!iswatchdog && qrenderer == QR_OPENGL)
if (!iswatchdog && qrenderer == QR_OPENGL && Sys_IsMainThread())
DumpGLState();
#endif
@ -2841,7 +2841,7 @@ void Sys_SetAutoUpdateSetting(int newval)
Update_Check();
}
qboolean Sys_CheckUpdated(void)
qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize)
{
int ffe = COM_CheckParm("--fromfrontend");
PROCESS_INFORMATION childinfo;
@ -2924,7 +2924,12 @@ qboolean Sys_CheckUpdated(void)
return true;
}
if (com_argv[ffe+2])
{
com_argv[0] = com_argv[ffe+2];
Q_strncpyz(bindir, com_argv[0], bindirsize);
*COM_SkipPath(bindir) = 0;
}
}
return false;
}
@ -2936,7 +2941,7 @@ int Sys_GetAutoUpdateSetting(void)
void Sys_SetAutoUpdateSetting(int newval)
{
}
qboolean Sys_CheckUpdated(void)
qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize)
{
return false;
}
@ -3024,6 +3029,7 @@ void Sys_DoFileAssociations(qboolean elevated)
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", ".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\\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;
}
//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)
{
// 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);
else
#endif
if (!(idedx&(1<<25)))
MessageBox(NULL, "This is an SSE optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0);
if (!(idedx&(1<<25)))
MessageBox(NULL, "This is an SSE optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0);
}
#endif
#endif
@ -3297,7 +3890,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
isPlugin = 0;
}
if (Sys_CheckUpdated())
if (Sys_CheckUpdated(bindir, sizeof(bindir)))
return true;
if (COM_CheckParm("-register_types"))
@ -3349,6 +3942,15 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
if (!GetCurrentDirectoryA (sizeof(cwd), cwd))
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.argv[1] != '-' && *parms.argv[1] != '+')
@ -3380,7 +3982,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
}
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;
}
@ -3408,8 +4010,10 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
TL_InitLanguages();
//tprints are now allowed
if (*cwd && cwd[strlen(cwd)-1] != '\\' && cwd[strlen(cwd)-1] != '/')
Q_strncatz(cwd, "/", sizeof(cwd));
parms.basedir = cwd;
parms.binarydir = bindir;
parms.argc = com_argc;
parms.argv = com_argv;
@ -3545,8 +4149,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
#endif
#endif
/* return success of application */
return TRUE;
/* return success of application */
return TRUE;
}
int __cdecl main(void)

View file

@ -532,7 +532,7 @@ void Validation_Apply_Ruleset(void)
#endif
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
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')
c += ('a' - 'A');
if (c == '*') //not a valid filesystem char
c = '#';
out[i] = c;
}
@ -253,9 +255,9 @@ int numwadtextures;
static texwadlump_t texwadlump[TEXWAD_MAXIMAGES];
typedef struct wadfile_s {
char name[64];
vfsfile_t *file;
struct wadfile_s *next;
char name[1];
} wadfile_t;
wadfile_t *openwadfiles;
@ -345,6 +347,12 @@ void W_LoadTextureWadFile (char *filename, int complain)
}
}
// 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))
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!
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;
*height = tex->height;
pal = in + (((tex->width * tex->height) * 85) >> 6);
pal += 2;
if (pal+768 - (qbyte*)tex > lumpsize)
//halflife wads have palettes embedded in them. but make sure everything else is packed because some quake wads are weird.
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;
for (d = 0;d < tex->width * tex->height;d++)
{
p = *in++;
@ -482,6 +500,39 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp
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 {
char *mapname;
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);
qboolean Wad_NextDownload (void);
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_forceTriggers, "0"); \
TP_CVAR(tp_loadlocs, "1"); \
TP_CVARC(cl_teamskin, "", TP_SkinCvar_Callback); \
TP_CVARC(cl_enemyskin, "", TP_SkinCvar_Callback); \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVAR(tp_soundtrigger, "~"); \
\
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.
#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_CVARAC(name,def,name2,call) cvar_t name = CVARAFC(#name, def, #name2, 0, call)
TP_CVARS;
#undef TP_CVAR
#undef TP_CVARC
#undef TP_CVARAC
extern cvar_t host_mapname;
@ -2092,57 +2094,118 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
player_info_t *player;
char *name;
*offset = 0;
*plr = NULL;
flags = TPM_UNKNOWN;
msglen = strlen(s);
if (!msglen)
return TPM_UNKNOWN;
*offset = 0;
*plr = NULL;
for (i=0, player=cl.players ; i < cl.allocated_client_slots ; i++, player++)
if ((s[0] == '^' && s[1] == '[') || (s[0] == '(' && s[1] == '^' && s[2] == '['))
{
name = player->name;
if (!(*name))
continue;
len = strlen(name);
// check messagemode1
if (len+2 <= msglen && s[len] == ':' && s[len+1] == ' ' &&
!strncmp(name, s, len))
char *end, *info;
i = 0;
for(info = s; *info; )
{
if (info[0] == '^' && info[1] == ']')
break;
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)
flags |= TPM_SPECTATOR;
else
flags |= TPM_NORMAL;
*offset = len + 2;
*plr = player;
}
// check messagemode2
else if (s[0] == '(' && len+4 <= msglen &&
!strncmp(s+len+1, "): ", 3) &&
!strncmp(name, s+1, len))
}
else
{
for (i=0, player=cl.players ; i < cl.allocated_client_slots ; i++, player++)
{
// no team messages in teamplay 0, except for our own
if (cl.spectator)
name = player->name;
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 (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) )
{
flags |= TPM_OBSERVEDTEAM;
}
if (player->spectator)
flags |= TPM_SPECTATOR;
else
flags |= TPM_NORMAL;
*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 &&
!strcmp(cl.players[cl.playerview[SP].playernum].team, player->team)) )
// no team messages in teamplay 0, except for our own
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;
*plr = player;
*offset = len + 4;
*plr = player;
}
}
}
@ -3390,9 +3453,11 @@ void TP_Init (void)
//register all the TeamPlay cvars.
#define TP_CVAR(name,def) 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;
#undef TP_CVAR
#undef TP_CVARC
#undef TP_CVARAC
Cmd_AddCommand ("loadloc", TP_LoadLocFile_f);
Cmd_AddCommand ("filter", TP_MsgFilter_f);
@ -3429,7 +3494,7 @@ qboolean TP_SuppressMessage(char *buf) {
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)
{
@ -3509,7 +3574,7 @@ void CL_Say (qboolean team, char *extra)
if (team)
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

View file

@ -149,7 +149,7 @@ struct {
sizebuf_t buf;
int noclear;
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...)
/*

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
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
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));
frames[count].fps = atof(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));
if (frames[count].posecount>0 && frames[count].fps)
count++;
@ -3150,6 +3153,40 @@ static void *Q1_LoadSkins_GL (model_t *loadmodel, daliasskintype_t *pskintype, u
}
#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)
{
#ifndef SERVERONLY
@ -3440,6 +3477,8 @@ qboolean QDECL Mod_LoadQ1Model (model_t *mod, void *buffer, size_t fsize)
mod->type = mod_alias;
Mod_ClampModelSize(mod);
Mesh_HandleFramegroupsFile(mod, galias);
mod->meshinfo = galias;
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')
c2 -= ('a' - 'A');
if (c1 != c2)
return -1; // strings not equal
{ // strings not equal
if (c1 > c2)
return 1; // strings not equal
return -1;
}
}
if (!c1)
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);
if (bits & CM_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))
{
if (str[1] >= '0' && str[1] <= '9')
{
{ //q3 colour codes
if (ext & CON_RICHFORECOLOUR)
ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR));
ext = q3codemasks[str[1]-'0'] | (ext&~CON_Q3MASK); //change colour only.
@ -3344,7 +3348,7 @@ messedup:
}
else
{
if (uc == '\n' || uc == '\r' || uc == '\t' || uc == ' ')
if (uc == '\n' || uc == '\r' || uc == '\t' || uc == '\v' || uc == ' ')
*out++ = uc | ext;
else if (uc >= 32 && uc < 127)
*out++ = uc | ext;
@ -4693,10 +4697,11 @@ void COM_ErrorMe_f(void)
#ifdef LOADERTHREAD
#define WORKERTHREADS (1+1+4)
/*multithreading worker thread stuff*/
static void *com_workercondition[2];
static qboolean com_workerdone[2];
static void *com_workerthread;
static void *com_workercondition[WORKERTHREADS];
static qboolean com_workerdone[WORKERTHREADS];
static void *com_workerthread[WORKERTHREADS];
static unsigned int mainthreadid;
qboolean com_fatalerror;
static struct com_work_s
@ -4707,7 +4712,7 @@ static struct com_work_s
void *data;
size_t a;
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)
{
Sys_Error(data);
@ -4719,6 +4724,9 @@ void COM_WorkerAbort(char *message)
if (Sys_IsMainThread())
return;
if (!com_workercondition[0])
return; //Sys_IsMainThread was probably called too early...
work.func = Sys_ErrorThread;
work.ctx = NULL;
work.data = message;
@ -4743,22 +4751,34 @@ void COM_WorkerAbort(char *message)
//return if there's *any* loading that needs to be done anywhere.
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
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
struct com_work_s *work = Z_Malloc(sizeof(*work));
work = Z_Malloc(sizeof(*work));
work->func = func;
work->ctx = ctx;
work->data = data;
work->a = a;
work->b = b;
if (!com_workerthread || com_fatalerror)
thread = 0;
//queue it (fifo)
Sys_LockConditional(com_workercondition[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_UnlockConditional(com_workercondition[thread]);
if (!com_workerthread)
while(COM_DoWork(0, false))
;
// if (!com_workerthread[thread])
// while(COM_DoWork(thread, false))
// ;
}
//leavelocked = false == poll mode.
//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.
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)
{
int thread = *(int*)arg;
int thread = (void**)arg - com_workerthread;
Sys_LockConditional(com_workercondition[thread]);
do
{
@ -4828,15 +4859,14 @@ static int COM_WorkerThread(void *arg)
break;
} while (Sys_ConditionWait(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;
}
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
void COM_AssertMainThread(const char *msg)
{
@ -4848,22 +4878,45 @@ void COM_AssertMainThread(const char *msg)
#endif
void COM_DestroyWorkerThread(void)
{
int i;
com_fatalerror = false;
if (com_workerthread)
for (i = 0; i < WORKERTHREADS; i++)
{
//send it the terminate message
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 1, 0);
Sys_WaitOnThread(com_workerthread);
com_workerthread = NULL;
if (com_workerthread[i])
{
void *thread = com_workerthread[i];
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])
Sys_DestroyConditional(com_workercondition[0]);
com_workercondition[0] = NULL;
if (com_workercondition[1])
Sys_DestroyConditional(com_workercondition[1]);
com_workercondition[1] = NULL;
for (i = 0; i < WORKERTHREADS; i++)
{
if (com_workercondition[i])
Sys_DestroyConditional(com_workercondition[i]);
com_workercondition[i] = NULL;
}
if (com_resourcemutex)
Sys_DestroyMutex(com_resourcemutex);
@ -4874,33 +4927,38 @@ void COM_DestroyWorkerThread(void)
void COM_WorkerFullSync(void)
{
qboolean repeat;
if (!com_workerthread)
return;
int i;
//main thread asks worker thread to set main thread's 'done' flag.
//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
for (i = 1; i < WORKERTHREADS; i++)
{
int cmds = 0;
com_workerdone[0] = false;
repeat = COM_HasWork();
COM_AddWork(1, COM_WorkerSync_Stop, NULL, NULL, 0, 0);
Sys_LockConditional(com_workercondition[0]);
if (!com_workerthread[i])
continue;
//main thread asks worker thread to set main thread's 'done' flag.
//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;
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)
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)
break;
if (cmds > 1)
repeat = true;
} while (COM_DoWork(0, false) || repeat); //outer loop ensures there isn't anything pingponging between
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.
@ -4912,7 +4970,6 @@ void COM_WorkerPartialSync(void *priorityctx, int *address, int value)
{
struct com_work_s **link, *work, *prev;
double time1 = Sys_DoubleTime();
int thread = 1;
// 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.
if (priorityctx)
{
unsigned int thread;
qboolean found = false;
Sys_LockConditional(com_workercondition[thread]);
for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
for (thread = 1; thread < WORKERTHREADS && !found; thread++)
{
prev = work;
work = *link;
if (work->ctx == priorityctx)
{ //unlink it
Sys_LockConditional(com_workercondition[thread]);
for (link = &com_work_head[thread], work = NULL; *link; link = &(*link)->next)
{
prev = work;
work = *link;
if (work->ctx == priorityctx)
{ //unlink it
*link = work->next;
if (!work->next)
com_work_tail[thread] = prev;
//link it in at the head, so its the next thing seen.
work->next = com_work_head[thread];
com_work_head[thread] = work;
if (!work->next)
com_work_tail[thread] = work;
found = true;
*link = work->next;
if (!work->next)
com_work_tail[thread] = prev;
//link it in at the head, so its the next thing seen.
work->next = com_work_head[thread];
com_work_head[thread] = work;
if (!work->next)
com_work_tail[thread] = work;
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)
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]);
@ -4974,7 +5035,7 @@ static void COM_WorkerPing(void *ctx, void *data, size_t a, size_t b)
{
double *timestamp = data;
if (!b)
COM_AddWork(0, COM_WorkerPing, ctx, data , 0, 1);
COM_AddWork(0, COM_WorkerPing, ctx, data, 0, 1);
else
{
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.");
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.
com_resourcemutex = Sys_CreateMutex();
com_workercondition[0] = Sys_CreateConditional();
com_workercondition[1] = Sys_CreateConditional();
for (i = 0; i < WORKERTHREADS; i++)
{
com_workercondition[i] = Sys_CreateConditional();
}
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);
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)
{
const char *quotedvalue;
char buffer[1024];
char *command;
char *value;
char *value, t;
cvar_t *var;
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, command, value-command);
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);
}
}

View file

@ -477,10 +477,18 @@ void COM_FlushFSCache(qboolean purge, qboolean domutex); //a file was written us
void COM_RefreshFSCache_f(void);
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
{
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 maxver; //if not 0, the manifest will not be used
qboolean disablehomedir;
@ -490,13 +498,15 @@ typedef struct
char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise.
char *protocolname; //the name used for purposes of dpmaster
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
{
qboolean base;
char *path;
} gamepath[8];
struct
struct manpack_s
{
int type;
char *path; //the 'pure' name
qboolean crcknown; //if the crc was specified
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);
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 COM_Gamedir (const char *dir);
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);
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 qboolean standard_quake; //fixme: remove

View file

@ -106,23 +106,40 @@ typedef struct conline_s {
float time;
} 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_NOTIFY 2 /*text printed to console also appears as notify lines*/
#define CONF_NOTIFY_BOTTOM 4 /*align the bottom*/
#define CONF_NOTIMES 8
#define CONF_KEYFOCUSED 16
#define CONF_NOTIFY_RIGHT 8
#define CONF_NOTIMES 16
#define CONF_KEYFOCUSED 32
#define CONF_ISWINDOW 64
typedef struct console_s
{
int id;
int nextlineid; //the current line being written to. so we can rewrite links etc.
char name[64];
char title[64];
char name[128];
char title[128];
float wnd_x;
float wnd_y;
float wnd_w;
float wnd_h;
int linecount;
unsigned int flags;
int notif_x;
int notif_y;
int notif_w;
float notif_x;
float notif_y;
float notif_w;
int notif_l;
float notif_fade; // will be transparent for this long when fading
int maxlines;
float notif_t;
conline_t *oldest;
conline_t *current; // line where next message will be printed
@ -135,7 +152,7 @@ typedef struct console_s
unsigned parseflags;
conchar_t defaultcharbits;
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 *userdata;
@ -143,14 +160,16 @@ typedef struct console_s
conline_t *footerline; //temp text at the bottom of the console
conline_t *selstartline, *selendline;
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
struct console_s *next;
} console_t;
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_chat;
@ -178,23 +197,23 @@ void Con_Shutdown (void);
void Con_History_Save(void);
void Con_History_Load(void);
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);
char *Con_CopyConsole(qboolean nomarkup, qboolean onlyiflink);
char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink);
void Con_Print (char *txt);
void Con_PrintFlags(char *text, unsigned int setflags, unsigned int clearflags);
void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_TPrintf (translation_t text, ...);
void VARGS Con_DPrintf (const 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_DrawNotify (void);
void Con_ClearNotify (void);
void Con_ToggleConsole_f (void);//note: allows csqc to intercept the toggleconsole
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);

File diff suppressed because it is too large Load diff

View file

@ -3,15 +3,16 @@
#include "winquake.h"
//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;
//utf-8 to utf-16, not ucs-2.
unsigned int codepoint;
int error;
outlen = outbytes/sizeof(wchar_t);
if (!outlen)
return L"";
outlen /= sizeof(wchar_t);
outlen--;
while (*utf8)
{
@ -304,7 +305,7 @@ static vfsfile_t *QDECL VFSW32_OpenInternal(vfsw32path_t *handle, const char *qu
file->offset = 0;
file->length = fsize;
return (vfsfile_t*)file;
return &file->funcs;
}
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;
}
//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

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)
{
mins[0] = mins[1] = mins[2] = 999999999;
maxs[0] = maxs[1] = maxs[2] = -999999999;
mins[0] = mins[1] = mins[2] = FLT_MAX;
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;
Q_snprintfz (name, sizeof(name), "textures/%s.wal", texname);
wal = (void *)FS_LoadMallocFile (texname, NULL);
wal = (void *)FS_LoadMallocFile (name, NULL);
if (!wal)
{
wal = &replacementwal;
@ -1263,11 +1263,31 @@ texture_t *Mod_LoadWall(model_t *loadmodel, char *mapname, char *texname, char *
tex->width = base->width;
tex->height = base->height;
}
else
Con_Printf("Unable to load textures/%s.wal\n", wal->name);
}
}
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);
}
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)
{
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;
if (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)
{
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->fraction = trace_nearfraction;
}
*/
static void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
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;
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_WriteShort(&buf, BigShort(sequence)); //seq
MSG_WriteShort(&buf, BigShort(sequence)&0xffff); //seq
MSG_WriteLong(&buf, BigLong(timestamp)); //timestamp
MSG_WriteLong(&buf, BigLong(0)); //ssrc
SZ_Write(&buf, cdata, clength);

View file

@ -76,9 +76,10 @@ qboolean SSL_Inited(void)
struct sslbuf
{
char data[8192];
int avail;
int newd;
size_t datasize;
char *data;
size_t avail;
size_t newd;
};
typedef struct {
@ -113,13 +114,20 @@ typedef struct {
static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes)
{
if (bytes > sizeof(buf->data) - buf->avail)
bytes = sizeof(buf->data) - buf->avail;
if (bytes > buf->datasize - buf->avail)
bytes = buf->datasize - buf->avail;
memcpy(buf->data + buf->avail, data, bytes);
buf->avail += 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)
{
@ -153,7 +161,7 @@ static int SSPI_CheckNewInCrypt(sslfile_t *f)
int newd;
if (!f->stream)
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)
return newd;
else
@ -193,7 +201,11 @@ static void SSPI_Decode(sslfile_t *f)
if (ss < 0)
{
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.
}
switch(ss)
{
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
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
{
wchar_t *hostname;
unsigned int datasize;
qbyte *data;
const qbyte *data;
//FIXME: include expiry information
//FIXME: add alternative when one is about to expire
} 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}
};
@ -543,7 +557,7 @@ static void SSPI_Handshake (sslfile_t *f)
OutBuffDesc.cBuffers = 1;
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.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);
if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return;
}
//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)
@ -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);
if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return;
}
f->handshaking = HS_SERVER;
//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;
qboolean success = f->stream != NULL;
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);
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.seekingisabadplan = true;
SSPI_ExpandBuffer(&newf->outraw, 8192);
SSPI_ExpandBuffer(&newf->outcrypt, 8192);
SSPI_ExpandBuffer(&newf->inraw, 8192);
SSPI_ExpandBuffer(&newf->incrypt, 8192);
if (server)
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);
else
#endif
#ifdef _WIN32
Con_TPrintf ("NET_SendPacket ERROR: %i\n", ecode);
#else
Con_TPrintf ("NET_SendPacket ERROR: %s\n", strerror(ecode));
#endif
}
return true;
#endif
@ -2807,6 +2811,82 @@ void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen)
*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"
qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
{
@ -3218,35 +3298,47 @@ handshakeerror:
unsigned int payoffs = 2;
unsigned int mask = 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)
{
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)
// if (sizeof(paylen) < 8)
if (sizeof(ullpaylen) < 8)
{
Con_Printf ("%s: payload frame too large\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
}
/* else
else
{
if (payoffs + 8 > st->inlen)
break;
paylen =
((unsigned char*)st->inbuffer)[payoffs+0]<<56 |
((unsigned char*)st->inbuffer)[payoffs+1]<<48 |
((unsigned char*)st->inbuffer)[payoffs+2]<<40 |
((unsigned char*)st->inbuffer)[payoffs+3]<<32 |
((unsigned char*)st->inbuffer)[payoffs+4]<<24 |
((unsigned char*)st->inbuffer)[payoffs+5]<<16 |
((unsigned char*)st->inbuffer)[payoffs+6]<<8 |
((unsigned char*)st->inbuffer)[payoffs+7]<<0;
if (paylen < 0x10000)
ullpaylen =
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+0]<<56ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+1]<<48ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+2]<<40ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+3]<<32ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+4]<<24ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+5]<<16ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+6]<< 8ull |
(unsigned long long)((unsigned char*)st->inbuffer)[payoffs+7]<< 0ull;
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;
}
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;
}
*/ }
}
else if ((ctrl & 0x7f) == 126)
{
if (payoffs + 2 > st->inlen)
@ -3293,10 +3385,10 @@ handshakeerror:
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));
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));
{
/*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;
}
break;
case 2: /*binary frame*/
// Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), st->remoteaddr));
case 0x2: /*binary frame*/
Con_Printf ("websocket binary frame from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
net_message.cursize = paylen;
if (net_message.cursize+8 >= sizeof(net_message_buffer) )
{
@ -3350,13 +3442,15 @@ handshakeerror:
else
memcpy(net_message_buffer, st->inbuffer+payoffs, paylen);
break;
case 8: /*connection close*/
case 0x8: /*connection close*/
Con_Printf ("websocket closure %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
case 9: /*ping*/
case 0x9: /*ping*/
Con_Printf ("websocket ping from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
case 10: /*pong*/
if (!FTENET_TCPConnect_WebSocket_Splurge(st, 0xa, st->inbuffer+payoffs, paylen))
goto closesvstream;
break;
case 0xa: /*pong*/
Con_Printf ("websocket pong from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
default:
@ -3479,67 +3573,7 @@ qboolean FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
//fallthrough
case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
{
/*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;
}
FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length);
break;
default:
break;
@ -4395,7 +4429,8 @@ static qboolean FTENET_WebSocket_SendPacket(ftenet_generic_connection_t *gcon, i
ftenet_websocket_connection_t *wsc = (void*)gcon;
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 false;
@ -5846,8 +5881,16 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea
if (tf->sock != INVALID_SOCKET)
{
trying = sizeof(tf->readbuffer) - tf->readbuffered;
if (trying > 1500)
trying = 1500;
if (bytestoread > 1500)
{
if (trying > bytestoread)
trying = bytestoread;
}
else
{
if (trying > 1500)
trying = 1500;
}
len = recv(tf->sock, tf->readbuffer + tf->readbuffered, trying, 0);
if (len == -1)
{
@ -5924,7 +5967,7 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt
timeout.tv_usec = 0;
FD_ZERO(&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;
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.
case NET_ENOTCONN:
Con_Printf("connection to \"%s\" failed\n", tf->peer);
break;
return -1; //don't bother trying to read if we never connected.
default:
Sys_Printf("tcp socket error %i (%s)\n", e, tf->peer);
break;

View file

@ -77,7 +77,7 @@ typedef struct plugin_s {
struct plugin_s *next;
} plugin_t;
void Plug_SubConsoleCommand(console_t *con, char *line);
int Plug_SubConsoleCommand(console_t *con, char *line);
plugin_t *currentplug;
@ -262,6 +262,8 @@ plugin_t *Plug_Load(const char *file, int type)
newplug->name = (char*)(newplug+1);
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))
newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL);
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)
*dot = 0;
}
len = strlen(vmname);
if (len > 0 && vmname[len-1] == '_')
vmname[len-1] = 0;
if (!Plug_Load(vmname, PLUG_NATIVE))
Con_Printf("Couldn't load plugin %s\n", vmname);
@ -1538,16 +1543,18 @@ qboolean Plug_ConsoleLink(char *text, char *info)
return result;
}
void Plug_SubConsoleCommand(console_t *con, char *line)
int Plug_SubConsoleCommand(console_t *con, char *line)
{
int ret;
char buffer[2048];
plugin_t *oldplug = currentplug; //shouldn't really be needed, but oh well
currentplug = con->userdata;
Q_strncpyz(buffer, va("\"%s\" %s", con->name, line), sizeof(buffer));
Cmd_TokenizeString(buffer, false, false);
VM_Call(currentplug->vm, currentplug->conexecutecommand, 0);
ret = VM_Call(currentplug->vm, currentplug->conexecutecommand, 0);
currentplug = oldplug;
return ret;
}
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;
debuggerfile = filename;
if (reason)
Con_Footerf(false, "^bDebugging: %s", reason);
Con_Footerf(NULL, false, "^bDebugging: %s", reason);
else
Con_Footerf(false, "^bDebugging");
Con_Footerf(NULL, false, "^bDebugging");
while(debuggerresume == -1 && !wantquit)
{
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)
{
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);
}
@ -1231,6 +1240,11 @@ void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
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
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
////////////////////////////////////////////////////
//hash table stuff
#define MAX_QC_HASHTABLES 256
typedef struct
{
pubprogfuncs_t *prinst;
@ -1458,12 +1470,16 @@ typedef struct
char *stringdata;
};
} 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_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts.
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)
{
@ -1475,9 +1491,6 @@ static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx)
}
return &pf_peristanthashtab;
}
idx -= 1;
if (idx >= 0 && idx < MAX_QC_HASHTABLES && pf_hashtab[idx].prinst)
return &pf_hashtab[idx];
else
PR_BIError(prinst, "PF_hash_findtab: invalid hash table\n");
return NULL;
@ -1585,7 +1598,7 @@ void QCBUILTIN PF_hash_add (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
{
if (!type)
type = tab->defaulttype;
if (flags & 256)
if (!(flags & 512) || (flags & 256))
{
ent = Hash_Get(&tab->tab, name);
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)
{
//FIXME: these need to be managed by the qcvm for garbage collection
int i;
int numbuckets = G_FLOAT(OFS_PARM0);
// 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;
if (numbuckets < 4)
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)
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;
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;
G_FLOAT(OFS_RETURN) = 0;
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.
@ -4847,6 +4868,11 @@ void QCBUILTIN PF_localcmd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
char *str;
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"))
Cbuf_AddText ("sv_mintic 0\n", RESTRICT_INSECURE); //hmm... do this better...
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_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_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);
//pr_cmds.c builtins that need to be moved to a common.
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_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_setf (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...
VF_PERSPECTIVE = 200,
//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_SCREENVSIZE = 204,
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_setangledelta 85 // [angle3] add this to the current viewangles
#define svcfte_updateentities 86
#define svcfte_brushedit 87 // networked brush editing, paired with clcfte_brushedit.
//fitz svcs
@ -413,14 +414,15 @@ enum clcq2_ops_e
#define clc_stringcmd 4 // [string] message
#define clc_delta 5 // [qbyte] sequence number, requests delta compression of message
#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_ackdownloaddata 51
#define clc_qcrequest 81
#define clc_prydoncursor 82
#define clc_voicechat 83
#define clcfte_qcrequest 81
#define clcfte_prydoncursor 82
#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)
qboolean Sys_remove (char *path);
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
@ -49,6 +49,7 @@ void Sys_Warn (char *fmt, ...) LIKEPRINTF(1);
void Sys_Quit (void);
void Sys_RecentServer(char *command, char *target, char *title, char *desc);
qboolean Sys_RunInstaller(void);
typedef struct {
void **funcptr;

View file

@ -72,6 +72,8 @@ typedef struct trace_s
qboolean inopen, inwater;
float truefraction; //can be negative, also has floating point precision issues, etc.
int brush_id;
int brush_face;
} trace_t;
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)
{

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_TagFree(void *ptr);
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.
//(this is a nicer name for malloc)

View file

@ -759,9 +759,9 @@ static void (D3D9_VID_DeInit) (void)
mainwindow = NULL;
}
Cvar_Unhook(&v_gamma);
Cvar_Unhook(&v_contrast);
Cvar_Unhook(&v_brightness);
// Cvar_Unhook(&v_gamma);
// Cvar_Unhook(&v_contrast);
// Cvar_Unhook(&v_brightness);
}
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
Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}"
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}
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{82285268-9C3B-44AD-BBE7-40670F9D2628} = {82285268-9C3B-44AD-BBE7-40670F9D2628}
EndProjectSection
EndProject
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
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}"
ProjectSection(ProjectDependencies) = postProject
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080}
EndProjectSection
EndProject
@ -351,6 +352,7 @@ Global
{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}.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}.GLRelease|Win32.ActiveCfg = Release|Win32
{9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|x64.ActiveCfg = Release|Win32

View file

@ -26099,6 +26099,10 @@
RelativePath="..\common\fs_win32.c"
>
</File>
<File
RelativePath="..\common\fs_xz.c"
>
</File>
<File
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.loweroverlay = 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
//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,
"{\n"
"program crepuscular_sky\n"
"{\n"
"map $diffuse\n"
"}\n"
"{\n"
"map $fullbright\n"
"}\n"
"}\n"
);
}
@ -3988,7 +3994,7 @@ static void DrawMeshes(void)
{
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_SubmitMeshChain(false);
@ -4629,6 +4635,7 @@ static void BE_UpdateLightmaps(void)
lightmapinfo_t *lm;
int lmidx;
int glformat, gltype;
int internalformat = GL_RGBA;
switch (lightmap_bytes)
{
case 4:
@ -4644,6 +4651,9 @@ static void BE_UpdateLightmaps(void)
gltype = GL_UNSIGNED_BYTE;
break;
}
if (gl_config.gles)
internalformat = glformat;
for (lmidx = 0; lmidx < numlightmaps; lmidx++)
{
lm = lightmap[lmidx];
@ -4660,7 +4670,7 @@ static void BE_UpdateLightmaps(void)
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_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->lightmaps);
}

View file

@ -45,7 +45,7 @@ http://prideout.net/archive/bloom/ contains some sample code
#include "shader.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_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.");
static shader_t *bloomfilter;
static shader_t *bloomrescale;

View file

@ -233,7 +233,7 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
}
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))
min = GL_LINEAR_MIPMAP_LINEAR;
@ -242,7 +242,7 @@ static void GL_Texturemode_Apply(GLenum targ, unsigned int flags)
}
else
{
if (filter[0] && !(flags & IF_NEAREST) || (flags & IF_LINEAR))
if ((filter[0] && !(flags & IF_NEAREST)) || (flags & IF_LINEAR))
min = GL_LINEAR_MIPMAP_NEAREST;
else
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.
//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 is available in gles3
if (!gl_config.gles)
{
if (targ != GL_TEXTURE_CUBE_MAP_ARB && (tex->flags & IF_MIPCAP))

View file

@ -10,7 +10,7 @@
void Font_Init(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_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*/
@ -161,6 +161,7 @@ static const char *imgs[] =
#define BITMAPPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-2)
#define DEFAULTPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-3)
#define SINGLEPLANE ((1<<(8*sizeof(PLANEIDXTYPE)))-4)
#define TRACKERIMAGE ((1<<(8*sizeof(PLANEIDXTYPE)))-5)
#define PLANEWIDTH (1<<8)
#define PLANEHEIGHT PLANEWIDTH
@ -226,6 +227,7 @@ typedef struct font_s
typedef struct {
texid_t texnum[FONTPLANES];
texid_t defaultfont;
texid_t trackerimage;
unsigned char plane[PLANEWIDTH*PLANEHEIGHT][4]; //tracks the current plane
PLANEIDXTYPE activeplane;
@ -259,12 +261,56 @@ static struct font_s *curfont;
static float curfont_scale[2];
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
void Font_Init(void)
{
int i;
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.xyz_array = font_coord;
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];
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.
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.
//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;
int i = 0;
int defaultplane;
char *aname;
char *parms;
int height = (vheight * vid.rotpixelheight)/vid.height;
int height = ((vheight * vid.rotpixelheight)/vid.height) + 0.5;
char facename[MAX_QPATH];
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
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;
px = Font_CharEndCoord(font, px, start[l]);
l++;
@ -1600,7 +1657,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
if (start == end)
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
}
@ -1707,16 +1764,16 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
if ((charcode & CON_CHARMASK) == ' ')
return nextx;
if (charcode & CON_BLINKTEXT)
/* if (charcode & CON_BLINKTEXT)
{
if (!cl_noblink.ival)
if ((int)(realtime*3) & 1)
return nextx;
}
*/
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)
{
vec4_t rgba;
@ -1749,6 +1806,11 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
rgba[1] *= font_foretint[1];
rgba[2] *= font_foretint[2];
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[1] = min(rgba[1], 255);
font_forecolour[2] = min(rgba[2], 255);
@ -1757,7 +1819,7 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
}
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)
{
vec4_t rgba;
@ -1793,6 +1855,11 @@ int Font_DrawChar(int px, int py, unsigned int charcode)
rgba[1] *= font_foretint[1];
rgba[2] *= font_foretint[2];
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[1] = min(rgba[1], 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)
{
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:
sx = ((px+c->left + dxbias)*(int)vid.width) / (float)vid.rotpixelwidth;
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
model_t *lightmodel;
struct relight_ctx_s *lightcontext;
int numlightdata;
qboolean writelitfile;
@ -254,6 +255,7 @@ volatile qboolean wantrelight;
int RelightThread(void *arg)
{
int surf;
void *threadctx = malloc(lightthreadctxsize);
while (wantrelight)
{
#ifdef _WIN32
@ -265,9 +267,10 @@ int RelightThread(void *arg)
#endif
if (surf >= lightmodel->numsurfaces)
break;
LightFace(surf);
LightFace(lightcontext, threadctx, surf);
lightmodel->surfaces[surf].cached_dlight = -1;
}
free(threadctx);
return 0;
}
#endif
@ -312,7 +315,7 @@ void Mod_Think (void)
return;
}
#else
LightFace(relitsurface);
LightFace(lightcontext, relitsurface);
Mod_UpdateLightmap(relitsurface);
relitsurface++;
@ -337,6 +340,9 @@ void Mod_Think (void)
}
#endif
LightShutdown(lightcontext, lightmodel);
lightcontext = NULL;
if (lightmodel->deluxdata)
{
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)
{
#ifndef SERVERONLY
extern cvar_t gl_shadeq1_name;
char altname[MAX_QPATH];
char *star;
const char *origname = NULL;
const char *shadername = tx->name;
/*skies? just replace with the override sky*/
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.
//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
{
strncpy(altname, gl_shadeq1_name.string, star-gl_shadeq1_name.string); //copy the left
altname[star-gl_shadeq1_name.string] = '\0';
strcat(altname, tx->name); //insert the *
strcat(altname, star+1); //add any final text.
tx->shader = R_RegisterCustom (altname, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
//remap to avoid bugging out on textures with the same name and different images (vanilla content sucks)
shadername = Mod_RemapBuggyTexture(shadername, tx->mips[0], tx->width*tx->height);
if (shadername)
origname = tx->name;
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))
R_InitSky (&tx->shader->defaulttextures, tx, tx->mips[0]);
R_InitSky (&tx->shader->defaulttextures, shadername, tx->mips[0], tx->width, tx->height);
else
{
unsigned int maps = 0;
@ -1216,53 +1285,42 @@ void Mod_FinishTexture(texture_t *tx, const char *loadname)
maps |= SHADER_HASNORMALMAP;
if (gl_specular.ival)
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]);
#endif
}
#ifndef SERVERONLY
static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt)
{
#ifndef SERVERONLY
qbyte *base;
qboolean alphaed;
int pixels = mt->width*mt->height/64*85;
base = (qbyte *)(mt+1);
unsigned int size =
(mt->width>>0)*(mt->height>>0) +
(mt->width>>1)*(mt->height>>1) +
(mt->width>>2)*(mt->height>>2) +
(mt->width>>3)*(mt->height>>3);
if (loadmodel->fromgame == fg_halflife)
{//external textures have already been filtered.
//size is not directly known.
//we might be able to infer based upon neighbours, but that seems like too much hassle
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);
{ //mostly identical, just a specific palette hidden at the end. handle fences elsewhere.
tx->mips[0] = BZ_Malloc(size + 768);
tx->palette = tx->mips[0] + size;
memcpy(tx->palette, (qbyte *)mt + mt->offsets[3] + (mt->width>>3)*(mt->height>>3) + 2, 768);
}
else
{
qbyte *mipbase;
unsigned int mipwidth, mipheight;
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);
tx->mips[0] = BZ_Malloc(size);
tx->palette = host_basepal;
}
#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;
}
#ifndef SERVERONLY
Mod_LoadMiptex(loadmodel, tx, mt);
#endif
}
//
// 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.
char luxname[MAX_QPATH];
size_t luxsz = 0;
*luxname = 0;
if (!luxdata)
{
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);
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)
{
int size;
@ -1594,20 +1661,12 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
luxdata = NULL;
luxtmp = true;
}
else if (luxdata)
else
{
if (l->filelen && l->filelen != (luxsz-8)/3)
{
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 (luxdata[0] == 'Q' && luxdata[1] == 'L' && luxdata[2] == 'I' && luxdata[3] == 'T')
{
if (LittleLong(*(int *)&luxdata[4]) == 1)
{
luxdata+=8;
loadmodel->deluxdata = luxdata;
}
else
{
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)
litname = litnamemaps; //maps has priority over lits
else
{
litname = litnamelits;
}
litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize);
littmp = false;
if (!litdata)
{
int size;
litdata = Q1BSPX_FindLump("RGBLIGHTING", &size);
if (size != samples*3)
if (litdata)
{ //validate it, if we loaded one.
if (litdata[0] != 'Q' || litdata[1] != 'L' || litdata[2] != 'I' || litdata[3] != 'T')
{
litdata = NULL;
littmp = true;
}
else if (litdata[0] == 'Q' && litdata[1] == 'L' && litdata[2] == 'I' && litdata[3] == 'T')
{
if (LittleLong(*(int *)&litdata[4]) == 1 && l->filelen && samples*3 != (litsize-8))
Con_Printf("lit \"%s\" isn't a lit\n", litname);
}
else if (LittleLong(*(int *)&litdata[4]) == 1 && l->filelen && samples*3 != (litsize-8))
{
litdata = NULL;
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);
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;
int i;
@ -1711,13 +1777,6 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
//end anti-cheat
}
}
else if (litdata)
{
Con_Printf("lit \"%s\" isn't a lit\n", litname);
litdata = NULL;
}
// else
//failed to find
}
#endif
@ -1850,7 +1909,7 @@ char *Mod_ParseWorldspawnKey(const char *ents, const char *key, char *buffer, si
{
char keyname[64];
char value[1024];
while(*ents)
while(ents && *ents)
{
ents = COM_ParseOut(ents, keyname, sizeof(keyname));
if (*keyname == '{') //an entity
@ -2731,28 +2790,20 @@ static void Mod_Batches_Generate(model_t *mod)
}
}
typedef struct
{
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)
void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height, int firstlm)
{
memset(lmallocator, 0, sizeof(*lmallocator));
lmallocator->deluxe = hasdeluxe;
lmallocator->lmnum = LM_FIRST;
lmallocator->lmnum = firstlm;
lmallocator->firstlm = firstlm;
lmallocator->width = width;
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.count = (lmallocator->lmnum - LM_FIRST);
mod->lightmaps.first = lmallocator->firstlm;
mod->lightmaps.count = (lmallocator->lmnum - lmallocator->firstlm);
if (lmallocator->allocated[0])
mod->lightmaps.count++;
@ -2765,7 +2816,7 @@ static void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod)
else
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 i, j;
@ -2920,6 +2971,8 @@ static void Mod_Batches_AllocLightmaps(model_t *mod)
}
samps /= 4;
samps = sqrt(samps);
if (j > 128)
samps *= 2;
mod->lightmaps.width = bound(j, samps, LMBLOCK_SIZE_MAX);
mod->lightmaps.height = bound(j, samps, LMBLOCK_SIZE_MAX);
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.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 (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);
//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 numverts = 0, numindicies=0;
@ -4099,6 +4152,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b)
{
#ifndef SERVERONLY
model_t *mod = ctx;
char loadname[MAX_QPATH];
if (!a)
{ //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)
{
COM_FileBase (mod->name, loadname, sizeof(loadname));
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);
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
{
char loadname[MAX_QPATH];
COM_FileBase (mod->name, loadname, sizeof(loadname));
if (!strncmp(loadname, "b_", 2))
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 ofs;
qbyte *file;
char *mapname;
memset(patch, 0, sizeof(*patch));
if (!mod_external_vis.ival)
return;
mapname = COM_SkipPath(mod->name);
COM_StripExtension(mod->name, patchname, 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);
if (!patch->fileptr)
return;
ofs = 0;
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)
break;
// if (!Q_strcasecmp(patchname, "foo"))
if (!Q_strcasecmp(patchname, mapname))
{
lenptr = (int*)file;
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)
{
Con_Printf("Vis patch is unsuitable\n");
patch->visptr = NULL;
patch->leafptr = NULL;
}
else
break;
}
ofs += 36+len;
}
@ -4494,7 +4564,10 @@ TRACE(("LoadBrushModel %i\n", __LINE__));
#ifdef RUNTIMELIGHTING
TRACE(("LoadBrushModel %i\n", __LINE__));
if (lightmodel == mod)
LightLoadEntities(lightmodel->entities);
{
lightcontext = LightStartup(NULL, lightmodel, true);
LightReloadEntities(lightcontext, lightmodel->entities);
}
#endif
TRACE(("LoadBrushModel %i\n", __LINE__));
if (!isDedicated)

View file

@ -51,7 +51,11 @@ typedef enum {
} shadersort_t;
#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.
#endif
struct doll_s;
void rag_flushdolls(qboolean force);
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
qbyte *mips[4]; //the different mipmap levels.
qbyte *palette; //host_basepal or halflife per-texture palette
} texture_t;
/*
typedef struct
@ -999,6 +1004,9 @@ unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org)
struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);
qboolean Terr_DownloadedSection(char *fname);
void CL_Parse_BrushEdit(void);
qboolean SV_Parse_BrushEdit(void);
#endif

View file

@ -100,6 +100,7 @@ void R_NetGraph (void)
int lost;
char st[80];
unsigned ngraph_pixels[NET_GRAPHHEIGHT][NET_TIMINGS];
float pi, po, bi, bo;
x = 0;
if (r_netgraph.value < 0)
@ -130,15 +131,22 @@ void R_NetGraph (void)
x = ((vid.width - 320)>>1);
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;
sprintf(st, "%3i%% packet loss", lost);
Draw_FunString(8, y, st);
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);
x=8;
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;
float f;
//if (r_lightstylescale.value > 2)
//r_lightstylescale.value = 2;
//
// light animations
@ -74,13 +77,13 @@ void R_AnimateLight (void)
int v1, v2, vd;
if (!cl_lightstyle[j].length)
{
d_lightstylevalue[j] = ('m'-'a')*22;
d_lightstylevalue[j] = ('m'-'a')*22 * r_lightstylescale.value;
continue;
}
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;
}
@ -92,9 +95,9 @@ void R_AnimateLight (void)
vd = v1 - v2;
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
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)
return;
if (!mesh->xyz_array)
return;
if (!mesh->normals_array)
{
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 vid_conautoscale, vid_conheight, vid_conwidth;
extern cvar_t crosshair, crosshairimage, crosshaircolor, r_skyboxname;
extern cvar_t r_floorcolour, r_wallcolour, r_floortexture, r_walltexture;
extern cvar_t r_fastskycolour;
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_conheight);
Cvar_Unhook(&vid_conwidth);
Cvar_Unhook(&r_walltexture);
Cvar_Unhook(&r_floortexture);
Cvar_Unhook(&r_drawflat);
Cvar_Unhook(&v_gamma);
Cvar_Unhook(&v_contrast);
Cvar_Unhook(&v_brightness);
// Cvar_Unhook(&v_gamma);
// Cvar_Unhook(&v_contrast);
// Cvar_Unhook(&v_brightness);
Surf_DeInit();
@ -478,10 +474,6 @@ void GLR_Init (void)
// 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();
}

View file

@ -657,10 +657,18 @@ static int Shader_SetImageFlags(shader_t *shader, shaderpass_t *pass, char **nam
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 data[256*(VID_GRADES-1)];
unsigned int data[256*(VID_GRADES)];
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)
{
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);
}
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 )
{
shader->flags |= SHADER_NOPICMIP;
@ -2056,6 +2070,7 @@ static shaderkey_t shaderkeys[] =
{"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d
{"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d
{"param", Shader_ProgramParam, "fte"}, //legacy
{"affine", Shader_Affine, "fte"}, //some hardware is horribly slow, and can benefit from certain hints.
{"bemode", Shader_BEMode, "fte"},
@ -4134,6 +4149,7 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
char *h;
char imagename[MAX_QPATH];
char *subpath = NULL;
unsigned int imageflags = 0;
strcpy(imagename, shader->name);
h = strchr(imagename, '#');
if (h)
@ -4172,6 +4188,8 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
TEXASSIGN(shader->defaulttextures.paletted, tn->paletted);
}
imageflags |= IF_LOWPRIORITY;
COM_StripExtension(imagename, imagename, sizeof(imagename));
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 (!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))
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);
}
@ -4191,9 +4209,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if (shader->flags & SHADER_HASTOPBOTTOM)
{
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))
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);
}
@ -4203,9 +4221,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader)
if (shader->flags & SHADER_HASTOPBOTTOM)
{
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))
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);
}
@ -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 (!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))
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);
}
@ -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 (!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))
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);
}
}
//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 imagename[MAX_QPATH];
//extern cvar_t gl_miptexLevel;
texnums_t *tex = &shader->defaulttextures;
unsigned int imageflags;
qbyte *dontcrashme[4] = {NULL};
if (!mipdata)
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);
h = strchr(imagename, '#');
if (h)
@ -4263,8 +4294,11 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned
if (shader->generator == Shader_DefaultSkin)
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.
imageflags = (basefmt==TF_SOLID8)?IF_NOALPHA:0;
imageflags = (basefmt==TF_SOLID8 || basefmt == TF_MIP4_SOLID8)?IF_NOALPHA:0;
imageflags |= IF_MIPCAP;
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)
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);
}
@ -4283,9 +4332,10 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *subpath, unsigned
if (!TEXVALID(tex->paletted) && *shader->mapname)
tex->paletted = R_LoadHiResTexture(va("%s_pal", shader->mapname), NULL, imageflags|IF_NEAREST);
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.
imageflags &= ~IF_NOALPHA;
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));
}
else if (!strncmp(shortname, "trans/", 6))
{
Shader_DefaultScript(shortname, s,
"{\n"
"{\n"
@ -4676,6 +4727,19 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args)
"}\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
Shader_DefaultBSPLM(shortname, s, args);
}

View file

@ -3201,13 +3201,17 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
"}\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);
}
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_SelectDLight(dl, colours, dl->axis, LSHADER_STANDARD);
@ -3217,6 +3221,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours)
oldsrccol = NULL;//shaderstate.tex_sourcecol;
GLBE_FBO_Sources(crepuscular_texture_id, NULL);
// crepuscular_shader->defaulttextures.base = crepuscular_texture_id;
//shaderstate.tex_sourcecol = oldsrccol;
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[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)
continue; //just switch these off.

View file

@ -1062,6 +1062,23 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
qglDebugMessageCallbackARB = (void *)getglext("glDebugMessageCallbackARB");
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
{
qglDebugMessageControlARB = NULL;
@ -1640,7 +1657,13 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
strings++;
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]);
strings++;
}
@ -2612,13 +2635,22 @@ void DumpGLState(void)
// if (qglGetVertexAttribiv)
{
qglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &rval);
Sys_Printf("VERTEX_ARRAY_BINDING: %i\n", rval);
qglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &rval);
Sys_Printf("GL_ARRAY_BUFFER_BINDING: %i\n", rval);
if (qglBindVertexArray)
{
qglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &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))
{
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);
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))
{
qglGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &rval);
if (qglBindBufferARB)
qglGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &rval);
else
rval = 0;
#ifndef GL_INDEX_ARRAY_POINTER
Sys_Printf("GL_ELEMENT_ARRAY_BUFFER_BINDING: %i:%p\n", rval, (void*)0);
#else
@ -2639,7 +2674,10 @@ void DumpGLState(void)
}
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);
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);
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);
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))
{
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);
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);
if (!en)
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_STRIDE, &st);
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);
}
qglGetIntegerv(GL_CURRENT_PROGRAM, &glint);
Sys_Printf("GL_CURRENT_PROGRAM: %i\n", glint);
if (qglUseProgramObjectARB)
{
qglGetIntegerv(GL_CURRENT_PROGRAM, &glint);
Sys_Printf("GL_CURRENT_PROGRAM: %i\n", glint);
}
qglGetIntegerv(GL_BLEND, &glint);
Sys_Printf("GL_BLEND: %i\n", glint);

View file

@ -2009,6 +2009,9 @@ void INS_ReInit(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)
{

View file

@ -205,6 +205,9 @@ void INS_Shutdown (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)
{
}

View file

@ -578,7 +578,6 @@ RECT centerrect(unsigned int parentleft, unsigned int parenttop, unsigned int pa
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)
{
int width, height;
@ -2157,6 +2156,10 @@ LONG WINAPI GLMainWndProc (
INS_TranslateKeyEvent(wParam, lParam, false, 0, false);
break;
case WM_MOUSEACTIVATE:
lRet = MA_ACTIVATEANDEAT;
break;
// 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
case WM_LBUTTONDOWN:

View file

@ -352,6 +352,8 @@ static void R_CalcSkyChainBounds (batch_t *batch)
for (m = batch->firstmesh; m < batch->meshes; m++)
{
mesh = batch->mesh[m];
if (!mesh->xyz_array)
continue;
//triangulate
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
==============
*/
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;
unsigned trans[128*128];
@ -751,45 +753,51 @@ void R_InitSky (struct texnums_s *tn, texture_t *mt, qbyte *src)
unsigned *rgba;
char name[MAX_QPATH];
unsigned int stride = width;
width /= 2;
memset(tn, 0, sizeof(*tn));
if (width < 1 || height < 1 || stride != width*2)
return;
// make an average value for the back to avoid
// a fringe on the top level
r = g = b = 0;
for (i=0 ; i<128 ; i++)
for (j=0 ; j<128 ; j++)
for (i=0 ; i<height ; i++)
for (j=0 ; j<width ; j++)
{
p = src[i*256 + j + 128];
p = src[i*stride + j + width];
rgba = &d_8to24rgbtable[p];
trans[(i*128) + j] = *rgba;
trans[(i*width) + j] = *rgba;
r += ((qbyte *)rgba)[0];
g += ((qbyte *)rgba)[1];
b += ((qbyte *)rgba)[2];
}
Q_snprintfz(name, sizeof(name), "%s_solid", mt->name);
Q_snprintfz(name, sizeof(name), "%s_solid", skyname);
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)[1] = g/(128*128);
((qbyte *)&transpix)[2] = b/(128*128);
((qbyte *)&transpix)[0] = r/(width*height);
((qbyte *)&transpix)[1] = g/(width*height);
((qbyte *)&transpix)[2] = b/(width*height);
((qbyte *)&transpix)[3] = 0;
alphamask = LittleLong(0x7fffffff);
for (i=0 ; i<128 ; i++)
for (j=0 ; j<128 ; j++)
for (i=0 ; i<height ; i++)
for (j=0 ; j<width ; j++)
{
p = src[i*256 + j];
p = src[i*stride + j];
if (p == 0)
trans[(i*128) + j] = transpix;
trans[(i*width) + j] = transpix;
else
trans[(i*128) + j] = d_8to24rgbtable[p] & alphamask;
trans[(i*width) + j] = d_8to24rgbtable[p] & alphamask;
}
//FIXME: support _trans
Q_snprintfz(name, sizeof(name), "%s_alpha", mt->name);
Q_snprintfz(name, sizeof(name), "%s_alpha", skyname);
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

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
typedef struct
{
int allocated[LMBLOCK_SIZE_MAX];
int firstlm;
int lmnum;
unsigned int width;
unsigned int height;
qboolean deluxe;
} lmalloc_t;
void Mod_LightmapAllocInit(lmalloc_t *lmallocator, qboolean hasdeluxe, unsigned int width, unsigned int height, int firstlm); //firstlm is for debugging stray lightmap indexes
void Mod_LightmapAllocDone(lmalloc_t *lmallocator, model_t *mod);
void Mod_LightmapAllocBlock(lmalloc_t *lmallocator, int w, int h, unsigned short *x, unsigned short *y, int *tnum);
#ifdef GLQUAKE
#if defined(ANDROID) /*FIXME: actually just to use standard GLES headers instead of full GL*/
#if 1

View file

@ -1,34 +1,6 @@
#include "quakedef.h"
#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 {
vec3_t origin;
@ -41,11 +13,40 @@ typedef struct mentity_s {
char target[64];
char targetname[64];
struct mentity_s *targetent;
int targetentnum;
} mentity_t;
static mentity_t entities[8192];
static int num_entities;
struct relight_ctx_s
{
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
@ -56,14 +57,17 @@ CastRay
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;
vec3_t move;
lightmodel->funcs.NativeTrace (lightmodel, 0, 0, NULL, p1, p2, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &trace);
if (trace.fraction < 1)
return -1;
if (ctx->shadows)
{
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);
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
mentity_t *mapent;
@ -122,7 +152,7 @@ void LightLoadEntities(char *entstring)
char value[1024];
int i;
int switchedstyle=32;
num_entities = 0;
ctx->num_entities = 0;
while(1)
{
@ -135,11 +165,18 @@ void LightLoadEntities(char *entstring)
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));
mapent->colour[0] = 0;
mapent->colour[1] = 0;
mapent->colour[2] = 0;
mapent->targetentnum = -1;
while(1)
{
entstring = COM_ParseOut(entstring, key, sizeof(key));
@ -158,7 +195,7 @@ void LightLoadEntities(char *entstring)
for (i = 0; i < 256; i+=16)
{
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))
break;
}
@ -204,35 +241,35 @@ void LightLoadEntities(char *entstring)
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;
}
}
if (i == num_entities)
if (i == ctx->num_entities)
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)
{
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;
if (!strcmp(mapent->target, entities[i].targetname))
if (!strcmp(mapent->target, ctx->entities[i].targetname))
{
mapent->targetent = &entities[i];
mapent->targetentnum = i;
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 lightnorm[MAXQ1LIGHTMAPS][SINGLEMAP];
int numlightstyles;
@ -319,11 +322,11 @@ typedef struct
vec_t exactmins[2], exactmaxs[2];
int texmins[2], texsize[2];
int lightstyles[256];
int surfnum;
dface_t *face;
int lightstyles[MAXQ1LIGHTMAPS];
} llightinfo_t;
const size_t lightthreadctxsize = sizeof(llightinfo_t);
/*
================
@ -332,35 +335,36 @@ CalcFaceVectors
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;
vec3_t texnormal;
float distscale;
vec_t dist, len;
tex = &bsptexinfo(l->face->texinfo);
// convert from float to vec_t
for (i=0 ; i<2 ; i++)
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
// without changing their S/T
texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2]
- tex->vecs[1][2]*tex->vecs[0][1];
texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0]
- tex->vecs[1][0]*tex->vecs[0][2];
texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1]
- tex->vecs[1][1]*tex->vecs[0][0];
texnormal[0] = surf_texplanes[1][1]*surf_texplanes[0][2]
- surf_texplanes[1][2]*surf_texplanes[0][1];
texnormal[1] = surf_texplanes[1][2]*surf_texplanes[0][0]
- surf_texplanes[1][0]*surf_texplanes[0][2];
texnormal[2] = surf_texplanes[1][0]*surf_texplanes[0][1]
- surf_texplanes[1][1]*surf_texplanes[0][0];
VectorNormalize (texnormal);
// flip it towards plane normal
distscale = DotProduct (texnormal, l->facenormal);
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)
{
distscale = -distscale;
@ -383,7 +387,7 @@ static void LightCalcFaceVectors (llightinfo_t *l)
// calculate texorg on the texture plane
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
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[]
================
*/
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;
int i,j, e;
dvertex_t *v;
texinfo_t *tex;
s = l->face;
mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -99999;
maxs[0] = maxs[1] = -999999;
tex = &bsptexinfo(s->texinfo);
@ -425,9 +426,9 @@ static void LightCalcFaceExtents (llightinfo_t *l)
for (j=0 ; j<2 ; j++)
{
val = v->point[0] * tex->vecs[j][0] +
v->point[1] * tex->vecs[j][1] +
v->point[2] * tex->vecs[j][2] +
val = v->position[0] * tex->vecs[j][0] +
v->position[1] * tex->vecs[j][1] +
v->position[2] * tex->vecs[j][2] +
tex->vecs[j][3];
if (val < mins[j])
mins[j] = val;
@ -438,17 +439,17 @@ static void LightCalcFaceExtents (llightinfo_t *l)
for (i=0 ; i<2 ; i++)
{
l->exactmins[i] = mins[i];
l->exactmaxs[i] = maxs[i];
exactmins[i] = mins[i];
exactmaxs[i] = maxs[i];
mins[i] = floor(mins[i]/(1<<s->lmshift));
maxs[i] = ceil(maxs[i]/(1<<s->lmshift));
l->texmins[i] = mins[i];
l->texsize[i] = maxs[i] - mins[i];
if (l->texsize[i] > 17)
texmins[i] = mins[i];
texsize[i] = maxs[i] - mins[i];
if (texsize[i] > MAXIMUMEXTENT-1)
{
l->texsize[i] = 17;
texsize[i] = MAXIMUMEXTENT-1;
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
=================
*/
static int c_bad;
static void LightCalcPoints (llightinfo_t *l)
static void LightCalcPoints (llightinfo_t *l, float lmscale)
{
int i;
int s, t, j;
int w, h, step;
int w, h;
vec_t step;
vec_t starts, startt, us, ut;
vec_t *surf;
vec_t mids, midt;
@ -489,17 +490,17 @@ static void LightCalcPoints (llightinfo_t *l)
{ // extra filtering
h = (l->texsize[1]+1)*2;
w = (l->texsize[0]+1)*2;
starts = (l->texmins[0]-0.5)*16;
startt = (l->texmins[1]-0.5)*16;
step = 8;
starts = (l->texmins[0]-0.5)*lmscale;
startt = (l->texmins[1]-0.5)*lmscale;
step = 0.5 * lmscale;
}
else
{
h = l->texsize[1]+1;
w = l->texsize[0]+1;
starts = l->texmins[0]*16;
startt = l->texmins[1]*16;
step = 16;
starts = l->texmins[0]*lmscale;
startt = l->texmins[1]*lmscale;
step = lmscale;
}
l->numsurfpt = w * h;
@ -518,19 +519,19 @@ static void LightCalcPoints (llightinfo_t *l)
surf[j] = l->texorg[j] + l->textoworld[0][j]*us
+ l->textoworld[1][j]*ut;
if (CastRay (facemid, surf) != -1)
if (CastRay (l->ctx, facemid, surf) != -1)
break; // got it
if (i & 1)
{
if (us > mids)
{
us -= 8;
us -= lmscale*0.5;
if (us < mids)
us = mids;
}
else
{
us += 8;
us += lmscale*0.5;
if (us > mids)
us = mids;
}
@ -539,13 +540,13 @@ static void LightCalcPoints (llightinfo_t *l)
{
if (ut > midt)
{
ut -= 8;
ut -= lmscale*0.5;
if (ut < midt)
ut = midt;
}
else
{
ut += 8;
ut += lmscale*0.5;
if (ut > midt)
ut = midt;
}
@ -555,9 +556,9 @@ static void LightCalcPoints (llightinfo_t *l)
VectorSubtract (facemid, surf, move);
VectorNormalize (move);
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
@ -588,8 +587,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
vec_t *surf;
qboolean hit;
int mapnum;
int size;
int c, i;
int c;
vec3_t rel;
vec3_t spotvec;
vec_t falloff;
@ -605,14 +603,11 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
// don't bother with light too far away
if (dist > light->light)
{
c_culldistplane++;
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);
if (!light->angle)
falloff = -cos(20*Q_PI/180);
@ -631,6 +626,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
norms = l->lightnorm[mapnum];
if (mapnum == l->numlightstyles)
{ // init a new light map
#ifdef UTILITY
if (mapnum == MAXQ1LIGHTMAPS)
{
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][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
//
hit = false;
c_proper++;
surf = l->surfpt[0];
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)
continue; // light doesn't reach
VectorSubtract (light->origin, surf, incoming);
VectorNormalize (incoming);
if (light->targetent)
if (light->targetentnum >= 0)
{ // spotlight cutoff
if (DotProduct (spotvec, incoming) > falloff)
continue;
@ -680,14 +678,14 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l)
lightsamp[c][1] += add*light->colour[1];
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][2] += add * incoming[2];
if (add > 1) // ignore real tiny lights
hit = true;
}
if (mapnum == l->numlightstyles && hit)
{
l->lightstyles[mapnum] = light->style;
@ -749,12 +747,10 @@ static void FixMinlight (llightinfo_t *l)
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 i,j,c,ch;
int i,c,ch;
vec_t total, mean;
int size;
int lightmapwidth;
@ -762,82 +758,62 @@ void LightFace (int surfnum)
int lightmapsize;
byte *out;
#endif
byte *rgbout;
byte *dulout;
qbyte *rgbout;
qbyte *dulout;
vec3_t *light, *norm;
vec3_t wnorm, temp, svector, tvector;
int w;
f = dfaces + surfnum;
//
// some surfaces don't need lightmaps
//
#ifdef UTILITY
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
if (!surf_rgbsamples)
return;
}
#ifndef UTILITY
if (!f->samples)
return;
#endif
memset (&l, 0, sizeof(l));
l.surfnum = surfnum;
l.face = f;
memset (l, 0, sizeof(*l));
l->ctx = ctx;
//
// rotate plane
//
#ifndef UTILITY
VectorCopy (f->plane->normal, l.facenormal);
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;
}
VectorCopy (surf_plane, l->facenormal);
l->facedist = surf_plane[3];
LightCalcFaceVectors (&l);
LightCalcFaceExtents (&l);
LightCalcPoints (&l);
LightCalcFaceVectors (l, surf_texplanes);
Vector2Copy(exactmins, l->exactmins);
Vector2Copy(exactmaxs, l->exactmaxs);
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)
Error ("Bad lightmap size");
Host_Error ("Bad lightmap size");
for (i=0 ; i<MAXQ1LIGHTMAPS ; i++)
l.lightstyles[i] = 255;
i = 0;
#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
//
l.numlightstyles = 0;
for (i=0 ; i<num_entities ; i++)
for (i=0 ; i<ctx->num_entities ; i++)
{
if (entities[i].light)
SingleLightFace (&entities[i], &l);
if (ctx->entities[i].light)
SingleLightFace (&ctx->entities[i], l);
}
FixMinlight (&l);
FixMinlight (l);
if (!l.numlightstyles)
if (!l->numlightstyles)
{ // no light hitting it
#ifdef UTILITY
f->lightofs = -1;
@ -845,20 +821,15 @@ void LightFace (int surfnum)
return;
}
#ifndef UTILITY
for (j=0 ; j<MAXQ1LIGHTMAPS ; j++)
f->styles[j] = 255;
#endif
//
// save out the values
//
for (i=0 ; i <MAXQ1LIGHTMAPS ; i++)
f->styles[i] = l.lightstyles[i];
surf_styles[i] = l->lightstyles[i];
#ifdef UTILITY
lightmapsize = size*l.numlightstyles;
lightmapsize = size*l->numlightstyles;
if (runningrgblightdatabase)
{
out = GetFakeFileSpace(&f->lightofs, lightmapsize);
@ -873,13 +844,13 @@ void LightFace (int surfnum)
dulout = GetNormFileSpace (f->lightofs, lightmapsize);
}
#else
rgbout = f->samples;
if (lightmodel->deluxdata)
rgbout = surf_rgbsamples;
if (l->ctx->models[0]->deluxdata)
{
dulout = f->samples - lightmodel->lightdata + lightmodel->deluxdata;
dulout = surf_deluxesamples;
VectorCopy(bsptexinfo(f->texinfo).vecs[0], svector);
VectorNegate(bsptexinfo(f->texinfo).vecs[1], tvector);
VectorCopy(surf_texplanes[0], svector);
VectorNegate(surf_texplanes[1], tvector);
VectorNormalize(svector);
VectorNormalize(tvector);
}
@ -891,18 +862,20 @@ void LightFace (int surfnum)
// extra filtering
// 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)
Error ("Wrote empty lightmap");
light = l.lightmaps[i];
norm = l.lightnorm[i];
if (l->lightstyles[i] == 0xff)
Host_Error ("Wrote empty lightmap");
light = l->lightmaps[i];
norm = l->lightnorm[i];
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;
@ -924,11 +897,13 @@ void LightFace (int surfnum)
}
total *= rangescale; // scale before clamping
#ifndef UTILITY
if (total > *rgbout) //sorry - for qw
total = *rgbout;
// if (total > *rgbout) //sorry - for qw
// total = *rgbout;
#endif
if (total < 0)
Error ("light < 0");
total = 0;
if (total > 0xff)
total = 0xff;
*rgbout++ = total;
mean += total;
@ -941,15 +916,11 @@ void LightFace (int surfnum)
{
temp[0] = DotProduct(wnorm, svector);
temp[1] = DotProduct(wnorm, tvector);
temp[2] = DotProduct(wnorm, l.facenormal);
temp[2] = DotProduct(wnorm, l->facenormal);
if (!temp[0] && !temp[1] && !temp[2])
VectorSet(temp, 0, 0, 1);
else
{
VectorNormalize(temp);
// temp[2] += 0.5;
VectorNormalize(temp);
}
*dulout++ = (temp[0]+1)*128;
*dulout++ = (temp[1]+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

View file

@ -1691,8 +1691,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#define r_glsl_pcf 9\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"
"#define DOTEXTUREGATHER\n"
"#endif\n"
"#ifdef UPPERLOWER\n"
@ -1851,7 +1854,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"{\n"
"vec3 shadowcoord = ShadowmapCoord();\n"
"#if 0//def GL_ARB_texture_gather\n"
"#ifdef DOTEXTUREGATHER\n"
"vec2 ipart, fpart;\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"

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);
//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_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);
cin_t *R_ShaderGetCinematic(shader_t *s);

View file

@ -5,6 +5,8 @@
#include "netinc.h"
#include "fs.h"
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
#if defined(WEBCLIENT)
#if defined(FTE_TARGET_WEB)
@ -287,20 +289,20 @@ struct http_dl_ctx_s {
char *buffer;
int bufferused;
int bufferlen;
size_t bufferused;
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.
qboolean gzip;
qboolean chunking;
int chunksize;
int chunked;
size_t chunksize;
size_t chunked;
enum {HC_REQUESTING, HC_GETTINGHEADER, HC_GETTING} state;
int contentlength;
size_t contentlength;
};
void HTTP_Cleanup(struct dl_download *dl)
@ -400,7 +402,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
msg = con->buffer;
con->chunking = false;
con->contentlength = 0;
con->contentlength = -1;
con->gzip = false;
*mimetype = 0;
*Location = 0;
@ -567,7 +569,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
if (con->gzip)
{
#if !defined(NPFTE) && defined(AVAIL_ZLIB)
#if 1
con->file = FS_GZ_DecompressWriteFilter(dl->file, false);
#else
con->file = FS_OpenTemp();
#endif
#else
Con_Printf("HTTP: no support for gzipped files \"%s\"\n", dl->localname);
dl->status = DL_FAILED;
@ -659,7 +665,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
}
else
{
con->totalreceived+=ammount;
con->totalreceived+=con->bufferused;
if (con->file) //we've got a chunk in the buffer
{ //write it
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;
}
if (con->totalreceived == con->contentlength)
ammount = 0;
}
if (!ammount)
@ -678,6 +686,13 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
else
{
#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)
{
VFS_SEEK(con->file, 0);
@ -685,7 +700,11 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
con->file = NULL;
}
#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;
}

View file

@ -82,28 +82,41 @@ char *authedusername;
char *autheduserpassword;
int main(int argc, char **argv)
{
int httpport = 80;
int arg = 1;
WSADATA pointlesscrap;
WSAStartup(2, &pointlesscrap);
if (argc == 3)
{
authedusername = argv[1];
autheduserpassword = argv[2];
if (arg < argc && atoi(argv[arg]))
httpport = atoi(argv[arg++]);
if (arg < argc)
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);
}
else
printf("Server is read only\n");
while(1)
{
// FTP_ServerRun(1, 21);
HTTP_ServerPoll(1, 80);
if (httpport)
HTTP_ServerPoll(1, httpport);
Sleep(1);
}
}
void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *f), void *parm)
static time_t Sys_FileTimeToTime(FILETIME ft)
{
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;
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
{
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
{
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);
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 len;

View file

@ -284,7 +284,7 @@ r_part +te_explosion
randomvel 1000
friction 0.01
gravity 100
stretchfactor 5
stretchfactor -80
}
//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;
break;
case svc_updateuserinfo:
protocollen = 6;
nullterms = 1;
protocollen = 6+nullterms;
break;
case svcqw_updatestatlong:
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_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 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];
char cvargroup_progs[] = "Progs variables";
@ -1295,6 +1296,7 @@ void PR_Init(void)
Cvar_Register (&pr_ssqc_progs, cvargroup_progs);
Cvar_Register (&pr_compatabilitytest, cvargroup_progs);
Cvar_Register (&dpcompat_nopreparse, cvargroup_progs);
Cvar_Register (&pr_nonetaccess, 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)
{
int i, soundnum, j;
sizebuf_t *buf[3] = {&sv.signon, &sv.nqmulticast, &sv.multicast};
sizebuf_t *msg;
staticsound_state_t *state;
int soundnum;
// check to see if samp was properly precached
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;
}
SV_FlushSignon();
if (soundnum > 255)
return;
for (j = 0; j < 3; j++)
if (sv.num_static_sounds == sv_max_staticsounds)
{
msg = buf[j];
if (sv.state == ss_loading && j)
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_max_staticsounds += 16;
sv_staticsounds = BZ_Realloc(sv_staticsounds, sizeof(*sv_staticsounds) * sv_max_staticsounds);
}
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)
@ -4212,7 +4206,7 @@ static void QCBUILTIN PF_aim (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
vec3_t start, dir, end, bestdir;
int i, j;
trace_t tr;
float dist, bestdist;
float dist, bestdist = sv_aim.value;
char *noaim;
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));
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
@ -4433,7 +4435,9 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteByte(dest, val);
return;
@ -4444,7 +4448,7 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteByte(dest, val);
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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);
}
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)
@ -4475,7 +4483,9 @@ void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteChar(dest, val);
return;
@ -4486,7 +4496,7 @@ void QCBUILTIN PF_WriteChar (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteChar(dest, val);
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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);
}
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)
@ -4517,7 +4531,9 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteShort(dest, val);
return;
@ -4528,8 +4544,8 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteShort(dest, val);
return;
}
#else
if (desf == MSG_ONE)
#endif
if (dest == MSG_ONE)
{
client_t *cl = Write_GetClient();
if (!cl)
@ -4538,8 +4554,12 @@ void QCBUILTIN PF_WriteShort (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
ClientReliableWrite_Short(cl, val);
}
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)
@ -4558,7 +4578,9 @@ void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteLong(dest, G_FLOAT(OFS_PARM1));
return;
@ -4569,7 +4591,7 @@ void QCBUILTIN PF_WriteLong (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
NPP_QWWriteLong(dest, G_FLOAT(OFS_PARM1));
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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));
}
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)
@ -4599,7 +4625,9 @@ void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteAngle(dest, G_FLOAT(OFS_PARM1));
return;
@ -4610,7 +4638,7 @@ void QCBUILTIN PF_WriteAngle (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteAngle(dest, G_FLOAT(OFS_PARM1));
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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));
}
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)
@ -4640,7 +4672,9 @@ void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteCoord(dest, G_FLOAT(OFS_PARM1));
return;
@ -4651,7 +4685,7 @@ void QCBUILTIN PF_WriteCoord (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteCoord(dest, G_FLOAT(OFS_PARM1));
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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));
}
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)
@ -4681,7 +4719,9 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return;
#endif
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteFloat(dest, G_FLOAT(OFS_PARM1));
return;
@ -4692,7 +4732,7 @@ void QCBUILTIN PF_WriteFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
NPP_QWWriteFloat(dest, G_FLOAT(OFS_PARM1));
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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));
}
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)
@ -4721,7 +4765,9 @@ void PF_WriteString_Internal (int target, const char *str)
)
return;
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteString(target, str);
return;
@ -4732,7 +4778,7 @@ void PF_WriteString_Internal (int target, const char *str)
NPP_QWWriteString(target, str);
return;
}
#else
#endif
if (target == MSG_ONE)
{
client_t *cl = Write_GetClient();
@ -4742,8 +4788,12 @@ void PF_WriteString_Internal (int target, const char *str)
ClientReliableWrite_String(cl, str);
}
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)
@ -4769,7 +4819,9 @@ void QCBUILTIN PF_WriteEntity (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
)
return;
if (progstype != PROG_QW)
if (dpcompat_nopreparse.ival)
;
else if (progstype != PROG_QW)
{
NPP_NQWriteEntity(dest, G_EDICTNUM(prinst, OFS_PARM1));
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));
return;
}
#else
#endif
if (dest == MSG_ONE)
{
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));
}
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.
@ -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)
{
edict_t *ent;
int mdlindex;
entity_state_t *state;
ent = G_EDICT(prinst, OFS_PARM0);
mdlindex = SV_ModelIndex(PR_GetString(prinst, ent->v->model));
if (sv.num_static_entities == sv_max_staticentities)
{
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)
{"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)"},//
{"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)
@ -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_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.")},
{"cvar_unsaved", PF_Fixme, 0, 0, 0, 0, D("float()", "Returns true if any archived cvar has an unsaved value.")},
//end fte 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
{"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.")},
{"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
{"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
@ -10534,6 +10611,9 @@ void PR_DumpPlatform_f(void)
{"input_cursor_trace_endpos", "vector", 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 comfieldvector(name,desc) {#name, ".vector", 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},
{"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."},
{"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},
{"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_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_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_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},
@ -11561,19 +11642,19 @@ void PR_DumpPlatform_f(void)
VFS_PRINTF(f,
"accessor hashtable : float\n{\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 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 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 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");
VFS_PRINTF(f,
"accessor infostring : string\n{\n"
"\tget string[string] = infoget;\n"
#ifdef QCGC
"\tinline set* string[string] = {(*this) = infoadd(*this, value);};\n"
"\tinline set* string[string fld] = {(*this) = infoadd(*this, fld, value);};\n"
#endif
"};\n");
VFS_PRINTF(f,

View file

@ -93,8 +93,18 @@ typedef struct
char fatness;
} 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 int sv_max_staticentities;
extern staticsound_state_t *sv_staticsounds;
extern int sv_max_staticsounds;
typedef struct
{
@ -271,6 +281,7 @@ typedef struct
//end this lot... (demo playback)
int num_static_entities;
int num_static_sounds;
svcustomtents_t customtents[255];
@ -354,6 +365,7 @@ enum
PRESPAWN_CUSTOMTENTS,
PRESPAWN_SIGNON_BUF,
PRESPAWN_SPAWNSTATIC,
PRESPAWN_AMBIENTSOUND,
PRESPAWN_BASELINES,
PRESPAWN_DONE
};
@ -376,6 +388,8 @@ typedef struct client_s
unsigned int prespawn_stage;
unsigned int prespawn_idx;
qboolean prespawn_allow_modellist;
qboolean prespawn_allow_soundlist;
int spectator; // non-interactive
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
return true;
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;
}
static void SV_MapList_f(void)
{
COM_EnumerateFiles("maps/*.bsp", ShowMapList, NULL);
COM_EnumerateFiles("maps/*.map", ShowMapListExt, NULL);
COM_EnumerateFiles("maps/*.cm", ShowMapList, NULL);
COM_EnumerateFiles("maps/*.hmp", ShowMapList, NULL);
}
@ -413,7 +421,10 @@ void SV_Map_f (void)
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;
}
@ -458,7 +469,7 @@ void SV_Map_f (void)
if (!strcmp(level, ".")) //restart current
{
//grab the current map name
COM_StripExtension(COM_SkipPath(sv.modelname), level, sizeof(level));
Q_strncpyz(level, sv.name, sizeof(level));
isrestart = true;
flushparms = false;
newunit = false;
@ -505,7 +516,7 @@ void SV_Map_f (void)
}
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;
for (i = 0; exts[i]; i++)

View file

@ -30,6 +30,8 @@ server_t sv; // local server
entity_state_t *sv_staticentities;
int sv_max_staticentities;
staticsound_state_t *sv_staticsounds;
int sv_max_staticsounds;
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
#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;
Q_strncpyz (sv.name, server, sizeof(sv.name));
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);
sprintf(text, "0x%x", sv.csqcchecksum);
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);
if (strcmp(sv_csqc_progname.string, "csprogs.dat"))
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