Compare commits
50 commits
bf6ddf21ae
...
247556928f
Author | SHA1 | Date | |
---|---|---|---|
|
247556928f | ||
|
12721c764b | ||
|
f101a82066 | ||
|
7339ddd47a | ||
|
ad5366ae54 | ||
|
e5e7dde336 | ||
|
8cc2fdd591 | ||
|
f767d952e3 | ||
|
f1b76e4832 | ||
|
64f805980a | ||
|
edda391be5 | ||
|
3837beb84e | ||
|
f35c156800 | ||
|
46636fd08e | ||
|
f38f27e388 | ||
64f4e2a10a | |||
|
247f186a68 | ||
|
0df247d4c1 | ||
|
1ea029f789 | ||
|
778bbefc8f | ||
|
0c5e912397 | ||
|
59c0c8857a | ||
|
249ff8777b | ||
|
62ff790114 | ||
|
b1b0f5e654 | ||
|
c9de6f4bff | ||
|
6e35299bf8 | ||
|
affb96a3b3 | ||
|
0650610667 | ||
|
39e921624f | ||
|
0a7f0cd7d4 | ||
|
dc010d6ec8 | ||
|
7e9d138d5f | ||
|
e82f61256a | ||
|
777b4b1fd9 | ||
|
9bc9700506 | ||
|
28a880c56e | ||
|
d26b741e4b | ||
|
dd4ff8d530 | ||
|
fe6ef90c44 | ||
|
3b554f3742 | ||
|
3b140e9cf8 | ||
|
9c32640189 | ||
|
0ac7268cc5 | ||
|
3df06cd519 | ||
|
ee534acb8c | ||
|
84438b5f9b | ||
|
6f579815d2 | ||
|
a1bf9dd60a | ||
|
f0e57311d6 |
158 changed files with 13404 additions and 7694 deletions
|
@ -124,7 +124,7 @@ ENDIF()
|
|||
|
||||
# libepoll-shim needs to be installed on the BSDs and Mac OSX to get
|
||||
# some of the server code to compile and work correctly on those platforms - Brad
|
||||
IF(UNIX AND NOT LINUX AND NOT CYGWIN)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "BSD" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
INCLUDE(FetchContent)
|
||||
FetchContent_Declare(
|
||||
epoll-shim
|
||||
|
@ -161,6 +161,7 @@ IF(ZLIB_FOUND)
|
|||
SET(FTE_LIBS ${FTE_LIBS} ${ZLIB_LIBRARIES})
|
||||
SET(FTESV_LIBS ${FTESV_LIBS} ${ZLIB_LIBRARIES})
|
||||
SET(FTEQCC_LIBS ${FTEQCC_LIBS} ${ZLIB_LIBRARIES})
|
||||
SET(FTEQTV_LIBS ${FTEQTV_LIBS} ${ZLIB_LIBRARIES})
|
||||
ELSE()
|
||||
MESSAGE(WARNING "libz library NOT available. compressed pk3, ICE, Q2E, etc etc, yada yada, blah blah will not be available.")
|
||||
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_ZLIB)
|
||||
|
@ -202,16 +203,18 @@ ELSE()
|
|||
SET(JPEG_LIBRARIES)
|
||||
ENDIF()
|
||||
|
||||
SET(FTE_DEP_DBUS true CACHE BOOL "Link against libdbus.")
|
||||
IF(FTE_DEP_DBUS)
|
||||
FIND_PACKAGE(DBus1)
|
||||
ENDIF()
|
||||
IF(DBUS1_FOUND)
|
||||
INCLUDE_DIRECTORIES( ${DBus1_INCLUDE_DIRS} )
|
||||
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_DBUS)
|
||||
SET(FTE_LIBS ${FTE_LIBS} ${DBus1_LIBRARIES})
|
||||
ELSE()
|
||||
MESSAGE(WARNING "libdbus-1 library NOT available. Who cares?")
|
||||
IF(NOT ${WIN32})
|
||||
SET(FTE_DEP_DBUS true CACHE BOOL "Link against libdbus.")
|
||||
IF(FTE_DEP_DBUS)
|
||||
FIND_PACKAGE(DBus1)
|
||||
ENDIF()
|
||||
IF(DBUS1_FOUND)
|
||||
INCLUDE_DIRECTORIES( ${DBus1_INCLUDE_DIRS} )
|
||||
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_DBUS)
|
||||
SET(FTE_LIBS ${FTE_LIBS} ${DBus1_LIBRARIES})
|
||||
ELSE()
|
||||
MESSAGE(WARNING "libdbus-1 library NOT available. Who cares?")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET(FTE_DEP_PNG true CACHE BOOL "Link against libpng.")
|
||||
|
@ -520,10 +523,11 @@ ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
|
|||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(NOT LINUX AND NOT CYGWIN)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "BSD" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
FIND_LIBRARY(epoll-shim REQUIRED)
|
||||
INCLUDE_DIRECTORIES(${EPOLL_INC_DIR})
|
||||
SET(FTESV_LIBS ${FTESV_LIBS} epoll-shim)
|
||||
SET(FTESV_DEFINES ${FTESV_DEFINES};HAVE_EPOLL)
|
||||
ENDIF()
|
||||
|
||||
SET(FTESV_DEFINES ${FTESV_DEFINES};MULTITHREAD)
|
||||
|
@ -781,6 +785,7 @@ SET(FTE_COMMON_FILES
|
|||
engine/client/pr_skelobj.c
|
||||
engine/client/m_download.c
|
||||
engine/client/net_master.c
|
||||
engine/client/r_d3.c
|
||||
|
||||
#these are here because of hitmodel etc
|
||||
engine/gl/gl_heightmap.c
|
||||
|
@ -1087,10 +1092,11 @@ ELSE()
|
|||
${FTE_CLIENT_FILES}
|
||||
${FTE_SERVER_FILES}
|
||||
)
|
||||
IF(UNIX AND NOT LINUX AND NOT CYGWIN)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "BSD" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
FIND_LIBRARY(epoll-shim REQUIRED)
|
||||
SET(FTE_INCLUDES ${FTE_INCLUDES} "${EPOLL_INC_DIR}")
|
||||
SET(FTE_LIBS ${FTE_LIBS} epoll-shim)
|
||||
SET(FTE_DEFINES ${FTE_DEFINES};HAVE_EPOLL)
|
||||
ENDIF()
|
||||
SET_TARGET_PROPERTIES(fteqw PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_DEFINES};${FTE_REVISON}")
|
||||
TARGET_INCLUDE_DIRECTORIES(fteqw PUBLIC ${FTE_INCLUDES})
|
||||
|
@ -1191,16 +1197,17 @@ ELSE()
|
|||
fteqtv/libqtvc/glibc_sucks.c
|
||||
engine/common/sha1.c
|
||||
)
|
||||
SET_TARGET_PROPERTIES(qtv PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON}")
|
||||
SET_TARGET_PROPERTIES(qtv PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON};${FTE_LIB_DEFINES}")
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(qtv ws2_32 winmm ${SYS_LIBS} ${ZLIB_LIBRARIES})
|
||||
ELSEIF(LINUX)
|
||||
TARGET_LINK_LIBRARIES(qtv ${SYS_LIBS} ${ZLIB_LIBRARIES})
|
||||
# Add Epoll-shim for the Unixes here - Brad
|
||||
ELSE()
|
||||
TARGET_LINK_LIBRARIES(qtv ws2_32 winmm ${SYS_LIBS} ${FTEQTV_LIBS})
|
||||
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "BSD" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
# Add Epoll-shim for the kqueue Unixes here - Brad
|
||||
FIND_LIBRARY(epoll-shim REQUIRED)
|
||||
TARGET_INCLUDE_DIRECTORIES(qtv PUBLIC "${EPOLL_INC_DIR}")
|
||||
TARGET_LINK_LIBRARIES(qtv epoll-shim ${SYS_LIBS} ${ZLIB_LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(qtv epoll-shim ${SYS_LIBS} ${FTEQTV_LIBS})
|
||||
SET_TARGET_PROPERTIES(qtv PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON};${FTE_LIB_DEFINES};HAVE_EPOLL")
|
||||
ELSE()
|
||||
TARGET_LINK_LIBRARIES(qtv ${SYS_LIBS} ${FTEQTV_LIBS})
|
||||
ENDIF()
|
||||
SET(INSTALLTARGS ${INSTALLTARGS} qtv)
|
||||
ENDIF()
|
||||
|
@ -1243,14 +1250,28 @@ ELSE()
|
|||
SET_TARGET_PROPERTIES(httpserver PROPERTIES COMPILE_DEFINITIONS "WEBSERVER;WEBSVONLY;${FTE_REVISON}")
|
||||
IF(WIN32)
|
||||
TARGET_LINK_LIBRARIES(httpserver ws2_32)
|
||||
ELSEIF(UNIX AND NOT LINUX AND NOT CYGWIN)
|
||||
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "BSD" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
FIND_LIBRARY(epoll-shim REQUIRED)
|
||||
TARGET_INCLUDE_DIRECTORIES(httpserver PUBLIC "${EPOLL_INC_DIR}")
|
||||
TARGET_LINK_LIBRARIES(httpserver epoll-shim)
|
||||
SET_TARGET_PROPERTIES(httpserver PROPERTIES COMPILE_DEFINITIONS "WEBSERVER;WEBSVONLY;${FTE_REVISON};HAVE_EPOLL")
|
||||
ENDIF()
|
||||
#SET(INSTALLTARGS ${INSTALLTARGS} httpserver)
|
||||
ENDIF()
|
||||
|
||||
SET(FTE_TOOL_QCVM false CACHE BOOL "Compile standalone qcvm.")
|
||||
IF(FTE_TOOL_QCVM)
|
||||
ADD_EXECUTABLE(qcvm
|
||||
engine/qclib/test.c
|
||||
|
||||
engine/qclib/hash.c
|
||||
${FTE_QCVM_FILES}
|
||||
)
|
||||
SET_TARGET_PROPERTIES(qcvm PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON}")
|
||||
TARGET_LINK_LIBRARIES(qcvm ${FTEQCC_LIBS} ${SYS_LIBS})
|
||||
SET(INSTALLTARGS ${INSTALLTARGS} qcvm)
|
||||
ENDIF()
|
||||
|
||||
SET(FTE_TOOL_QCC true CACHE BOOL "Compile commandline qc compiler.")
|
||||
IF(FTE_TOOL_QCC)
|
||||
ADD_EXECUTABLE(fteqcc
|
||||
|
@ -1479,6 +1500,7 @@ IF(FTE_PLUG_IRC)
|
|||
EMBED_PLUGIN_META(irc "IRC Plugin" "Allows you to chat on IRC without tabbing out.")
|
||||
ENDIF()
|
||||
|
||||
IF(ZLIB_FOUND)
|
||||
#mpq package format plugin (blizzard games)
|
||||
SET(FTE_PLUG_MPQ false CACHE BOOL "Compile mpq junk.")
|
||||
IF(FTE_PLUG_MPQ)
|
||||
|
@ -1492,6 +1514,7 @@ IF(FTE_PLUG_MPQ)
|
|||
|
||||
EMBED_PLUGIN_META(irc "MPQ Archive Plugin" "Adds support for reading .mpq files. Not very useful...")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
#vpk package format plugin (halflife2)
|
||||
SET(FTE_PLUG_HL2 true CACHE BOOL "Compile support for hl2 file formats.")
|
||||
|
@ -1705,7 +1728,6 @@ IF(FTE_PLUG_CEF)
|
|||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(NOT ANDROID) #libresolv issues.
|
||||
SET(FTE_PLUG_XMPP true CACHE BOOL "Compile xmpp/jabber instant-messenger plugin.")
|
||||
IF(FTE_PLUG_XMPP)
|
||||
#XMPP/jabber client plugin
|
||||
|
@ -1720,14 +1742,16 @@ IF(FTE_PLUG_XMPP)
|
|||
plugins/emailnot/md5.c
|
||||
)
|
||||
SET_TARGET_PROPERTIES(plug_xmpp PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
|
||||
IF(${WIN32})
|
||||
ELSEIF(LINUX OR APPLE)
|
||||
|
||||
#for SRV lookups, so we actually get the right server from account names/etc.
|
||||
IF(ANDROID) #libresolv issues.
|
||||
ELSEIF(${WIN32}) #softlinks a dll
|
||||
ELSE()
|
||||
TARGET_LINK_LIBRARIES(plug_xmpp ${SYS_LIBS} resolv)
|
||||
ENDIF()
|
||||
|
||||
EMBED_PLUGIN_META(xmpp "XMPP Plugin" "XMPP/Jabber instant messenger plugin for chatting without tabbing out.")
|
||||
ENDIF()
|
||||
ENDIF() #android
|
||||
|
||||
INSTALL(TARGETS ${INSTALLTARGS}
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/${FTE_INSTALL_BINDIR}"
|
||||
|
|
|
@ -955,7 +955,7 @@ void Cam_SetModAutoTrack(int userid)
|
|||
return;
|
||||
}
|
||||
}
|
||||
Con_Printf("//at: invalid userid\n");
|
||||
Con_Printf("//at: invalid userid %i\n", userid);
|
||||
}
|
||||
|
||||
/*static void Cam_TrackCrosshairedPlayer(playerview_t *pv)
|
||||
|
|
|
@ -76,7 +76,7 @@ void CL_StopPlayback (void)
|
|||
cls.demoinfile = NULL;
|
||||
cls.state = ca_disconnected;
|
||||
cls.demoplayback = DPB_NONE;
|
||||
cls.demoseeking = false; //just in case
|
||||
cls.demoseeking = DEMOSEEK_NOT; //just in case
|
||||
cls.demotrack = -1;
|
||||
cls.demoeztv_ext = 0;
|
||||
|
||||
|
@ -393,7 +393,7 @@ void CL_ProgressDemoTime(void)
|
|||
void CL_DemoJump_f(void)
|
||||
{
|
||||
float newtime;
|
||||
char *s = Cmd_Argv(1);
|
||||
char *s = (!strncmp(Cmd_Argv(0), "demo_jump_", 10))?Cmd_Argv(0)+10:Cmd_Argv(1);
|
||||
char *colon = strchr(s, ':');
|
||||
|
||||
if (!cls.demoplayback)
|
||||
|
@ -414,6 +414,17 @@ void CL_DemoJump_f(void)
|
|||
return; //can't seek live streams...
|
||||
}
|
||||
|
||||
if (!strcmp(s, "intermission") || !strcmp(s, "end"))
|
||||
{ //seeks until we see an svc_intermission
|
||||
cls.demoseeking = DEMOSEEK_INTERMISSION;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(s, "mark"))
|
||||
{ //seeks until we see an svc_stufftext `//demomark`
|
||||
cls.demoseeking = DEMOSEEK_MARK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*s == '+' || *s == '-')
|
||||
{
|
||||
if (colon)
|
||||
|
@ -457,7 +468,7 @@ void CL_DemoJump_f(void)
|
|||
//now fastparse it.
|
||||
cls.demoseektime = newtime;
|
||||
}
|
||||
cls.demoseeking = true;
|
||||
cls.demoseeking = DEMOSEEK_TIME;
|
||||
}
|
||||
|
||||
void CL_DemoNudge_f(void)
|
||||
|
@ -610,11 +621,11 @@ qboolean CL_GetDemoMessage (void)
|
|||
return 0;
|
||||
}*/
|
||||
cls.netchan.last_received = realtime;
|
||||
if (cls.demoseeking)
|
||||
if (cls.demoseeking == DEMOSEEK_TIME)
|
||||
{
|
||||
if (cl.gametime > cls.demoseektime)
|
||||
{
|
||||
cls.demoseeking = false;
|
||||
cls.demoseeking = DEMOSEEK_NOT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -731,11 +742,11 @@ readnext:
|
|||
|
||||
|
||||
// decide if it is time to grab the next message
|
||||
if (cls.demoseeking)
|
||||
if (cls.demoseeking != DEMOSEEK_NOT)
|
||||
{
|
||||
demtime = demotime; //warp
|
||||
if (demtime >= cls.demoseektime)
|
||||
cls.demoseeking = false;
|
||||
if (cls.demoseeking == DEMOSEEK_TIME && demtime >= cls.demoseektime)
|
||||
cls.demoseeking = DEMOSEEK_NOT;
|
||||
}
|
||||
else if (cls.timedemo)
|
||||
{
|
||||
|
@ -1986,7 +1997,7 @@ void CL_Record_f (void)
|
|||
|
||||
n = 0;
|
||||
s = cl.sound_name[n+1];
|
||||
while (*s)
|
||||
while (s && *s)
|
||||
{
|
||||
MSG_WriteString (&buf, s);
|
||||
if (buf.cursize > buf.maxsize/2 && (n&0xff))
|
||||
|
@ -2024,7 +2035,7 @@ void CL_Record_f (void)
|
|||
|
||||
n = 0;
|
||||
s = cl.model_name[n+1];
|
||||
while (*s)
|
||||
while (s && *s)
|
||||
{
|
||||
MSG_WriteString (&buf, s);
|
||||
if (buf.cursize > buf.maxsize/2 && (n&0xff))
|
||||
|
@ -3037,7 +3048,7 @@ fail:
|
|||
MC_AddCenterPicture(sourcesmenu, 4, 24, "gfx/p_option.lmp");
|
||||
}
|
||||
if (init_numplayers == true && init_numviewers == true)
|
||||
MC_AddConsoleCommand(sourcesmenu, 42, 170, (sourcenum++)*8 + 32, va("%s (p%i, v%i)", srchost, numplayers, numviewers), va("qtvplay %s@%s\n", streamid, qtv->hostname));
|
||||
MC_AddConsoleCommand(sourcesmenu, 42, 170, (sourcenum++)*8 + 32, va("%s (p%i, v%i)", *srchost?srchost:streamid, numplayers, numviewers), va("qtvplay %s@%s\n", streamid, qtv->hostname));
|
||||
//else
|
||||
// FIXME: add error message here
|
||||
#else
|
||||
|
@ -3060,7 +3071,7 @@ fail:
|
|||
if (streamavailable)
|
||||
{
|
||||
if (*streamavailable)
|
||||
Con_Printf("streaming \"%s\" from qtv\n", streamavailable);
|
||||
Con_Printf("streaming \"%s\" via \"%s\"\n", streamavailable, qtv->hostname);
|
||||
else
|
||||
Con_Printf("qtv connection established to %s\n", qtv->hostname);
|
||||
CL_PlayDemoStream(qtv->stream, NULL, false, DPB_MVD, BUFFERTIME, iseztv);
|
||||
|
@ -3138,6 +3149,7 @@ void CL_QTVPlay_Establish (const char *host, const char *password, const char *c
|
|||
return;
|
||||
}
|
||||
|
||||
Q_strncpyz(qtv->hostname, host, sizeof(qtv->hostname));
|
||||
Q_strncpyz(qtv->password, password, sizeof(qtv->password));
|
||||
|
||||
if (qtvcl_forceversion1.ival)
|
||||
|
|
|
@ -854,8 +854,8 @@ qboolean IN_DrawWeaponWheel(int pnum)
|
|||
}
|
||||
void IN_WWheelDown (void)
|
||||
{
|
||||
#ifdef CSQC_DAT
|
||||
int pnum = CL_TargettedSplit(false);
|
||||
#ifdef CSQC_DAT
|
||||
if (CSQC_ConsoleCommand(pnum, Cmd_Argv(0)))
|
||||
return;
|
||||
#endif
|
||||
|
|
|
@ -736,8 +736,8 @@ static void CL_SendConnectPacket (netadr_t *to)
|
|||
}
|
||||
|
||||
connectinfo.ext.fte1 &= (PEXT_MODELDBL|PEXT_SOUNDDBL|PEXT_SPLITSCREEN);
|
||||
connectinfo.ext.fte2 = 0;
|
||||
connectinfo.ext.ez1 = 0;
|
||||
connectinfo.ext.fte2 &= PEXT2_STUNAWARE;
|
||||
connectinfo.ext.ez1 &= 0;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
|
@ -2632,6 +2632,14 @@ void CL_Disconnect_f (void)
|
|||
(void)CSQC_UnconnectedInit();
|
||||
}
|
||||
|
||||
void CL_Disconnect2_f (void)
|
||||
{
|
||||
char *reason = Cmd_Argv(1);
|
||||
if (*reason)
|
||||
Cvar_Set(&cl_disconnectreason, reason);
|
||||
CL_Disconnect_f();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_User_f
|
||||
|
@ -3786,7 +3794,7 @@ void CL_Changing_f (void)
|
|||
if (cls.download && cls.download->method <= DL_QWPENDING) // don't change when downloading
|
||||
return;
|
||||
|
||||
cls.demoseeking = false; //don't seek over it
|
||||
cls.demoseeking = DEMOSEEK_NOT; //don't seek over it
|
||||
|
||||
if (*mapname)
|
||||
SCR_ImageName(mapname);
|
||||
|
@ -5553,6 +5561,8 @@ void CL_Status_f(void)
|
|||
}
|
||||
Con_Printf("Server address : %s\n", NET_AdrToString(adr, sizeof(adr), &cls.netchan.remote_address)); //not relevent as a limit.
|
||||
Con_Printf("Server cert fp : %s\n", b64); //not relevent as a limit.
|
||||
|
||||
Con_Printf("Network MTU : %u (max %u) %s\n", cls.netchan.mtu_cur, cls.netchan.mtu_max, (cls.netchan.flags&NCF_FRAGABLE)?"":" (strict)"); //not relevent as a limit.
|
||||
switch(cls.protocol)
|
||||
{
|
||||
default:
|
||||
|
@ -5715,6 +5725,7 @@ static void CL_UserinfoChanged(void *ctx, const char *keyname)
|
|||
|
||||
|
||||
void CL_Skygroup_f(void);
|
||||
void WAD_ImageList_f(void);
|
||||
/*
|
||||
=================
|
||||
CL_Init
|
||||
|
@ -5956,7 +5967,9 @@ void CL_Init (void)
|
|||
Cmd_AddCommand ("qtvplay", CL_QTVPlay_f);
|
||||
Cmd_AddCommand ("qtvlist", CL_QTVList_f);
|
||||
Cmd_AddCommand ("qtvdemos", CL_QTVDemos_f);
|
||||
Cmd_AddCommandD ("demo_jump", CL_DemoJump_f, "Jump to a specified time in a demo. Prefix with a + or - for a relative offset. Seeking backwards will restart the demo and the fast forward, which can take some time in long demos.");
|
||||
Cmd_AddCommandD ("demo_jump", CL_DemoJump_f, "Jump to a specified time in a demo. Prefix with a + or - for a relative offset. Seeking backwards will restart the demo and the fast forward, which can take some time in long demos.");
|
||||
Cmd_AddCommandD ("demo_jump_mark", CL_DemoJump_f, "Jump to the next '//demomark' marker.");
|
||||
Cmd_AddCommandD ("demo_jump_end", CL_DemoJump_f, "Jump to the next intermission message.");
|
||||
Cmd_AddCommandD ("demo_nudge", CL_DemoNudge_f, "Nudge the demo by one frame. Argument should be +1 or -1. Nudging backwards is limited.");
|
||||
Cmd_AddCommandAD ("timedemo", CL_TimeDemo_f, CL_DemoList_c, NULL);
|
||||
#ifdef _DEBUG
|
||||
|
@ -6090,6 +6103,7 @@ void CL_Init (void)
|
|||
Cmd_AddCommandD ("waterfog", CL_Fog_f, "waterfog <density> <red> <green> <blue> <alpha> <depthbias>");
|
||||
Cmd_AddCommandD ("skyroomfog", CL_Fog_f, "skyroomfog <density> <red> <green> <blue> <alpha> <depthbias>");
|
||||
Cmd_AddCommandD ("skygroup", CL_Skygroup_f, "Provides a way to associate a skybox name with a series of maps, so that the requested skybox will override on a per-map basis.");
|
||||
Cmd_AddCommandD ("r_imagelist_wad", WAD_ImageList_f, "displays the available wad images.");
|
||||
//
|
||||
// Windows commands
|
||||
//
|
||||
|
@ -6214,7 +6228,7 @@ void Host_WriteConfiguration (void)
|
|||
}
|
||||
|
||||
Key_WriteBindings (f);
|
||||
Cvar_WriteVariables (f, false);
|
||||
Cvar_WriteVariables (f, false, false);
|
||||
|
||||
VFS_CLOSE (f);
|
||||
|
||||
|
@ -7229,7 +7243,7 @@ double Host_Frame (double time)
|
|||
}
|
||||
else
|
||||
spare = 0;
|
||||
host_frametime = (realtime - oldrealtime)*cl.gamespeed;
|
||||
host_frametime = (realtime-spare - oldrealtime)*cl.gamespeed;
|
||||
oldrealtime = realtime-spare;
|
||||
|
||||
if (host_speeds.ival)
|
||||
|
@ -7650,8 +7664,6 @@ void CL_ExecInitialConfigs(char *resetcommand, qboolean fullvidrestart)
|
|||
Cbuf_Execute (); //make sure any pending console commands are done with. mostly, anyway...
|
||||
|
||||
Cbuf_AddText("unbindall\nshowpic_removeall\n", RESTRICT_LOCAL);
|
||||
Cbuf_AddText("bind volup \"inc volume 0.1\"\n", RESTRICT_LOCAL);
|
||||
Cbuf_AddText("bind voldown \"inc volume -0.1\"\n", RESTRICT_LOCAL);
|
||||
Cbuf_AddText("alias restart_ents \"changelevel . .\"\n",RESTRICT_LOCAL);
|
||||
Cbuf_AddText("alias restart map_restart\n",RESTRICT_LOCAL);
|
||||
Cbuf_AddText("alias startmap_sp \"map start\"\n", RESTRICT_LOCAL);
|
||||
|
|
|
@ -37,7 +37,6 @@ static char *CLNQ_ParseProQuakeMessage (char *s);
|
|||
static void DLC_Poll(qdownload_t *dl);
|
||||
static void CL_ProcessUserInfo (int slot, player_info_t *player);
|
||||
static void CL_ParseStuffCmd(char *msg, int destsplit);
|
||||
void Con_HexDump(qbyte *packet, size_t len, size_t badoffset);
|
||||
|
||||
#define MSG_ReadBigIndex() ((cls.fteprotocolextensions2&PEXT2_LONGINDEXES)?(unsigned int)MSG_ReadUInt64():MSG_ReadByte ())
|
||||
#define MSG_ReadPlayer() MSG_ReadBigIndex()
|
||||
|
@ -734,8 +733,11 @@ static void CL_WebDownloadFinished(struct dl_download *dl)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int flags)
|
||||
static void CL_SendDownloadStartRequest(downloadlist_t *pending)
|
||||
{
|
||||
char *filename = pending->rname;
|
||||
char *localname = pending->localname;
|
||||
unsigned int flags = pending->flags;
|
||||
static int dlsequence;
|
||||
qdownload_t *dl;
|
||||
|
||||
|
@ -1671,7 +1673,6 @@ void CL_RequestNextDownload (void)
|
|||
if (cl.downloadlist)
|
||||
{
|
||||
downloadlist_t *dl;
|
||||
unsigned int fl;
|
||||
|
||||
//download required downloads first
|
||||
for (dl = cl.downloadlist; dl; dl = dl->next)
|
||||
|
@ -1689,14 +1690,13 @@ void CL_RequestNextDownload (void)
|
|||
if (!dl)
|
||||
dl = cl.downloadlist;
|
||||
}
|
||||
fl = dl->flags;
|
||||
|
||||
/*if we don't require downloads don't queue requests until we're actually on the server, slightly more deterministic*/
|
||||
if (cls.state == ca_active || (requiredownloads.value && !(cls.demoplayback && !(fl&DLLF_TRYWEB))) || (fl & DLLF_REQUIRED))
|
||||
if (cls.state == ca_active || (requiredownloads.value && !(cls.demoplayback && !(dl->flags&DLLF_TRYWEB))) || (dl->flags & DLLF_REQUIRED))
|
||||
{
|
||||
if ((fl & DLLF_OVERWRITE) || !CL_CheckFile (dl->localname))
|
||||
if ((dl->flags & DLLF_OVERWRITE) || !CL_CheckFile (dl->localname))
|
||||
{
|
||||
CL_SendDownloadStartRequest(dl->rname, dl->localname, fl);
|
||||
CL_SendDownloadStartRequest(dl);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -4219,7 +4219,7 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut
|
|||
CL_CheckServerInfo();
|
||||
|
||||
#if _MSC_VER > 1200
|
||||
Sys_RecentServer("+nqconnect", cls.servername, cls.servername, "Join NQ Server");
|
||||
Sys_RecentServer("+connectnq", cls.servername, cls.servername, "Join NQ Server");
|
||||
#endif
|
||||
|
||||
if (CPNQ_IS_DP) //DP's protocol requires client+server to have exactly the same data files. this is shit, but in the interests of compatibility...
|
||||
|
@ -7040,13 +7040,13 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
|
|||
if (developer.ival)
|
||||
{
|
||||
Con_DPrintf("Proquake Message:\n");
|
||||
Con_HexDump(msg, strlen(msg), 1);
|
||||
Con_HexDump(msg, strlen(msg), 1, 16);
|
||||
}
|
||||
msg = CLNQ_ParseProQuakeMessage(msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
strncat(stufftext, msg, sizeof(stufftext)-1);
|
||||
Q_strncatz(stufftext, msg, sizeof(stufftext)-1);
|
||||
while((msg = strchr(stufftext, '\n')))
|
||||
{
|
||||
*msg = '\0';
|
||||
|
@ -7313,6 +7313,11 @@ static void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds
|
|||
Plug_Command_f();
|
||||
}
|
||||
#endif
|
||||
else if (!strncmp(stufftext, "//demomark", 10) && (stufftext[10]==0||stufftext[10]==' ') && cls.demoseeking == DEMOSEEK_MARK)
|
||||
{ //found the next marker. we're done seeking.
|
||||
cls.demoseeking = DEMOSEEK_NOT;
|
||||
//FIXME: pause it.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strncmp(stufftext, "cmd ", 4))
|
||||
|
@ -7378,7 +7383,7 @@ static void CL_ParsePrecache(void)
|
|||
}
|
||||
}
|
||||
|
||||
void Con_HexDump(qbyte *packet, size_t len, size_t badoffset)
|
||||
void Con_HexDump(qbyte *packet, size_t len, size_t badoffset, size_t stride)
|
||||
{
|
||||
int i;
|
||||
int pos;
|
||||
|
@ -7387,7 +7392,7 @@ void Con_HexDump(qbyte *packet, size_t len, size_t badoffset)
|
|||
while(pos < len)
|
||||
{
|
||||
Con_Printf("%5i ", pos);
|
||||
for (i = 0; i < 16; i++)
|
||||
for (i = 0; i < stride; i++)
|
||||
{
|
||||
if (pos >= len)
|
||||
Con_Printf(" - ");
|
||||
|
@ -7397,8 +7402,8 @@ void Con_HexDump(qbyte *packet, size_t len, size_t badoffset)
|
|||
Con_Printf("%2x ", packet[pos]);
|
||||
pos++;
|
||||
}
|
||||
pos-=16;
|
||||
for (i = 0; i < 16; i++)
|
||||
pos-=stride;
|
||||
for (i = 0; i < stride; i++)
|
||||
{
|
||||
if (pos >= len)
|
||||
Con_Printf("X");
|
||||
|
@ -7424,7 +7429,7 @@ void Con_HexDump(qbyte *packet, size_t len, size_t badoffset)
|
|||
}
|
||||
void CL_DumpPacket(void)
|
||||
{
|
||||
Con_HexDump(net_message.data, net_message.cursize, MSG_GetReadCount()-1);
|
||||
Con_HexDump(net_message.data, net_message.cursize, MSG_GetReadCount()-1, 16);
|
||||
}
|
||||
|
||||
static void CL_ParsePortalState(void)
|
||||
|
@ -7838,11 +7843,18 @@ void CLQW_ParseServerMessage (void)
|
|||
else
|
||||
{
|
||||
inframe_t *inf = &cl.inframes[cls.netchan.incoming_sequence&UPDATE_MASK];
|
||||
int fixtype = 2;
|
||||
if (cls.ezprotocolextensions1 & EZPEXT1_SETANGLEREASON)
|
||||
MSG_ReadByte(); //0=unknown, 1=tele, 2=spawn
|
||||
fixtype = MSG_ReadByte(); //0=unknown, 1=tele, 2=spawn
|
||||
for (i=0 ; i<3 ; i++)
|
||||
ang[i] = MSG_ReadAngle();
|
||||
if (!CSQC_Parse_SetAngles(destsplit, ang, false))
|
||||
if (fixtype == 1)
|
||||
{ //relative
|
||||
VectorAdd(ang, cl.playerview[destsplit].viewangles, ang);
|
||||
VectorSubtract(ang, cl.outframes[cls.netchan.incoming_sequence&UPDATE_MASK].cmd->angles, ang);
|
||||
}
|
||||
else fixtype = 2; //snap
|
||||
if (!CSQC_Parse_SetAngles(destsplit, ang, fixtype==1))
|
||||
{
|
||||
inf->packet_entities.fixangles[destsplit] = true;
|
||||
VectorCopy (ang, cl.playerview[destsplit].viewangles);
|
||||
|
@ -8061,6 +8073,12 @@ void CLQW_ParseServerMessage (void)
|
|||
cl.playerview[destsplit].simorg[i] = MSG_ReadCoord ();
|
||||
for (i=0 ; i<3 ; i++)
|
||||
cl.playerview[destsplit].intermissionangles[i] = MSG_ReadAngle ();
|
||||
|
||||
if (cls.demoseeking == DEMOSEEK_INTERMISSION)
|
||||
{
|
||||
cls.demoseeking = DEMOSEEK_NOT; //reached it.
|
||||
//FIXME: pause it.
|
||||
}
|
||||
break;
|
||||
|
||||
case svc_finale:
|
||||
|
@ -9863,6 +9881,12 @@ void CLNQ_ParseServerMessage (void)
|
|||
cl.completed_time = cl.gametime;
|
||||
}
|
||||
cl.intermissionmode = IM_NQSCORES;
|
||||
|
||||
if (cls.demoseeking == DEMOSEEK_INTERMISSION)
|
||||
{
|
||||
cls.demoseeking = DEMOSEEK_NOT; //reached it.
|
||||
//FIXME: pause it.
|
||||
}
|
||||
break;
|
||||
|
||||
case svc_finale:
|
||||
|
|
|
@ -2003,7 +2003,10 @@ void SCR_DrawFPS (void)
|
|||
fps_count = 0;
|
||||
lastupdatetime = t;
|
||||
|
||||
R_GetGPUUtilisation(&gpu, &gpumem); //not all that accurate, but oh well.
|
||||
if (developer.ival)
|
||||
R_GetGPUUtilisation(&gpu, &gpumem); //not all that accurate, but oh well.
|
||||
else
|
||||
gpu=gpumem=-1;
|
||||
}
|
||||
frametime = t - lastsystemtime;
|
||||
lastsystemtime = t;
|
||||
|
|
|
@ -310,8 +310,9 @@ cvar_t r_bluelight_colour = CVARFD("r_bluelight_colour", "0.5 0.5 3.0 200", CVA
|
|||
cvar_t r_rocketlight_colour = CVARFD("r_rocketlight_colour", "2.0 1.0 0.25 200", CVAR_ARCHIVE, "This controls the RGB+radius values of MF_ROCKET effects.");
|
||||
cvar_t r_muzzleflash_colour = CVARFD("r_muzzleflash_colour", "1.5 1.3 1.0 200", CVAR_ARCHIVE, "This controls the initial RGB+radius of EF_MUZZLEFLASH/svc_muzzleflash effects.");
|
||||
cvar_t r_muzzleflash_fade = CVARFD("r_muzzleflash_fade", "1.5 0.75 0.375 1000", CVAR_ARCHIVE, "This controls the per-second RGB+radius decay of EF_MUZZLEFLASH/svc_muzzleflash effects.");
|
||||
cvar_t cl_truelightning = CVARF("cl_truelightning", "0", CVAR_SEMICHEAT);
|
||||
static cvar_t cl_beam_trace = CVAR("cl_beam_trace", "0");
|
||||
cvar_t cl_truelightning = CVARFD("cl_truelightning", "0", CVAR_SEMICHEAT, "Manipulate the end position of the player's own beams, to hide lag. Can be set to fractional values to reduce the effect.");
|
||||
static cvar_t cl_beam_trace = CVARD("cl_beam_trace", "0", "Clips the length of any beams according to any walls they may have impacted.");
|
||||
static cvar_t cl_beam_alpha = CVARAFD("cl_beam_alpha", "1", "r_shaftalpha", 0, "Specifies the translucency of the lightning beam segments.");
|
||||
static cvar_t cl_legacystains = CVARD("cl_legacystains", "1", "WARNING: this cvar will default to 0 and later removed at some point"); //FIXME: do as the description says!
|
||||
static cvar_t cl_shaftlight = CVAR("gl_shaftlight", "0.8");
|
||||
static cvar_t cl_part_density_fade_start = CVARD("cl_part_density_fade_start", "1024", "Specifies the distance at which ssqc's pointparticles will start to get less dense.");
|
||||
|
@ -454,6 +455,7 @@ void CL_InitTEnts (void)
|
|||
Cvar_Register (&cl_expsprite, "Temporary entity control");
|
||||
Cvar_Register (&cl_truelightning, "Temporary entity control");
|
||||
Cvar_Register (&cl_beam_trace, "Temporary entity control");
|
||||
Cvar_Register (&cl_beam_alpha, "Temporary entity control");
|
||||
Cvar_Register (&r_explosionlight, "Temporary entity control");
|
||||
Cvar_Register (&r_explosionlight_colour, "Temporary entity control");
|
||||
Cvar_Register (&r_explosionlight_fade, "Temporary entity control");
|
||||
|
@ -905,7 +907,9 @@ beam_t *CL_AddBeam (enum beamtype_e tent, int ent, vec3_t start, vec3_t end) //f
|
|||
b->tag = -1;
|
||||
b->bflags |= /*STREAM_ATTACHED|*/STREAM_ATTACHTOPLAYER;
|
||||
b->endtime = cl.time + 0.2;
|
||||
b->alpha = 1;
|
||||
b->alpha = bound(0, cl_beam_alpha.value, 1);
|
||||
if(b->alpha < 1)
|
||||
b->rflags |= RF_TRANSLUCENT;
|
||||
b->skin = 0;
|
||||
VectorCopy (start, b->start);
|
||||
VectorCopy (end, b->end);
|
||||
|
|
|
@ -533,7 +533,13 @@ typedef struct
|
|||
#define EZTV_SETINFO (1u<<1) //proxy wants setinfo + ptrack commands
|
||||
#define EZTV_QTVUSERLIST (1u<<2) //'//qul cmd id [name]' commands from proxy.
|
||||
qboolean demohadkeyframe; //q2 needs to wait for a packet with a key frame, supposedly.
|
||||
qboolean demoseeking;
|
||||
enum
|
||||
{
|
||||
DEMOSEEK_NOT,
|
||||
DEMOSEEK_TIME, //stops one we reach demoseektime
|
||||
DEMOSEEK_MARK, //stops once we reach a '//demomark'
|
||||
DEMOSEEK_INTERMISSION, //stops once we reach an svc_intermission
|
||||
} demoseeking;
|
||||
float demoseektime;
|
||||
int demotrack;
|
||||
qboolean timedemo;
|
||||
|
@ -1197,7 +1203,7 @@ extern scenetris_t *cl_stris;
|
|||
extern vecV_t *fte_restrict cl_strisvertv;
|
||||
extern vec4_t *fte_restrict cl_strisvertc;
|
||||
extern vec2_t *fte_restrict cl_strisvertt;
|
||||
extern vec3_t *fte_restrict cl_strisvertn[3];
|
||||
//extern vec3_t *fte_restrict cl_strisvertn[3];
|
||||
extern index_t *fte_restrict cl_strisidx;
|
||||
extern unsigned int cl_numstrisidx;
|
||||
extern unsigned int cl_maxstrisidx;
|
||||
|
@ -1579,6 +1585,7 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr);
|
|||
void TP_ExecTrigger (char *s, qboolean indemos); //executes one of the user's f_foo aliases from some engine-defined event.
|
||||
qboolean TP_FilterMessage (char *s);
|
||||
void TP_Init(void);
|
||||
qboolean TP_HaveLocations(void);
|
||||
char* TP_LocationName (const vec3_t location);
|
||||
void TP_NewMap (void);
|
||||
qboolean TP_CheckSoundTrigger (char *str); //plays sound files when some substring exists in chat.
|
||||
|
|
|
@ -336,7 +336,7 @@ static qbyte *CIN_ReadNextFrame (cinematics_t *cin)
|
|||
else if (cin->s_width == 2)
|
||||
COM_SwapLittleShortBlock((short *)samples, count*cin->s_channels);
|
||||
|
||||
S_RawAudio (0, samples, cin->s_rate, count, cin->s_channels, cin->s_width, volume.value );
|
||||
S_RawAudio (SOURCEID_CINEMATIC, samples, cin->s_rate, count, cin->s_channels, cin->s_width, volume.value );
|
||||
|
||||
in.data = compressed;
|
||||
in.count = size;
|
||||
|
|
|
@ -8819,6 +8819,34 @@ static void Image_Tr_RGBX8toPaletted(struct pendingtextureinfo *mips, int args)
|
|||
*out++ = GetPaletteIndexRange(first, stop, in[0], in[1], in[2]);
|
||||
}
|
||||
}
|
||||
static void Image_Tr_RGBA8toPaletted(struct pendingtextureinfo *mips, int args)
|
||||
{
|
||||
unsigned int mip;
|
||||
int first=args&0xffff;
|
||||
int stop=(args>>16)&0xffff;
|
||||
int tr = first?0:255;
|
||||
for (mip = 0; mip < mips->mipcount; mip++)
|
||||
{
|
||||
qbyte *in = mips->mip[mip].data;
|
||||
qbyte *out = mips->mip[mip].data;
|
||||
unsigned int p = mips->mip[mip].width*mips->mip[mip].height*mips->mip[mip].depth;
|
||||
unsigned short tmp;
|
||||
if (!mips->mip[mip].needfree && !mips->extrafree)
|
||||
{
|
||||
mips->mip[mip].needfree = true;
|
||||
mips->mip[mip].data = out = BZ_Malloc(sizeof(tmp)*p);
|
||||
}
|
||||
mips->mip[mip].datasize = p*sizeof(*out);
|
||||
|
||||
for(; p-->0; in += 4)
|
||||
{
|
||||
if (in[3] < 128)
|
||||
*out++ = tr;
|
||||
else
|
||||
*out++ = GetPaletteIndexRange(first, stop, in[0], in[1], in[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//may operate in place
|
||||
static void Image_Tr_8888toLuminence(struct pendingtextureinfo *mips, int channels)
|
||||
|
@ -12184,7 +12212,9 @@ static struct
|
|||
{PTI_RG8, PTI_RGBX8, Image_Tr_RG8ToRGXX8},
|
||||
{PTI_RGBX8, PTI_P8, Image_Tr_RGBX8toPaletted, 0|(256<<16)},
|
||||
{PTI_RGBX8, TF_H2_TRANS8_0, Image_Tr_RGBX8toPaletted, 1|(256<<16)},
|
||||
{PTI_RGBA8, TF_H2_TRANS8_0, Image_Tr_RGBA8toPaletted, 1|(256<<16)},
|
||||
{PTI_RGBX8, TF_TRANS8, Image_Tr_RGBX8toPaletted, 0|(255<<16)},
|
||||
{PTI_RGBA8, TF_TRANS8, Image_Tr_RGBA8toPaletted, 0|(255<<16)},
|
||||
{PTI_P8, PTI_RGBX8, Image_Tr_PalettedtoRGBX8, -1},
|
||||
{TF_SOLID8, PTI_RGBX8, Image_Tr_PalettedtoRGBX8, -1},
|
||||
{TF_H2_TRANS8_0,PTI_RGBA8, Image_Tr_PalettedtoRGBX8, 0},
|
||||
|
|
|
@ -31,8 +31,8 @@ void IN_ActivateMouse(void)
|
|||
SDL_ShowCursor(0);
|
||||
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
SDL_SetRelativeMouseMode(true);
|
||||
SDL_SetWindowGrab(sdlwindow, true);
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
SDL_SetWindowGrab(sdlwindow, SDL_TRUE);
|
||||
#else
|
||||
SDL_WM_GrabInput(SDL_GRAB_ON);
|
||||
#endif
|
||||
|
@ -46,8 +46,8 @@ void IN_DeactivateMouse(void)
|
|||
mouseactive = false;
|
||||
SDL_ShowCursor(1);
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
SDL_SetRelativeMouseMode(false);
|
||||
SDL_SetWindowGrab(sdlwindow, false);
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_SetWindowGrab(sdlwindow, SDL_FALSE);
|
||||
#else
|
||||
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||
#endif
|
||||
|
|
|
@ -2964,8 +2964,9 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
}
|
||||
}
|
||||
|
||||
//yes, csqc is allowed to steal the escape key.
|
||||
if (key != '`' && (!down || key != K_ESCAPE || (!Key_Dest_Has(~kdm_game) && !shift_down)) &&
|
||||
//yes, csqc is allowed to steal the escape key (unless shift).
|
||||
//it is blocked from blocking backtick (unless shift).
|
||||
if ((key != '`'||shift_down) && (!down || key != K_ESCAPE || (!Key_Dest_Has(~kdm_game) && !shift_down)) &&
|
||||
!Key_Dest_Has(~kdm_game))
|
||||
{
|
||||
#ifdef CSQC_DAT
|
||||
|
|
|
@ -239,7 +239,7 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text)
|
|||
}
|
||||
#endif
|
||||
|
||||
mpic_t *QBigFontWorks(void)
|
||||
void *QBigFontWorks(void)
|
||||
{
|
||||
mpic_t *p;
|
||||
int i;
|
||||
|
@ -250,14 +250,15 @@ mpic_t *QBigFontWorks(void)
|
|||
"textures/mcharset.lmp",
|
||||
NULL
|
||||
};
|
||||
if (font_menu)
|
||||
return font_menu;
|
||||
for (i = 0; names[i]; i++)
|
||||
{
|
||||
p = R2D_SafeCachePic (names[i]);
|
||||
if (p && R_GetShaderSizes(p, NULL, NULL, true))
|
||||
return p;
|
||||
}
|
||||
|
||||
return (mpic_t*)font_menu;
|
||||
return NULL;
|
||||
}
|
||||
void Draw_BigFontString(int x, int y, const char *text)
|
||||
{
|
||||
|
@ -598,7 +599,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
|
|||
}
|
||||
}
|
||||
|
||||
if (&menu->menu == topmenu && menu->mouseitem == option && option->common.type != mt_frameend)
|
||||
if (&menu->menu == topmenu && menu->mouseitem == option && option->common.type != mt_frameend && !Key_Dest_Has_Higher(kdm_menu))
|
||||
{
|
||||
float alphamax = 0.5, alphamin = 0.2;
|
||||
R2D_ImageColours(.5,.4,0,(sin(realtime*2)+1)*0.5*(alphamax-alphamin)+alphamin);
|
||||
|
@ -608,12 +609,16 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
|
|||
switch(option->common.type)
|
||||
{
|
||||
case mt_menucursor:
|
||||
if (Key_Dest_Has_Higher(kdm_menu))
|
||||
break;
|
||||
if ((int)(realtime*4)&1)
|
||||
Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d");
|
||||
break;
|
||||
case mt_text:
|
||||
if (!option->text.text)
|
||||
{ //blinking cursor image hack (FIXME)
|
||||
if (Key_Dest_Has_Higher(kdm_menu))
|
||||
break;
|
||||
if ((int)(realtime*4)&1)
|
||||
Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d");
|
||||
}
|
||||
|
@ -636,16 +641,18 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
|
|||
Draw_BigFontString(xpos+option->common.posx, ypos+option->common.posy, option->button.text);
|
||||
break;
|
||||
case mt_menudot:
|
||||
if (Key_Dest_Has_Higher(kdm_menu))
|
||||
break;
|
||||
i = (int)(realtime * 10)%maxdots;
|
||||
p = R2D_SafeCachePic(va(menudotstyle, i+mindot ));
|
||||
if (R_GetShaderSizes(p, NULL, NULL, false)>0)
|
||||
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, option->common.width, option->common.height, p);
|
||||
if (R_GetShaderSizes(p, &pw, &ph, false)>0)
|
||||
R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, (pw/(float)ph)*option->common.width, option->common.height, p);
|
||||
else if ((int)(realtime*4)&1)
|
||||
Draw_FunString(xpos+option->common.posx, ypos+option->common.posy + (option->common.height-8)/2, "^a^Ue00d");
|
||||
break;
|
||||
case mt_picturesel:
|
||||
p = NULL;
|
||||
if (menu->selecteditem && menu->selecteditem->common.posx == option->common.posx && menu->selecteditem->common.posy == option->common.posy)
|
||||
if (menu->selecteditem && menu->selecteditem->common.posx == option->common.posx && menu->selecteditem->common.posy == option->common.posy && !Key_Dest_Has_Higher(kdm_menu))
|
||||
{
|
||||
char selname[MAX_QPATH];
|
||||
Q_strncpyz(selname, option->picture.picturename, sizeof(selname));
|
||||
|
@ -816,7 +823,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
|
|||
Draw_ApproxTextBox(x, y, 16*8, 8);
|
||||
Draw_FunString(x, y, option->edit.text);
|
||||
|
||||
if (menu->selecteditem == option && (int)(realtime*4) & 1)
|
||||
if (menu->selecteditem == option && (int)(realtime*4) & 1 && !Key_Dest_Has_Higher(kdm_menu))
|
||||
{
|
||||
vid.ime_allow = true;
|
||||
vid.ime_position[0] = x;
|
||||
|
@ -904,7 +911,7 @@ static void MenuDraw(emenu_t *menu)
|
|||
menu->menu.showosk = false;
|
||||
MenuDrawItems(menu->xpos, menu->ypos, menu->options, menu);
|
||||
// draw tooltip
|
||||
if (menu->mouseitem && menu->tooltip && realtime > menu->tooltiptime)
|
||||
if (menu->mouseitem && menu->tooltip && realtime > menu->tooltiptime && !Key_Dest_Has_Higher(kdm_menu))
|
||||
{
|
||||
// menuoption_t *option = menu->mouseitem;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ static cvar_t sb_showtimelimit = CVARF("sb_showtimelimit", "0", CVAR_ARCHIVE);
|
|||
|
||||
static cvar_t sb_alpha = CVARF("sb_alpha", "0.7", CVAR_ARCHIVE);
|
||||
|
||||
vrect_t joinbutton, specbutton;
|
||||
vrect_t joinbutton, streambutton, specbutton;
|
||||
static float refreshedtime;
|
||||
static int isrefreshing;
|
||||
static enum
|
||||
|
@ -372,7 +372,7 @@ static qboolean SL_ServerKey (menucustom_t *ths, emenu_t *menu, int key, unsigne
|
|||
return true;
|
||||
}
|
||||
if (oldselection == info->selectedpos)
|
||||
serverpreview = 1;
|
||||
serverpreview = (server->adr.prot>=NP_STREAM)?SVPV_RULES:1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -466,6 +466,7 @@ static void SL_PostDraw (emenu_t *menu)
|
|||
serverinfo_t *server = selectedserver.inuse?Master_InfoForServer(&selectedserver.adr, selectedserver.brokerid):NULL;
|
||||
int h = 0;
|
||||
int w = 240;
|
||||
char *qtv;
|
||||
#ifdef HAVE_PACKET
|
||||
if (server && selectedserver.refreshtime < realtime)
|
||||
{
|
||||
|
@ -706,6 +707,35 @@ static void SL_PostDraw (emenu_t *menu)
|
|||
Draw_FunStringWidth(lx, y + (bh-8)/2, localtext("Observe"), bw, 2, active);y+=8;
|
||||
}
|
||||
|
||||
qtv = Info_ValueForKey(server->moreinfo->info, "qtvstream");
|
||||
if (server && *qtv)
|
||||
{
|
||||
int lx = vid.width/2 - w/2;
|
||||
int y = vid.height/2 - h/2 - 4 + h;
|
||||
int bh, bw;
|
||||
qboolean active = false;
|
||||
bw = w+16+12;
|
||||
bh = 24;
|
||||
// lx += bw-12;
|
||||
bw = strlen(localtext("Stream"))*8 + 24;
|
||||
bw = ((bw+15)/16) * 16; //width must be a multiple of 16
|
||||
// lx -= bw;
|
||||
|
||||
streambutton.x = lx;
|
||||
streambutton.y = y;
|
||||
streambutton.width = bw + 16;
|
||||
streambutton.height = bh + 16;
|
||||
R2D_ImageColours(1,1,1,1);
|
||||
y += 8;
|
||||
Draw_ApproxTextBox(lx, y, bw, bh);
|
||||
|
||||
if (mousecursor_x >= streambutton.x && mousecursor_x < streambutton.x+streambutton.width)
|
||||
if (mousecursor_y >= streambutton.y && mousecursor_y < streambutton.y+streambutton.height)
|
||||
active = true;
|
||||
|
||||
Draw_FunStringWidth(lx, y + (bh-8)/2, localtext("Stream"), bw, 2, active);y+=8;
|
||||
}
|
||||
|
||||
{
|
||||
int lx = vid.width/2 - w/2;
|
||||
int y = vid.height/2 - h/2 - 4 + h;
|
||||
|
@ -794,6 +824,12 @@ static qboolean SL_Key (emenu_t *menu, int key, unsigned int unicode)
|
|||
serverpreview = SVPV_NO;
|
||||
goto dospec;
|
||||
}
|
||||
if (mousecursor_x >= streambutton.x && mousecursor_x < streambutton.x+streambutton.width)
|
||||
if (mousecursor_y >= streambutton.y && mousecursor_y < streambutton.y+streambutton.height)
|
||||
{
|
||||
serverpreview = SVPV_NO;
|
||||
goto dostream;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#ifdef HAVE_PACKET
|
||||
|
@ -839,6 +875,13 @@ static qboolean SL_Key (emenu_t *menu, int key, unsigned int unicode)
|
|||
return true;
|
||||
}
|
||||
#endif
|
||||
else if (key == 't')
|
||||
{
|
||||
dostream:
|
||||
Cbuf_AddText(va("qtvplay \"%s\"\n", Info_ValueForKey(server->moreinfo->info, "qtvstream")), RESTRICT_LOCAL);
|
||||
M_RemoveAllMenus(true);
|
||||
return true;
|
||||
}
|
||||
else if (key == 'b' || key == 'o' || key == 'j' || key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_GP_DIAMOND_ALTCONFIRM) //join
|
||||
{
|
||||
if (key == 's' || key == 'o' || key == K_GP_DIAMOND_ALTCONFIRM)
|
||||
|
|
|
@ -1801,10 +1801,10 @@ static qboolean Media_WinAvi_DecodeFrame (cin_t *cin, qboolean nosound, qboolean
|
|||
qacmStreamConvert(cin->avi.audiodecoder, &strhdr, ACM_STREAMCONVERTF_BLOCKALIGN);
|
||||
qacmStreamUnprepareHeader(cin->avi.audiodecoder, &strhdr, 0);
|
||||
|
||||
S_RawAudio(-1, strhdr.pbDst, cin->avi.pWaveFormat->nSamplesPerSec, strhdr.cbDstLengthUsed/4, cin->avi.pWaveFormat->nChannels, 2, volume.value);
|
||||
S_RawAudio(SOURCEID_CINEMATIC, strhdr.pbDst, cin->avi.pWaveFormat->nSamplesPerSec, strhdr.cbDstLengthUsed/4, cin->avi.pWaveFormat->nChannels, 2, volume.value);
|
||||
}
|
||||
else
|
||||
S_RawAudio(-1, pBuffer, cin->avi.pWaveFormat->nSamplesPerSec, samples, cin->avi.pWaveFormat->nChannels, 2, volume.value);
|
||||
S_RawAudio(SOURCEID_CINEMATIC, pBuffer, cin->avi.pWaveFormat->nSamplesPerSec, samples, cin->avi.pWaveFormat->nChannels, 2, volume.value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2223,7 +2223,7 @@ static qboolean Media_Roq_DecodeFrame (cin_t *cin, qboolean nosound, qboolean fo
|
|||
while (cin->roq.roqfilm->audio_channels && S_HaveOutput() && cin->roq.roqfilm->aud_pos < cin->roq.roqfilm->vid_pos)
|
||||
{
|
||||
if (roq_read_audio(cin->roq.roqfilm)>0)
|
||||
S_RawAudio(-1, cin->roq.roqfilm->audio, 22050, cin->roq.roqfilm->audio_size/cin->roq.roqfilm->audio_channels, cin->roq.roqfilm->audio_channels, 2, volume.value );
|
||||
S_RawAudio(SOURCEID_CINEMATIC, cin->roq.roqfilm->audio, 22050, cin->roq.roqfilm->audio_size/cin->roq.roqfilm->audio_channels, cin->roq.roqfilm->audio_channels, 2, volume.value );
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -2589,7 +2589,7 @@ qboolean Media_StopFilm(qboolean all)
|
|||
R_UnloadShader(videoshader);
|
||||
videoshader = NULL;
|
||||
|
||||
S_RawAudio(-1, NULL, 0, 0, 0, 0, 0);
|
||||
S_RawAudio(SOURCEID_CINEMATIC, NULL, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
while (pendingfilms && !videoshader)
|
||||
|
@ -3524,7 +3524,7 @@ void Media_RecordFrame (void)
|
|||
Draw_FunString(0, y, capturemessage.string);
|
||||
}
|
||||
|
||||
//time for annother frame?
|
||||
//time for another frame?
|
||||
if (!captureframeforce)
|
||||
{
|
||||
if (capturelastvideotime > realtime+1)
|
||||
|
|
|
@ -3377,8 +3377,8 @@ typedef struct
|
|||
int boneidx;
|
||||
int bonebias; //shift the bones menu down to ensure the boneidx stays visible
|
||||
int textype;
|
||||
double framechangetime;
|
||||
double skinchangetime;
|
||||
double frametime;
|
||||
double skintime;
|
||||
|
||||
float pitch;
|
||||
float yaw;
|
||||
|
@ -3394,6 +3394,7 @@ typedef struct
|
|||
char shaderfile[MAX_QPATH];
|
||||
char *shadertext;
|
||||
|
||||
qboolean paused;
|
||||
#ifdef RAGDOLL
|
||||
lerpents_t ragent;
|
||||
world_t ragworld;
|
||||
|
@ -3505,7 +3506,9 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
modelview_t *mods = c->dptr;
|
||||
skinfile_t *skin;
|
||||
texnums_t *texnums;
|
||||
#ifdef SKELETALMODELS
|
||||
qboolean boneanimsonly;
|
||||
#endif
|
||||
model_t *animmodel = NULL;
|
||||
|
||||
if (R2D_Flush)
|
||||
|
@ -3523,7 +3526,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
r_refdef.grect.height = vid.height;
|
||||
r_refdef.grect.x = 0;
|
||||
r_refdef.grect.y = 0;
|
||||
r_refdef.time = realtime;
|
||||
r_refdef.time = mods->skintime;
|
||||
|
||||
r_refdef.flags = RDF_NOWORLDMODEL;
|
||||
|
||||
|
@ -3620,7 +3623,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
ent.shaderTime = 0;//realtime;
|
||||
ent.framestate.g[FS_REG].lerpweight[0] = 1;
|
||||
ent.framestate.g[FS_REG].frame[0] = mods->framegroup;
|
||||
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
|
||||
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = mods->frametime;
|
||||
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
|
||||
if (*mods->skinname)
|
||||
{
|
||||
|
@ -3651,6 +3654,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
#endif
|
||||
|
||||
V_ApplyRefdef();
|
||||
|
||||
if (!mods->paused)
|
||||
{
|
||||
mods->frametime += host_frametime;
|
||||
mods->skintime += host_frametime;
|
||||
}
|
||||
/*
|
||||
{
|
||||
trace_t tr;
|
||||
|
@ -3707,9 +3716,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
ent.framestate.g[FS_REG].frame[0] |= 0x8000;
|
||||
if (ent.model->dollinfo && mods->ragworld.rbe)
|
||||
{
|
||||
float rate = 1.0/60;
|
||||
float rate = 1.0/60; //try a fixed tick rate...
|
||||
rag_doallanimations(&mods->ragworld);
|
||||
mods->fixedrate += host_frametime;
|
||||
if (mods->fixedrate > 1)
|
||||
mods->fixedrate = 1;
|
||||
while (mods->fixedrate >= rate)
|
||||
|
@ -3717,11 +3725,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
mods->ragworld.rbe->RunFrame(&mods->ragworld, rate, 800);
|
||||
mods->fixedrate -= rate;
|
||||
}
|
||||
if (!mods->paused)
|
||||
mods->fixedrate += host_frametime;
|
||||
|
||||
rag_updatedeltaent(&mods->ragworld, &ent, &mods->ragent);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SKELETALMODELS
|
||||
if (animmodel)// && Mod_GetNumBones(ent.model, false)==Mod_GetNumBones(animmodel, false))
|
||||
{
|
||||
int numbones = Mod_GetNumBones(ent.model, false);
|
||||
|
@ -3732,6 +3743,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
ent.framestate.skeltype = SKEL_RELATIVE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
animmodel = ent.model; //not using it. sorry. warn?
|
||||
|
||||
|
||||
|
@ -3842,6 +3854,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef SKELETALMODELS
|
||||
boneanimsonly = false;
|
||||
if (ent.model && ent.model->loadstate == MLS_LOADED && ent.model->type == mod_alias)
|
||||
{ //some models don't actually contain any mesh data, but exist as containers for skeletal animations that can be skel_built into a different model's anims.
|
||||
|
@ -3900,6 +3913,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
V_AddAxisEntity(&ent);
|
||||
|
||||
|
@ -4250,10 +4264,18 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int
|
|||
case MV_NORMALS: mods->mode = MV_NONE; break;
|
||||
}
|
||||
}
|
||||
else if (key >= '1' && key <= '7')
|
||||
{
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
mods->mode = MV_NONE + (key - '1');
|
||||
}
|
||||
else if (key == 'p')
|
||||
mods->paused = !mods->paused;
|
||||
else if (key == 'r')
|
||||
{
|
||||
mods->framechangetime = realtime;
|
||||
mods->skinchangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
mods->skintime = 0;
|
||||
}
|
||||
#ifdef RAGDOLL
|
||||
else if (key == 'f')
|
||||
|
@ -4290,28 +4312,28 @@ static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int
|
|||
else if (key == K_END)
|
||||
{
|
||||
mods->skingroup = max(0, mods->skingroup-1);
|
||||
mods->skinchangetime = realtime;
|
||||
mods->skintime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_HOME)
|
||||
{
|
||||
mods->skingroup += 1;
|
||||
mods->skinchangetime = realtime;
|
||||
mods->skintime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_PGDN)
|
||||
{
|
||||
mods->framegroup = max(0, mods->framegroup-1);
|
||||
mods->framechangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
Z_Free(mods->shadertext);
|
||||
mods->shadertext = NULL;
|
||||
}
|
||||
else if (key == K_PGUP)
|
||||
{
|
||||
mods->framegroup += 1;
|
||||
mods->framechangetime = realtime;
|
||||
mods->frametime = 0;
|
||||
}
|
||||
else if (key == K_DEL)
|
||||
{
|
||||
|
@ -4393,8 +4415,8 @@ void M_Menu_ModelViewer_f(void)
|
|||
Q_strncpyz(mv->skinname, Cmd_Argv(2), sizeof(mv->skinname));
|
||||
Q_strncpyz(mv->animname, Cmd_Argv(3), sizeof(mv->animname));
|
||||
|
||||
mv->framechangetime = realtime;
|
||||
mv->skinchangetime = realtime;
|
||||
mv->frametime = 0;
|
||||
mv->skintime = 0;
|
||||
#ifdef RAGDOLL
|
||||
menu->menu.videoreset = M_Modelviewer_Reset;
|
||||
menu->remove = M_Modelviewer_Shutdown;
|
||||
|
|
|
@ -1183,7 +1183,8 @@ void M_Menu_Demos_f (void)
|
|||
{
|
||||
char *demoexts[] = {
|
||||
".mvd", ".mvd.gz",
|
||||
".qwz", ".qwz.gz",
|
||||
".qwd", ".qwd.gz",
|
||||
//".qwz", ".qwz.gz",
|
||||
#ifdef NQPROT
|
||||
".dem", ".dem.gz",
|
||||
#endif
|
||||
|
@ -1191,7 +1192,7 @@ void M_Menu_Demos_f (void)
|
|||
".dm2", ".dm2.gz"
|
||||
#endif
|
||||
//there are also qizmo demos (.qwz) out there...
|
||||
//we don't support them, but if we were to ask quizmo to decode them for us, we could do.
|
||||
//we don't support them, but if we were to ask qizmo to decode them for us, we could do.
|
||||
};
|
||||
char *archiveexts[] = {
|
||||
#ifdef PACKAGE_PK3
|
||||
|
|
|
@ -1283,7 +1283,10 @@ void M_Menu_Quit_f (void)
|
|||
else if (!strcmp(arg, "forcesave") || cfg_save_auto.ival)
|
||||
{
|
||||
Cmd_ExecuteString("cfg_save", RESTRICT_LOCAL);
|
||||
mode = 0;
|
||||
if (!strcmp(arg, "prompt"))
|
||||
mode = 1;
|
||||
else
|
||||
mode = 0;
|
||||
}
|
||||
else if (!strcmp(arg, "save"))
|
||||
mode = 2;
|
||||
|
|
|
@ -138,6 +138,7 @@ void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const cha
|
|||
#define Menu_PromptOrPrint(messages,optioncancel,highpri) Con_Printf("%s", messages)
|
||||
#endif
|
||||
|
||||
void M_Window_ClosePrompt (void); //called when the window was requested to be closed. displays whatever quit menu is appropriate.
|
||||
#ifndef NOBUILTINMENUS
|
||||
|
||||
//
|
||||
|
@ -150,8 +151,6 @@ 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_Window_ClosePrompt (void); //called when the window was requested to be closed. displays whatever quit menu is appropriate.
|
||||
void menufixme(void); //REMOVE REMOVE REMOVE
|
||||
typedef struct emenu_s emenu_t;
|
||||
|
||||
|
||||
|
@ -365,7 +364,7 @@ menucheck_t *MC_AddCheckBox(emenu_t *menu, int tx, int cx, int y, const char *te
|
|||
menucheck_t *MC_AddCheckBoxFunc(emenu_t *menu, int tx, int cx, int y, const char *text, qboolean (*func) (menucheck_t *option, emenu_t *menu, chk_set_t set), int bits);
|
||||
menubutton_t *MC_AddConsoleCommand(emenu_t *menu, int lhs, int rhs, int y, const char *text, const char *command);
|
||||
menubutton_t *MC_AddConsoleCommandQBigFont(emenu_t *menu, int x, int y, const char *text, const char *command);
|
||||
mpic_t *QBigFontWorks(void);
|
||||
void *QBigFontWorks(void); //treat as a boolean.
|
||||
menubutton_t *MC_AddConsoleCommandHexen2BigFont(emenu_t *menu, int x, int y, const char *text, const char *command);
|
||||
menubutton_t *VARGS MC_AddConsoleCommandf(emenu_t *menu, int lhs, int rhs, int y, int rightalign, const char *text, char *command, ...);
|
||||
menubutton_t *MC_AddCommand(emenu_t *menu, int lhs, int rhs, int y, const char *text, qboolean (*command) (union menuoption_s *,struct emenu_s *,int));
|
||||
|
|
|
@ -388,6 +388,8 @@ typedef struct texnums_s {
|
|||
texid_t reflectmask; //2d, defines how reflective it is (for cubemap reflections)
|
||||
texid_t displacement; //2d, alternative to bump.a, eg R16[F] for offsetmapping or tessellation
|
||||
texid_t occlusion; //2d, occlusion map... only red is used.
|
||||
texid_t transmission; //2d, multiplier for transmissionfactor... only red is used.
|
||||
texid_t thickness; //2d, multiplier for thicknessfactor... only green is used.
|
||||
|
||||
//the material's pushconstants. vulkan guarentees only 128 bytes. so 8 vec4s. note that lmscales should want 4 of them...
|
||||
/*struct
|
||||
|
|
|
@ -2965,7 +2965,7 @@ static void MasterInfo_Request(master_t *mast)
|
|||
break;
|
||||
#endif
|
||||
case MP_QUAKEWORLD:
|
||||
NET_SendPollPacket (14, va("%c%c%c%cstatus 23\n", 255, 255, 255, 255), mast->adr);
|
||||
NET_SendPollPacket (14, va("%c%c%c%cstatus %i\n", 255, 255, 255, 255, STATUS_QTVLIST|STATUS_SHOWTEAMS|STATUS_SPECTATORS|STATUS_PLAYERS|STATUS_SERVERINFO), mast->adr);
|
||||
break;
|
||||
#ifdef NQPROT
|
||||
case MP_NETQUAKE:
|
||||
|
@ -3151,7 +3151,7 @@ void Master_QueryServer(serverinfo_t *server)
|
|||
return;
|
||||
#endif
|
||||
case SS_QUAKEWORLD:
|
||||
Q_snprintfz(data, sizeof(data), "%c%c%c%cstatus 23\n", 255, 255, 255, 255);
|
||||
Q_snprintfz(data, sizeof(data), "%c%c%c%cstatus %i\n", 255, 255, 255, 255, STATUS_QTVLIST|STATUS_SHOWTEAMS|STATUS_SPECTATORS|STATUS_PLAYERS|STATUS_SERVERINFO);
|
||||
break;
|
||||
case SS_QUAKE2:
|
||||
Q_snprintfz(data, sizeof(data), "%c%c%c%cstatus\n", 255, 255, 255, 255);
|
||||
|
@ -3487,8 +3487,10 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
|
|||
|
||||
if (!MasterInfo_ReadProtocol(info, msg))
|
||||
{ //try and guess.
|
||||
if (0)
|
||||
;
|
||||
#ifdef Q2CLIENT
|
||||
if (prototype == MP_QUAKE2)
|
||||
else if (prototype == MP_QUAKE2)
|
||||
info->special |= SS_QUAKE2;
|
||||
#endif
|
||||
#ifdef Q3CLIENT
|
||||
|
@ -3499,9 +3501,7 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
|
|||
else if (prototype == MP_NETQUAKE)
|
||||
info->special |= SS_NETQUAKE;
|
||||
#endif
|
||||
#if defined(Q2CLIENT) || defined(Q3CLIENT) || defined(NQPROT)
|
||||
else
|
||||
#endif
|
||||
info->special |= SS_QUAKEWORLD;
|
||||
}
|
||||
if (favorite) //was specifically named, not retrieved from a master.
|
||||
|
@ -3577,13 +3577,35 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
|
|||
{
|
||||
int clnum;
|
||||
|
||||
for (clnum=0; clnum < MAX_CLIENTS; clnum++)
|
||||
for (clnum=0; ; clnum++)
|
||||
{
|
||||
nl = strchr(msg, '\n');
|
||||
if (!nl)
|
||||
break;
|
||||
*nl = '\0';
|
||||
|
||||
if (!strncmp(msg, "qtv ", 4))
|
||||
{ //qtv destnum "proxyname" "stream@host:port" viewercount
|
||||
char proxstream[128];
|
||||
char tokval[256];
|
||||
token = msg+4;
|
||||
|
||||
token = COM_ParseOut(token, tokval,sizeof(tokval));
|
||||
//destnum = atoi(tokval);
|
||||
token = COM_ParseOut(token, tokval,sizeof(tokval));
|
||||
//proxy name...
|
||||
token = COM_ParseOut(token, proxstream,sizeof(proxstream));
|
||||
token = COM_ParseOut(token, tokval,sizeof(tokval));
|
||||
//viewercount = atoi(tokval);
|
||||
|
||||
if (*proxstream)
|
||||
Info_SetValueForKey(details.info, "qtvstream", proxstream, sizeof(details.info));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clnum == MAX_CLIENTS)
|
||||
break;
|
||||
|
||||
details.players[clnum].isspec = 0;
|
||||
details.players[clnum].team[0] = 0;
|
||||
details.players[clnum].skin[0] = 0;
|
||||
|
|
|
@ -567,6 +567,20 @@ void QCBUILTIN PF_cl_runningserver (pubprogfuncs_t *prinst, struct globalvars_s
|
|||
#endif
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_cl_addprogs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
int newp;
|
||||
if (!s || !*s)
|
||||
newp = -1;
|
||||
else
|
||||
{
|
||||
newp = PR_LoadProgs(prinst, s);
|
||||
if (newp >= 0)
|
||||
PR_ProgsAdded(prinst, newp, s);
|
||||
}
|
||||
G_FLOAT(OFS_RETURN) = newp;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_MEDIA_DECODER
|
||||
|
@ -1050,6 +1064,55 @@ void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
|
||||
S_LocalSound2(s, chan, vol);
|
||||
}
|
||||
void QCBUILTIN PF_cl_queueaudio(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
world_t *world = prinst->parms->user;
|
||||
int sourceid = (world->keydestmask == kdm_menu)?SOURCEID_MENUQC:SOURCEID_CSQC;
|
||||
int hz = G_INT(OFS_PARM0);
|
||||
int channels = G_INT(OFS_PARM1);
|
||||
int type = G_INT(OFS_PARM2);
|
||||
int qcptr = G_INT(OFS_PARM3);
|
||||
int numframes = G_INT(OFS_PARM4);
|
||||
int i;
|
||||
const float volume = 1;
|
||||
qaudiofmt_t fmt;
|
||||
const void *data;
|
||||
void *ndata;
|
||||
|
||||
if (hz < 1 || (channels != 1 && channels != 2) || numframes <= 0)
|
||||
{ //dumb arg.
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
return;
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case 8: fmt = QAF_S8; data = PR_GetReadQCPtr(prinst, qcptr, numframes*channels*QAF_BYTES(fmt));
|
||||
ndata = alloca(sizeof(char)*numframes*channels);
|
||||
for (i = numframes*channels; i --> 0; )
|
||||
((char*)ndata)[i] = ((const qbyte*)data)[i]-128;
|
||||
data = ndata; break;
|
||||
case -8: fmt = QAF_S8; data = PR_GetReadQCPtr(prinst, qcptr, numframes*channels*QAF_BYTES(fmt)); break;
|
||||
case -16: fmt = QAF_S16; data = PR_GetReadQCPtr(prinst, qcptr, numframes*channels*QAF_BYTES(fmt)); break;
|
||||
// case 16: fmt = QAF_U16: data = PR_GetReadQCPtr(prinst, qcptr, numframes*channels*QAF_BYTES(fmt)); break;
|
||||
#ifdef MIXER_F32
|
||||
case 256|32: fmt = QAF_F32; data = PR_GetReadQCPtr(prinst, qcptr, numframes*channels*QAF_BYTES(fmt)); break;
|
||||
#endif
|
||||
default:
|
||||
G_FLOAT(OFS_RETURN) = -2; //unsupported width.
|
||||
return;
|
||||
}
|
||||
|
||||
S_RawAudio(sourceid, data, hz, numframes*channels, channels, fmt, volume);
|
||||
|
||||
G_FLOAT(OFS_RETURN) = 1;
|
||||
}
|
||||
void QCBUILTIN PF_cl_getqueuedaudiotime(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
world_t *world = prinst->parms->user;
|
||||
int sourceid = (world->keydestmask == kdm_menu)?SOURCEID_MENUQC:SOURCEID_CSQC;
|
||||
|
||||
G_FLOAT(OFS_RETURN) = S_RawAudioQueued(sourceid);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_cl_getlocaluserinfoblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
|
|
@ -42,20 +42,10 @@ extern cvar_t sv_demo_write_csqc;
|
|||
|
||||
static pubprogfuncs_t *csqcprogs;
|
||||
|
||||
typedef struct csqctreadstate_s {
|
||||
float resumetime;
|
||||
struct qcthread_s *thread;
|
||||
int self;
|
||||
int other;
|
||||
|
||||
struct csqctreadstate_s *next;
|
||||
} csqctreadstate_t;
|
||||
|
||||
static qboolean csprogs_promiscuous;
|
||||
static unsigned int csprogs_checksum;
|
||||
static size_t csprogs_checksize;
|
||||
static char csprogs_checkname[MAX_QPATH];
|
||||
static csqctreadstate_t *csqcthreads;
|
||||
qboolean csqc_resortfrags;
|
||||
world_t csqc_world;
|
||||
|
||||
|
@ -127,7 +117,7 @@ static csqcglobals_t csqcg;
|
|||
|
||||
playerview_t csqc_nullview;
|
||||
|
||||
static void VARGS CSQC_Abort (char *format, ...); //an error occured.
|
||||
static void VARGS CSQC_Abort (const char *format, ...); //an error occured.
|
||||
static void cs_set_input_state (usercmd_t *cmd);
|
||||
|
||||
//fixme: we should be using entity numbers, not view numbers.
|
||||
|
@ -348,7 +338,7 @@ static void CSQC_FindGlobals(qboolean nofuncs)
|
|||
|
||||
if (!csqc_world.g.physics_mode)
|
||||
{
|
||||
csphysicsmode = 0; /*note: dp handles think functions as part of addentity rather than elsewhere. if we're in a compat mode, we don't want to have to duplicate work*/
|
||||
csphysicsmode = csqc_isdarkplaces?1:0; /*note: dp handles think functions as part of addentity rather than elsewhere. if we're in a compat mode, we don't want to have to duplicate work*/
|
||||
csqc_world.g.physics_mode = &csphysicsmode;
|
||||
}
|
||||
|
||||
|
@ -2342,9 +2332,12 @@ uploadfmt_t PR_TranslateTextureFormat(int qcformat)
|
|||
case 13: return PTI_RG8;
|
||||
case 14: return PTI_RGB32F;
|
||||
|
||||
case 15: return TF_8PAL24;
|
||||
case 16: return TF_8PAL32;
|
||||
|
||||
default:
|
||||
qcformat = -qcformat;
|
||||
if (qcformat < PTI_MAX)
|
||||
if ((unsigned int)qcformat < PTI_MAX)
|
||||
return qcformat;
|
||||
return PTI_INVALID;
|
||||
}
|
||||
|
@ -2371,6 +2364,9 @@ int PR_UnTranslateTextureFormat(uploadfmt_t pixelformat)
|
|||
case PTI_RG8: return 13;
|
||||
case PTI_RGB32F: return 14;
|
||||
|
||||
case TF_8PAL24: return 15;
|
||||
case TF_8PAL32: return 16;
|
||||
|
||||
default:return -pixelformat;
|
||||
}
|
||||
}
|
||||
|
@ -2615,7 +2611,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
Q_strncpyz(r_refdef.rt_destcolour[i].texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_destcolour[i].texname));
|
||||
if (prinst->callargc >= 4 && *r_refdef.rt_destcolour[i].texname)
|
||||
{
|
||||
float fmt = G_FLOAT(OFS_PARM2);
|
||||
int fmt = G_FLOAT(OFS_PARM2);
|
||||
float *size = G_VECTOR(OFS_PARM3);
|
||||
if (fmt < 0)
|
||||
R2D_RT_Configure(r_refdef.rt_destcolour[i].texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
|
||||
|
@ -2629,7 +2625,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
Q_strncpyz(r_refdef.rt_sourcecolour.texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_sourcecolour));
|
||||
if (prinst->callargc >= 4 && *r_refdef.rt_sourcecolour.texname)
|
||||
{
|
||||
float fmt = G_FLOAT(OFS_PARM2);
|
||||
int fmt = G_FLOAT(OFS_PARM2);
|
||||
float *size = G_VECTOR(OFS_PARM3);
|
||||
if (fmt < 0)
|
||||
R2D_RT_Configure(r_refdef.rt_sourcecolour.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
|
||||
|
@ -2642,7 +2638,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
Q_strncpyz(r_refdef.rt_depth.texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_depth.texname));
|
||||
if (prinst->callargc >= 4 && *r_refdef.rt_depth.texname)
|
||||
{
|
||||
float fmt = G_FLOAT(OFS_PARM2);
|
||||
int fmt = G_FLOAT(OFS_PARM2);
|
||||
float *size = G_VECTOR(OFS_PARM3);
|
||||
if (fmt < 0)
|
||||
R2D_RT_Configure(r_refdef.rt_depth.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
|
||||
|
@ -2655,7 +2651,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
Q_strncpyz(r_refdef.rt_ripplemap.texname, PR_GetStringOfs(prinst, OFS_PARM1), sizeof(r_refdef.rt_ripplemap.texname));
|
||||
if (prinst->callargc >= 4 && *r_refdef.rt_ripplemap.texname)
|
||||
{
|
||||
float fmt = G_FLOAT(OFS_PARM2);
|
||||
int fmt = G_FLOAT(OFS_PARM2);
|
||||
float *size = G_VECTOR(OFS_PARM3);
|
||||
if (fmt < 0)
|
||||
R2D_RT_Configure(r_refdef.rt_ripplemap.texname, size[0], size[1], PR_TranslateTextureFormat(-fmt), (RT_IMAGEFLAGS&~IF_LINEAR)|IF_NEAREST);
|
||||
|
@ -3814,6 +3810,16 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
|
|||
MSG_WriteByte(&cls.netchan.message, ev_string);
|
||||
MSG_WriteString(&cls.netchan.message, PR_GetStringOfs(prinst, OFS_PARM2+i*3));
|
||||
}
|
||||
else if (argtypes[i] == 'p' && i>0)
|
||||
{
|
||||
unsigned int len = G_UINT(OFS_PARM1+i*3);
|
||||
unsigned int qcptr = G_UINT(OFS_PARM2+i*3);
|
||||
char *p = prinst->stringtable + qcptr;
|
||||
if (len >= prinst->stringtablesize || qcptr > prinst->stringtablesize-len)
|
||||
break;
|
||||
MSG_WriteByte(&cls.netchan.message, ev_pointer);
|
||||
SZ_Write(&cls.netchan.message, p, len);
|
||||
}
|
||||
else if (argtypes[i] == 'f')
|
||||
{
|
||||
MSG_WriteByte(&cls.netchan.message, ev_float);
|
||||
|
@ -3842,7 +3848,7 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
|
|||
else if (argtypes[i] == 'U')
|
||||
{
|
||||
MSG_WriteByte(&cls.netchan.message, ev_uint64);
|
||||
MSG_WriteInt64(&cls.netchan.message, G_UINT64(OFS_PARM2+i*3));
|
||||
MSG_WriteUInt64(&cls.netchan.message, G_UINT64(OFS_PARM2+i*3));
|
||||
}
|
||||
else if (argtypes[i] == 'v')
|
||||
{
|
||||
|
@ -4839,7 +4845,13 @@ static void QCBUILTIN PF_getlightstylergb (pubprogfuncs_t *prinst, struct global
|
|||
return;
|
||||
}
|
||||
|
||||
if (stnum >= cl_max_lightstyles || !cl_lightstyle[stnum].length)
|
||||
if (stnum >= cl_max_lightstyles)
|
||||
{
|
||||
value = ('m'-'a')*22 * r_lightstylescale.value;
|
||||
G_VECTOR(OFS_RETURN)[0] = G_VECTOR(OFS_RETURN)[1] = G_VECTOR(OFS_RETURN)[2] = value*(1.0/256);
|
||||
return;
|
||||
}
|
||||
else if (!cl_lightstyle[stnum].length)
|
||||
value = ('m'-'a')*22 * r_lightstylescale.value;
|
||||
else if (cl_lightstyle[stnum].map[0] == '=')
|
||||
value = atof(cl_lightstyle[stnum].map+1)*256*r_lightstylescale.value;
|
||||
|
@ -4847,7 +4859,7 @@ static void QCBUILTIN PF_getlightstylergb (pubprogfuncs_t *prinst, struct global
|
|||
{
|
||||
int v1, v2, vd, i;
|
||||
float f;
|
||||
|
||||
|
||||
f = (cl.time*r_lightstylespeed.value);
|
||||
if (f < 0)
|
||||
f = 0;
|
||||
|
@ -5227,50 +5239,6 @@ static void QCBUILTIN PF_cl_te_particlesnow (pubprogfuncs_t *prinst, struct glob
|
|||
P_RunParticleWeather(min, max, vel, howmany, colour, "snow");
|
||||
}
|
||||
|
||||
void CSQC_RunThreads(void)
|
||||
{
|
||||
csqctreadstate_t *state = csqcthreads, *next;
|
||||
csqcthreads = NULL;
|
||||
while(state)
|
||||
{
|
||||
next = state->next;
|
||||
|
||||
if (state->resumetime > cl.servertime)
|
||||
{ //not time yet, reform original list.
|
||||
state->next = csqcthreads;
|
||||
csqcthreads = state;
|
||||
}
|
||||
else
|
||||
{ //call it and forget it ever happened. The Sleep biltin will recreate if needed.
|
||||
|
||||
|
||||
*csqcg.self = EDICT_TO_PROG(csqcprogs, EDICT_NUM_UB(csqcprogs, state->self));
|
||||
*csqcg.other = EDICT_TO_PROG(csqcprogs, EDICT_NUM_UB(csqcprogs, state->other));
|
||||
|
||||
csqcprogs->RunThread(csqcprogs, state->thread);
|
||||
csqcprogs->parms->memfree(state->thread);
|
||||
csqcprogs->parms->memfree(state);
|
||||
}
|
||||
|
||||
state = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_cs_addprogs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
int newp;
|
||||
if (!s || !*s)
|
||||
newp = -1;
|
||||
else
|
||||
{
|
||||
newp = PR_LoadProgs(prinst, s);
|
||||
if (newp >= 0)
|
||||
PR_ProgsAdded(csqcprogs, newp, s);
|
||||
}
|
||||
G_FLOAT(OFS_RETURN) = newp;
|
||||
}
|
||||
|
||||
static void QCBUILTIN PF_cs_OpenPortal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int state = G_FLOAT(OFS_PARM1)!=0;
|
||||
|
@ -6793,8 +6761,10 @@ static struct {
|
|||
{"fputs", PF_fputs, 113}, // #113 void(float fnum, string str) fputs (FRIK_FILE)
|
||||
{"fread", PF_fread, 0},
|
||||
{"fwrite", PF_fwrite, 0},
|
||||
{"fseek", PF_fseek, 0},
|
||||
{"fsize", PF_fsize, 0},
|
||||
{"fseek", PF_fseek32, 0},
|
||||
{"fsize", PF_fsize32, 0},
|
||||
{"fseek64", PF_fseek64, 0},
|
||||
{"fsize64", PF_fsize64, 0},
|
||||
{"strlen", PF_strlen, 114}, // #114 float(string str) strlen (FRIK_FILE)
|
||||
|
||||
{"strcat", PF_strcat, 115}, // #115 string(string str1, string str2, ...) strcat (FRIK_FILE)
|
||||
|
@ -6812,7 +6782,7 @@ static struct {
|
|||
{"getmodelindex", PF_cs_getmodelindex, 200},
|
||||
{"getsoundindex", PF_cs_getsoundindex, 0},
|
||||
{"externcall", PF_externcall, 201},
|
||||
{"addprogs", PF_cs_addprogs, 202},
|
||||
{"addprogs", PF_cl_addprogs, 202},
|
||||
{"externvalue", PF_externvalue, 203},
|
||||
{"externset", PF_externset, 204},
|
||||
|
||||
|
@ -6822,9 +6792,9 @@ static struct {
|
|||
{"registertempent", PF_NoCSQC, 208},//{"RegisterTempEnt", PF_RegisterTEnt, 0, 0, 0, 208},
|
||||
{"customtempent", PF_NoCSQC, 209},//{"CustomTempEnt", PF_CustomTEnt, 0, 0, 0, 209},
|
||||
//210
|
||||
{"fork", PF_Fixme, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
|
||||
{"fork", PF_Fork, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
|
||||
{"abort", PF_Abort, 211}, //#211 void() abort (FTE_MULTITHREADED)
|
||||
{"sleep", PF_Fixme, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
|
||||
{"sleep", PF_Sleep, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
|
||||
{"forceinfokey", PF_NoCSQC, 213},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
|
||||
{"forceinfokeyblob", PF_NoCSQC, 0},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
|
||||
{"chat", PF_NoCSQC, 214},//{"chat", PF_chat, 0, 0, 0, 214},// #214 void(string filename, float starttag, entity edict) SV_Chat (FTE_NPCCHAT)
|
||||
|
@ -6905,6 +6875,8 @@ static struct {
|
|||
{"htos", PF_htos, 262},
|
||||
{"ftoi", PF_ftoi, 0},
|
||||
{"itof", PF_itof, 0},
|
||||
{"ftou", PF_ftou, 0},
|
||||
{"utof", PF_utof, 0},
|
||||
|
||||
{"skel_create", PF_skel_create, 263},//float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS)
|
||||
{"skel_build", PF_skel_build, 264},//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addition) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS)
|
||||
|
@ -7043,6 +7015,7 @@ static struct {
|
|||
|
||||
{"cprint", PF_cl_cprint, 338}, // #338 void(string s) cprint (EXT_CSQC)
|
||||
{"print", PF_print, 339}, // #339 void(string s) print (EXT_CSQC)
|
||||
{"setwatchpoint", PF_setwatchpoint, 0},
|
||||
|
||||
//340
|
||||
{"keynumtostring", PF_cl_keynumtostring, 340}, // #340 string(float keynum) keynumtostring (EXT_CSQC)
|
||||
|
@ -7076,6 +7049,8 @@ static struct {
|
|||
|
||||
{"SetListener", PF_cs_setlistener, 351}, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
|
||||
{"setup_reverb", PF_cs_setupreverb, 0},
|
||||
{"queueaudio", PF_cl_queueaudio, 0},
|
||||
{"getqueuedaudiotime", PF_cl_getqueuedaudiotime, 0},
|
||||
{"registercommand", PF_cs_registercommand, 352}, // #352 void(string cmdname) registercommand (EXT_CSQC)
|
||||
{"wasfreed", PF_WasFreed, 353}, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
|
||||
|
||||
|
@ -7120,6 +7095,7 @@ static struct {
|
|||
{"releasecustomskin", PF_cs_releasecustomskin, 379},
|
||||
|
||||
{"memalloc", PF_memalloc, 384},
|
||||
{"memrealloc", PF_memrealloc, 0},
|
||||
{"memfree", PF_memfree, 385},
|
||||
{"memcmp", PF_memcmp, 0},
|
||||
{"memcpy", PF_memcpy, 386},
|
||||
|
@ -7335,7 +7311,8 @@ static struct {
|
|||
{"buf_cvarlist", PF_buf_cvarlist, 517},
|
||||
{"cvar_description", PF_cvar_description, 518},
|
||||
|
||||
{"gettime", PF_gettime, 519},
|
||||
{"gettimef", PF_gettimef, 519},
|
||||
{"gettimed", PF_gettimed, 0},
|
||||
|
||||
{"keynumtostring_omgwtf", PF_cl_keynumtostring, 520},
|
||||
{"findkeysforcommand", PF_cl_findkeysforcommand, 521},
|
||||
|
@ -7509,7 +7486,7 @@ static progparms_t csqcprogparms;
|
|||
|
||||
|
||||
//Any menu builtin error or anything like that will come here.
|
||||
static void VARGS CSQC_Abort (char *format, ...) //an error occured.
|
||||
static void VARGS CSQC_Abort (const char *format, ...) //an error occured.
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
@ -7532,21 +7509,6 @@ static void VARGS CSQC_Abort (char *format, ...) //an error occured.
|
|||
Host_EndGame("csqc error");
|
||||
}
|
||||
|
||||
static void CSQC_ForgetThreads(void)
|
||||
{
|
||||
csqctreadstate_t *state = csqcthreads, *next;
|
||||
csqcthreads = NULL;
|
||||
while(state)
|
||||
{
|
||||
next = state->next;
|
||||
|
||||
csqcprogs->parms->memfree(state->thread);
|
||||
csqcprogs->parms->memfree(state);
|
||||
|
||||
state = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void PDECL CSQC_EntSpawn (struct edict_s *e, int loading)
|
||||
{
|
||||
struct csqcedict_s *ent = (csqcedict_t*)e;
|
||||
|
@ -7706,7 +7668,6 @@ void CSQC_Shutdown(void)
|
|||
Material_RegisterLoader(&csqc_world, NULL);
|
||||
|
||||
key_dest_absolutemouse &= ~kdm_game;
|
||||
CSQC_ForgetThreads();
|
||||
PR_ReleaseFonts(kdm_game);
|
||||
PR_Common_Shutdown(csqcprogs, false);
|
||||
World_Destroy(&csqc_world);
|
||||
|
@ -7714,7 +7675,10 @@ void CSQC_Shutdown(void)
|
|||
csqc_world.progs = csqcprogs = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
PR_Route_Shutdown (&csqc_world);
|
||||
World_Destroy(&csqc_world);
|
||||
}
|
||||
|
||||
Cmd_RemoveCommands(CS_ConsoleCommand_f);
|
||||
|
||||
|
@ -8663,7 +8627,7 @@ void CSQC_WatchPoint_f(void)
|
|||
Con_Printf("csqc not running\n");
|
||||
return;
|
||||
}
|
||||
if (csqcprogs->SetWatchPoint(csqcprogs, variable))
|
||||
if (csqcprogs->SetWatchPoint(csqcprogs, variable, variable))
|
||||
Con_Printf("Watchpoint set\n");
|
||||
else
|
||||
Con_Printf("Watchpoint cleared\n");
|
||||
|
@ -8773,11 +8737,27 @@ qboolean CSQC_DrawView(void)
|
|||
csqc_dp_lastwas3d = false;
|
||||
|
||||
RSpeedRemark();
|
||||
if (csqc_isdarkplaces && *csqc_world.g.physics_mode == 1)
|
||||
if (*csqc_world.g.physics_mode == 0)
|
||||
{
|
||||
csqc_world.physicstime = cl.servertime;
|
||||
// let the progs know that a new frame has started
|
||||
if (csqcg.StartFrame)
|
||||
{
|
||||
*csqc_world.g.self = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.other = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.time = csqc_world.physicstime;
|
||||
PR_ExecuteProgram (csqcprogs, csqcg.StartFrame);
|
||||
}
|
||||
PR_RunThreads(&csqc_world);
|
||||
if (csqcg.EndFrame)
|
||||
{ //consistency. or something.
|
||||
*csqc_world.g.self = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.other = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.time = csqc_world.physicstime;
|
||||
PR_ExecuteProgram (csqcprogs, csqcg.EndFrame);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (*csqc_world.g.physics_mode)
|
||||
{
|
||||
#ifdef USERBE
|
||||
if (csqc_world.rbe)
|
||||
|
@ -8796,6 +8776,15 @@ qboolean CSQC_DrawView(void)
|
|||
if (host_frametime > maxtic)
|
||||
host_frametime = maxtic;
|
||||
|
||||
// let the progs know that a new frame has started
|
||||
if (csqcg.StartFrame)
|
||||
{
|
||||
*csqc_world.g.self = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.other = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.time = csqc_world.physicstime;
|
||||
PR_ExecuteProgram (csqcprogs, csqcg.StartFrame);
|
||||
}
|
||||
|
||||
#ifdef USERBE
|
||||
if (csqc_world.rbe)
|
||||
{
|
||||
|
@ -8806,8 +8795,18 @@ qboolean CSQC_DrawView(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
PR_RunThreads(&csqc_world);
|
||||
World_Physics_Frame(&csqc_world);
|
||||
csqc_world.physicstime += host_frametime;
|
||||
|
||||
//all thinks done. for consistency with the ssqc extension.
|
||||
if (csqcg.EndFrame)
|
||||
{
|
||||
*csqc_world.g.self = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.other = EDICT_TO_PROG(csqcprogs, csqc_world.edicts);
|
||||
*csqc_world.g.time = csqc_world.physicstime;
|
||||
PR_ExecuteProgram (csqcprogs, csqcg.EndFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
RSpeedEnd(RSPEED_CSQCPHYSICS);
|
||||
|
@ -8866,8 +8865,6 @@ qboolean CSQC_DrawView(void)
|
|||
if (cl.worldmodel)
|
||||
Surf_LessenStains();
|
||||
|
||||
CSQC_RunThreads(); //wake up any qc threads
|
||||
|
||||
#ifdef HAVE_LEGACY
|
||||
if (csqcg.autocvar_vid_conwidth)
|
||||
*csqcg.autocvar_vid_conwidth = vid.width;
|
||||
|
|
|
@ -901,17 +901,25 @@ void QCBUILTIN PF_CL_uploadimage (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
}
|
||||
else
|
||||
{
|
||||
void *palette = NULL;
|
||||
unsigned int blockbytes, blockwidth, blockheight, blockdepth;
|
||||
//get format info
|
||||
Image_BlockSizeForEncoding(format, &blockbytes, &blockwidth, &blockheight, &blockdepth);
|
||||
//round up as appropriate
|
||||
blockwidth = ((width+blockwidth-1)/blockwidth)*blockwidth;
|
||||
blockheight = ((height+blockheight-1)/blockheight)*blockheight;
|
||||
|
||||
//we do allow palettes on the end.
|
||||
if (format == TF_8PAL24)
|
||||
size -= 768, palette = (qbyte*)imgptr+size, blockbytes=1;
|
||||
else if (format == TF_8PAL32)
|
||||
size -= 1024, palette = (qbyte*)imgptr+size, blockbytes=1;
|
||||
|
||||
if (size != blockwidth*blockheight*blockbytes)
|
||||
G_INT(OFS_RETURN) = 0; //size isn't right. which means the pointer might be invalid too.
|
||||
else
|
||||
{
|
||||
Image_Upload(tid, format, imgptr, NULL, width, height, 1, RT_IMAGEFLAGS);
|
||||
Image_Upload(tid, format, imgptr, palette, width, height, 1, RT_IMAGEFLAGS);
|
||||
tid->width = width;
|
||||
tid->height = height;
|
||||
G_INT(OFS_RETURN) = 1;
|
||||
|
@ -2450,6 +2458,8 @@ static struct {
|
|||
{"htos", PF_htos, 0},
|
||||
{"ftoi", PF_ftoi, 0},
|
||||
{"itof", PF_itof, 0},
|
||||
{"ftou", PF_ftou, 0},
|
||||
{"utof", PF_utof, 0},
|
||||
|
||||
{"spawn", PF_Spawn, 22},
|
||||
{"remove", PF_Remove_, 23},
|
||||
|
@ -2475,7 +2485,7 @@ static struct {
|
|||
{"sin", PF_Sin, 38},
|
||||
{"cos", PF_Cos, 39},
|
||||
{"sqrt", PF_Sqrt, 40},
|
||||
{"randomvector", PF_randomvector, 41},
|
||||
{"randomvec", PF_randomvector, 41},
|
||||
{"registercvar", PF_registercvar, 42},
|
||||
{"min", PF_min, 43},
|
||||
{"max", PF_max, 44},
|
||||
|
@ -2490,8 +2500,10 @@ static struct {
|
|||
{"fputs", PF_fputs, 51},
|
||||
{"fread", PF_fread, 0},
|
||||
{"fwrite", PF_fwrite, 0},
|
||||
{"fseek", PF_fseek, 0},
|
||||
{"fsize", PF_fsize, 0},
|
||||
{"fseek", PF_fseek32, 0},
|
||||
{"fsize", PF_fsize32, 0},
|
||||
{"fseek64", PF_fseek64, 0},
|
||||
{"fsize64", PF_fsize64, 0},
|
||||
{"strlen", PF_strlen, 52},
|
||||
{"strcat", PF_strcat, 53},
|
||||
{"substring", PF_substring, 54},
|
||||
|
@ -2510,7 +2522,8 @@ static struct {
|
|||
{"changelevel", PF_cl_changelevel, 64}, //void changelevel(string map) = #64;
|
||||
{"localsound", PF_cl_localsound, 65},
|
||||
{"getmousepos", PF_cl_getmousepos, 66},
|
||||
{"gettime", PF_gettime, 67},
|
||||
{"gettime", PF_gettimef, 67},
|
||||
{"gettimed", PF_gettimed, 0},
|
||||
{"loadfromdata", PF_loadfromdata, 68},
|
||||
{"loadfromfile", PF_loadfromfile, 69},
|
||||
{"mod", PF_mod, 70},
|
||||
|
@ -2542,8 +2555,14 @@ static struct {
|
|||
{"setorigin", PF_m_setorigin, 92},
|
||||
//gap
|
||||
{"getmodelindex", PF_m_getmodelindex, 200},
|
||||
{"externcall", PF_externcall, 201},
|
||||
{"addprogs", PF_cl_addprogs, 202},
|
||||
{"externvalue", PF_externvalue, 203},
|
||||
{"externset", PF_externset, 204},
|
||||
//gap
|
||||
{"fork", PF_Fork, 210},
|
||||
{"abort", PF_Abort, 211},
|
||||
{"sleep", PF_Sleep, 212},
|
||||
//gap
|
||||
{"strstrofs", PF_strstrofs, 221},
|
||||
{"str2chr", PF_str2chr, 222},
|
||||
|
@ -2621,6 +2640,7 @@ static struct {
|
|||
|
||||
|
||||
{"print_csqc", PF_print, 339},
|
||||
{"setwatchpoint", PF_setwatchpoint, 0},
|
||||
{"keynumtostring_csqc", PF_cl_keynumtostring, 340},
|
||||
{"stringtokeynum_csqc", PF_cl_stringtokeynum, 341},
|
||||
{"getkeybind", PF_cl_getkeybind, 342},
|
||||
|
@ -2644,6 +2664,8 @@ static struct {
|
|||
{"isdemo", PF_isdemo, 349},
|
||||
// {NULL, PF_Fixme, 350},
|
||||
// {NULL, PF_Fixme, 351},
|
||||
{"queueaudio", PF_cl_queueaudio, 0},
|
||||
{"getqueuedaudiotime", PF_cl_getqueuedaudiotime, 0},
|
||||
{"registercommand", PF_menu_registercommand, 352},
|
||||
{"wasfreed", PF_WasFreed, 353},
|
||||
{"serverkey", PF_cl_serverkey, 354}, // #354 string(string key) serverkey;
|
||||
|
@ -2662,6 +2684,7 @@ static struct {
|
|||
{"setcustomskin", PF_m_setcustomskin, 376},
|
||||
//gap
|
||||
{"memalloc", PF_memalloc, 384},
|
||||
{"memrealloc", PF_memrealloc, 0},
|
||||
{"memfree", PF_memfree, 385},
|
||||
{"memcmp", PF_memcmp, 0},
|
||||
{"memcpy", PF_memcpy, 386},
|
||||
|
@ -3120,7 +3143,7 @@ void *VARGS PR_CB_Malloc(int size); //these functions should be tracked by the l
|
|||
void VARGS PR_CB_Free(void *mem);
|
||||
|
||||
//Any menu builtin error or anything like that will come here.
|
||||
void VARGS Menu_Abort (char *format, ...)
|
||||
void VARGS Menu_Abort (const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
@ -3290,7 +3313,7 @@ qboolean MP_Init (void)
|
|||
menu_world.Get_FrameState = MP_Get_FrameState;
|
||||
|
||||
menu_world.progs = InitProgs(&menuprogparms);
|
||||
PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 1, pr_enable_profiling.ival);
|
||||
PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 16, pr_enable_profiling.ival);
|
||||
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat");
|
||||
if (mprogs < 0) //no per-progs builtins.
|
||||
{
|
||||
|
@ -3408,9 +3431,14 @@ qboolean MP_ConsoleCommand(const char *cmdtext)
|
|||
|
||||
void MP_CoreDump_f(void)
|
||||
{
|
||||
if (Cmd_IsInsecure())
|
||||
{
|
||||
Con_TPrintf("Refusing to execute insecure %s\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (!menu_world.progs)
|
||||
{
|
||||
Con_Printf("Can't core dump, you need to be running the CSQC progs first.");
|
||||
Con_Printf("Can't core dump, you need to be running the MenuQC progs first.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3425,21 +3453,28 @@ void MP_CoreDump_f(void)
|
|||
|
||||
static void MP_Poke_f(void)
|
||||
{
|
||||
/*if (!SV_MayCheat())
|
||||
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");
|
||||
else */if (menu_world.progs && menu_world.progs->EvaluateDebugString)
|
||||
if (Cmd_IsInsecure())
|
||||
Con_TPrintf("Refusing to execute insecure %s\n", Cmd_Argv(0));
|
||||
/*else if (!SV_MayCheat())
|
||||
Con_TPrintf ("Please set sv_cheats 1 and restart the map first.\n");*/
|
||||
else if (menu_world.progs && menu_world.progs->EvaluateDebugString)
|
||||
Con_TPrintf("Result: %s\n", menu_world.progs->EvaluateDebugString(menu_world.progs, Cmd_Args()));
|
||||
else
|
||||
Con_TPrintf ("not supported.\n");
|
||||
}
|
||||
|
||||
void MP_Breakpoint_f(void)
|
||||
static void MP_Breakpoint_f(void)
|
||||
{
|
||||
int wasset;
|
||||
int isset;
|
||||
char *filename = Cmd_Argv(1);
|
||||
int line = atoi(Cmd_Argv(2));
|
||||
|
||||
if (Cmd_IsInsecure())
|
||||
{
|
||||
Con_TPrintf("Refusing to execute insecure %s\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (!menu_world.progs)
|
||||
{
|
||||
Con_Printf("Menu not running\n");
|
||||
|
@ -3457,17 +3492,51 @@ void MP_Breakpoint_f(void)
|
|||
|
||||
Cvar_Set(Cvar_FindVar("pr_debugger"), "1");
|
||||
}
|
||||
static void MP_Watchpoint_f(void)
|
||||
{
|
||||
char *variable = Cmd_Argv(1);
|
||||
if (!*variable)
|
||||
variable = NULL;
|
||||
|
||||
if (Cmd_IsInsecure())
|
||||
{
|
||||
Con_TPrintf("Refusing to execute insecure %s\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (!menu_world.progs)
|
||||
{
|
||||
Con_Printf("menuqc not running\n");
|
||||
return;
|
||||
}
|
||||
if (menu_world.progs->SetWatchPoint(menu_world.progs, variable, variable))
|
||||
Con_Printf("Watchpoint set\n");
|
||||
else
|
||||
Con_Printf("Watchpoint cleared\n");
|
||||
}
|
||||
static void MP_Profile_f(void)
|
||||
{
|
||||
if (Cmd_IsInsecure())
|
||||
{
|
||||
Con_TPrintf("Refusing to execute insecure %s\n", Cmd_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (menu_world.progs && menu_world.progs->DumpProfile)
|
||||
if (!menu_world.progs->DumpProfile(menu_world.progs, !atof(Cmd_Argv(1))))
|
||||
Con_Printf("Enabled menuqc Profiling.\n");
|
||||
}
|
||||
|
||||
void MP_RegisterCvarsAndCmds(void)
|
||||
{
|
||||
Cmd_AddCommand("coredump_menuqc", MP_CoreDump_f);
|
||||
Cmd_AddCommand("menu_cmd", MP_GameCommand_f);
|
||||
Cmd_AddCommand("breakpoint_menu", MP_Breakpoint_f);
|
||||
Cmd_AddCommand("breakpoint_menuqc", MP_Breakpoint_f);
|
||||
Cmd_AddCommand("watchpoint_menuqc", MP_Watchpoint_f);
|
||||
#ifdef HAVE_LEGACY
|
||||
Cmd_AddCommand("loadfont", CL_LoadFont_f);
|
||||
#endif
|
||||
|
||||
Cmd_AddCommand("poke_menuqc", MP_Poke_f);
|
||||
Cmd_AddCommand("profile_menuqc", MP_Profile_f);
|
||||
|
||||
|
||||
Cvar_Register(&forceqmenu, MENUPROGSGROUP);
|
||||
|
@ -3546,6 +3615,8 @@ void MP_Draw(void)
|
|||
*menu_world.g.frametime = host_frametime;
|
||||
|
||||
inmenuprogs++;
|
||||
PR_RunThreads(&menu_world);
|
||||
|
||||
pr_globals = PR_globals(menu_world.progs, PR_CURRENT);
|
||||
|
||||
if (scr_drawloading||scr_disabled_for_loading)
|
||||
|
|
|
@ -52,6 +52,8 @@ typedef struct doll_s
|
|||
struct doll_s *next;
|
||||
|
||||
qboolean drawn:1;
|
||||
int refanim; //-1 for skining pose. otherwise the first pose of the specified anim. probaly 0.
|
||||
float refanimtime; //usually just 0
|
||||
int numdefaultanimated;
|
||||
int numbodies;
|
||||
int numjoints;
|
||||
|
@ -349,6 +351,7 @@ static dollcreatectx_t *rag_createdoll(model_t *mod, const char *fname, int numb
|
|||
ctx->d->next = dolllist;
|
||||
ctx->d->name = strdup(fname);
|
||||
ctx->d->model = mod;
|
||||
ctx->d->refanim = -1; //skin pose.
|
||||
ctx->d->numbodies = 0;
|
||||
ctx->d->body = NULL;
|
||||
ctx->d->numjoints = 0;
|
||||
|
@ -377,6 +380,13 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum)
|
|||
if (!argc)
|
||||
{
|
||||
}
|
||||
else if (argc == 2 && !stricmp(cmd, "refpose") && !strcmp(val, "skin"))
|
||||
ctx->d->refanim = -1;
|
||||
else if (argc == 3 && !stricmp(cmd, "refpose"))
|
||||
{
|
||||
ctx->d->refanim = atoi(val);
|
||||
ctx->d->refanimtime = atoi(Cmd_Argv(2));
|
||||
}
|
||||
//create a new body
|
||||
else if (argc == 3 && !stricmp(cmd, "body"))
|
||||
{
|
||||
|
@ -911,7 +921,13 @@ void skel_generateragdoll_f(void)
|
|||
if (i == 0)
|
||||
VFS_PUTS(f, "//NO FRAME INFO\n");
|
||||
|
||||
//print background frame info.
|
||||
VFS_PUTS(f, "\n//reference pose that offsets are defined in terms of\n");
|
||||
if (mod->type == mod_halflife)
|
||||
VFS_PUTS(f, "refpose 0 0.0 //use first anim's first pose\n");
|
||||
else
|
||||
VFS_PUTS(f, "refpose skin\n");
|
||||
|
||||
//print background frame info.
|
||||
VFS_PUTS(f, "\n//skins are as follows:\n");
|
||||
for (i = 0; i < 32768; i++)
|
||||
{
|
||||
|
@ -1248,11 +1264,34 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
int bone;
|
||||
rbebody_t *body1, *body2;
|
||||
rbejointinfo_t *j;
|
||||
float *absolutes;
|
||||
sko->numbodies = doll->numbodies;
|
||||
sko->body = BZ_Malloc(sizeof(*sko->body) * sko->numbodies);
|
||||
sko->doll = doll;
|
||||
doll->uses++;
|
||||
sko->numanimated = 0;
|
||||
|
||||
if (bones && doll->refanim)
|
||||
{
|
||||
framestate_t fstate = {0};
|
||||
float *relatives = alloca(sizeof(float)*12*numbones*2);
|
||||
fstate.g[FS_REG].frame[0] = doll->refanim; //which anim we're using as the reference
|
||||
fstate.g[FS_REG].frametime[0] = doll->refanimtime; //first pose of the anim
|
||||
fstate.g[FS_REG].lerpweight[0] = 1;
|
||||
fstate.g[FS_REG].endbone = numbones;
|
||||
|
||||
absolutes = relatives+numbones*12;
|
||||
numbones = Mod_GetBoneRelations(sko->model, 0, numbones, bones, &fstate, relatives);
|
||||
for (i = 0; i < numbones; i++)
|
||||
{ //compute the absolutes. not gonna make a bg3 reference here.
|
||||
if (bones[i].parent>=0)
|
||||
R_ConcatTransforms((void*)(absolutes+12*bones[i].parent), (void*)(relatives+12*i), (void*)(absolutes+12*i));
|
||||
else
|
||||
memcpy(absolutes+12*i, relatives+12*i, sizeof(float)*12);
|
||||
}
|
||||
}
|
||||
else absolutes = NULL;
|
||||
|
||||
for (i = 0; i < sko->numbodies; i++)
|
||||
{
|
||||
memset(&sko->body[i], 0, sizeof(sko->body[i]));
|
||||
|
@ -1262,7 +1301,9 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
sko->numanimated++;
|
||||
|
||||
//spawn the body in the base pose, so we can add joints etc (also ignoring the entity matrix, we'll fix all that up later).
|
||||
if (1)
|
||||
if (absolutes) //we have a reference pose
|
||||
memcpy(bodymat, absolutes+12*doll->body[i].bone, sizeof(float)*12);
|
||||
else if (1)
|
||||
Matrix3x4_Invert_Simple(bones[doll->body[i].bone].inverse, bodymat);
|
||||
else
|
||||
rag_genbodymatrix(sko, &doll->body[i], emat, bodymat);
|
||||
|
@ -1281,8 +1322,10 @@ static qboolean rag_instanciate(skelobject_t *sko, doll_t *doll, float *emat, we
|
|||
bone = j->bonepivot;
|
||||
bmat = sko->bonematrix + bone*12;
|
||||
|
||||
if (1)
|
||||
{
|
||||
if (absolutes) //we have a reference pose
|
||||
memcpy(worldmat, absolutes+12*doll->body[i].bone, sizeof(float)*12);
|
||||
else if (1)
|
||||
{ //FIXME: j->offset isn't actually used?!?
|
||||
Matrix3x4_Invert_Simple(bones[j->bonepivot].inverse, worldmat);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -53,21 +53,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#pragma warning(2:4032) // function arg has different type from declaration
|
||||
#pragma warning(2:4092) // 'sizeof' value too big
|
||||
#pragma warning(2:4132 4268)// const object not initialized
|
||||
//#pragma warning(2:4152) // pointer conversion between function and data
|
||||
//#pragma warning(2:4152) // pointer conversion between function and data
|
||||
#pragma warning(2:4239) // standard doesn't allow this conversion
|
||||
#pragma warning(2:4701) // local variable used without being initialized
|
||||
//#pragma warning(2:4706) // if (a=b) instead of (if a==b)
|
||||
//#pragma warning(2:4706) // if (a=b) instead of (if a==b)
|
||||
#pragma warning(2:4709) // comma in array subscript
|
||||
#pragma warning(3:4061) // not all enum values tested in switch statement
|
||||
#pragma warning(3:4710) // inline function was not inlined
|
||||
#pragma warning(3:4121) // space added for structure alignment
|
||||
#pragma warning(3:4505) // unreferenced local function removed
|
||||
#pragma warning(3:4019) // empty statement at global scope
|
||||
//#pragma warning(3:4057) // pointers refer to different base types
|
||||
//#pragma warning(3:4057) // pointers refer to different base types
|
||||
#pragma warning(3:4125) // decimal digit terminates octal escape
|
||||
#pragma warning(2:4131) // old-style function declarator
|
||||
#pragma warning(3:4211) // extern redefined as static
|
||||
//#pragma warning(3:4213) // cast on left side of = is non-standard
|
||||
//#pragma warning(3:4213) // cast on left side of = is non-standard
|
||||
#pragma warning(3:4222) // member function at file scope shouldn't be static
|
||||
#pragma warning(3:4234 4235)// keyword not supported or reserved for future
|
||||
#pragma warning(3:4504) // type ambiguous; simplify code
|
||||
|
@ -132,10 +132,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__unix__) && !defined(__CYGWIN__)
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_MSVCRT_DEBUG
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
|
@ -408,7 +404,7 @@ void COM_AssertMainThread(const char *msg);
|
|||
#endif
|
||||
|
||||
extern qboolean msg_suppress_1; // suppresses resolution and cache size console output
|
||||
// an fullscreen DIB focus gain/loss
|
||||
// an fullscreen DIB focus gain/loss
|
||||
|
||||
#ifndef HAVE_CLIENT
|
||||
#define isDedicated true
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "quakedef.h"
|
||||
#ifdef MAP_PROC
|
||||
|
||||
#ifndef SERVERONLY
|
||||
#ifdef HAVE_CLIENT
|
||||
#include "shader.h"
|
||||
#endif
|
||||
#include "com_mesh.h"
|
||||
|
@ -10,15 +10,9 @@
|
|||
//fixme: merge areas and static ents too somehow.
|
||||
|
||||
void Mod_SetParent (mnode_t *node, mnode_t *parent);
|
||||
static int D3_ClusterForPoint (struct model_s *model, vec3_t point);
|
||||
|
||||
#ifndef SERVERONLY
|
||||
void ModD3_GenAreaVBO(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
model_t *sub = ctx;
|
||||
BE_GenBrushModelVBO(sub);
|
||||
}
|
||||
static int D3_ClusterForPoint (struct model_s *model, const vec3_t point, int *areaout);
|
||||
|
||||
#ifdef HAVE_CLIENT
|
||||
static void R_BuildDefaultTexnums_Doom3(shader_t *shader)
|
||||
{
|
||||
extern qboolean r_loadbumpmapping;
|
||||
|
@ -140,6 +134,37 @@ static void R_BuildDefaultTexnums_Doom3(shader_t *shader)
|
|||
}
|
||||
}
|
||||
}
|
||||
static void ModD3_GenAreaVBO(void *ctx, void *data, size_t a, size_t barg)
|
||||
{
|
||||
model_t *sub = ctx;
|
||||
batch_t *b = sub->batches[0];
|
||||
int surf;
|
||||
sub->batches[0] = NULL;
|
||||
|
||||
for (surf = 0; surf < sub->numbatches; surf++)
|
||||
sub->numsurfaces += b[surf].meshes;
|
||||
sub->texinfo = ZG_Malloc(&sub->memgroup, sizeof(*sub->texinfo)*sub->numsurfaces);
|
||||
sub->surfaces = ZG_Malloc(&sub->memgroup, sizeof(*sub->surfaces)*sub->numsurfaces);
|
||||
sub->firstmodelsurface = sub->nummodelsurfaces = 0;
|
||||
|
||||
for (surf = 0; surf < sub->numbatches; surf++)
|
||||
{
|
||||
b[surf].shader = R_RegisterShader_Vertex(sub, b[surf].texture->name);
|
||||
R_BuildDefaultTexnums_Doom3(b[surf].shader);
|
||||
|
||||
//now we know its sort key, we can link it properly. *sigh*
|
||||
b[surf].next = sub->batches[b[surf].shader->sort];
|
||||
sub->batches[b[surf].shader->sort] = &b[surf];
|
||||
|
||||
//all this extra stuff so r_showshaders works. *sigh*
|
||||
sub->surfaces[sub->nummodelsurfaces].texinfo = &sub->texinfo[sub->nummodelsurfaces];
|
||||
sub->surfaces[sub->nummodelsurfaces].texinfo->texture = b[surf].texture;
|
||||
sub->surfaces[sub->nummodelsurfaces].mesh = b[surf].mesh[0];
|
||||
sub->nummodelsurfaces++;
|
||||
}
|
||||
|
||||
BE_GenBrushModelVBO(sub);
|
||||
}
|
||||
|
||||
static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
|
||||
{
|
||||
|
@ -186,8 +211,14 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
|
|||
if (strcmp(token, "{"))
|
||||
return false;
|
||||
|
||||
data = COM_ParseOut(data, token, sizeof(token));
|
||||
sub = Mod_FindName(va("*%s", token));
|
||||
*token = '*';
|
||||
data = COM_ParseOut(data, token+1, sizeof(token)-1);
|
||||
Q_strncatz(token, ":", sizeof(token));
|
||||
Q_strncatz(token, model->publicname, sizeof(token));
|
||||
sub = Mod_FindName(token);
|
||||
|
||||
if (sub->loadstate != MLS_NOTLOADED)
|
||||
return false;
|
||||
|
||||
data = COM_ParseOut(data, token, sizeof(token));
|
||||
numsurfs = atoi(token);
|
||||
|
@ -241,16 +272,14 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
|
|||
b[surf].lmlightstyle[3] = INVALID_LIGHTSTYLE;
|
||||
|
||||
data = COM_ParseOut(data, token, sizeof(token));
|
||||
b[surf].shader = R_RegisterShader_Vertex(token);
|
||||
R_BuildDefaultTexnums_Doom3(b[surf].shader);
|
||||
b[surf].texture = ZG_Malloc(&sub->memgroup, sizeof(*b[surf].texture));
|
||||
Q_strncpyz(b[surf].texture->name, token, sizeof(b[surf].texture->name));
|
||||
|
||||
data = COM_ParseOut(data, token, sizeof(token));
|
||||
numverts = atoi(token);
|
||||
data = COM_ParseOut(data, token, sizeof(token));
|
||||
numindicies = atoi(token);
|
||||
|
||||
b[surf].next = sub->batches[b[surf].shader->sort];
|
||||
sub->batches[b[surf].shader->sort] = &b[surf];
|
||||
|
||||
m[surf].numvertexes = numverts;
|
||||
m[surf].numindexes = numindicies;
|
||||
vdata = ZG_Malloc(&sub->memgroup, numverts * (sizeof(vecV_t) + sizeof(vec2_t) + sizeof(vec3_t)*3 + sizeof(vec4_t)) + numindicies * sizeof(index_t));
|
||||
|
@ -334,10 +363,14 @@ static qboolean Mod_LoadMap_Proc(model_t *model, char *data)
|
|||
if (strcmp(token, "}"))
|
||||
return false;
|
||||
// sub->loadstate = MLS_LOADED;
|
||||
sub->fromgame = fg_doom3;
|
||||
sub->fromgame = fg_new;
|
||||
sub->type = mod_brush;
|
||||
sub->lightmaps.surfstyles = 1;
|
||||
|
||||
memset(sub->batches, 0, sizeof(sub->batches));
|
||||
sub->batches[0] = b;
|
||||
sub->numbatches = numsurfs;
|
||||
|
||||
COM_AddWork(WG_MAIN, ModD3_GenAreaVBO, sub, NULL, MLS_LOADED, 0);
|
||||
COM_AddWork(WG_MAIN, Mod_ModelLoaded, sub, NULL, MLS_LOADED, 0);
|
||||
}
|
||||
|
@ -536,7 +569,7 @@ static void D3_WalkPortal(model_t *mod, int start, vec_t bounds[4], unsigned cha
|
|||
}
|
||||
}
|
||||
|
||||
unsigned char *D3_CalcVis(model_t *mod, vec3_t org)
|
||||
static void D3_PrepareFrame(model_t *mod, refdef_t *refdef, int inarea, int inclusters[2], pvsbuffer_t *vis, qbyte **entvis_out, qbyte **surfvis_out)
|
||||
{
|
||||
int start;
|
||||
static qbyte visbuf[256];
|
||||
|
@ -546,7 +579,7 @@ unsigned char *D3_CalcVis(model_t *mod, vec3_t org)
|
|||
int area;
|
||||
entity_t ent;
|
||||
|
||||
start = D3_ClusterForPoint(mod, org);
|
||||
start = D3_ClusterForPoint(mod, refdef->vieworg, NULL);
|
||||
/*figure out which area we're in*/
|
||||
if (start < 0)
|
||||
{
|
||||
|
@ -588,13 +621,25 @@ unsigned char *D3_CalcVis(model_t *mod, vec3_t org)
|
|||
V_AddEntity(&ent);
|
||||
}
|
||||
}
|
||||
return usevis;
|
||||
*entvis_out = *surfvis_out = usevis;
|
||||
}
|
||||
|
||||
static void D3_StainNode (struct model_s *model, float *parms)
|
||||
{
|
||||
}
|
||||
|
||||
static void D3_LightPointValues (struct model_s *model, const vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir)
|
||||
{
|
||||
/*basically require rtlighting for any light*/
|
||||
VectorClear(res_diffuse);
|
||||
VectorClear(res_ambient);
|
||||
VectorClear(res_dir);
|
||||
res_dir[2] = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
//edict system as opposed to q2 game dll system.
|
||||
static void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs)
|
||||
static void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, const vec3_t cullmins, const vec3_t cullmaxs)
|
||||
{
|
||||
}
|
||||
static qbyte *D3_ClusterPVS (struct model_s *model, int num, pvsbuffer_t *buffer, pvsmerge_t merge)
|
||||
|
@ -602,12 +647,14 @@ static qbyte *D3_ClusterPVS (struct model_s *model, int num, pvsbuffer_t *buffer
|
|||
memset(buffer->buffer, 0xff, buffer->buffersize);
|
||||
return buffer->buffer;
|
||||
}
|
||||
static int D3_ClusterForPoint (struct model_s *model, vec3_t point)
|
||||
static int D3_ClusterForPoint (struct model_s *model, const vec3_t point, int *areaout)
|
||||
{
|
||||
float p;
|
||||
int c;
|
||||
mnode_t *node;
|
||||
node = model->nodes;
|
||||
if (areaout)
|
||||
*areaout = 0;
|
||||
while(1)
|
||||
{
|
||||
p = DotProduct(point, node->plane->normal) + node->plane->dist;
|
||||
|
@ -618,26 +665,12 @@ static int D3_ClusterForPoint (struct model_s *model, vec3_t point)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
static unsigned int D3_FatPVS (struct model_s *model, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge)
|
||||
static unsigned int D3_FatPVS (struct model_s *model, const vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void D3_StainNode (struct mnode_s *node, float *parms)
|
||||
{
|
||||
}
|
||||
|
||||
static void D3_LightPointValues (struct model_s *model, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir)
|
||||
{
|
||||
/*basically require rtlighting for any light*/
|
||||
VectorClear(res_diffuse);
|
||||
VectorClear(res_ambient);
|
||||
VectorClear(res_dir);
|
||||
res_dir[2] = 1;
|
||||
}
|
||||
|
||||
|
||||
static qboolean D3_EdictInFatPVS (struct model_s *model, struct pvscache_s *edict, qbyte *pvsbuffer)
|
||||
static qboolean D3_EdictInFatPVS (struct model_s *model, const struct pvscache_s *edict, const qbyte *pvsbuffer, const int *areas)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < edict->num_leafs; i++)
|
||||
|
@ -879,7 +912,7 @@ static void D3_InsertClipBrush(cm_node_t *node, cm_brush_t *brush)
|
|||
node->brushlist = brush;
|
||||
}
|
||||
|
||||
static void D3_RecursiveSurfCheck (cm_node_t *node, float p1f, float p2f, vec3_t p1, vec3_t p2)
|
||||
static void D3_RecursiveSurfCheck (cm_node_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2)
|
||||
{
|
||||
float t1, t2, offset;
|
||||
float frac, frac2;
|
||||
|
@ -973,7 +1006,7 @@ return;
|
|||
D3_RecursiveSurfCheck (node->child[side^1], midf, p2f, mid, p2);
|
||||
}
|
||||
|
||||
static qboolean D3_Trace (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t axis[3], vec3_t p1, vec3_t p2, vec3_t mins, vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, struct trace_s *trace)
|
||||
static qboolean D3_Trace (struct model_s *model, int hulloverride, const framestate_t *framestate, const vec3_t axis[3], const vec3_t p1, const vec3_t p2, const vec3_t mins, const vec3_t maxs, qboolean capsule, unsigned int hitcontentsmask, struct trace_s *trace)
|
||||
{
|
||||
int i;
|
||||
float e1,e2;
|
||||
|
@ -1055,21 +1088,21 @@ static qboolean D3_Trace (struct model_s *model, int hulloverride, framestate_t
|
|||
return false;
|
||||
}
|
||||
|
||||
static unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec3_t p)
|
||||
static unsigned int D3_PointContents (struct model_s *model, const vec3_t axis[3], const vec3_t p)
|
||||
{
|
||||
cm_node_t *node = model->cnodes;
|
||||
cm_brush_t *brush;
|
||||
float t1;
|
||||
unsigned int contents = 0;
|
||||
int i;
|
||||
vec3_t np;
|
||||
|
||||
if (axis)
|
||||
{
|
||||
vec3_t tmp;
|
||||
VectorCopy(p, tmp);
|
||||
p[0] = DotProduct(tmp, axis[0]);
|
||||
p[1] = DotProduct(tmp, axis[1]);
|
||||
p[2] = DotProduct(tmp, axis[2]);
|
||||
np[0] = DotProduct(p, axis[0]);
|
||||
np[1] = DotProduct(p, axis[1]);
|
||||
np[2] = DotProduct(p, axis[2]);
|
||||
p = np;
|
||||
}
|
||||
|
||||
while(node)
|
||||
|
@ -1106,7 +1139,7 @@ static unsigned int D3_PointContents (struct model_s *model, vec3_t axis[3], vec
|
|||
return contents;
|
||||
}
|
||||
|
||||
#define ensurenewtoken(t) buf = COM_ParseOut(buf, token, sizeof(token)); if (strcmp(token, t)) break;
|
||||
#define ensurenewtoken(t) buf = COM_ParseOut(buf, token, sizeof(token)); if (strcmp(token, t)) break
|
||||
|
||||
static int D3_ParseContents(char *str)
|
||||
{
|
||||
|
@ -1173,7 +1206,13 @@ qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, void *buf, size_t bufsize)
|
|||
if (!strcmp(token, "worldMap"))
|
||||
cmod = mod;
|
||||
else
|
||||
{
|
||||
Q_strncatz(token, ":", sizeof(token));
|
||||
Q_strncatz(token, mod->publicname, sizeof(token));
|
||||
cmod = Mod_FindName(token);
|
||||
if (cmod->loadstate != MLS_NOTLOADED)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filever == 3)
|
||||
{
|
||||
|
@ -1298,7 +1337,7 @@ qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, void *buf, size_t bufsize)
|
|||
ensurenewtoken(")");
|
||||
|
||||
buf = COM_ParseOut(buf, token, sizeof(token));
|
||||
#ifndef SERVERONLY
|
||||
#ifdef HAVE_CLIENT
|
||||
// surf->shader = R_RegisterShader_Vertex(token);
|
||||
// R_BuildDefaultTexnums_Doom3(NULL, surf->shader);
|
||||
#endif
|
||||
|
@ -1429,32 +1468,37 @@ qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, void *buf, size_t bufsize)
|
|||
|
||||
/*load up the .map so we can get some entities (anyone going to bother making a qc mod compatible with this?)*/
|
||||
COM_StripExtension(mod->name, token, sizeof(token));
|
||||
Mod_SetEntitiesString(mod, FS_LoadMallocFile(va("%s.map", token), NULL), true);
|
||||
Q_strncatz(token, ".map", sizeof(token));
|
||||
Mod_SetEntitiesString(mod, FS_LoadMallocFile(token, NULL), true);
|
||||
|
||||
mod->funcs.FindTouchedLeafs = D3_FindTouchedLeafs;
|
||||
mod->funcs.NativeTrace = D3_Trace;
|
||||
mod->funcs.PointContents = D3_PointContents;
|
||||
mod->funcs.FatPVS = D3_FatPVS;
|
||||
mod->funcs.ClusterForPoint = D3_ClusterForPoint;
|
||||
mod->funcs.StainNode = D3_StainNode;
|
||||
mod->funcs.LightPointValues = D3_LightPointValues;
|
||||
mod->funcs.EdictInFatPVS = D3_EdictInFatPVS;
|
||||
mod->funcs.ClusterPVS = D3_ClusterPVS;
|
||||
#ifdef HAVE_CLIENT
|
||||
mod->funcs.StainNode = D3_StainNode;
|
||||
mod->funcs.LightPointValues = D3_LightPointValues;
|
||||
mod->funcs.PrepareFrame = D3_PrepareFrame;
|
||||
#endif
|
||||
|
||||
mod->fromgame = fg_doom3;
|
||||
mod->type = mod_brush; //err, kinda, sorta, maybe.
|
||||
mod->fromgame = fg_new;
|
||||
|
||||
/*that's the physics sorted*/
|
||||
#ifndef SERVERONLY
|
||||
#ifdef HAVE_CLIENT
|
||||
if (!isDedicated)
|
||||
{
|
||||
COM_StripExtension(mod->name, token, sizeof(token));
|
||||
buf = FS_LoadMallocFile(va("%s.proc", token), NULL);
|
||||
Q_strncatz(token, ".proc", sizeof(token));
|
||||
buf = FS_LoadMallocFile(token, NULL);
|
||||
Mod_LoadMap_Proc(mod, buf);
|
||||
BZ_Free(buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ int webo_blocklightmapupdates; //0 no webo, &1=using threadedworld, &2=already u
|
|||
#ifdef BEF_PUSHDEPTH
|
||||
qboolean r_pushdepth;
|
||||
#endif
|
||||
qboolean r_dlightlightmaps; //updated each frame, says whether to do lightmap hack dlights.
|
||||
|
||||
extern cvar_t r_ambient;
|
||||
|
||||
|
@ -2314,7 +2315,7 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
|
|||
|
||||
currententity = ent;
|
||||
currentmodel = ent->model;
|
||||
if (model->nummodelsurfaces != 0 && r_dynamic.ival > 0)
|
||||
if (model->nummodelsurfaces != 0 && r_dlightlightmaps && model->funcs.MarkLights)
|
||||
{
|
||||
for (k=rtlights_first; k<RTL_FIRST; k++)
|
||||
{
|
||||
|
@ -2999,7 +3000,7 @@ void Surf_DrawWorld (void)
|
|||
currentmodel = cl.worldmodel;
|
||||
currententity = &r_worldentity;
|
||||
|
||||
r_dynamic.ival = r_dynamic.value;
|
||||
r_dlightlightmaps = !!r_dynamic.ival;
|
||||
|
||||
{
|
||||
#ifdef THREADEDWORLD
|
||||
|
@ -3026,8 +3027,8 @@ void Surf_DrawWorld (void)
|
|||
{
|
||||
r_dynamic.modified = false;
|
||||
r_temporalscenecache.modified = false;
|
||||
#ifdef RTLIGHT
|
||||
Sh_CheckSettings(); //fiddle with r_dynamic vs r_shadow_realtime_dlight.
|
||||
#ifdef RTLIGHTS
|
||||
// Sh_CheckSettings(); //fiddle with r_dynamic vs r_shadow_realtime_dlight.
|
||||
#endif
|
||||
COM_WorkerPartialSync(webogenerating, &webogeneratingstate, true);
|
||||
while (webostates)
|
||||
|
@ -3219,7 +3220,7 @@ void Surf_DrawWorld (void)
|
|||
if (webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2)
|
||||
VectorCopy(r_refdef.vieworg, webostate->lastpos);
|
||||
|
||||
r_dynamic.ival = -1; //don't waste time on dlighting models.
|
||||
r_dlightlightmaps = false; //don't waste time on dlighting bmodels.
|
||||
|
||||
RSpeedEnd(RSPEED_WORLDNODE);
|
||||
|
||||
|
@ -3242,9 +3243,9 @@ void Surf_DrawWorld (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef RTLIGHT
|
||||
#ifdef RTLIGHTS
|
||||
if (r_shadow_realtime_dlight.ival || currentmodel->type != mod_brush || !(currentmodel->fromgame == fg_quake || currentmodel->fromgame == fg_halflife) || !currentmodel->funcs.MarkLights)
|
||||
r_dynamic.ival = -1;
|
||||
r_dlightlightmaps = false; //don't do double lighting.
|
||||
#endif
|
||||
|
||||
Surf_PushChains(currentmodel->batches);
|
||||
|
@ -3256,10 +3257,6 @@ void Surf_DrawWorld (void)
|
|||
}
|
||||
else if (currentmodel->type != mod_brush)
|
||||
entvis = surfvis = NULL;
|
||||
#ifdef MAP_PROC
|
||||
else if (currentmodel->fromgame == fg_doom3)
|
||||
entvis = surfvis = D3_CalcVis(currentmodel, r_origin);
|
||||
#endif
|
||||
#ifdef MAP_DOOM
|
||||
else if (currentmodel->fromgame == fg_doom)
|
||||
{
|
||||
|
|
|
@ -688,6 +688,7 @@ extern cvar_t r_lavastyle;
|
|||
extern cvar_t r_slimestyle;
|
||||
extern cvar_t r_telestyle;
|
||||
extern cvar_t r_dynamic;
|
||||
extern qboolean r_dlightlightmaps;
|
||||
extern cvar_t r_temporalscenecache;
|
||||
extern cvar_t r_novis;
|
||||
extern cvar_t r_netgraph;
|
||||
|
|
|
@ -1802,7 +1802,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
|
|||
memcpy(¤trendererstate, newr, sizeof(currentrendererstate));
|
||||
|
||||
TRACE(("dbg: R_ApplyRenderer: S_Restart_f\n"));
|
||||
if (!isDedicated)
|
||||
if (!isDedicated && newr)
|
||||
S_DoRestart(true);
|
||||
|
||||
#ifdef VM_UI
|
||||
|
@ -1936,7 +1936,7 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n"));
|
|||
|
||||
void R_ReloadRenderer_f (void)
|
||||
{
|
||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
||||
#if !defined(CLIENTONLY)
|
||||
void *portalblob = NULL;
|
||||
size_t portalsize = 0;
|
||||
#endif
|
||||
|
@ -2200,7 +2200,7 @@ static int QDECL R_SortRenderers(const void *av, const void *bv)
|
|||
|
||||
void R_RestartRenderer (rendererstate_t *newr)
|
||||
{
|
||||
#if !defined(CLIENTONLY) && (defined(Q2BSPS) || defined(Q3BSPS))
|
||||
#if !defined(CLIENTONLY)
|
||||
void *portalblob = NULL;
|
||||
size_t portalsize = 0;
|
||||
#endif
|
||||
|
@ -2766,7 +2766,6 @@ int SignbitsForPlane (mplane_t *out)
|
|||
}
|
||||
return bits;
|
||||
}
|
||||
#if 1
|
||||
void R_SetFrustum (float projmat[16], float viewmat[16])
|
||||
{
|
||||
float scale;
|
||||
|
@ -2873,47 +2872,6 @@ void R_SetFrustum (float projmat[16], float viewmat[16])
|
|||
p->signbits = SignbitsForPlane (p);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void R_SetFrustum (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (r_novis.ival & 4)
|
||||
return;
|
||||
|
||||
/* removed - assumes fov_x == fov_y
|
||||
if (r_refdef.fov_x == 90)
|
||||
{
|
||||
// front side is visible
|
||||
|
||||
VectorAdd (vpn, vright, frustum[0].normal);
|
||||
VectorSubtract (vpn, vright, frustum[1].normal);
|
||||
|
||||
VectorAdd (vpn, vup, frustum[2].normal);
|
||||
VectorSubtract (vpn, vup, frustum[3].normal);
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
|
||||
// rotate VPN right by FOV_X/2 degrees
|
||||
RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
|
||||
// rotate VPN left by FOV_X/2 degrees
|
||||
RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
|
||||
// rotate VPN up by FOV_X/2 degrees
|
||||
RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
|
||||
// rotate VPN down by FOV_X/2 degrees
|
||||
RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
|
||||
}
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
frustum[i].type = PLANE_ANYZ;
|
||||
frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
|
||||
frustum[i].signbits = SignbitsForPlane (&frustum[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ static cvar_t scr_scoreboard_drawtitle = CVARD("scr_scoreboard_drawtitle", "1",
|
|||
static cvar_t scr_scoreboard_forcecolors = CVARD("scr_scoreboard_forcecolors", "0", "Makes the scoreboard colours obey enemycolor/teamcolor rules."); //damn americans
|
||||
static cvar_t scr_scoreboard_newstyle = CVARD("scr_scoreboard_newstyle", "1", "Display team colours and stuff in a style popularised by Electro. Looks more modern, but might not quite fit classic huds."); // New scoreboard style ported from Electro, by Molgrum
|
||||
static cvar_t scr_scoreboard_showfrags = CVARD("scr_scoreboard_showfrags", "0", "Display kills+deaths+teamkills, as determined by fragfile.dat-based conprint parsing. These may be inaccurate if you join mid-game.");
|
||||
#ifdef QUAKESTATS
|
||||
static cvar_t scr_scoreboard_showlocation = CVARD("scr_scoreboard_showlocation", "1", "Display player location names when playing mvd/qtv streams, if available.");
|
||||
static cvar_t scr_scoreboard_showhealth = CVARD("scr_scoreboard_showhealth", "3", "Display health information when playing mvd/qtv streams.\n0: off\n1: on\n2: show armour too. 3: combined health ('+' says more armour than health allows).");
|
||||
static cvar_t scr_scoreboard_showweapon = CVARD("scr_scoreboard_showweapon", "1", "Display weapon information when playing mvd/qtv streams.");
|
||||
#endif
|
||||
static cvar_t scr_scoreboard_showflags = CVARD("scr_scoreboard_showflags", "2", "Display flag caps+touches on the scoreboard, where our fragfile.dat supports them.\n0: off\n1: on\n2: on only if someone appears to have interacted with a flag.");
|
||||
static cvar_t scr_scoreboard_fillalpha = CVARD("scr_scoreboard_fillalpha", "0.7", "Transparency amount for newstyle scoreboard.");
|
||||
static cvar_t scr_scoreboard_backgroundalpha = CVARD("scr_scoreboard_backgroundalpha", "0.5", "Further multiplier for the background alphas.");
|
||||
|
@ -1178,6 +1183,11 @@ void Sbar_Init (void)
|
|||
Cvar_Register(&scr_scoreboard_forcecolors, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_newstyle, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_showfrags, "Scoreboard settings");
|
||||
#ifdef QUAKESTATS
|
||||
Cvar_Register(&scr_scoreboard_showlocation, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_showhealth, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_showweapon, "Scoreboard settings");
|
||||
#endif
|
||||
Cvar_Register(&scr_scoreboard_showflags, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_showruleset, "Scoreboard settings");
|
||||
Cvar_Register(&scr_scoreboard_afk, "Scoreboard settings");
|
||||
|
@ -3619,6 +3629,12 @@ ping time frags name
|
|||
code \
|
||||
} \
|
||||
}, fill)
|
||||
#define COLUMN_STAT2(title, width, code, fill) COLUMN(title, width, { \
|
||||
if (!s->spectator) \
|
||||
{ \
|
||||
code \
|
||||
} \
|
||||
}, fill)
|
||||
#define COLUMN_RULESET COLUMN(ruleset, 8*8, {Draw_FunStringWidth(x, y, s->ruleset, 8*8+4, false, false);},NOFILL)
|
||||
#define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, highlight);},NOFILL)
|
||||
#define COLUMN_KILLS COLUMN_STAT(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8+4, false, false);},NOFILL)
|
||||
|
@ -3626,11 +3642,46 @@ ping time frags name
|
|||
#define COLUMN_DEATHS COLUMN_STAT(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8+4, false, false);},NOFILL)
|
||||
#define COLUMN_TOUCHES COLUMN_STAT(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8+4, false, false);},NOFILL)
|
||||
#define COLUMN_CAPS COLUMN_STAT(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8+4, false, false);},NOFILL)
|
||||
#ifdef QUAKESTATS
|
||||
#define COLUMN_HEALTH COLUMN_STAT2(hlth, (scr_scoreboard_showhealth.ival==2)?7*8:4*8, { \
|
||||
float t;int c; \
|
||||
int a = cl.players[k].stats[STAT_ARMOR]; \
|
||||
int h = cl.players[k].stats[STAT_HEALTH]; \
|
||||
if (cl.players[k].stats[STAT_ITEMS] & IT_ARMOR3) {c='1';t = 0.8f;}\
|
||||
else if (cl.players[k].stats[STAT_ITEMS] & IT_ARMOR2) {c='3';t = 0.6f;}\
|
||||
else if (cl.players[k].stats[STAT_ITEMS] & IT_ARMOR1) {c='2';t = 0.3f;}\
|
||||
else {c='7';t = 0.f ;}\
|
||||
if (h <= 0) /*draw nothing*/ ; \
|
||||
else if (scr_scoreboard_showhealth.ival==3&&a>0) { int m = h/(1-t); Draw_FunStringWidth(x, y, va(a>m?"^%c%+4i":"^%c%4i", c,h + bound(0, m, a)), 4*8+4, false, false); } \
|
||||
else if (scr_scoreboard_showhealth.ival==2) Draw_FunStringWidth(x, y, (a>0)?va("^%c%3i^7/%-3i", c,a,h):va("---/%-3i", h), 7*8+4, false, false); \
|
||||
else Draw_FunStringWidth(x, y, va("%4i", h), 4*8+4, false, false); \
|
||||
},NOFILL)
|
||||
#define COLUMN_BESTWEAPON COLUMN_STAT2(wep, 4*8, { \
|
||||
Draw_FunStringWidth(x, y, va("%s%s%s", \
|
||||
(cl.players[k].stats[STAT_ITEMS] & IT_LIGHTNING)?"^5L":" ", \
|
||||
(cl.players[k].stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)?"^1R":" ", \
|
||||
(cl.players[k].stats[STAT_ITEMS] & IT_GRENADE_LAUNCHER)?"^2G":" " \
|
||||
), 4*8+4, false, false); \
|
||||
},NOFILL)
|
||||
#define COLUMN_LOCATION COLUMN_STAT2(loc, 8*8, { \
|
||||
lerpents_t *le; \
|
||||
const char *loc; \
|
||||
if (k+1 < cl.maxlerpents && cl.lerpentssequence && cl.lerpents[k+1].sequence == cl.lerpentssequence) le = &cl.lerpents[k+1]; \
|
||||
else if (cl.lerpentssequence && cl.lerpplayers[k].sequence == cl.lerpentssequence) le = &cl.lerpplayers[k];\
|
||||
else le = NULL;\
|
||||
loc = le?TP_LocationName(le->origin):""; \
|
||||
Draw_FunStringWidth(x, y, loc, 8*8+4, false, false); \
|
||||
},NOFILL)
|
||||
#else
|
||||
#define COLUMN_HEALTH
|
||||
#define COLUMN_BESTWEAPON
|
||||
#define COLUMN_LOCATION
|
||||
#endif
|
||||
#define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(InfoBuf_ValueForKey(&s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL)
|
||||
|
||||
|
||||
//columns are listed here in display order
|
||||
#define ALLCOLUMNS COLUMN_PING COLUMN_PL COLUMN_TIME COLUMN_RULESET COLUMN_FRAGS COLUMN_TEAMNAME COLUMN_NAME COLUMN_KILLS COLUMN_TKILLS COLUMN_DEATHS COLUMN_TOUCHES COLUMN_CAPS COLUMN_AFK
|
||||
#define ALLCOLUMNS COLUMN_PING COLUMN_PL COLUMN_TIME COLUMN_RULESET COLUMN_FRAGS COLUMN_TEAMNAME COLUMN_NAME COLUMN_HEALTH COLUMN_BESTWEAPON COLUMN_LOCATION COLUMN_KILLS COLUMN_TKILLS COLUMN_DEATHS COLUMN_TOUCHES COLUMN_CAPS COLUMN_AFK
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -3674,12 +3725,15 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
|
|||
cl.last_ping_request = realtime;
|
||||
CL_SendClientCommand(true, "pings");
|
||||
}
|
||||
#ifdef NQPROT
|
||||
else if (cls.protocol == CP_NETQUAKE && !cls.qex)
|
||||
{
|
||||
cl.last_ping_request = realtime;
|
||||
CL_SendClientCommand(true, "ping");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef NQPROT
|
||||
if (cls.protocol == CP_NETQUAKE && !cls.qex)
|
||||
{
|
||||
if (cl.nqplayernamechanged && cl.nqplayernamechanged < realtime)
|
||||
|
@ -3689,6 +3743,7 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
|
|||
CL_SendClientCommand(true, "status");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (start)
|
||||
y = start;
|
||||
|
@ -3768,6 +3823,20 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
|
|||
COLUMN_TKILLS
|
||||
}
|
||||
}
|
||||
#ifdef QUAKESTATS
|
||||
if (scr_scoreboard_showhealth.ival && cls.demoplayback==DPB_MVD)
|
||||
{
|
||||
COLUMN_HEALTH
|
||||
}
|
||||
if (scr_scoreboard_showweapon.ival && cls.demoplayback==DPB_MVD)
|
||||
{
|
||||
COLUMN_BESTWEAPON
|
||||
}
|
||||
if (scr_scoreboard_showlocation.ival && cls.demoplayback==DPB_MVD && TP_HaveLocations())
|
||||
{
|
||||
COLUMN_LOCATION
|
||||
}
|
||||
#endif
|
||||
if (scr_scoreboard_showflags.ival && cl.teamplay && Stats_HaveFlags(scr_scoreboard_showflags.ival&1))
|
||||
{
|
||||
COLUMN_TOUCHES
|
||||
|
|
|
@ -322,7 +322,7 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
|
|||
{
|
||||
qwskin_t *skin = skinptr;
|
||||
char name[MAX_QPATH];
|
||||
qbyte *out;
|
||||
qbyte *out = NULL;
|
||||
int srcw = 0, srch = 0;
|
||||
|
||||
size_t pcxsize = 0;
|
||||
|
@ -362,9 +362,14 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
|
|||
Q_snprintfz (name, sizeof(name), "skins/%s.pcx", skin->name);
|
||||
pcxfiledata = FS_LoadMallocFileFlags (name, FSLF_IGNOREPURE, &pcxsize);
|
||||
if (!pcxfiledata)
|
||||
{
|
||||
//use 24bit skins even if gl_load24bit is failed
|
||||
if (strcmp(skin->name, baseskin.string))
|
||||
{ //FIXME: use 24bit skins even if gl_load24bit is failed
|
||||
if (!strcmp(skin->name, "solid") || !strcmp(skin->name, "block"))
|
||||
{ //allow block colour, even if the file isn't found.
|
||||
srcw = srch = 1;
|
||||
out = BZ_Malloc(srcw*srch);
|
||||
memset(out, BOTTOM_DEFAULT | 15, srcw*srch);
|
||||
}
|
||||
else if (strcmp(skin->name, baseskin.string))
|
||||
{
|
||||
//if its not already the base skin, try the base (and warn if anything not base couldn't load).
|
||||
Con_Printf ("Couldn't load skin %s\n", name);
|
||||
|
@ -374,15 +379,12 @@ void Skin_WorkerLoad(void *skinptr, void *data, size_t a, size_t b)
|
|||
pcxfiledata = FS_LoadMallocFileFlags (name, FSLF_IGNOREPURE, &pcxsize);
|
||||
}
|
||||
}
|
||||
if (!pcxfiledata)
|
||||
{
|
||||
Skin_WorkerDone(skin, NULL, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pcxfiledata)
|
||||
if (out)
|
||||
;
|
||||
else if (pcxfiledata)
|
||||
{
|
||||
out = Skin_ParsePCX(name, pcxfiledata, pcxsize, &srcw, &srch);
|
||||
FS_FreeFile(pcxfiledata);
|
||||
|
|
|
@ -434,7 +434,8 @@ typedef struct
|
|||
ALuint handle;
|
||||
qbyte allocated; //there is no guarenteed-unused handle (and I don't want to have to keep spamming alIsSource).
|
||||
qbyte queuesize;
|
||||
ALuint queue[3];
|
||||
ALuint queue_b[3];
|
||||
usamplepos_t queue_f[3];
|
||||
} *source;
|
||||
size_t max_sources;
|
||||
|
||||
|
@ -746,7 +747,7 @@ static qboolean OpenAL_ReclaimASource(soundcardinfo_t *sc)
|
|||
{
|
||||
palDeleteSources(1, &src);
|
||||
if (oali->source[i].queuesize)
|
||||
palDeleteBuffers(oali->source[i].queuesize, oali->source[i].queue);
|
||||
palDeleteBuffers(oali->source[i].queuesize, oali->source[i].queue_b);
|
||||
oali->source[i].queuesize = 0;
|
||||
oali->source[i].handle = 0;
|
||||
oali->source[i].allocated = false;
|
||||
|
@ -778,7 +779,7 @@ static qboolean OpenAL_ReclaimASource(soundcardinfo_t *sc)
|
|||
i = furthest;
|
||||
palDeleteSources(1, &oali->source[i].handle);
|
||||
if (oali->source[i].queuesize)
|
||||
palDeleteBuffers(oali->source[i].queuesize, oali->source[i].queue);
|
||||
palDeleteBuffers(oali->source[i].queuesize, oali->source[i].queue_b);
|
||||
oali->source[i].queuesize = 0;
|
||||
oali->source[i].handle = 0;
|
||||
oali->source[i].allocated = false;
|
||||
|
@ -802,7 +803,32 @@ static ssamplepos_t OpenAL_GetChannelPos(soundcardinfo_t *sc, channel_t *chan)
|
|||
|
||||
//alcMakeContextCurrent
|
||||
|
||||
palGetSourcei(src, AL_SAMPLE_OFFSET, &spos);
|
||||
if (oali->source[chnum].queuesize)
|
||||
{ //we're streaming, for whatever reason.
|
||||
ssamplepos_t pos;
|
||||
ALuint processed;
|
||||
int i;
|
||||
//reclaim any queued buffers
|
||||
palGetSourcei(src, AL_BUFFERS_PROCESSED, &processed); //get number of buffers
|
||||
palGetSourcei(src, AL_SAMPLE_OFFSET, &spos); //get our position within the current one.
|
||||
if (processed)
|
||||
{
|
||||
palSourceUnqueueBuffers(src, processed, oali->source[chnum].queue_b);
|
||||
palDeleteBuffers(processed, oali->source[chnum].queue_b);
|
||||
oali->source[chnum].queuesize -= processed;
|
||||
memmove(oali->source[chnum].queue_b, oali->source[chnum].queue_b+processed, oali->source[chnum].queuesize*sizeof(*oali->source[chnum].queue_b));
|
||||
memmove(oali->source[chnum].queue_f, oali->source[chnum].queue_f+processed, oali->source[chnum].queuesize*sizeof(*oali->source[chnum].queue_f));
|
||||
}
|
||||
|
||||
pos = chan->pos>>PITCHSHIFT; //this is the point of thedata that was already submitted to openal.
|
||||
for (i = 0; i < oali->source[chnum].queuesize; i++)
|
||||
pos -= oali->source[chnum].queue_f[i];
|
||||
//pos is now 'chan->pos at start of current buffer'
|
||||
pos += spos; //current playback position (should always be smaller than chan->pos originally was...)
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
palGetSourcei(src, AL_SAMPLE_OFFSET, &spos);
|
||||
return spos; //FIXME: result is probably going to be wrong when streaming
|
||||
}
|
||||
|
||||
|
@ -860,7 +886,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
palSourceStop(src);
|
||||
palSourcei(src, AL_BUFFER, 0);
|
||||
if (oali->source[chnum].queuesize)
|
||||
palDeleteBuffers(oali->source[chnum].queuesize, oali->source[chnum].queue);
|
||||
palDeleteBuffers(oali->source[chnum].queuesize, oali->source[chnum].queue_b);
|
||||
oali->source[chnum].queuesize = 0;
|
||||
|
||||
}
|
||||
|
@ -870,10 +896,11 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
palGetSourcei(src, AL_BUFFERS_PROCESSED, &processed);
|
||||
if (processed)
|
||||
{
|
||||
palSourceUnqueueBuffers(src, processed, oali->source[chnum].queue);
|
||||
palDeleteBuffers(processed, oali->source[chnum].queue);
|
||||
palSourceUnqueueBuffers(src, processed, oali->source[chnum].queue_b);
|
||||
palDeleteBuffers(processed, oali->source[chnum].queue_b);
|
||||
oali->source[chnum].queuesize -= processed;
|
||||
memmove(oali->source[chnum].queue, oali->source[chnum].queue+processed, oali->source[chnum].queuesize*sizeof(*oali->source[chnum].queue));
|
||||
memmove(oali->source[chnum].queue_b, oali->source[chnum].queue_b+processed, oali->source[chnum].queuesize*sizeof(*oali->source[chnum].queue_b));
|
||||
memmove(oali->source[chnum].queue_f, oali->source[chnum].queue_f+processed, oali->source[chnum].queuesize*sizeof(*oali->source[chnum].queue_f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -902,7 +929,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
#else
|
||||
palDeleteSources(1, &src);
|
||||
if (oali->source[chnum].queuesize)
|
||||
palDeleteBuffers(oali->source[chnum].queuesize, oali->source[chnum].queue);
|
||||
palDeleteBuffers(oali->source[chnum].queuesize, oali->source[chnum].queue_b);
|
||||
oali->source[chnum].queuesize = 0;
|
||||
oali->source[chnum].handle = 0;
|
||||
oali->source[chnum].allocated = false;
|
||||
|
@ -947,7 +974,7 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
{
|
||||
int offset;
|
||||
sfxcache_t sbuf, *sc;
|
||||
while (oali->source[chnum].queuesize < countof(oali->source[chnum].queue))
|
||||
while (oali->source[chnum].queuesize < countof(oali->source[chnum].queue_b))
|
||||
{ //decode periodically instead of all at the start.
|
||||
int tryduration = snd_speed*0.5;
|
||||
ssamplepos_t pos = chan->pos>>PITCHSHIFT;
|
||||
|
@ -985,7 +1012,9 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
if (OpenAL_LoadCache(oali, &buf, &sbuf, max(1,cvolume), 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
oali->source[chnum].queue_b[oali->source[chnum].queuesize] = buf;
|
||||
oali->source[chnum].queue_f[oali->source[chnum].queuesize] = sbuf.length;
|
||||
oali->source[chnum].queuesize++;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1000,7 +1029,9 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
if (OpenAL_LoadCache(oali, &buf, &silence, 1, 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
oali->source[chnum].queue_b[oali->source[chnum].queuesize] = buf;
|
||||
oali->source[chnum].queue_f[oali->source[chnum].queuesize] = 0; //don't count silence.
|
||||
oali->source[chnum].queuesize++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1062,9 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
|
|||
if (OpenAL_LoadCache(oali, &buf, &silence, 1, 0))
|
||||
{
|
||||
palSourceQueueBuffers(src, 1, &buf);
|
||||
oali->source[chnum].queue[oali->source[chnum].queuesize++] = buf;
|
||||
oali->source[chnum].queue_b[oali->source[chnum].queuesize] = buf;
|
||||
oali->source[chnum].queue_f[oali->source[chnum].queuesize] = 0; //don't count silence.
|
||||
oali->source[chnum].queuesize++;
|
||||
if (oali->can_source_spatialise) //force spacialisation as desired, if supported (this solves browsers forcing stereo on mono files which should mean static audio is full volume...)
|
||||
palSourcei(src, AL_SOURCE_SPATIALIZE_SOFT, !srcrel);
|
||||
}
|
||||
|
|
|
@ -4214,7 +4214,7 @@ typedef struct {
|
|||
int length;
|
||||
void *data;
|
||||
} streaming_t;
|
||||
#define MAX_RAW_SOURCES (MAX_CLIENTS+1)
|
||||
#define MAX_RAW_SOURCES (MAX_CLIENTS+3)
|
||||
streaming_t s_streamers[MAX_RAW_SOURCES];
|
||||
|
||||
void S_ClearRaw(void)
|
||||
|
@ -4256,8 +4256,47 @@ void QDECL S_Raw_Purge(sfx_t *sfx)
|
|||
memset(&sfx->decoder, 0, sizeof(sfx->decoder));
|
||||
}
|
||||
|
||||
float S_RawAudioQueued(int sourceid) //returns in seconds. we don't know what the original sample count was.
|
||||
{
|
||||
soundcardinfo_t *si;
|
||||
streaming_t *s;
|
||||
int i;
|
||||
float r;
|
||||
ssamplepos_t highest, pos;
|
||||
for (s = s_streamers, i = 0; i < MAX_RAW_SOURCES; i++, s++)
|
||||
{
|
||||
if (s->inuse && s->id == sourceid)
|
||||
{
|
||||
S_LockMixer();
|
||||
|
||||
highest = ((~(usamplepos_t)0)>>1);
|
||||
for (si = sndcardinfo; si; si=si->next) //make sure all cards are playing, and that we still get a prepad if just one is.
|
||||
{
|
||||
for (i = 0; i < si->total_chans; i++)
|
||||
if (si->channel[i].sfx == s->sfx)
|
||||
{
|
||||
if (si->GetChannelPos)
|
||||
pos = si->GetChannelPos(si, &si->channel[i]);
|
||||
else
|
||||
pos = si->channel[i].pos>>PITCHSHIFT;
|
||||
if (highest > pos)
|
||||
highest = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (highest == ((~(usamplepos_t)0)>>1))
|
||||
r = 0; //nothing playing it... needs to be woken up. pretend nothing is there so it gets poked a bit.
|
||||
else
|
||||
r = (s->length - highest) / (float)snd_speed;
|
||||
S_UnlockMixer();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0; //not found
|
||||
}
|
||||
|
||||
//streaming audio. //this is useful when there is one source, and the sound is to be played with no attenuation
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, qaudiofmt_t format, float volume)
|
||||
void S_RawAudio(int sourceid, const qbyte *data, int speed, int samples, int channels, qaudiofmt_t format, float volume)
|
||||
{
|
||||
soundcardinfo_t *si;
|
||||
int i;
|
||||
|
|
|
@ -291,11 +291,11 @@ static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
|
|||
// SND_ResampleStream: takes a sound stream and converts with given parameters. Limited to
|
||||
// 8-16-bit signed conversions and mono-to-mono/stereo-to-stereo conversions.
|
||||
// Not an in-place algorithm.
|
||||
void SND_ResampleStream (void *in, int inrate, qaudiofmt_t informat, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outformat, int outchannels, int resampstyle)
|
||||
void SND_ResampleStream (const void *in, int inrate, qaudiofmt_t informat, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outformat, int outchannels, int resampstyle)
|
||||
{
|
||||
double scale;
|
||||
signed char *in8 = (signed char *)in;
|
||||
short *in16 = (short *)in;
|
||||
const signed char *in8 = (const signed char *)in;
|
||||
const short *in16 = (const short *)in;
|
||||
signed char *out8 = (signed char *)out;
|
||||
short *out16 = (short *)out;
|
||||
int outsamps, outnlsamps, outsampleft, outsampright;
|
||||
|
|
|
@ -262,7 +262,7 @@ qboolean S_IsPlayingSomewhere(sfx_t *s);
|
|||
// picks a channel based on priorities, empty slots, number of channels
|
||||
channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel);
|
||||
|
||||
void SND_ResampleStream (void *in, int inrate, qaudiofmt_t inwidth, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outwidth, int outchannels, int resampstyle);
|
||||
void SND_ResampleStream (const void *in, int inrate, qaudiofmt_t inwidth, int inchannels, int insamps, void *out, int outrate, qaudiofmt_t outwidth, int outchannels, int resampstyle);
|
||||
|
||||
// restart entire sound subsystem (doesn't flush old sounds, so make sure that happens)
|
||||
void S_DoRestart (qboolean onlyifneeded);
|
||||
|
@ -270,7 +270,13 @@ void S_DoRestart (qboolean onlyifneeded);
|
|||
void S_Restart_f (void);
|
||||
|
||||
//plays streaming audio
|
||||
void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, qaudiofmt_t width, float volume);
|
||||
#define SOURCEID_MENUQC -3
|
||||
#define SOURCEID_CSQC -2
|
||||
#define SOURCEID_CINEMATIC -1
|
||||
#define SOURCEID_VOIP_FIRST 0
|
||||
#define SOURCEID_VOIP_MAX MAX_CLIENTS-1
|
||||
void S_RawAudio(int sourceid, const qbyte *data, int speed, int samples, int channels, qaudiofmt_t width, float volume);
|
||||
float S_RawAudioQueued(int sourceid);
|
||||
|
||||
void CLVC_Poll (void);
|
||||
|
||||
|
|
|
@ -66,13 +66,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#undef malloc
|
||||
|
||||
#if defined(__unix__) && !defined(__CYGWIN__)
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
static int noconinput = 0;
|
||||
static int nostdout = 0;
|
||||
|
||||
static FILE *dedcon; //replaces our stdin/out when set.
|
||||
static int dedconproc = -1;
|
||||
|
||||
extern int isPlugin;
|
||||
int sys_parentleft;
|
||||
int sys_parenttop;
|
||||
|
@ -86,10 +85,77 @@ static void Sys_InitClock(void);
|
|||
|
||||
qboolean Sys_InitTerminal (void) //we either have one or we don't.
|
||||
{
|
||||
return isatty(STDIN_FILENO);
|
||||
if (isatty(STDIN_FILENO))
|
||||
return true; //already attached to a terminal in some form. don't need another.
|
||||
|
||||
if (dedcon) //already got one open... shouldn't really happen. future paranoia.
|
||||
return true;
|
||||
else
|
||||
{
|
||||
int pty = posix_openpt(O_RDWR|O_NOCTTY);
|
||||
if (pty >= 0)
|
||||
{
|
||||
int fd;
|
||||
char *slavename, window[64], buf[64];
|
||||
grantpt(pty);
|
||||
unlockpt(pty);
|
||||
slavename = ptsname(pty);
|
||||
dedcon = fopen(slavename, "r+e");
|
||||
if (dedcon)
|
||||
{
|
||||
snprintf(buf, sizeof buf, "-S%s/%d", strrchr(slavename,'/')+1, pty);
|
||||
dedconproc = fork();
|
||||
if(!dedconproc)
|
||||
{ //oh hey, we're the child.
|
||||
execlp("xterm", "xterm", buf, (char *)0);
|
||||
_exit(1);
|
||||
}
|
||||
close(pty); //can close it now, we'll keep track of it with our slave fd
|
||||
if (dedconproc >= 0)
|
||||
{ //if the xterm fails, does this EPIPE properly?
|
||||
fgets(window, sizeof window, dedcon);
|
||||
//printf("window: %s\n", window);
|
||||
|
||||
//switch input to non-blocking, so we can actually still do stuff...
|
||||
fd = fileno(dedcon);
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
{
|
||||
extern int epoll_fd;
|
||||
if (epoll_fd >= 0)
|
||||
{
|
||||
struct epoll_event event = {EPOLLIN, {NULL}};
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event);
|
||||
}
|
||||
}
|
||||
#else
|
||||
//FIXME: NET_Sleep needs to wake up on dedcon input
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
//else fork failed.
|
||||
fclose(dedcon);
|
||||
dedcon = NULL;
|
||||
}
|
||||
close(pty);
|
||||
}
|
||||
}
|
||||
return false; //nope, soz
|
||||
}
|
||||
void Sys_CloseTerminal (void)
|
||||
{
|
||||
if (dedcon)
|
||||
{
|
||||
#ifdef HAVE_EPOLL
|
||||
extern int epoll_fd;
|
||||
if (epoll_fd >= 0)
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fileno(dedcon), NULL); //don't get confused if the FD# is later reopened as something else...
|
||||
#endif
|
||||
fclose(dedcon);
|
||||
dedcon = NULL;
|
||||
}
|
||||
dedconproc = -1;
|
||||
}
|
||||
|
||||
void Sys_RecentServer(char *command, char *target, char *title, char *desc)
|
||||
|
@ -186,7 +252,9 @@ void Sys_Printf (char *fmt, ...)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (nostdout)
|
||||
if (dedcon)
|
||||
out = dedcon;
|
||||
else if (nostdout)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
out = stderr;
|
||||
|
@ -1137,6 +1205,27 @@ char *Sys_ConsoleInput(void)
|
|||
static char text[256];
|
||||
char *nl;
|
||||
|
||||
if (dedcon)
|
||||
{
|
||||
int e;
|
||||
if (fgets(text, sizeof(text), dedcon))
|
||||
return text;
|
||||
e = errno;
|
||||
switch(e)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR: //not meant to be blocking, but can still be interrupted.
|
||||
break; //cos we made it non-blocking.
|
||||
case EPIPE: //not seen, but possible I guess.
|
||||
case EIO: //can happen if the other end dies.
|
||||
Sys_CloseTerminal();
|
||||
return "quit"; //kill the server if we were actually using the terminal... or at least try not to run silently.
|
||||
default:
|
||||
Sys_Printf(CON_WARNING "fgets errno %i\n", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (noconinput)
|
||||
return NULL;
|
||||
|
||||
|
@ -1227,7 +1316,9 @@ static void DoSign(const char *fname, int signtype)
|
|||
}
|
||||
else if (f)
|
||||
{
|
||||
hashfunc_t *h = (signtype==1)?&hash_sha2_256:&hash_sha2_512;
|
||||
hashfunc_t *h = (signtype==1)?&hash_sha1:
|
||||
(signtype==256)?&hash_sha2_256:
|
||||
&hash_sha2_512;
|
||||
size_t l, ts = 0;
|
||||
void *ctx = alloca(h->contextsize);
|
||||
qbyte data[65536*16];
|
||||
|
@ -1350,6 +1441,29 @@ static void SigCont(int code)
|
|||
fcntl(STDIN_FILENO, F_SETFL, fl | FNDELAY);
|
||||
noconinput &= ~2;
|
||||
}
|
||||
static void SigChldTerminalDied(int code, void *data)
|
||||
{ //our terminal dieded? restart again (this shouldn't loop infinitely...)
|
||||
Sys_CloseTerminal();
|
||||
Cbuf_AddText ("vid_renderer \"\"; vid_restart\n", RESTRICT_LOCAL);
|
||||
}
|
||||
static void SigChld(int code)
|
||||
{
|
||||
int wstat;
|
||||
pid_t pid;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
pid = wait3 (&wstat, WNOHANG, (struct rusage *)NULL);
|
||||
if (pid == -1)
|
||||
return; //error
|
||||
else if (pid == 0)
|
||||
return; //nothing left to report (linux seems to like errors instead)
|
||||
else if (pid == dedconproc)
|
||||
Cmd_AddTimer(0, SigChldTerminalDied, 0, NULL, 0);
|
||||
// else //forked subserver? we use pipes to track when it dies.
|
||||
// printf ("Return code: %d\n", wstat);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int main (int c, const char **v)
|
||||
{
|
||||
|
@ -1362,7 +1476,7 @@ int main (int c, const char **v)
|
|||
#ifdef _POSIX_C_SOURCE
|
||||
signal(SIGTTIN, SIG_IGN); //have to ignore this if we want to not lock up when running backgrounded.
|
||||
signal(SIGCONT, SigCont);
|
||||
signal(SIGCHLD, SIG_IGN); //mapcluster stuff might leak zombie processes if we don't do this.
|
||||
signal(SIGCHLD, SigChld); //mapcluster stuff might leak zombie processes if we don't do this.
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -2072,9 +2072,12 @@ void R_DrawNameTags(void)
|
|||
else
|
||||
{
|
||||
shader = NULL;
|
||||
#ifdef TERRAIN
|
||||
if (cl.worldmodel->terrain && trace.brush_id && (shader = Terr_GetShader(cl.worldmodel, &trace)))
|
||||
shadername = shader->name;
|
||||
else if ((surf = (trace.fraction == 1)?NULL:Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos)))
|
||||
else
|
||||
#endif
|
||||
if ((surf = (trace.fraction == 1)?NULL:Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos)))
|
||||
{
|
||||
shadername = surf->texinfo->texture->name;
|
||||
shader = surf->texinfo->texture->shader;
|
||||
|
|
|
@ -626,6 +626,24 @@ miptex_t *W_GetMipTex(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void WAD_ImageList_f(void)
|
||||
{
|
||||
wadfile_t *wad;
|
||||
int i;
|
||||
char *match = Cmd_Argv(1);
|
||||
Sys_LockMutex(wadmutex);
|
||||
for (i = 0;i < numwadtextures;i++)
|
||||
{
|
||||
if (*match && !wildcmp(match, texwadlump[i].name))
|
||||
continue;
|
||||
for (wad = openwadfiles; wad; wad = wad->next)
|
||||
if (wad->file == texwadlump[i].file)
|
||||
break;
|
||||
Con_Printf("^[\\img\\%s\\s\\%i\\tip\\From inside %s^] %s\n", texwadlump[i].name, 64, wad?wad->name:"<unknown>", texwadlump[i].name);
|
||||
}
|
||||
Sys_UnlockMutex(wadmutex);
|
||||
}
|
||||
|
||||
typedef struct mapgroup_s {
|
||||
char *mapname;
|
||||
char *skyname;
|
||||
|
|
|
@ -1529,16 +1529,16 @@ TP_ParseFunChars
|
|||
Doesn't check for overflows, so strlen(s) should be < MAX_MACRO_STRING
|
||||
==============
|
||||
*/
|
||||
char *TP_ParseFunChars (char *s)
|
||||
const char *TP_ParseFunChars (const char *s)
|
||||
{
|
||||
static char buf[MAX_MACRO_STRING];
|
||||
char *out = buf;
|
||||
int c;
|
||||
|
||||
if (!cl_parseFunChars.ival)
|
||||
if (!cl_parseFunChars.ival || com_parseutf8.ival != 0)
|
||||
return s;
|
||||
|
||||
while (*s) {
|
||||
while (*s && out < buf+countof(buf)-1) {
|
||||
if (*s == '$' && s[1] == 'x') {
|
||||
int i;
|
||||
// check for $x10, $x8a, etc
|
||||
|
@ -1788,7 +1788,10 @@ static void TP_LoadLocFile_f (void)
|
|||
|
||||
TP_LoadLocFile (Cmd_Argv(1), false);
|
||||
}
|
||||
|
||||
qboolean TP_HaveLocations(void)
|
||||
{
|
||||
return loc_numentries>0;
|
||||
}
|
||||
char *TP_LocationName (const vec3_t location)
|
||||
{
|
||||
int i, j, minnum;
|
||||
|
@ -3885,7 +3888,11 @@ void CL_Say (qboolean team, char *extra)
|
|||
//messagemode always adds quotes. the console command never did.
|
||||
//the server is expected to use Cmd_Args and to strip first+last chars if the first is a quote. this is annoying and clumsy for mods to parse.
|
||||
#ifdef HAVE_LEGACY
|
||||
if (!dpcompat_console.ival && !cls.qex)
|
||||
if (!dpcompat_console.ival
|
||||
#ifdef NQPROT
|
||||
&& !cls.qex
|
||||
#endif
|
||||
)
|
||||
CL_SendSeatClientCommand(true, split, "%s \"%s%s\"", team ? "say_team" : "say", extra?extra:"", sendtext);
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -254,8 +254,7 @@ void Cmd_AddTimer(float delay, void(*callback)(int iarg, void *data), int iarg,
|
|||
|
||||
n->timer = realtime + delay;
|
||||
|
||||
n->next = cmdtimers;
|
||||
cmdtimers = n;
|
||||
FTE_Atomic_Insert(cmdtimers, n, n->next);
|
||||
}
|
||||
static void Cmd_In_Callback(int iarg, void *data)
|
||||
{
|
||||
|
@ -715,6 +714,9 @@ static const char *replacementq1binds =
|
|||
"bind F10 menu_quit\n"
|
||||
// "bind F11 +zoom\n"
|
||||
"bind F12 screenshot\n"
|
||||
|
||||
"bind volup \"if $volume < 0.9 then inc volume 0.1 else if $volume < 1.0 then set volume 1\"\n"
|
||||
"bind voldown \"inc volume -0.1; if $volume < 0 then set volume 0\"\n"
|
||||
;
|
||||
static const char *defaulttouchcfg =
|
||||
"showpic_removeall\n"
|
||||
|
@ -1038,11 +1040,11 @@ Cmd_Echo_f
|
|||
Just prints the rest of the line to the console
|
||||
===============
|
||||
*/
|
||||
char *TP_ParseFunChars (char *s);
|
||||
static void Cmd_Echo_f (void)
|
||||
{
|
||||
char text[4096];
|
||||
char extext[4096], *t;
|
||||
char extext[4096];
|
||||
const char *t;
|
||||
int level = Cmd_ExecLevel;
|
||||
int i;
|
||||
*text = 0;
|
||||
|
@ -1465,9 +1467,9 @@ static void Cmd_AliasList_f (void)
|
|||
if (!num)
|
||||
Con_TPrintf("Alias list:\n");
|
||||
if (cmd->execlevel)
|
||||
Con_Printf("(%2i)(%2i) %s\n", (int)(cmd->restriction?cmd->restriction:rcon_level.ival), cmd->execlevel, cmd->name);
|
||||
Con_Printf(S_COLOR_TRANS"(%2i)(%2i) "S_COLOR_WHITE"^[%s\\type\\/%s^]\n", (int)(cmd->restriction?cmd->restriction:rcon_level.ival), cmd->execlevel, cmd->name, cmd->name);
|
||||
else
|
||||
Con_Printf("(%2i) %s\n", (int)(cmd->restriction?cmd->restriction:rcon_level.ival), cmd->name);
|
||||
Con_Printf(S_COLOR_TRANS "(%2i) "S_COLOR_WHITE"^[%s\\type\\/%s^]\n", (int)(cmd->restriction?cmd->restriction:rcon_level.ival), cmd->name, cmd->name);
|
||||
num++;
|
||||
}
|
||||
if (num)
|
||||
|
@ -2733,16 +2735,16 @@ static void Cmd_Apropos_f (void)
|
|||
{
|
||||
COM_QuotedString(var->latched_string, latchedvalue, sizeof(latchedvalue), false);
|
||||
if (d)
|
||||
Con_TPrintf("cvar ^2%s^7: %s (effective %s): ^3%s\n", name, latchedvalue, escapedvalue, d);
|
||||
Con_TPrintf("cvar ^[^2%s\\type\\%s^]: %s (effective %s): ^3%s\n", name,name, latchedvalue, escapedvalue, d);
|
||||
else
|
||||
Con_TPrintf("cvar ^2%s^7: %s (effective %s): ^3no description\n", name, latchedvalue, escapedvalue);
|
||||
Con_TPrintf("cvar ^[^2%s\\type\\%s^]: %s (effective %s): ^3no description\n", name,name, latchedvalue, escapedvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d)
|
||||
Con_TPrintf("cvar ^2%s^7: %s : ^3%s\n", name, escapedvalue, d);
|
||||
Con_TPrintf("cvar ^[^2%s\\type\\%s^]: %s : ^3%s\n", name,name, escapedvalue, d);
|
||||
else
|
||||
Con_TPrintf("cvar ^2%s^7: %s : ^3no description\n", name, escapedvalue);
|
||||
Con_TPrintf("cvar ^[^2%s\\type\\%s^]: %s : ^3no description\n", name,name, escapedvalue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2757,9 +2759,9 @@ static void Cmd_Apropos_f (void)
|
|||
continue;
|
||||
|
||||
if (d)
|
||||
Con_TPrintf("command ^2%s^7: ^3%s\n", cmd->name, d);
|
||||
Con_TPrintf("command ^[^2%s\\type\\%s^]: ^3%s\n", cmd->name,cmd->name, d);
|
||||
else
|
||||
Con_TPrintf("command ^2%s^7: ^3no description\n", cmd->name);
|
||||
Con_TPrintf("command ^[^2%s\\type\\%s^]: ^3no description\n", cmd->name,cmd->name);
|
||||
}
|
||||
//FIXME: add aliases.
|
||||
}
|
||||
|
@ -3739,7 +3741,7 @@ skipblock:
|
|||
if (trueblock)
|
||||
goto skipblock; //we've had our true, all others are assumed to be false.
|
||||
else
|
||||
goto elseif; //and have annother go.
|
||||
goto elseif; //and have another go.
|
||||
}
|
||||
else
|
||||
{ //we got an else. This is the last block. Don't go through the normal way, cos that would let us follow up with a second else.
|
||||
|
@ -4139,6 +4141,7 @@ static void Cmd_WriteConfig_f(void)
|
|||
char fname[MAX_QPATH];
|
||||
char displayname[MAX_OSPATH];
|
||||
qboolean all = true;
|
||||
qboolean nohidden = false;
|
||||
|
||||
//special variation that only saves if an archived cvar was actually modified.
|
||||
if (!Q_strcasecmp(Cmd_Argv(0), "cfg_save_ifmodified"))
|
||||
|
@ -4167,7 +4170,9 @@ static void Cmd_WriteConfig_f(void)
|
|||
Q_snprintfz(fname, sizeof(fname), "%s", filename);
|
||||
COM_RequireExtension(fname, ".cfg", sizeof(fname));
|
||||
|
||||
if (Cmd_IsInsecure() && strncmp(fname, "data/", 5))
|
||||
if (!strncmp(fname, "data/", 5))
|
||||
nohidden = true; //we're writing to the data/ dir, which mods may potentially read. don't write any settings they're not allowed to see.
|
||||
else if (Cmd_IsInsecure())
|
||||
{
|
||||
Con_Printf ("%s %s: not allowed\n", Cmd_Argv(0), Cmd_Args());
|
||||
return;
|
||||
|
@ -4235,7 +4240,7 @@ static void Cmd_WriteConfig_f(void)
|
|||
#endif
|
||||
if (cfg_save_aliases.ival)
|
||||
Alias_WriteAliases (f);
|
||||
Cvar_WriteVariables (f, all);
|
||||
Cvar_WriteVariables (f, all, nohidden);
|
||||
VFS_CLOSE(f);
|
||||
|
||||
Cvar_Saved();
|
||||
|
|
|
@ -251,6 +251,7 @@ void Cmd_MessageTrigger (char *message, int type);
|
|||
|
||||
void Cmd_ShiftArgs (int ammount, qboolean expandstring);
|
||||
|
||||
const char *TP_ParseFunChars (const char *s);
|
||||
char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accesslevel, qboolean expandargs, qboolean expandcvars, qboolean expandmacros);
|
||||
qboolean If_EvaluateBoolean(const char *text, int restriction);
|
||||
|
||||
|
|
|
@ -896,7 +896,7 @@ static void BIH_RecursiveTrace (struct bihtrace_s *fte_restrict tr, const struct
|
|||
|
||||
VectorSubtract (tr->startpos, node->data.mesh.tr->origin, start_l);
|
||||
VectorSubtract (tr->endpos, node->data.mesh.tr->origin, end_l);
|
||||
node->data.mesh.model->funcs.NativeTrace(node->data.mesh.model, 0, NULLFRAMESTATE, node->data.mesh.tr->axis, start_l, end_l, tr->size.min, tr->size.max, tr->shape==shape_iscapsule, tr->hitcontents, &sub);
|
||||
submod->funcs.NativeTrace(submod, 0, NULLFRAMESTATE, node->data.mesh.tr->axis, start_l, end_l, tr->size.min, tr->size.max, tr->shape==shape_iscapsule, tr->hitcontents, &sub);
|
||||
|
||||
if (sub.truefraction < tr->trace.truefraction)
|
||||
{
|
||||
|
@ -1850,6 +1850,7 @@ void BIH_Build (model_t *mod, struct bihleaf_s *leafs, size_t numleafs)
|
|||
mod->funcs.PointContents = BIH_PointContents;
|
||||
mod->funcs.NativeContents = BIH_NativeContents;
|
||||
}
|
||||
#ifdef SKELETALMODELS
|
||||
void BIH_BuildAlias (model_t *mod, galiasinfo_t *meshes)
|
||||
{
|
||||
size_t numleafs, i;
|
||||
|
@ -1883,3 +1884,4 @@ void BIH_BuildAlias (model_t *mod, galiasinfo_t *meshes)
|
|||
}
|
||||
BIH_Build(mod, leafs, leaf-leafs);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1160,6 +1160,9 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
|
|||
int endbone;
|
||||
int numbonegroups=0;
|
||||
|
||||
if (lastbone > inf->numbones)
|
||||
lastbone = inf->numbones;
|
||||
|
||||
for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++)
|
||||
{
|
||||
endbone = fstate->g[bonegroup].endbone;
|
||||
|
@ -1811,8 +1814,8 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
#endif
|
||||
mesh->xyz_array = meshcache.coords;
|
||||
|
||||
//we don't support meshes with one pose skeletal and annother not.
|
||||
//we don't support meshes with one group skeletal and annother not.
|
||||
//we don't support meshes with one pose skeletal and another not.
|
||||
//we don't support meshes with one group skeletal and another not.
|
||||
|
||||
#ifdef SKELETALMODELS
|
||||
meshcache.vbop = NULL;
|
||||
|
@ -1878,7 +1881,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
else
|
||||
{
|
||||
if (meshcache.bonecachetype != SKEL_ABSOLUTE)
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
|
||||
#ifndef SERVERONLY
|
||||
if (inf->shares_bones != surfnum && qrenderer)
|
||||
Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone);
|
||||
|
@ -1888,7 +1891,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
|
|||
else
|
||||
{
|
||||
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
|
||||
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
|
||||
|
||||
//hardware bone animation
|
||||
mesh->xyz_array = inf->ofs_skel_xyz;
|
||||
|
@ -2903,11 +2906,14 @@ typedef struct
|
|||
float fps;
|
||||
qboolean loop;
|
||||
int action;
|
||||
int actionweight;
|
||||
galiasevent_t *events;
|
||||
float actionweight;
|
||||
char name[MAX_QPATH];
|
||||
} frameinfo_t;
|
||||
static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
||||
static frameinfo_t *ParseFrameInfo(model_t *mod, int *numgroups)
|
||||
{
|
||||
const char *modelname = mod->name;
|
||||
|
||||
int count = 0;
|
||||
int maxcount = 0;
|
||||
char *line, *eol;
|
||||
|
@ -2917,11 +2923,84 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
char tok[MAX_FRAMEINFO_POSES * 4];
|
||||
size_t fsize;
|
||||
com_tokentype_t ttype;
|
||||
json_t *rootjson;
|
||||
Q_snprintfz(fname, sizeof(fname), "%s.framegroups", modelname);
|
||||
line = file = FS_LoadMallocFile(fname, &fsize);
|
||||
if (!file)
|
||||
return NULL;
|
||||
while(line && *line)
|
||||
|
||||
rootjson = JSON_Parse(file); //must be a fully valid json file, so any space-separated tokens from the dp format will return NULL here just fine.
|
||||
if (rootjson)
|
||||
{
|
||||
json_t *framegroups = JSON_FindChild(rootjson, "framegroups");
|
||||
maxcount = JSON_GetCount(framegroups);
|
||||
frames = realloc(frames, sizeof(*frames)*maxcount);
|
||||
for(count = 0; count < maxcount; count++)
|
||||
{
|
||||
galiasevent_t *ev, **link;
|
||||
char eventdata[65536];
|
||||
unsigned int posecount;
|
||||
json_t *arr, *c;
|
||||
json_t *in = JSON_GetIndexed(framegroups, count);
|
||||
if (!in)
|
||||
break; //erk? shouldn't really happen. not an issue though.
|
||||
|
||||
frames[count].firstpose = JSON_GetInteger(in, "firstpose", 0);
|
||||
frames[count].posecount = JSON_GetInteger(in, "numposes", 1);
|
||||
frames[count].posesarray = false;
|
||||
arr = JSON_FindChild(in, "poses");
|
||||
if (arr)
|
||||
{ //override with explicit poses, if specified.
|
||||
for (posecount = 0; posecount < countof(frames[count].poses); posecount++)
|
||||
{
|
||||
c = JSON_GetIndexed(arr, posecount);
|
||||
if (!c) //ran out of elements...
|
||||
break;
|
||||
frames[count].poses[posecount] = JSON_GetUInteger(c, NULL, 0);
|
||||
}
|
||||
if (posecount>0)
|
||||
{
|
||||
frames[count].posecount = posecount;
|
||||
frames[count].posesarray = true;
|
||||
}
|
||||
}
|
||||
|
||||
frames[count].fps = JSON_GetFloat(in, "fps", 20);
|
||||
if (frames[count].fps <= 0)
|
||||
frames[count].fps = 10;
|
||||
frames[count].loop = JSON_GetUInteger(in, "loop", false);
|
||||
|
||||
Q_snprintfz(frames[count].name,sizeof(frames[count].name), "%s[%d]", fname, count);
|
||||
JSON_GetString(in, "name", frames[count].name, sizeof(frames[count].name), NULL);
|
||||
|
||||
frames[count].action = JSON_GetInteger(in, "action", -1);
|
||||
frames[count].actionweight = JSON_GetFloat(in, "actionweight", 0);
|
||||
frames[count].events = NULL;
|
||||
|
||||
arr = JSON_FindChild(in, "events");
|
||||
for (posecount = 0; (c=JSON_GetIndexed(arr, posecount))!=NULL; posecount++)
|
||||
{
|
||||
*eventdata = 0;
|
||||
JSON_GetString(c, "value", eventdata,sizeof(eventdata), NULL);
|
||||
ev = ZG_Malloc(&mod->memgroup, sizeof(*ev) + strlen(eventdata)+1);
|
||||
ev->code = JSON_GetInteger(c, "code", 0);
|
||||
ev->timestamp = JSON_GetFloat(c, "timestamp", JSON_GetFloat(c, "pose", 0)/frames[count].fps);
|
||||
ev->data = strcpy((char*)(ev+1), eventdata);
|
||||
|
||||
link = &frames[count].events;
|
||||
while (*link && (*link)->timestamp <= ev->timestamp)
|
||||
link = &(*link)->next;
|
||||
ev->next = *link;
|
||||
*link = ev;
|
||||
}
|
||||
}
|
||||
|
||||
mod->flags = JSON_GetUInteger(rootjson, "modelflags", mod->flags);
|
||||
|
||||
|
||||
JSON_Destroy(rootjson);
|
||||
}
|
||||
else while(line && *line)
|
||||
{
|
||||
unsigned int posecount = 0;
|
||||
|
||||
|
@ -2961,6 +3040,7 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
else
|
||||
frames[count].loop = !!atoi(tok);
|
||||
|
||||
frames[count].events = NULL;
|
||||
frames[count].action = -1;
|
||||
frames[count].actionweight = 0;
|
||||
Q_snprintfz(frames[count].name, sizeof(frames[count].name), "groupified_%d_anim", count); //to match DP. frameforname cares.
|
||||
|
@ -2990,6 +3070,11 @@ static frameinfo_t *ParseFrameInfo(char *modelname, int *numgroups)
|
|||
BZ_Free(file);
|
||||
|
||||
*numgroups = count;
|
||||
if (!count)
|
||||
{
|
||||
free(frames);
|
||||
frames = NULL;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
@ -3985,10 +4070,10 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
|
|||
#endif
|
||||
|
||||
static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
|
||||
{
|
||||
{ //use ONLY with vertex models.
|
||||
unsigned int numanims, a, p, g, oldnumanims = galias->numanimations, targpose;
|
||||
galiasanimation_t *o, *oldanims = galias->ofsanimations, *frame;
|
||||
frameinfo_t *framegroups = ParseFrameInfo(mod->name, &numanims);
|
||||
frameinfo_t *framegroups = ParseFrameInfo(mod, &numanims);
|
||||
if (framegroups)
|
||||
{
|
||||
galias->ofsanimations = o = ZG_Malloc(&mod->memgroup, sizeof(*galias->ofsanimations) * numanims);
|
||||
|
@ -4014,8 +4099,9 @@ static void Mesh_HandleFramegroupsFile(model_t *mod, galiasinfo_t *galias)
|
|||
o->numposes = p;
|
||||
o->rate = framegroups[a].fps;
|
||||
o->loop = framegroups[a].loop;
|
||||
o->action = -1;
|
||||
o->actionweight = 0;
|
||||
o->events = framegroups[a].events;
|
||||
o->action = framegroups[a].action;
|
||||
o->actionweight = framegroups[a].actionweight;
|
||||
Q_strncpyz(o->name, framegroups[a].name, sizeof(o->name));
|
||||
}
|
||||
galias->numanimations = numanims;
|
||||
|
@ -5128,25 +5214,23 @@ int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, const gali
|
|||
galiasbone_t *Mod_GetBoneInfo(model_t *model, int *numbones)
|
||||
{
|
||||
#ifdef SKELETALMODELS
|
||||
galiasbone_t *bone;
|
||||
galiasinfo_t *inf;
|
||||
|
||||
|
||||
if (!model || model->type != mod_alias)
|
||||
if (model && model->type == mod_alias)
|
||||
{
|
||||
*numbones = 0;
|
||||
return NULL;
|
||||
galiasinfo_t *inf = Mod_Extradata(model);
|
||||
*numbones = inf->numbones;
|
||||
return inf->ofsbones;
|
||||
}
|
||||
|
||||
inf = Mod_Extradata(model);
|
||||
|
||||
bone = inf->ofsbones;
|
||||
*numbones = inf->numbones;
|
||||
return bone;
|
||||
#else
|
||||
#endif
|
||||
#ifdef HALFLIFEMODELS
|
||||
if (model && model->type == mod_halflife)
|
||||
{
|
||||
hlmodel_t *hlmod = Mod_Extradata(model);
|
||||
*numbones = hlmod->header->numbones;
|
||||
return hlmod->compatbones;
|
||||
}
|
||||
#endif
|
||||
*numbones = 0;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Mod_GetBoneParent(model_t *model, int bonenum)
|
||||
|
@ -6014,7 +6098,7 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
externalskins = Mod_CountSkinFiles(mod);
|
||||
#endif
|
||||
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
|
||||
ClearBounds(min, max);
|
||||
|
||||
|
@ -6087,46 +6171,6 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
tvector = (vec3_t*)(svector + numverts*numposes);
|
||||
#endif
|
||||
|
||||
if (framegroups)
|
||||
{ //group the poses into animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
int first = framegroups[i].firstpose, count = framegroups[i].posecount;
|
||||
if (first >= numposes) //bound the numbers.
|
||||
first = numposes-1;
|
||||
if (first < 0)
|
||||
first = 0;
|
||||
if (count > numposes-first)
|
||||
count = numposes-first;
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
Q_snprintfz(group->name, sizeof(group->name), "%s", framegroups[i].name);
|
||||
group->numposes = count;
|
||||
group->rate = framegroups[i].fps;
|
||||
group->poseofs = pose + first;
|
||||
group->loop = framegroups[i].loop;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //raw poses, no animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "frame%i", i);
|
||||
group->numposes = 1;
|
||||
group->rate = 1;
|
||||
group->poseofs = pose + i;
|
||||
group->loop = false;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
|
||||
//load in that per-pose data
|
||||
invert = (md3XyzNormal_t *)((qbyte*)surf + LittleLong(surf->ofsXyzNormals));
|
||||
for (i = 0; i < numposes; i++)
|
||||
|
@ -6172,6 +6216,64 @@ static galiasinfo_t *Mod_LoadQ3ModelLod(model_t *mod, int *surfcount, void *buff
|
|||
#endif
|
||||
pose++;
|
||||
}
|
||||
pose -= numposes;
|
||||
|
||||
if (framegroups)
|
||||
{ //group the poses into animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "%s", framegroups[i].name);
|
||||
|
||||
if (framegroups[i].posesarray)
|
||||
{
|
||||
unsigned int p, targpose;
|
||||
group->poseofs = ZG_Malloc(&mod->memgroup, sizeof(*group->poseofs) * framegroups[i].posecount);
|
||||
group->numposes = 0;
|
||||
for (p = 0; p < framegroups[i].posecount; p++)
|
||||
{
|
||||
targpose = framegroups[i].poses[p];
|
||||
if (targpose < numposes)
|
||||
group->poseofs[group->numposes++] = pose[targpose];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int first = framegroups[i].firstpose, count = framegroups[i].posecount;
|
||||
if (first >= numposes) //bound the numbers.
|
||||
first = numposes-1;
|
||||
if (first < 0)
|
||||
first = 0;
|
||||
if (count > numposes-first)
|
||||
count = numposes-first;
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
group->poseofs = pose + first;
|
||||
group->numposes = count;
|
||||
}
|
||||
|
||||
group->rate = framegroups[i].fps;
|
||||
group->loop = framegroups[i].loop;
|
||||
group->events = framegroups[i].events;
|
||||
group->action = framegroups[i].action;
|
||||
group->actionweight = framegroups[i].actionweight;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //raw poses, no animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
Q_snprintfz(group->name, sizeof(group->name), "frame%i", i);
|
||||
group->numposes = 1;
|
||||
group->rate = 1;
|
||||
group->poseofs = pose + i;
|
||||
group->loop = false;
|
||||
group->events = NULL;
|
||||
group->action = -1;
|
||||
group->actionweight = 0;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVERONLY
|
||||
if (externalskins<LittleLong(surf->numShaders))
|
||||
|
@ -7160,7 +7262,7 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
if (animinfo && animkeys)
|
||||
{
|
||||
int numgroups = 0;
|
||||
frameinfo_t *frameinfo = ParseFrameInfo(mod->name, &numgroups);
|
||||
frameinfo_t *frameinfo = ParseFrameInfo(mod, &numgroups);
|
||||
if (numgroups)
|
||||
{
|
||||
/*externally supplied listing of frames. ignore all framegroups in the model and use only the pose info*/
|
||||
|
@ -7169,6 +7271,8 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
for (j = 0; j < numgroups; j++)
|
||||
{
|
||||
/*bound check*/
|
||||
if (frameinfo[j].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_LoadPSKModel(%s): framegroup[%i] poses array not suppported\n", mod->name, j);
|
||||
if (frameinfo[j].firstpose+frameinfo[j].posecount > num_animkeys)
|
||||
frameinfo[j].posecount = num_animkeys - frameinfo[j].firstpose;
|
||||
if (frameinfo[j].firstpose >= num_animkeys)
|
||||
|
@ -7186,8 +7290,9 @@ static qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
group[j].loop = frameinfo[j].loop;
|
||||
group[j].rate = frameinfo[j].fps;
|
||||
group[j].skeltype = SKEL_RELATIVE;
|
||||
group[j].action = -1;
|
||||
group[j].actionweight = 0;
|
||||
group[j].events = frameinfo[j].events;
|
||||
group[j].action = frameinfo[j].action;
|
||||
group[j].actionweight = frameinfo[j].actionweight;
|
||||
}
|
||||
num_animinfo = numgroups;
|
||||
}
|
||||
|
@ -7537,7 +7642,7 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
|
|||
//throw away the flags.
|
||||
}
|
||||
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
if (!framegroups)
|
||||
{ //use the dpm's poses directly.
|
||||
numgroups = header->num_frames;
|
||||
|
@ -7596,14 +7701,16 @@ static qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer, size_t
|
|||
numposes = 0;
|
||||
if (firstpose + numposes > header->num_frames)
|
||||
numposes = header->num_frames - firstpose;
|
||||
if (framegroups[i].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_LoadDarkPlacesModel(%s): No support for explicit pose lists\n", mod->name);
|
||||
outgroups[i].skeltype = SKEL_RELATIVE;
|
||||
outgroups[i].boneofs = outposedata + firstpose*header->num_bones*12;
|
||||
outgroups[i].numposes = numposes;
|
||||
outgroups[i].loop = framegroups[i].loop;
|
||||
outgroups[i].rate = framegroups[i].fps;
|
||||
outgroups[i].events = NULL;
|
||||
outgroups[i].action = -1;
|
||||
outgroups[i].actionweight = 0;
|
||||
outgroups[i].events = framegroups[i].events;
|
||||
outgroups[i].action = framegroups[i].action;
|
||||
outgroups[i].actionweight = framegroups[i].actionweight;
|
||||
Q_strncpyz(outgroups[i].name, framegroups[i].name, sizeof(outgroups[i].name));
|
||||
}
|
||||
}
|
||||
|
@ -8406,7 +8513,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
numgroups = 0;
|
||||
framegroups = NULL;
|
||||
if (!numgroups)
|
||||
framegroups = ParseFrameInfo(mod->name, &numgroups);
|
||||
framegroups = ParseFrameInfo(mod, &numgroups);
|
||||
if (!numgroups && h->num_anims)
|
||||
{
|
||||
/*use the model's framegroups*/
|
||||
|
@ -8421,6 +8528,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
framegroups[i].posecount = LittleLong(anim[i].num_frames);
|
||||
framegroups[i].fps = LittleFloat(anim[i].framerate);
|
||||
framegroups[i].loop = !!(LittleLong(anim[i].flags) & IQM_LOOP);
|
||||
framegroups[i].events = NULL;
|
||||
framegroups[i].action = -1;
|
||||
framegroups[i].actionweight = 0;
|
||||
Q_strncpyz(framegroups[i].name, Mod_IQMString(&strings, anim[i].name), sizeof(fgroup[i].name));
|
||||
|
@ -8437,6 +8545,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
framegroups->posecount = 1;
|
||||
framegroups->fps = 10;
|
||||
framegroups->loop = 1;
|
||||
framegroups->events = NULL;
|
||||
framegroups->action = -1;
|
||||
framegroups->actionweight = 0;
|
||||
strcpy(framegroups->name, "base");
|
||||
|
@ -8606,6 +8715,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
//now generate the animations.
|
||||
for (i = 0; i < numgroups; i++)
|
||||
{
|
||||
if (framegroups[i].posesarray)
|
||||
Con_Printf(CON_WARNING"Mod_ParseIQMMeshModel(%s): framegroup[%i] poses array not suppported\n", mod->name, i);
|
||||
if (framegroups[i].firstpose + framegroups[i].posecount > h->num_frames)
|
||||
framegroups[i].posecount = h->num_frames - framegroups[i].firstpose;
|
||||
if (framegroups[i].firstpose >= h->num_frames)
|
||||
|
@ -8629,6 +8740,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz
|
|||
if (fgroup[i].rate <= 0)
|
||||
fgroup[i].rate = 10;
|
||||
|
||||
fgroup[i].events = framegroups[i].events;
|
||||
fgroup[i].action = framegroups[i].action;
|
||||
fgroup[i].actionweight = framegroups[i].actionweight;
|
||||
}
|
||||
|
|
|
@ -5970,6 +5970,7 @@ static void COM_Version_f (void)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SERVER) || defined(HAVE_CLIENT)
|
||||
Con_Printf("^3Games:^7");
|
||||
#if defined(Q3SERVER) && defined(Q3CLIENT)
|
||||
#ifdef BOTLIB_STATIC
|
||||
|
@ -6030,6 +6031,7 @@ static void COM_Version_f (void)
|
|||
Con_Printf(" ssqc");
|
||||
#endif
|
||||
Con_Printf("\n");
|
||||
#endif
|
||||
|
||||
Con_Printf("^3Networking:^7");
|
||||
#ifdef WEBCLIENT
|
||||
|
@ -6043,14 +6045,16 @@ static void COM_Version_f (void)
|
|||
#endif
|
||||
#if (defined(SUPPORT_ICE)&&defined(HAVE_DTLS)) || defined(FTE_TARGET_WEB)
|
||||
Con_Printf(" WebRTC");
|
||||
#elif defined(SUPPORT_ICE)
|
||||
Con_Printf(" ICE");
|
||||
#endif
|
||||
#ifdef FTE_TARGET_WEB
|
||||
Con_Printf(" WebSocket/WSS");
|
||||
#else
|
||||
#if defined(HAVE_TCP)
|
||||
#ifdef TCPCONNECT
|
||||
Con_Printf(" TCPConnect");
|
||||
#endif
|
||||
#ifdef TCPCONNECT
|
||||
Con_Printf(" TCPConnect");
|
||||
#endif
|
||||
#else
|
||||
Con_Printf(" ^h(disabled: TCP)");
|
||||
#endif
|
||||
|
@ -6060,9 +6064,6 @@ static void COM_Version_f (void)
|
|||
#endif
|
||||
#ifdef HAVE_WINSSPI //on windows
|
||||
Con_Printf(" WINSSPI");
|
||||
#endif
|
||||
#ifdef SUPPORT_ICE
|
||||
Con_Printf(" ICE");
|
||||
#endif
|
||||
Con_Printf("\n");
|
||||
}
|
||||
|
@ -6364,6 +6365,9 @@ static int COM_WorkerThread(void *arg)
|
|||
}
|
||||
static void Sys_ErrorThread(void *ctx, void *data, size_t a, size_t b)
|
||||
{
|
||||
if (ctx)
|
||||
COM_WorkerSync_WorkerStopped(ctx, NULL, a, b);
|
||||
|
||||
//posted to main thread from a worker.
|
||||
Sys_Error("%s", (const char*)data);
|
||||
}
|
||||
|
@ -6383,12 +6387,12 @@ void COM_WorkerAbort(char *message)
|
|||
if (com_worker[us].thread && Sys_IsThread(com_worker[us].thread))
|
||||
{
|
||||
group = WG_LOADER;
|
||||
COM_AddWork(WG_MAIN, COM_WorkerSync_WorkerStopped, &com_worker[us], NULL, 0, group);
|
||||
COM_InsertWork(WG_MAIN, Sys_ErrorThread, &com_worker[us], Z_StrDup(message), 0, group);
|
||||
break;
|
||||
}
|
||||
|
||||
//now tell the main thread that it should be crashing, and why.
|
||||
COM_AddWork(WG_MAIN, Sys_ErrorThread, NULL, Z_StrDup(message), 0, 0);
|
||||
if (us == WORKERTHREADS) //don't know who it was.
|
||||
COM_AddWork(WG_MAIN, Sys_ErrorThread, NULL, Z_StrDup(message), 0, 0);
|
||||
|
||||
Sys_ThreadAbort();
|
||||
}
|
||||
|
@ -6416,11 +6420,10 @@ void COM_DestroyWorkerThread(void)
|
|||
|
||||
while(COM_DoWork(WG_LOADER, false)) //finish any work that got posted to it that it neglected to finish.
|
||||
;
|
||||
COM_WorkerFullSync();
|
||||
while(COM_DoWork(WG_MAIN, false))
|
||||
;
|
||||
|
||||
COM_WorkerFullSync();
|
||||
|
||||
for (i = 0; i < WG_COUNT; i++)
|
||||
{
|
||||
if (com_workercondition[i])
|
||||
|
@ -6435,33 +6438,35 @@ void COM_DestroyWorkerThread(void)
|
|||
//Dangerous: stops workers WITHOUT flushing their queue. Be SURE to 'unlock' to start them up again.
|
||||
void COM_WorkerLock(void)
|
||||
{
|
||||
#define NOFLUSH 0x40000000
|
||||
int i;
|
||||
if (!com_liveworkers[WG_LOADER])
|
||||
return; //nothing to do.
|
||||
|
||||
//add a fake worker and ask workers to die
|
||||
//don't let liveworkers become 0 (so the main thread doesn't flush any pending work) and ask workers to die
|
||||
Sys_LockConditional(com_workercondition[WG_LOADER]);
|
||||
com_liveworkers[WG_LOADER] += 1;
|
||||
com_liveworkers[WG_LOADER] |= NOFLUSH;
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
com_worker[i].request = WR_DIE; //flag them all to die
|
||||
Sys_ConditionBroadcast(com_workercondition[WG_LOADER]); //and make sure they ALL wake up to check their new death values.
|
||||
Sys_UnlockConditional(com_workercondition[WG_LOADER]);
|
||||
|
||||
//wait for the workers to stop (leaving their work, because of our fake worker)
|
||||
while(com_liveworkers[WG_LOADER]>1)
|
||||
while((com_liveworkers[WG_LOADER]&~NOFLUSH)>0)
|
||||
{
|
||||
if (!COM_DoWork(WG_MAIN, false)) //need to check this to know they're done.
|
||||
COM_DoWork(WG_LOADER, false); //might as well, while we're waiting.
|
||||
}
|
||||
|
||||
//remove our fake worker now...
|
||||
//remove our flush-blocker now...
|
||||
Sys_LockConditional(com_workercondition[WG_LOADER]);
|
||||
com_liveworkers[WG_LOADER] -= 1;
|
||||
com_liveworkers[WG_LOADER] &= ~NOFLUSH;
|
||||
Sys_UnlockConditional(com_workercondition[WG_LOADER]);
|
||||
}
|
||||
//called after COM_WorkerLock
|
||||
void COM_WorkerUnlock(void)
|
||||
{
|
||||
qboolean restarted = false;
|
||||
int i;
|
||||
for (i = 0; i < WORKERTHREADS; i++)
|
||||
{
|
||||
|
@ -6473,8 +6478,14 @@ void COM_WorkerUnlock(void)
|
|||
{
|
||||
com_worker[i].request = WR_NONE;
|
||||
com_worker[i].thread = Sys_CreateThread(va("loadworker_%i", i), COM_WorkerThread, &com_worker[i], 0, 256*1024);
|
||||
if (com_worker[i].thread)
|
||||
restarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!restarted)
|
||||
while (COM_DoWork(WG_LOADER, false))
|
||||
;
|
||||
}
|
||||
|
||||
//fully flushes ALL pending work.
|
||||
|
@ -6709,6 +6720,19 @@ static void COM_InitWorkerThread(void)
|
|||
Cvar_ForceCallback(&worker_count);
|
||||
}
|
||||
|
||||
qboolean FTE_AtomicPtr_ConditionalReplace(qint32_t *ptr, qint32_t old, qint32_t new)
|
||||
{
|
||||
Sys_LockMutex(com_resourcemutex);
|
||||
if (*ptr == old)
|
||||
{
|
||||
*ptr = new;
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
return true;
|
||||
}
|
||||
Sys_UnlockMutex(com_resourcemutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
qint32_t FTE_Atomic32Mutex_Add(qint32_t *ptr, qint32_t change)
|
||||
{
|
||||
qint32_t r;
|
||||
|
@ -6724,6 +6748,15 @@ qint32_t FTE_Atomic32Mutex_Add(qint32_t *ptr, qint32_t change)
|
|||
r = (*ptr += change);
|
||||
return r;
|
||||
}
|
||||
qboolean FTE_AtomicPtr_ConditionalReplace(qint32_t *ptr, qint32_t old, qint32_t new)
|
||||
{ //hope it ain't threaded
|
||||
if (*ptr == old)
|
||||
{
|
||||
*ptr = new;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
@ -201,11 +201,11 @@ typedef enum {
|
|||
} sbpacking_t;
|
||||
typedef struct sizebuf_s
|
||||
{
|
||||
qboolean allowoverflow; // if false, do a Sys_Error
|
||||
qboolean overflowed; // set to true if the buffer size failed
|
||||
qbyte *data;
|
||||
int maxsize; //storage size of data
|
||||
int cursize; //assigned size of data
|
||||
qboolean allowoverflow; // if false, do a Sys_Error
|
||||
qboolean overflowed; // set to true if the buffer size failed
|
||||
sbpacking_t packing; //required for q3
|
||||
int currentbit; //ignored for rawbytes
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
//#define GAME_DOWNLOADSURL NULL //url for the package manger to update from
|
||||
//#define GAME_DEFAULTCMDS NULL //a string containing the things you want to exec in order to override default.cfg
|
||||
|
||||
//#define ENGINE_HAS_ZIP //when defined, the engine is effectively a self-extrating zip with the gamedata zipped onto the end (if it in turn contains nested packages then they should probably be STOREd pk3s)
|
||||
|
||||
// Allowed renderers... There should ONLY be undefs here (other C files won't be pulled in automatically)
|
||||
//#undef GLQUAKE
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#define MULTITHREAD //misc basic multithreading - dsound, downloads, basic stuff that's unlikely to have race conditions.
|
||||
#define LOADERTHREAD //worker threads for loading misc stuff. falls back on main thread if not supported.
|
||||
#define AVAIL_DINPUT
|
||||
#define MAX_CLIENTS 32 //32 for vanilla qw. max 255.
|
||||
//#define SIDEVIEWS 4 //enable secondary/reverse views.
|
||||
//#define MAX_SPLITS 4u
|
||||
#define VERTEXINDEXBYTES 2 //16bit indexes work everywhere but may break some file types, 32bit indexes are optional in gles<=2 and d3d<=9 and take more memory/copying but allow for bigger batches/models. Plugins need to be compiled the same way so this is no longer set per-renderer.
|
||||
|
|
|
@ -21,13 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
// console
|
||||
//
|
||||
|
||||
// undefine this to solve build issues with epoll-shim - Brad
|
||||
#if defined(__unix__) && !defined(__linux__) && !defined(__CYGWIN__)
|
||||
#ifdef close
|
||||
#undef close
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAXCONCOLOURS 16
|
||||
typedef struct {
|
||||
float fr, fg, fb;
|
||||
|
@ -251,6 +244,9 @@ char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink, qb
|
|||
void Con_Print (const char *txt);
|
||||
void Con_CenterPrint(const char *txt);
|
||||
void Con_PrintFlags(const char *text, unsigned int setflags, unsigned int clearflags);
|
||||
#ifdef HAVE_CLIENT
|
||||
void Con_HexDump(qbyte *packet, size_t len, size_t badoffset, size_t stride);
|
||||
#endif
|
||||
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); //developer>=1, for stuff that's probably actually slightly useful
|
||||
|
|
|
@ -998,9 +998,10 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
|
|||
if (var->flags & CVAR_USERINFO)
|
||||
{
|
||||
char *old = InfoBuf_ValueForKey(&cls.userinfo[0], var->name);
|
||||
if (strcmp(old, value)) //only spam the server if it actually changed
|
||||
const char *corruptval = TP_ParseFunChars(value);
|
||||
if (strcmp(old, corruptval)) //only spam the server if it actually changed
|
||||
{ //this helps with config execs
|
||||
InfoBuf_SetKey (&cls.userinfo[0], var->name, value);
|
||||
InfoBuf_SetKey (&cls.userinfo[0], var->name, corruptval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1687,7 +1688,7 @@ Writes lines containing "set variable value" for all variables
|
|||
with the archive flag set to true.
|
||||
============
|
||||
*/
|
||||
void Cvar_WriteVariables (vfsfile_t *f, qboolean all)
|
||||
void Cvar_WriteVariables (vfsfile_t *f, qboolean all, qboolean nohidden)
|
||||
{
|
||||
qboolean writtengroupheader;
|
||||
cvar_group_t *grp;
|
||||
|
@ -1705,6 +1706,8 @@ void Cvar_WriteVariables (vfsfile_t *f, qboolean all)
|
|||
//yeah, don't force-save readonly cvars.
|
||||
if (var->flags & (CVAR_NOSET|CVAR_NOSAVE))
|
||||
continue;
|
||||
if (nohidden && (var->flags & CVAR_NOUNSAFEEXPAND))
|
||||
continue;
|
||||
|
||||
if (!writtengroupheader)
|
||||
{
|
||||
|
|
|
@ -213,7 +213,7 @@ qboolean Cvar_Command (cvar_t *v, int level);
|
|||
// command. Returns true if the command was a variable reference that
|
||||
// was handled. (print or change)
|
||||
|
||||
void Cvar_WriteVariables (vfsfile_t *f, qboolean all);
|
||||
void Cvar_WriteVariables (vfsfile_t *f, qboolean all, qboolean nohidden);
|
||||
// Writes lines containing "set variable value" for all variables
|
||||
// with the archive flag set to true.
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ static char *vidfilenames[] = //list of filenames to check to see if graphics st
|
|||
/*set some stuff so our regular qw client appears more like hexen2. sv_mintic must be 0.015 to 'fix' the ravenstaff so that its projectiles don't impact upon each other, or even 0.05 to exactly match the hardcoded assumptions in obj_push. There's maps that depend on a low framerate via waterjump framerate-dependance too.*/
|
||||
#define HEX2CFG "//schemes hexen2\n" "set v_gammainverted 1\nset com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset cl_forwardspeed 200\nset cl_backspeed 200\ncl_sidespeed 225\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.05\nset r_meshpitch -1\nset r_meshroll -1\nr_sprite_backfacing 1\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc/hith2o.wav\"\nsv_sound_land \"fx/thngland.wav\"\nset sv_walkpitch 0\n"
|
||||
/*yay q2!*/
|
||||
#define Q2CFG "//schemes quake2\n" "set v_gammainverted 1\nset com_parseutf8 0\ncom_gamedirnativecode 1\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)" "STRINGIFY(PORT_Q2EXSERVER)"\ncl_defaultport "STRINGIFY(PORT_Q2SERVER)"\n" \
|
||||
#define Q2CFG "//schemes quake2\n" "set com_protocolversion "STRINGIFY(PROTOCOL_VERSION_Q2)"\nset v_gammainverted 1\nset com_parseutf8 0\ncom_gamedirnativecode 1\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)" "STRINGIFY(PORT_Q2EXSERVER)"\ncl_defaultport "STRINGIFY(PORT_Q2SERVER)"\n" \
|
||||
"set r_replacemodels " IFMINIMAL("","md3 md5mesh")"\n" \
|
||||
"set r_glsl_emissive 0\n" /*work around the _glow textures not being meant to glow*/
|
||||
/*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/
|
||||
|
@ -364,7 +364,7 @@ char *VFS_GETS(vfsfile_t *vf, char *buffer, size_t buflen)
|
|||
void VARGS VFS_PRINTF(vfsfile_t *vf, const char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
char string[2048];
|
||||
|
||||
va_start (argptr, format);
|
||||
vsnprintf (string,sizeof(string)-1, format,argptr);
|
||||
|
@ -1119,7 +1119,7 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man)
|
|||
char *sl = strchr(newdir+6, '/');
|
||||
if (!sl)
|
||||
break; //malformed steam link
|
||||
man->gamepath[i].flags |= GAMEDIR_STEAMGAME;
|
||||
man->gamepath[i].flags |= GAMEDIR_PRIVATE|GAMEDIR_STEAMGAME;
|
||||
*sl = 0;
|
||||
if (!FS_GamedirIsOkay(sl+1))
|
||||
break;
|
||||
|
@ -1464,6 +1464,9 @@ static void COM_Path_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (fs_hidesyspaths.ival)
|
||||
Con_Printf("External paths are hidden, ^[click to unhide\\type\\set fs_hidesyspaths 0;path^]\n");
|
||||
|
||||
if (com_purepaths || fs_puremode)
|
||||
{
|
||||
Con_Printf ("Pure paths:\n");
|
||||
|
@ -1915,6 +1918,51 @@ static void FS_FlushFSHashReally(qboolean domutexes)
|
|||
}
|
||||
}
|
||||
|
||||
static void QDECL FS_AddFileHashUnsafe(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)
|
||||
{
|
||||
//threading stuff is fucked.
|
||||
fsbucket_t *old;
|
||||
|
||||
old = Hash_GetInsensitiveBucket(&filesystemhash, fname);
|
||||
|
||||
if (old)
|
||||
{
|
||||
fs_hash_dups++;
|
||||
if (depth >= old->depth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//remove the old version
|
||||
//FIXME: needs to be atomic. just live with multiple in there.
|
||||
//Hash_RemoveBucket(&filesystemhash, fname, &old->buck);
|
||||
}
|
||||
|
||||
if (!filehandle)
|
||||
{
|
||||
int nlen = strlen(fname)+1;
|
||||
int plen = sizeof(*filehandle)+nlen;
|
||||
plen = (plen+fte_alignof(fsbucket_t)-1) & ~(fte_alignof(fsbucket_t)-1);
|
||||
if (!fs_hash_filebuckets || fs_hash_filebuckets->used+plen > fs_hash_filebuckets->total)
|
||||
{
|
||||
void *o = fs_hash_filebuckets;
|
||||
fs_hash_filebuckets = Z_Malloc(65536);
|
||||
fs_hash_filebuckets->total = 65536 - sizeof(*fs_hash_filebuckets);
|
||||
fs_hash_filebuckets->prev = o;
|
||||
}
|
||||
filehandle = (fsbucket_t*)(fs_hash_filebuckets->data+fs_hash_filebuckets->used);
|
||||
fs_hash_filebuckets->used += plen;
|
||||
|
||||
if (!filehandle)
|
||||
return; //eep!
|
||||
memcpy((char*)(filehandle+1), fname, nlen);
|
||||
fname = (char*)(filehandle+1);
|
||||
}
|
||||
filehandle->depth = depth;
|
||||
|
||||
Hash_AddInsensitive(&filesystemhash, fname, pathhandle, &filehandle->buck);
|
||||
fs_hash_files++;
|
||||
}
|
||||
static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)
|
||||
{
|
||||
fsbucket_t *old;
|
||||
|
@ -2677,7 +2725,7 @@ static qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, ch
|
|||
Q_snprintfz(out, outlen, "$bindir/%s", fname+strlen(host_parms.binarydir));
|
||||
#ifdef FTE_LIBRARY_PATH
|
||||
else if (!strncmp(fname, STRINGIFY(FTE_LIBRARY_PATH)"/", strlen(STRINGIFY(FTE_LIBRARY_PATH)"/"))) //FS_LIBRARYDIR
|
||||
Q_snprintfz(out, outlen, "$libdir/%s", fname+strlen(host_parms.binarydir));
|
||||
Q_snprintfz(out, outlen, "$libdir/%s", fname+strlen(STRINGIFY(FTE_LIBRARY_PATH)"/"));
|
||||
#endif
|
||||
else //should try bindir
|
||||
Q_snprintfz(out, outlen, "$system/%s", COM_SkipPath(fname)); //FS_SYSTEM :(
|
||||
|
@ -2685,11 +2733,13 @@ static qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, ch
|
|||
else
|
||||
Q_snprintfz(out, outlen, "%s", fname);
|
||||
|
||||
#ifdef _WIN32
|
||||
for (; *out; out++)
|
||||
{
|
||||
if (*out == '\\')
|
||||
*out = '/';
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4250,20 +4300,37 @@ static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purep
|
|||
|
||||
if (flags & (SPF_TEMPORARY|SPF_SERVER))
|
||||
{
|
||||
int depth = 1;
|
||||
searchpath_t *s;
|
||||
//add at end. pureness will reorder if needed.
|
||||
link = &com_searchpaths;
|
||||
while(*link)
|
||||
{
|
||||
link = &(*link)->next;
|
||||
}
|
||||
|
||||
if (com_purepaths)
|
||||
{ //go for the pure paths first.
|
||||
for (s = com_purepaths; s; s = s->nextpure)
|
||||
depth++;
|
||||
}
|
||||
if (fs_puremode < 2)
|
||||
{
|
||||
for (s = com_searchpaths ; s ; s = s->next)
|
||||
depth++;
|
||||
}
|
||||
*link = search;
|
||||
|
||||
if (filesystemhash.numbuckets)
|
||||
search->handle->BuildHash(search->handle, depth, FS_AddFileHashUnsafe);
|
||||
}
|
||||
else
|
||||
{
|
||||
search->next = com_searchpaths;
|
||||
com_searchpaths = search;
|
||||
|
||||
com_fschanged = true; //depth values are screwy
|
||||
}
|
||||
com_fschanged = true;
|
||||
|
||||
return search;
|
||||
}
|
||||
|
@ -5185,6 +5252,19 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
|
|||
com_base_searchpaths = NULL;
|
||||
gameonly_gamedir = gameonly_homedir = NULL;
|
||||
|
||||
#if defined(ENGINE_HAS_ZIP) && defined(PACKAGE_PK3)
|
||||
{
|
||||
searchpathfuncs_t *pak;
|
||||
vfsfile_t *vfs;
|
||||
vfs = VFSOS_Open(com_argv[0], "rb");
|
||||
pak = FSZIP_LoadArchive(vfs, NULL, com_argv[0], com_argv[0], "");
|
||||
if (pak) //logically should have SPF_EXPLICIT set, but that would give it a worse gamedir depth
|
||||
{
|
||||
FS_AddPathHandle(&oldpaths, "", com_argv[0], pak, "", SPF_COPYPROTECTED, reloadflags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LEGACY) && defined(PACKAGE_PK3)
|
||||
{
|
||||
searchpathfuncs_t *pak;
|
||||
|
@ -6509,6 +6589,41 @@ static ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedir
|
|||
man->security = MANIFEST_SECURITY_DEFAULT;
|
||||
}
|
||||
|
||||
#if defined(ENGINE_HAS_ZIP) && defined(PACKAGE_PK3)
|
||||
if (!man && game == -1)
|
||||
{
|
||||
searchpathfuncs_t *pak;
|
||||
vfsfile_t *vfs;
|
||||
vfs = VFSOS_Open(com_argv[0], "rb");
|
||||
pak = FSZIP_LoadArchive(vfs, NULL, com_argv[0], com_argv[0], "");
|
||||
if (pak)
|
||||
{
|
||||
flocation_t loc;
|
||||
if (pak->FindFile(pak, &loc, "default.fmf", NULL))
|
||||
{
|
||||
f = pak->OpenVFS(pak, &loc, "rb");
|
||||
if (f)
|
||||
{
|
||||
size_t len = VFS_GETLEN(f);
|
||||
char *fdata = BZ_Malloc(len+1);
|
||||
if (fdata)
|
||||
{
|
||||
VFS_READ(f, fdata, len);
|
||||
fdata[len] = 0;
|
||||
man = FS_Manifest_ReadMem(NULL, NULL, fdata);
|
||||
if (man)
|
||||
man->security = MANIFEST_SECURITY_DEFAULT;
|
||||
BZ_Free(fdata);
|
||||
}
|
||||
VFS_CLOSE(f);
|
||||
}
|
||||
}
|
||||
pak->ClosePath(pak);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-basepack is primarily an android feature
|
||||
i = COM_CheckParm ("-basepack");
|
||||
while (!man && game == -1 && i && i < com_argc-1)
|
||||
|
|
|
@ -2197,7 +2197,7 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in
|
|||
}
|
||||
|
||||
if (!result)
|
||||
Con_Printf("zip: unable to find end-of-central-directory\n");
|
||||
Con_Printf("%s: unable to find end-of-central-directory (not a zip?)\n", zip->filename); //usually just not a zip.
|
||||
else
|
||||
|
||||
//now look for a zip64 header.
|
||||
|
@ -2249,13 +2249,13 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in
|
|||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("zip: zip64 end-of-central directory at unknown offset.\n");
|
||||
Con_Printf("%s: zip64 end-of-central directory at unknown offset.\n", zip->filename);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (info->diskcount < 1 || info->zip64_centraldirend_disk != info->thisdisk)
|
||||
{
|
||||
Con_Printf("zip: archive is spanned\n");
|
||||
{ //must read the segment with the central directory.
|
||||
Con_Printf("%s: archive is spanned\n", zip->filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2264,13 +2264,13 @@ static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip, struct zipinfo *in
|
|||
}
|
||||
|
||||
if (info->thisdisk != info->centraldir_startdisk || info->centraldir_numfiles_disk != info->centraldir_numfiles_all)
|
||||
{
|
||||
Con_Printf("zip: archive is spanned\n");
|
||||
{ //must read the segment with the central directory.
|
||||
Con_Printf("%s: archive is spanned\n", zip->filename);
|
||||
result = false;
|
||||
}
|
||||
if (info->centraldir_compressionmethod || info->centraldir_algid)
|
||||
{
|
||||
Con_Printf("zip: encrypted centraldir\n");
|
||||
Con_Printf("%s: encrypted centraldir\n", zip->filename);
|
||||
result = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -416,8 +416,7 @@ void Netchan_Setup (unsigned int flags, netchan_t *chan, netadr_t *adr, int qpor
|
|||
#endif
|
||||
chan->incoming_unreliable = -1;
|
||||
|
||||
if (flags&NCF_CLIENT)
|
||||
chan->outgoing_sequence = 1; //so the first one doesn't get dropped.
|
||||
chan->outgoing_sequence = 1; //so the first one doesn't get dropped.
|
||||
|
||||
if (adr->prot == NP_KEXLAN)
|
||||
chan->qportsize = 0;
|
||||
|
@ -472,7 +471,11 @@ void Netchan_Setup (unsigned int flags, netchan_t *chan, netadr_t *adr, int qpor
|
|||
|
||||
chan->message.data = chan->message_buf;
|
||||
chan->message.allowoverflow = true;
|
||||
chan->message.maxsize = min(chan->mtu_cur, sizeof(chan->message_buf));
|
||||
|
||||
if ((flags&NCF_FRAGABLE) && NET_AddrIsReliable(adr))
|
||||
chan->message.maxsize = sizeof(chan->message_buf); //something big. might as well if its all tcp anyway.
|
||||
else
|
||||
chan->message.maxsize = min(chan->mtu_cur, sizeof(chan->message_buf));
|
||||
}
|
||||
|
||||
|
||||
|
@ -733,7 +736,7 @@ A 0 length will still generate a packet and deal with the reliable messages.
|
|||
*/
|
||||
int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
|
||||
{
|
||||
sizebuf_t send = {false};
|
||||
sizebuf_t send = {NULL};
|
||||
qbyte send_buf[MAX_OVERALLMSGLEN + PACKET_HEADER];
|
||||
qboolean send_reliable;
|
||||
char remote_adr[MAX_ADR_SIZE];
|
||||
|
|
|
@ -504,7 +504,6 @@ static qboolean TURN_AddXorAddressAttrib(sizebuf_t *buf, unsigned int attr, neta
|
|||
MSG_WriteByte(buf, ((qbyte*)&to->address)[aofs+i] ^ (buf->data+4)[i]);
|
||||
return true;
|
||||
}
|
||||
void Con_HexDump(qbyte *packet, size_t len, size_t badoffset);
|
||||
static qboolean TURN_AddAuth(sizebuf_t *buf, struct iceserver_s *srv)
|
||||
{ //adds auth info to a stun packet
|
||||
unsigned short len;
|
||||
|
@ -5373,59 +5372,8 @@ static void FTENET_ICE_Heartbeat(ftenet_ice_connection_t *b)
|
|||
#ifdef HAVE_SERVER
|
||||
if (b->generic.islisten)
|
||||
{
|
||||
extern cvar_t maxclients;
|
||||
char info[2048];
|
||||
int i;
|
||||
client_t *cl;
|
||||
int numclients = 0;
|
||||
for (i=0 ; i<svs.allocated_client_slots ; i++)
|
||||
{
|
||||
cl = &svs.clients[i];
|
||||
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && !cl->spectator)
|
||||
numclients++;
|
||||
}
|
||||
|
||||
*info = 0;
|
||||
|
||||
//first line contains the serverinfo, or some form of it
|
||||
{
|
||||
char *resp = info;
|
||||
const char *ignorekeys[] = {
|
||||
"maxclients", "map", "*gamedir", "*z_ext", //this is a DP protocol query, so some QW fields are not needed
|
||||
"gamename", "modname", "protocol", "clients", "sv_maxclients", "mapname", "qcstatus", "challenge", NULL}; //and we need to add some
|
||||
const char *prioritykeys[] = {"hostname", NULL}; //make sure we include these before we start overflowing
|
||||
char protocolname[64];
|
||||
const char *gamestatus;
|
||||
|
||||
COM_ParseOut(com_protocolname.string, protocolname, sizeof(protocolname)); //we can only report one, so report the first.
|
||||
if (svprogfuncs)
|
||||
{
|
||||
eval_t *v = PR_FindGlobal(svprogfuncs, "worldstatus", PR_ANY, NULL);
|
||||
if (v)
|
||||
gamestatus = PR_GetString(svprogfuncs, v->string);
|
||||
else
|
||||
gamestatus = "";
|
||||
}
|
||||
else
|
||||
gamestatus = "";
|
||||
|
||||
Info_SetValueForKey(resp, "gamename", protocolname, sizeof(info) - (resp-info));//distinguishes it from other types of games
|
||||
Info_SetValueForKey(resp, "protocol", SV_GetProtocolVersionString(), sizeof(info) - (resp-info));
|
||||
Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(info) - (resp-info));
|
||||
Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(info) - (resp-info));
|
||||
Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(info) - (resp-info));
|
||||
Info_SetValueForKey(resp, "mapname", InfoBuf_ValueForKey(&svs.info, "map"), sizeof(info) - (resp-info));
|
||||
resp += strlen(resp);
|
||||
//now include the full/regular serverinfo
|
||||
resp += InfoBuf_ToString(&svs.info, resp, sizeof(info) - (resp-info), prioritykeys, ignorekeys, NULL, NULL, NULL);
|
||||
*resp = 0;
|
||||
//and any possibly-long qc status string
|
||||
if (*gamestatus)
|
||||
Info_SetValueForKey(resp, "qcstatus", gamestatus, sizeof(info) - (resp-info));
|
||||
resp += strlen(resp);
|
||||
*resp++ = 0;
|
||||
}
|
||||
|
||||
SV_GeneratePublicServerinfo(info, info+sizeof(info));
|
||||
FTENET_ICE_SplurgeCmd(b, ICEMSG_SERVERINFO, -1, info);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//This file should be easily portable.
|
||||
//The biggest strength of this plugin system is that ALL interactions are performed via
|
||||
//named functions, this makes it *really* easy to port plugins from one engine to annother.
|
||||
//named functions, this makes it *really* easy to port plugins from one engine to another.
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "netinc.h"
|
||||
|
|
|
@ -26,10 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <sys/stat.h> //to delete the file/socket.
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) && !defined(__linux__) && !defined(__APPLE__) && !defined(__CYGWIN__)
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
extern ftemanifest_t *fs_manifest;
|
||||
|
||||
// Eww, eww. This is hacky but so is netinc.h, so bite me
|
||||
|
@ -93,7 +89,7 @@ static cvar_t net_enable_kexlobby = CVARD("net_enable_"KEXLOBBY, "0", "If en
|
|||
//#endif
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
static int epoll_fd = -1;
|
||||
int epoll_fd = -1;
|
||||
#endif
|
||||
|
||||
void NET_GetLocalAddress (int socket, netadr_t *out);
|
||||
|
@ -223,10 +219,16 @@ static void NET_TLS_Provider_Changed(struct cvar_s *var, char *oldvalue)
|
|||
}
|
||||
if (host_initialized && !var->ival)
|
||||
{
|
||||
Con_Printf("%s: \"%s\" not loaded, valid values are:", var->name, var->string);
|
||||
int found = 0;
|
||||
for (i = 0; i < cryptolib_count; i++)
|
||||
if (cryptolib[i])
|
||||
{
|
||||
if (!found++)
|
||||
Con_Printf("%s: \"%s\" not loaded, valid values are:", var->name, var->string);
|
||||
Con_Printf(" ^[%s\\type\\%s %s^]", cryptolib[i]->drivername, var->name, cryptolib[i]->drivername);
|
||||
}
|
||||
if (!found)
|
||||
Con_Printf("%s: no tls plugins loaded", var->name);
|
||||
Con_Printf("\n");
|
||||
}
|
||||
|
||||
|
@ -2899,6 +2901,7 @@ static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(ftenet_conne
|
|||
#endif
|
||||
|
||||
newcon->islisten = col->islisten;
|
||||
newcon->prot = adr.prot;
|
||||
newcon->addrtype[0] = NA_LOOPBACK;
|
||||
newcon->addrtype[1] = NA_INVALID;
|
||||
|
||||
|
@ -4387,6 +4390,7 @@ ftenet_generic_connection_t *FTENET_Datagram_EstablishConnection(ftenet_connecti
|
|||
|
||||
newcon->owner = col;
|
||||
newcon->islisten = isserver;
|
||||
newcon->prot = adr.prot;
|
||||
if (hybrid)
|
||||
{
|
||||
newcon->addrtype[0] = NA_IP;
|
||||
|
@ -5475,7 +5479,7 @@ enum
|
|||
WCATTR_ACCEPT_ENCODING,
|
||||
WCATTR_TRANSFER_ENCODING
|
||||
};
|
||||
typedef char httparg_t[64];
|
||||
typedef char httparg_t[256];
|
||||
#include "fs.h"
|
||||
#ifdef _WIN32
|
||||
#include "resource.h"
|
||||
|
@ -5711,7 +5715,7 @@ qboolean FTENET_TCP_HTTPResponse(ftenet_tcp_stream_t *st, httparg_t arg[WCATTR_C
|
|||
"{"
|
||||
"if (Module['sched'] === undefined)"
|
||||
"{" //our main function failed to set up the main loop. ie: main didn't get called. panic.
|
||||
"alert('Unable to initialise. You may need to restart your browser. If you get this often and inconsistently, consider using a 64bit browser instead.');"
|
||||
"alert('Unable to initialise. You may need to restart your browser.');"
|
||||
"Module.setStatus('Initialisation Failure');"
|
||||
"}"
|
||||
"}"
|
||||
|
@ -6117,7 +6121,7 @@ static const char *FTENET_TCP_ParseHTTPRequest(ftenet_tcp_connection_t *con, fte
|
|||
int websocketver = 0;
|
||||
qboolean acceptsgzip = false;
|
||||
qboolean sendingweirdness = false;
|
||||
char arg[WCATTR_COUNT][64];
|
||||
httparg_t arg[WCATTR_COUNT];
|
||||
|
||||
|
||||
if (!net_enable_http.ival && !net_enable_websockets.ival && !net_enable_rtcbroker.ival)
|
||||
|
@ -6134,7 +6138,7 @@ static const char *FTENET_TCP_ParseHTTPRequest(ftenet_tcp_connection_t *con, fte
|
|||
arg[i][0] = 0;
|
||||
for (i = 0; i < st->inlen; i++)
|
||||
{
|
||||
if (alen == 63)
|
||||
if (alen >= sizeof(arg[attr])-1)
|
||||
{
|
||||
Con_Printf("http request overflow from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
|
||||
//we need to respond, firefox will create 10 different connections if we just close it
|
||||
|
@ -6285,7 +6289,7 @@ static const char *FTENET_TCP_ParseHTTPRequest(ftenet_tcp_connection_t *con, fte
|
|||
websocketver = atoi(&st->inbuffer[j]);
|
||||
break;
|
||||
default:
|
||||
Q_strncpyz(arg[attr], &st->inbuffer[j], (i-j > 63)?64:(i - j + 1));
|
||||
Q_strncpyz(arg[attr], &st->inbuffer[j], (i-j >= sizeof(arg[attr]))?sizeof(arg[attr]):(i - j + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7867,6 +7871,7 @@ static qboolean FTENET_TCP_ChangeLocalAddress(struct ftenet_generic_connection_s
|
|||
n.scopeid = adr->scopeid;
|
||||
addrsize2 = NetadrToSockadr(&n, &cur);
|
||||
|
||||
con->prot = NP_STREAM;
|
||||
if ((bind(newsocket, (struct sockaddr *)&cur, addrsize2) != INVALID_SOCKET) &&
|
||||
(listen(newsocket, 2) != INVALID_SOCKET) &&
|
||||
ioctlsocket (newsocket, FIONBIO, &_true) != -1)
|
||||
|
@ -8026,6 +8031,7 @@ ftenet_generic_connection_t *FTENET_TCP_EstablishConnection(ftenet_connections_t
|
|||
newcon = Z_Malloc(sizeof(*newcon));
|
||||
newcon->generic.thesocket = newsocket = INVALID_SOCKET;
|
||||
|
||||
newcon->generic.prot = adr.prot;
|
||||
newcon->generic.addrtype[0] = adr.type;
|
||||
newcon->generic.addrtype[1] = NA_INVALID;
|
||||
|
||||
|
@ -8732,6 +8738,7 @@ struct ftenet_generic_connection_s *FTENET_IRCConnect_EstablishConnection(qboole
|
|||
newcon->generic.Close = FTENET_IRCConnect_Close;
|
||||
|
||||
newcon->generic.islisten = isserver;
|
||||
newcon->generic.prot = adr.prot;
|
||||
newcon->generic.addrtype[0] = NA_IRC;
|
||||
newcon->generic.addrtype[1] = NA_INVALID;
|
||||
|
||||
|
@ -8824,30 +8831,11 @@ static void FTENET_WebRTC_Heartbeat(ftenet_websocket_connection_t *b)
|
|||
#ifdef HAVE_SERVER
|
||||
if (b->generic.islisten)
|
||||
{
|
||||
extern cvar_t maxclients;
|
||||
char info[2048];
|
||||
int i;
|
||||
client_t *cl;
|
||||
int numclients = 0;
|
||||
for (i=0 ; i<svs.allocated_client_slots ; i++)
|
||||
{
|
||||
cl = &svs.clients[i];
|
||||
if ((cl->state == cs_connected || cl->state == cs_spawned || cl->name[0]) && !cl->spectator)
|
||||
numclients++;
|
||||
}
|
||||
|
||||
info[0] = ICEMSG_SERVERINFO;
|
||||
info[1] =
|
||||
info[2] = 0xff; //to the broker rather than any actual client
|
||||
info[3] = 0;
|
||||
Info_SetValueForKey(info+3, "protocol", SV_GetProtocolVersionString(), sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "maxclients", maxclients.string, sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "clients", va("%i", numclients), sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "hostname", hostname.string, sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "modname", FS_GetGamedir(true), sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "mapname", InfoBuf_ValueForKey(&svs.info, "map"), sizeof(info)-3);
|
||||
Info_SetValueForKey(info+3, "needpass", InfoBuf_ValueForKey(&svs.info, "needpass"), sizeof(info)-3);
|
||||
|
||||
SV_GeneratePublicServerinfo(info+3, info+sizeof(info));
|
||||
if (emscriptenfte_ws_send(b->brokersock, info, 3+strlen(info+3)) <= 0)
|
||||
return;
|
||||
}
|
||||
|
@ -9309,6 +9297,7 @@ static ftenet_generic_connection_t *FTENET_WebSocket_EstablishConnection(ftenet_
|
|||
newcon->generic.Close = FTENET_WebSocket_Close;
|
||||
|
||||
newcon->generic.islisten = isserver;
|
||||
newcon->generic.prot = adr.prot;
|
||||
newcon->generic.addrtype[0] = NA_WEBSOCKET;
|
||||
newcon->generic.addrtype[1] = NA_INVALID;
|
||||
|
||||
|
@ -9360,6 +9349,7 @@ static ftenet_generic_connection_t *FTENET_WebRTC_EstablishConnection(ftenet_con
|
|||
newcon->generic.Close = FTENET_WebSocket_Close;
|
||||
|
||||
newcon->generic.islisten = isserver;
|
||||
newcon->generic.prot = adr.prot;
|
||||
newcon->generic.addrtype[0] = NA_WEBSOCKET;
|
||||
newcon->generic.addrtype[1] = NA_INVALID;
|
||||
|
||||
|
@ -10486,7 +10476,8 @@ NET_Init
|
|||
void NET_Init (void)
|
||||
{
|
||||
#ifdef HAVE_EPOLL
|
||||
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epoll_fd < 0)
|
||||
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
#endif
|
||||
|
||||
Cvar_Register(&net_enabled, "networking");
|
||||
|
@ -10885,7 +10876,7 @@ void NET_Shutdown (void)
|
|||
|
||||
#ifdef HAVE_EPOLL
|
||||
if (epoll_fd >= 0)
|
||||
close(epoll_fd);
|
||||
epoll_close(epoll_fd);
|
||||
epoll_fd = -1;
|
||||
stdin_epolling = false;
|
||||
#endif
|
||||
|
@ -11171,12 +11162,513 @@ vfsfile_t *FS_WrapTCPSocket(SOCKET sock, qboolean conpending, const char *peerna
|
|||
|
||||
return &newf->funcs;
|
||||
}
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
||||
|
||||
typedef struct {
|
||||
vfsfile_t funcs;
|
||||
|
||||
vfsfile_t *stream;
|
||||
int conpending; //waiting for the proper handshake response, don't write past this.
|
||||
unsigned int mask; //xor masking, to make it harder to exploit buggy shit that's parsing streams (like magic packets or w/e).
|
||||
|
||||
char readbuffer[65536];
|
||||
int readbufferofs;
|
||||
int readbuffered;
|
||||
|
||||
char *pending;
|
||||
int pendingofs;
|
||||
int pendingsize;
|
||||
int pendingmax;
|
||||
|
||||
int err;
|
||||
} websocketfile_t;
|
||||
static void VFSWS_Flush (websocketfile_t *f)
|
||||
{
|
||||
//try flushing it now. note: tls packet sizes can leak.
|
||||
int i = f->conpending?f->conpending:f->pendingsize;
|
||||
if (i == f->pendingofs)
|
||||
return; //nothing to flush.
|
||||
i = VFS_WRITE(f->stream, f->pending+f->pendingofs, i-f->pendingofs);
|
||||
if (i > 0)
|
||||
f->pendingofs += i;
|
||||
else if (i < 0)
|
||||
{
|
||||
f->err = i;
|
||||
VFS_CLOSE(f->stream); //close it.
|
||||
f->stream = NULL;
|
||||
}
|
||||
}
|
||||
static void VFSWS_Append (websocketfile_t *f, unsigned packettype, const unsigned char *data, size_t length)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char b[4];
|
||||
int i;
|
||||
} mask;
|
||||
unsigned short ctrl = 0x8000 | (packettype<<8);
|
||||
quint64_t paylen = 0;
|
||||
unsigned int payoffs = f->pendingsize;
|
||||
// int i;
|
||||
if (!f->stream)
|
||||
return; //can't do anything anyway...
|
||||
switch((ctrl>>8) & 0xf)
|
||||
{
|
||||
/*case WS_PACKETTYPE_TEXTFRAME:
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
paylen += (data[i] == 0 || data[i] >= 0x80)?2:1;
|
||||
}
|
||||
break;*/
|
||||
default:
|
||||
paylen = length;
|
||||
break;
|
||||
}
|
||||
payoffs = 2; //ctrl header
|
||||
if (paylen >= (1<<16))
|
||||
ctrl |= 127, payoffs+=8; //64bit len... overkill
|
||||
else if (paylen >= 126)
|
||||
ctrl |= 126, payoffs+=2; //16bit len.
|
||||
else
|
||||
ctrl |= paylen; //smol
|
||||
if (ctrl&0x80)
|
||||
payoffs += 4; //mask
|
||||
payoffs += paylen;
|
||||
|
||||
if (f->pendingmax < f->pendingsize+payoffs)
|
||||
{ //oh noes. wouldn't be space
|
||||
if (f->pendingofs && !f->conpending/*don't get confused*/)
|
||||
{ //move it down, we already sent that bit.
|
||||
f->pendingsize -= f->pendingofs;
|
||||
memmove(f->pending, f->pending + f->pendingofs, f->pendingsize);
|
||||
f->pendingofs = 0;
|
||||
}
|
||||
if (f->pendingmax < f->pendingsize + payoffs)
|
||||
{ //still too big. make the buffer bigger.
|
||||
f->pendingmax = f->pendingsize + payoffs;
|
||||
f->pending = realloc(f->pending, f->pendingmax);
|
||||
}
|
||||
}
|
||||
|
||||
payoffs = f->pendingsize;
|
||||
f->pending[payoffs++] = ctrl>>8;
|
||||
f->pending[payoffs++] = ctrl&0xff;
|
||||
if ((ctrl&0x7f) == 127)
|
||||
{
|
||||
f->pending[payoffs++] = (paylen>>56)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>48)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>40)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>32)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>24)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>16)&0xff;
|
||||
f->pending[payoffs++] = (paylen>> 8)&0xff;
|
||||
f->pending[payoffs++] = (paylen>> 0)&0xff;
|
||||
}
|
||||
else if ((ctrl&0x7f) == 126)
|
||||
{
|
||||
f->pending[payoffs++] = (paylen>>8)&0xff;
|
||||
f->pending[payoffs++] = (paylen>>0)&0xff;
|
||||
}
|
||||
if (ctrl&0x80)
|
||||
{
|
||||
mask.i = f->mask;
|
||||
//'re-randomise' it a bit
|
||||
f->mask = (f->mask<<4) | (f->mask>>(32-4));
|
||||
f->mask += (payoffs<<16) + paylen;
|
||||
|
||||
f->pending[payoffs++] = mask.b[0];
|
||||
f->pending[payoffs++] = mask.b[1];
|
||||
f->pending[payoffs++] = mask.b[2];
|
||||
f->pending[payoffs++] = mask.b[3];
|
||||
}
|
||||
switch((ctrl>>8) & 0xf)
|
||||
{
|
||||
#if 0
|
||||
case WS_PACKETTYPE_TEXTFRAME:/*utf8ify the data*/
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (!data[i])
|
||||
{ /*0 is encoded as 0x100 to avoid safety checks*/
|
||||
f->pending[payoffs++] = 0xc0 | (0x100>>6);
|
||||
f->pending[payoffs++] = 0x80 | (0x100&0x3f);
|
||||
}
|
||||
else if (data[i] >= 0x80)
|
||||
{ /*larger bytes require markup*/
|
||||
f->pending[payoffs++] = 0xc0 | (data[i]>>6);
|
||||
f->pending[payoffs++] = 0x80 | (data[i]&0x3f);
|
||||
}
|
||||
else
|
||||
{ /*lower 7 bits are as-is*/
|
||||
f->pending[payoffs++] = data[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default: //raw data
|
||||
memcpy(f->pending+payoffs, data, length);
|
||||
payoffs += length;
|
||||
break;
|
||||
}
|
||||
if (ctrl&0x80)
|
||||
{
|
||||
unsigned char *buf = f->pending+payoffs-paylen;
|
||||
int i;
|
||||
for (i = 0; i < paylen; i++)
|
||||
buf[i] ^= mask.b[i&3];
|
||||
}
|
||||
f->pendingsize = payoffs;
|
||||
|
||||
//try flushing it now. note: tls packet sizes can leak.
|
||||
VFSWS_Flush(f);
|
||||
}
|
||||
static qboolean QDECL VFSWS_Close (struct vfsfile_s *file)
|
||||
{
|
||||
websocketfile_t *f = (websocketfile_t *)file;
|
||||
qboolean success = f->stream != NULL;
|
||||
if (f->stream != NULL)
|
||||
{ //still open? o.O
|
||||
VFSWS_Append(f, WS_PACKETTYPE_CLOSE, NULL, 0); //let the other side know it was intended
|
||||
VFS_WRITE(f->stream, f->pending+f->pendingofs, f->pendingsize-f->pendingofs); //final flush
|
||||
success = VFS_CLOSE(f->stream); //close it.
|
||||
f->stream = NULL;
|
||||
}
|
||||
free(f->pending);
|
||||
f->pending = NULL;
|
||||
Z_Free(f);
|
||||
return success;
|
||||
}
|
||||
static int QDECL VFSWS_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
|
||||
{
|
||||
websocketfile_t *f = (websocketfile_t *)file;
|
||||
int r;
|
||||
int t;
|
||||
|
||||
VFSWS_Flush(f); //flush any pending writes.
|
||||
|
||||
for(t = 0; t < 2; t++)
|
||||
{
|
||||
if (t==1 && !f->err)
|
||||
{
|
||||
if (f->readbufferofs >= 1024)
|
||||
{
|
||||
f->readbuffered -= f->readbufferofs;
|
||||
memmove(f->readbuffer, f->readbuffer+f->readbufferofs, f->readbuffered);
|
||||
f->readbufferofs = 0;
|
||||
}
|
||||
r = f->stream?VFS_READ(f->stream, f->readbuffer+f->readbuffered, sizeof(f->readbuffer)-f->readbuffered):-1;
|
||||
if (r > 0)
|
||||
f->readbuffered += r;
|
||||
if (r < 0 && f->stream)
|
||||
f->err = r;
|
||||
if (r <= 0)
|
||||
return f->err; //needed more, couldn't get it.
|
||||
}
|
||||
|
||||
if (f->conpending)
|
||||
{ //look for \r\n\r\n
|
||||
char *l, *e, *le;
|
||||
char *upg=NULL, *con=NULL, *accept=NULL, *prot=NULL;
|
||||
char tok[128];
|
||||
if (!t)
|
||||
continue; //read the size
|
||||
|
||||
if (f->readbuffered < 13)
|
||||
continue; //not nuff data for the basic header
|
||||
if (strncmp(f->readbuffer, "HTTP/1.1 101 ", 13))
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED;
|
||||
break;
|
||||
}
|
||||
|
||||
l = f->readbuffer;
|
||||
e = f->readbuffer+f->readbuffered;
|
||||
for(;;)
|
||||
{
|
||||
for (le = l; le < e && *le != '\n'; le++)
|
||||
;
|
||||
if (le == e)
|
||||
break; //failed.
|
||||
//track interesting lines as we parse.
|
||||
if (!strncmp(l, "Upgrade:", 8))
|
||||
upg = l+8;
|
||||
else if (!strncmp(l, "Connection:", 11))
|
||||
con = l+11;
|
||||
else if (!strncmp(l, "Sec-WebSocket-Accept:", 21))
|
||||
accept = l+21;
|
||||
else if (!strncmp(l, "Sec-WebSocket-Protocol:", 23))
|
||||
prot = l+23;
|
||||
if (le[0] == '\n' && le[1] == '\r' && le[2] == '\n')
|
||||
{
|
||||
le += 3;
|
||||
|
||||
if (!con || !COM_ParseTokenOut(con, NULL, tok,sizeof(tok),NULL) || Q_strcasecmp(tok, "Upgrade"))
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //wrong connection state...
|
||||
else if (!upg || !COM_ParseTokenOut(upg, NULL, tok,sizeof(tok),NULL) || Q_strcasecmp(tok, "websocket"))
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //wrong type of upgrade...
|
||||
else if (!accept)
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //wrong hash
|
||||
else
|
||||
{
|
||||
COM_ParseTokenOut(prot, NULL, tok,sizeof(tok),NULL);
|
||||
Con_Printf("websocket connection using protocol %s\n", prot);
|
||||
}
|
||||
|
||||
f->conpending = false;
|
||||
f->readbufferofs = le-f->readbuffer;
|
||||
break;
|
||||
}
|
||||
l = le+1;
|
||||
}
|
||||
if (f->conpending)
|
||||
continue;
|
||||
if (f->err)
|
||||
break;
|
||||
//try and read the next thing.
|
||||
t = 0;
|
||||
continue;
|
||||
}
|
||||
else if (f->readbuffered-f->readbufferofs >= 2)
|
||||
{ //try to make sense of the packet..
|
||||
unsigned char *inbuffer = f->readbuffer + f->readbufferofs;
|
||||
size_t inlen = f->readbuffered-f->readbufferofs;
|
||||
|
||||
unsigned short ctrl = inbuffer[0]<<8 | inbuffer[1];
|
||||
unsigned long paylen;
|
||||
unsigned int payoffs = 2;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if (ctrl & 0x7000)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //reserved bits set
|
||||
break;
|
||||
}
|
||||
else if ((ctrl & 0x7f) == 127)
|
||||
{
|
||||
quint64_t 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(ullpaylen) < 8)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //wut...
|
||||
break;
|
||||
}
|
||||
|
||||
if (payoffs + 8 > inlen)
|
||||
continue; //not enough buffered
|
||||
ullpaylen =
|
||||
(quint64_t)inbuffer[payoffs+0]<<56u |
|
||||
(quint64_t)inbuffer[payoffs+1]<<48u |
|
||||
(quint64_t)inbuffer[payoffs+2]<<40u |
|
||||
(quint64_t)inbuffer[payoffs+3]<<32u |
|
||||
(quint64_t)inbuffer[payoffs+4]<<24u |
|
||||
(quint64_t)inbuffer[payoffs+5]<<16u |
|
||||
(quint64_t)inbuffer[payoffs+6]<< 8u |
|
||||
(quint64_t)inbuffer[payoffs+7]<< 0u;
|
||||
if (ullpaylen < 0x10000)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //should have used a smaller encoding...
|
||||
break;
|
||||
}
|
||||
if (ullpaylen > 0x40000)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //abusively large...
|
||||
break;
|
||||
}
|
||||
paylen = ullpaylen;
|
||||
payoffs += 8;
|
||||
}
|
||||
else if ((ctrl & 0x7f) == 126)
|
||||
{
|
||||
if (payoffs + 2 > inlen)
|
||||
continue; //not enough buffered
|
||||
paylen =
|
||||
inbuffer[payoffs+0]<<8 |
|
||||
inbuffer[payoffs+1]<<0;
|
||||
if (paylen < 126)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //should have used a smaller encoding...
|
||||
break;
|
||||
}
|
||||
payoffs += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
paylen = ctrl & 0x7f;
|
||||
}
|
||||
if (ctrl & 0x80)
|
||||
{
|
||||
if (payoffs + 4 > inlen)
|
||||
continue;
|
||||
/*this might read data that isn't set yet, but should be safe*/
|
||||
((unsigned char*)&mask)[0] = inbuffer[payoffs+0];
|
||||
((unsigned char*)&mask)[1] = inbuffer[payoffs+1];
|
||||
((unsigned char*)&mask)[2] = inbuffer[payoffs+2];
|
||||
((unsigned char*)&mask)[3] = inbuffer[payoffs+3];
|
||||
payoffs += 4;
|
||||
}
|
||||
/*if there isn't space, try again next time around*/
|
||||
if (payoffs + paylen > inlen)
|
||||
{
|
||||
if (payoffs + paylen >= sizeof(inbuffer)-1)
|
||||
{
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //payload is too big for out in buffer
|
||||
break;
|
||||
}
|
||||
continue; //need more data
|
||||
}
|
||||
|
||||
if (mask)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < paylen; i++)
|
||||
{
|
||||
inbuffer[i + payoffs] ^= ((unsigned char*)&mask)[i&3];
|
||||
}
|
||||
}
|
||||
|
||||
t = 0; //allow checking for new data again.
|
||||
f->readbufferofs += payoffs + paylen; //skip to end...
|
||||
switch((ctrl>>8) & 0xf)
|
||||
{
|
||||
case WS_PACKETTYPE_CLOSE:
|
||||
if (!f->err)
|
||||
{
|
||||
VFSWS_Flush(f);
|
||||
f->err = VFS_ERROR_EOF;
|
||||
if (f->pendingofs < f->pendingsize)
|
||||
return VFS_ERROR_EOF; //nothing more to read (might still have some to flush).
|
||||
}
|
||||
break; //will kill it.
|
||||
case WS_PACKETTYPE_CONTINUATION:
|
||||
f->err = VFS_ERROR_UNSPECIFIED; //a prior packet lacked the 'fin' flag. we don't support fragmentation though.
|
||||
break;
|
||||
case WS_PACKETTYPE_TEXTFRAME: //we don't distinguish. use utf-8 data if you wanted that.
|
||||
case WS_PACKETTYPE_BINARYFRAME: //actual data
|
||||
if (bytestoread >= paylen)
|
||||
{ //caller passed a big enough buffer
|
||||
memcpy(buffer, f->readbuffer+f->readbufferofs-paylen, paylen);
|
||||
return paylen;
|
||||
}
|
||||
else
|
||||
Con_Printf("websocket connection received %u-byte package. only %i requested\n", (unsigned)paylen, bytestoread);
|
||||
continue; //buffer too small... sorry
|
||||
case WS_PACKETTYPE_PING:
|
||||
VFSWS_Append(f, WS_PACKETTYPE_PONG, f->readbuffer+f->readbufferofs-paylen, paylen); //send it back
|
||||
continue; //and look for more.
|
||||
case WS_PACKETTYPE_PONG: //wut? we didn't ask for this
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
continue; //need more data
|
||||
|
||||
break; //oops?
|
||||
}
|
||||
|
||||
if (f->err)
|
||||
{ //something bad happened
|
||||
if (f->stream)
|
||||
VFS_CLOSE(f->stream);
|
||||
f->stream = NULL;
|
||||
return f->err;
|
||||
}
|
||||
return VFS_ERROR_TRYLATER;
|
||||
}
|
||||
static int QDECL VFSWS_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite)
|
||||
{ //websockets are a pseudo-packet protocol, so queue one packet at a time. there may still be extra data queued at a lower level.
|
||||
websocketfile_t *f = (websocketfile_t *)file;
|
||||
if (!f->stream)
|
||||
return f->err;
|
||||
if (f->pendingsize > 8192)
|
||||
return VFS_ERROR_TRYLATER; //something pending... don't queue excessively.
|
||||
|
||||
//okay, we're taking this packet. all or nothing.
|
||||
VFSWS_Append(f, WS_PACKETTYPE_BINARYFRAME, buffer, bytestowrite);
|
||||
return bytestowrite;
|
||||
}
|
||||
static vfsfile_t *Websocket_WrapStream(vfsfile_t *stream, const char *host, const char *resource, const char *proto)
|
||||
{ //this is kinda messy. Websocket_WrapStream(FS_OpenSSL(FS_WrapTCPSocket(TCP_OpenStream())))... *sigh*. wss uris kinda require all the extra layers.
|
||||
|
||||
websocketfile_t *newf;
|
||||
char *hello;
|
||||
if (!stream)
|
||||
return NULL;
|
||||
|
||||
hello = va("GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"Sec-WebSocket-Protocol: %s\r\n"
|
||||
"\r\n", resource, host, proto);
|
||||
|
||||
newf = Z_Malloc(sizeof(*newf) + strlen(host));
|
||||
Sys_RandomBytes((void*)&newf->mask, sizeof(newf->mask));
|
||||
newf->stream = stream;
|
||||
newf->funcs.Close = VFSWS_Close;
|
||||
newf->funcs.ReadBytes = VFSWS_ReadBytes;
|
||||
newf->funcs.WriteBytes = VFSWS_WriteBytes;
|
||||
newf->funcs.Flush = NULL;
|
||||
newf->funcs.GetLen = VFSTCP_GetLen;
|
||||
newf->funcs.Seek = VFSTCP_Seek;
|
||||
newf->funcs.Tell = VFSTCP_Tell;
|
||||
newf->funcs.seekstyle = SS_UNSEEKABLE;
|
||||
|
||||
//send the hello, the weird way.
|
||||
newf->pending = strdup(hello);
|
||||
newf->conpending = newf->pendingsize = newf->pendingmax = strlen(newf->pending);
|
||||
VFSWS_Flush(newf);
|
||||
|
||||
return &newf->funcs;
|
||||
}
|
||||
|
||||
vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls/*used when no scheme specified*/)
|
||||
{
|
||||
netadr_t adr = {0};
|
||||
if (NET_StringToAdr(name, defaultport, &adr))
|
||||
|
||||
const char *resource = "/";
|
||||
const char *host = name;
|
||||
const char *proto = NULL;
|
||||
if (!strncmp(name, "ws:", 3))
|
||||
assumetls = false, host += 3, defaultport=defaultport?defaultport:80;
|
||||
else if (!strncmp(name, "wss:", 4))
|
||||
assumetls = true, host += 4, defaultport=defaultport?defaultport:443;
|
||||
else
|
||||
host = name;
|
||||
if (host != name && host[0] == '/' && host[1] == '/')
|
||||
{
|
||||
qboolean wanttls = (adr.prot == NP_TLS || (adr.prot != NP_STREAM && assumetls));
|
||||
host += 2;
|
||||
proto = ""; //not specified
|
||||
}
|
||||
else
|
||||
{
|
||||
proto = host;
|
||||
host = strstr(host, "://");
|
||||
if (host)
|
||||
{
|
||||
char *t = alloca(1+host-proto);
|
||||
t[host-proto] = 0;
|
||||
proto = memcpy(t, proto, host-proto);
|
||||
host+=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
host = name;
|
||||
proto = "";
|
||||
}
|
||||
}
|
||||
|
||||
resource = strchr(host, '/');
|
||||
if (!resource)
|
||||
resource = "/";
|
||||
else
|
||||
{
|
||||
char *t = alloca(1+resource-host);
|
||||
t[resource-host] = 0;
|
||||
host = memcpy(t, host, resource-host);
|
||||
}
|
||||
|
||||
if (NET_StringToAdr(host, defaultport, &adr))
|
||||
{
|
||||
qboolean wanttls = (adr.prot == NP_WSS || adr.prot == NP_TLS || (adr.prot != NP_STREAM && assumetls));
|
||||
vfsfile_t *f;
|
||||
#ifndef HAVE_SSL
|
||||
if (wanttls)
|
||||
|
@ -11185,8 +11677,11 @@ vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
|||
f = FS_WrapTCPSocket(TCP_OpenStream(&adr, name), true, name);
|
||||
#ifdef HAVE_SSL
|
||||
if (f && wanttls)
|
||||
f = FS_OpenSSL(name, f, false);
|
||||
f = FS_OpenSSL(host, f, false);
|
||||
#endif
|
||||
|
||||
if (proto)
|
||||
f = Websocket_WrapStream(f, host, resource, proto);
|
||||
return f;
|
||||
}
|
||||
else
|
||||
|
@ -11196,6 +11691,7 @@ vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
|||
typedef struct {
|
||||
vfsfile_t funcs;
|
||||
|
||||
qboolean packetmode;
|
||||
int id;
|
||||
int readbuffered;
|
||||
char readbuffer[65536];
|
||||
|
@ -11206,6 +11702,14 @@ int QDECL VFSWS_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread
|
|||
int len;
|
||||
int trying;
|
||||
|
||||
if (f->packetmode)
|
||||
{ //just grab the next packet.
|
||||
len = emscriptenfte_ws_recv(f->id, buffer, bytestoread);
|
||||
if (len < 0)
|
||||
len = VFS_ERROR_EOF;
|
||||
return len;
|
||||
}
|
||||
|
||||
//websockets are pseudo-packetised. tcp isn't.
|
||||
while (f->readbuffered < bytestoread)
|
||||
{
|
||||
|
@ -11266,6 +11770,7 @@ vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
|||
{
|
||||
wsfile_t *newf;
|
||||
int id;
|
||||
const char *proto = "faketcp";
|
||||
if (!strncmp(name, "./", 2) || //relative-to-page
|
||||
!strncmp(name, "/", 1) || //relative-to-host
|
||||
!strncmp(name, "wss://", 6) || //what we'd rather be using...
|
||||
|
@ -11273,22 +11778,50 @@ vfsfile_t *FS_OpenTCP(const char *name, int defaultport, qboolean assumetls)
|
|||
;
|
||||
else
|
||||
{
|
||||
const char *host = name;
|
||||
if (!strncmp(name, "ws:", 3))
|
||||
assumetls = false, host += 3, defaultport=defaultport?defaultport:80;
|
||||
else if (!strncmp(name, "wss:", 4))
|
||||
assumetls = true, host += 4, defaultport=defaultport?defaultport:443;
|
||||
else
|
||||
host = name;
|
||||
if (host == name)
|
||||
; //no scheme
|
||||
else if (host != name && host[0] == '/' && host[1] == '/')
|
||||
name = host+2; //just ws:// without protocol name
|
||||
else
|
||||
{
|
||||
proto = host;
|
||||
host = strstr(host, "://");
|
||||
if (host)
|
||||
{
|
||||
char *t = alloca(1+host-proto);
|
||||
t[host-proto] = 0;
|
||||
proto = memcpy(t, proto, host-proto);
|
||||
name = host+3;
|
||||
}
|
||||
else
|
||||
return NULL; //something screwy.
|
||||
}
|
||||
|
||||
//bad prefix... probably just a real hostname. don't get confused with relative-to-page uris.
|
||||
//FIXME: we should probably be trying to handle the defaultport. oh well.
|
||||
if (assumetls)
|
||||
name = va("wss://%s", name);
|
||||
else
|
||||
{
|
||||
Con_Printf(CON_WARNING"FS_OpenTCP(%s): Assuming insecure\n", name);
|
||||
if (host == name)
|
||||
Con_Printf(CON_WARNING"FS_OpenTCP(%s): Assuming insecure\n", name);
|
||||
name = va("ws://%s", name); //urgh. will probably fail when browsers block it on https pages.
|
||||
}
|
||||
}
|
||||
id = emscriptenfte_ws_connect(name, "faketcp");
|
||||
id = emscriptenfte_ws_connect(name, proto);
|
||||
if (id < 0)
|
||||
return NULL;
|
||||
|
||||
newf = Z_Malloc(sizeof(*newf));
|
||||
newf->id = id;
|
||||
newf->packetmode = strcmp(proto, "faketcp");
|
||||
newf->funcs.Close = VFSWS_Close;
|
||||
newf->funcs.Flush = NULL;
|
||||
newf->funcs.GetLen = VFSWS_GetLen;
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) && !defined(__CYGWIN__)
|
||||
#if defined(__linux__) || defined(HAVE_EPOLL)
|
||||
//requires linux 2.6.27 up (and equivelent libc)
|
||||
//note that BSD does tend to support the api, but emulated.
|
||||
//this works around the select FD limit, and supposedly has better performance.
|
||||
|
@ -149,6 +149,13 @@
|
|||
#define HAVE_EPOLL
|
||||
//#else too old, probably android...
|
||||
#endif
|
||||
#if defined(close) //epoll-shim? stop it from breaking shit
|
||||
#undef close
|
||||
#undef fcntl
|
||||
#define epoll_close epoll_shim_close
|
||||
#else
|
||||
#define epoll_close close
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__MORPHOS__) && !defined(ixemul)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//This file should be easily portable.
|
||||
//The biggest strength of this plugin system is that ALL interactions are performed via
|
||||
//named functions, this makes it *really* easy to port plugins from one engine to annother.
|
||||
//named functions, this makes it *really* easy to port plugins from one engine to another.
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "fs.h"
|
||||
|
|
|
@ -826,7 +826,7 @@ void QCBUILTIN PF_json_get_name(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
void QCBUILTIN PF_json_get_integer(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
qcjson_t *handle = JSONFromQC(G_INT(OFS_PARM0));
|
||||
switch (handle->type)
|
||||
safeswitch (handle->type)
|
||||
{
|
||||
case json_type_number:
|
||||
case json_type_true:
|
||||
|
@ -836,7 +836,10 @@ void QCBUILTIN PF_json_get_integer(pubprogfuncs_t *prinst, struct globalvars_s *
|
|||
case json_type_string:
|
||||
G_INT(OFS_RETURN) = atoi(PR_GetString(prinst, handle->u.strofs));
|
||||
break;
|
||||
default:
|
||||
case json_type_object:
|
||||
case json_type_array:
|
||||
case json_type_null:
|
||||
safedefault:
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -844,7 +847,7 @@ void QCBUILTIN PF_json_get_integer(pubprogfuncs_t *prinst, struct globalvars_s *
|
|||
void QCBUILTIN PF_json_get_float(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
qcjson_t *handle = JSONFromQC(G_INT(OFS_PARM0));
|
||||
switch (handle->type)
|
||||
safeswitch (handle->type)
|
||||
{
|
||||
case json_type_number:
|
||||
case json_type_true:
|
||||
|
@ -854,7 +857,10 @@ void QCBUILTIN PF_json_get_float(pubprogfuncs_t *prinst, struct globalvars_s *pr
|
|||
case json_type_string:
|
||||
G_FLOAT(OFS_RETURN) = atof(PR_GetString(prinst, handle->u.strofs));
|
||||
break;
|
||||
default:
|
||||
case json_type_object:
|
||||
case json_type_array:
|
||||
case json_type_null:
|
||||
safedefault:
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -2040,6 +2046,8 @@ void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
{
|
||||
int size = G_INT(OFS_PARM0);
|
||||
void *ptr;
|
||||
if (!size)
|
||||
size = 1; //return something free can free.
|
||||
if (size <= 0 || size > 0x01000000)
|
||||
ptr = NULL; //don't let them abuse things too much. values that are too large might overflow.
|
||||
else
|
||||
|
@ -2050,7 +2058,29 @@ void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
PR_BIError(prinst, "PF_memalloc: failure (size %i)\n", size);
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_memrealloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
void *oldcptr = prinst->stringtable + G_INT(OFS_PARM0);
|
||||
int size = G_INT(OFS_PARM1);
|
||||
void *ptr;
|
||||
if (!size)
|
||||
size = 1; //return something free can free.
|
||||
if (size <= 0 || size > 0x01000000)
|
||||
ptr = NULL; //don't let them abuse things too much. values that are too large might overflow.
|
||||
else
|
||||
ptr = prinst->AddressableRealloc(prinst, oldcptr, size);
|
||||
if (ptr)
|
||||
G_INT(OFS_RETURN) = (char*)ptr - prinst->stringtable;
|
||||
else
|
||||
{
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
PR_BIError(prinst, "PF_memrealloc: failure (size %i)\n", size);
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
@ -2089,15 +2119,15 @@ void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_global
|
|||
int srcoffset = (prinst->callargc>3)?G_INT(OFS_PARM3):0;
|
||||
int dstoffset = (prinst->callargc>4)?G_INT(OFS_PARM4):0;
|
||||
if (size < 0)
|
||||
PR_BIError(prinst, "PF_memcpy: invalid size\n");
|
||||
PR_BIError(prinst, "PF_memcpy: invalid size %#x\n", size);
|
||||
else if (size)
|
||||
{
|
||||
void *dst = PR_PointerToNative_Resize(prinst, qcdst, dstoffset, size);
|
||||
void *src = PR_PointerToNative_MoInvalidate(prinst, qcsrc, srcoffset, size);
|
||||
if (!dst)
|
||||
PR_BIError(prinst, "PF_memcpy: invalid dest\n");
|
||||
PR_BIError(prinst, "PF_memcpy: invalid dest (%#x[%#x...%#x]\n", qcdst, dstoffset, dstoffset+size-1);
|
||||
else if (!src)
|
||||
PR_BIError(prinst, "PF_memcpy: invalid source\n");
|
||||
PR_BIError(prinst, "PF_memcpy: invalid source (%#x[%#x...%#x]\n", qcsrc, srcoffset, srcoffset+size-1);
|
||||
else
|
||||
memmove(dst, src, size);
|
||||
}
|
||||
|
@ -2632,16 +2662,24 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
if (!pf_fopen_files[i].prinst)
|
||||
break;
|
||||
|
||||
G_FLOAT(OFS_RETURN) = -1; //assume an error
|
||||
if (i == MAX_QC_FILES) //too many already open
|
||||
{
|
||||
Con_Printf("qcfopen(\"%s\"): too many files open\n", name);
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmode < 0 && (!strncmp(name, "tcp://", 6) || !strncmp(name, "tls://", 6)))
|
||||
if (fmode < 0 && (!strncmp(name, "tcp://", 6) || !strncmp(name, "tls://", 6) || !strncmp(name, "ws:", 3) || !strncmp(name, "wss:", 4)))
|
||||
{
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
extern cvar_t pr_enable_uriget;
|
||||
#if defined(CSQC_DAT) && !defined(SERVERONLY)
|
||||
extern world_t csqc_world;
|
||||
if (prinst == csqc_world.progs) //menuqc will refuse to load from untrusted sources. ssqc is the admin's choice. csqc is fundamentally untrusted though.
|
||||
return;
|
||||
#endif
|
||||
if (!pr_enable_uriget.ival) //same cvar to block http requests.
|
||||
return;
|
||||
|
||||
Q_strncpyz(pf_fopen_files[i].name, name, sizeof(pf_fopen_files[i].name));
|
||||
pf_fopen_files[i].accessmode = FRIK_FILE_STREAM;
|
||||
pf_fopen_files[i].bufferlen = 0;
|
||||
|
@ -2664,7 +2702,6 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
if (!QC_FixFileName(name, &name, &fallbackread))
|
||||
{
|
||||
Con_Printf("qcfopen(\"%s\"): Access denied\n", name);
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2700,10 +2737,7 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
}
|
||||
|
||||
if (!pf_fopen_files[i].data)
|
||||
{
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
pf_fopen_files[i].len = pf_fopen_files[i].bufferlen;
|
||||
pf_fopen_files[i].ofs = 0;
|
||||
|
@ -2729,8 +2763,6 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
G_FLOAT(OFS_RETURN) = i + FIRST_QC_FILE_INDEX;
|
||||
pf_fopen_files[i].prinst = prinst;
|
||||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2748,8 +2780,6 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
G_FLOAT(OFS_RETURN) = i + FIRST_QC_FILE_INDEX;
|
||||
pf_fopen_files[i].prinst = prinst;
|
||||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = -1;
|
||||
|
||||
pf_fopen_files[i].bufferlen = pf_fopen_files[i].len = fsize;
|
||||
pf_fopen_files[i].ofs = 0;
|
||||
|
@ -3213,23 +3243,23 @@ void QCBUILTIN PF_fread (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
|
||||
G_INT(OFS_RETURN) = PF_fread_internal (prinst, fnum, ptr, size);
|
||||
}
|
||||
void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
void QCBUILTIN PF_fseek64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX;
|
||||
G_INT(OFS_RETURN) = -1;
|
||||
G_INT64(OFS_RETURN) = -1;
|
||||
if (fnum < 0 || fnum >= MAX_QC_FILES)
|
||||
{
|
||||
PF_Warningf(prinst, "PF_fread: File out of range\n");
|
||||
PF_Warningf(prinst, "PF_fseek: File out of range\n");
|
||||
return; //out of range
|
||||
}
|
||||
if (!pf_fopen_files[fnum].prinst)
|
||||
{
|
||||
PF_Warningf(prinst, "PF_fread: File is not open\n");
|
||||
PF_Warningf(prinst, "PF_fseek: File is not open\n");
|
||||
return; //not open
|
||||
}
|
||||
if (pf_fopen_files[fnum].prinst != prinst)
|
||||
{
|
||||
PF_Warningf(prinst, "PF_fread: File is from wrong instance\n");
|
||||
PF_Warningf(prinst, "PF_fseek: File is from wrong instance\n");
|
||||
return; //this just isn't ours.
|
||||
}
|
||||
|
||||
|
@ -3245,23 +3275,29 @@ void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
|
||||
if (pf_fopen_files[fnum].file)
|
||||
{
|
||||
G_INT(OFS_RETURN) = VFS_TELL(pf_fopen_files[fnum].file);
|
||||
if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0)
|
||||
VFS_SEEK(pf_fopen_files[fnum].file, G_INT(OFS_PARM1));
|
||||
G_INT64(OFS_RETURN) = VFS_TELL(pf_fopen_files[fnum].file);
|
||||
if (prinst->callargc>1 && G_INT64(OFS_PARM1) >= 0)
|
||||
VFS_SEEK(pf_fopen_files[fnum].file, G_INT64(OFS_PARM1));
|
||||
}
|
||||
else
|
||||
{
|
||||
G_INT(OFS_RETURN) = pf_fopen_files[fnum].ofs;
|
||||
if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0)
|
||||
G_INT64(OFS_RETURN) = pf_fopen_files[fnum].ofs;
|
||||
if (prinst->callargc>1 && G_INT64(OFS_PARM1) >= 0)
|
||||
{
|
||||
pf_fopen_files[fnum].ofs = G_INT(OFS_PARM1);
|
||||
pf_fopen_files[fnum].ofs = G_INT64(OFS_PARM1);
|
||||
}
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
void QCBUILTIN PF_fseek32 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
G_INT64(OFS_PARM1) = G_INT(OFS_PARM1);
|
||||
PF_fseek64(prinst, pr_globals);
|
||||
G_INT(OFS_RETURN) = G_INT64(OFS_RETURN);
|
||||
}
|
||||
void QCBUILTIN PF_fsize64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX;
|
||||
G_INT(OFS_RETURN) = -1;
|
||||
G_INT64(OFS_RETURN) = -1;
|
||||
if (fnum < 0 || fnum >= MAX_QC_FILES)
|
||||
{
|
||||
PF_Warningf(prinst, "PF_fsize: File out of range\n");
|
||||
|
@ -3290,21 +3326,27 @@ void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
|
||||
if (pf_fopen_files[fnum].file)
|
||||
{
|
||||
G_INT(OFS_RETURN) = VFS_GETLEN(pf_fopen_files[fnum].file);
|
||||
if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0)
|
||||
G_INT64(OFS_RETURN) = VFS_GETLEN(pf_fopen_files[fnum].file);
|
||||
if (prinst->callargc>1 && G_INT64(OFS_PARM1) >= 0)
|
||||
PF_Warningf(prinst, "PF_fsize: truncation/extension is not supported for stream file types\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
G_INT(OFS_RETURN) = pf_fopen_files[fnum].len;
|
||||
if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0)
|
||||
G_INT64(OFS_RETURN) = pf_fopen_files[fnum].len;
|
||||
if (prinst->callargc>1 && G_INT64(OFS_PARM1) >= 0)
|
||||
{
|
||||
size_t newlen = G_INT(OFS_PARM1);
|
||||
size_t newlen = G_INT64(OFS_PARM1);
|
||||
PF_fresizebuffer_internal(&pf_fopen_files[fnum], newlen);
|
||||
pf_fopen_files[fnum].len = min(pf_fopen_files[fnum].bufferlen, newlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_fsize32 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
G_INT64(OFS_PARM1) = G_INT(OFS_PARM1);
|
||||
PF_fsize64(prinst, pr_globals);
|
||||
G_INT(OFS_RETURN) = G_INT64(OFS_RETURN);
|
||||
}
|
||||
|
||||
void PF_fcloseall (pubprogfuncs_t *prinst)
|
||||
{
|
||||
|
@ -3414,7 +3456,7 @@ void QCBUILTIN PF_fexists (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
|
|||
void QCBUILTIN PF_rmtree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *fname = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
Con_Printf("rmtree(\"%s\"): rmtree is not implemented at this\n", fname);
|
||||
Con_Printf("rmtree(\"%s\"): rmtree is not implemented at this time\n", fname);
|
||||
|
||||
/*flocation_t loc;
|
||||
G_FLOAT(OFS_RETURN) = -1; //error
|
||||
|
@ -4623,6 +4665,26 @@ void QCBUILTIN PF_ftos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
RETURN_TSTRING(pr_string_temp);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_ftou (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
G_UINT(OFS_RETURN) = G_FLOAT(OFS_PARM0);
|
||||
}
|
||||
void QCBUILTIN PF_utof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
if (prinst->callargc > 1)
|
||||
{
|
||||
unsigned int value = G_UINT(OFS_PARM0);
|
||||
unsigned int shift = G_FLOAT(OFS_PARM1);
|
||||
unsigned int count = G_FLOAT(OFS_PARM2);
|
||||
value >>= shift;
|
||||
if (count != 32)
|
||||
value &= ((1u<<count)-1u);
|
||||
G_FLOAT(OFS_RETURN) = value;
|
||||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = G_UINT(OFS_PARM0);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_ftoi (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
G_INT(OFS_RETURN) = G_FLOAT(OFS_PARM0);
|
||||
|
@ -4634,7 +4696,10 @@ void QCBUILTIN PF_itof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
unsigned int value = G_INT(OFS_PARM0);
|
||||
unsigned int shift = G_FLOAT(OFS_PARM1);
|
||||
unsigned int count = G_FLOAT(OFS_PARM2);
|
||||
G_FLOAT(OFS_RETURN) = (value >> shift) & ((1u<<count)-1u);
|
||||
value >>= shift;
|
||||
if (count != 32)
|
||||
value &= ((1u<<count)-1u);
|
||||
G_FLOAT(OFS_RETURN) = value;
|
||||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = G_INT(OFS_PARM0);
|
||||
|
@ -5032,7 +5097,6 @@ void QCBUILTIN PF_strftime (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
{
|
||||
const char *in = PF_VarString(prinst, 1, pr_globals);
|
||||
char result[8192];
|
||||
char uresult[8192];
|
||||
|
||||
time_t ctime;
|
||||
struct tm *tm;
|
||||
|
@ -5051,9 +5115,8 @@ void QCBUILTIN PF_strftime (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
in = "%Y-%m-%d";
|
||||
|
||||
strftime(result, sizeof(result), in, tm);
|
||||
unicode_strtoupper(result, uresult, sizeof(uresult), VMUTF8MARKUP);
|
||||
|
||||
RETURN_TSTRING(uresult);
|
||||
RETURN_TSTRING(result);
|
||||
}
|
||||
|
||||
//String functions
|
||||
|
@ -6846,12 +6909,135 @@ void QCBUILTIN PF_rotatevectorsbymatrix (pubprogfuncs_t *prinst, struct globalva
|
|||
////////////////////////////////////////////////////
|
||||
//Progs internals
|
||||
|
||||
qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait)
|
||||
{
|
||||
world_t *world = prinst->parms->user;
|
||||
qcstate_t *state;
|
||||
edict_t *ed;
|
||||
|
||||
state = prinst->parms->memalloc(sizeof(qcstate_t));
|
||||
state->next = world->qcthreads;
|
||||
world->qcthreads = state;
|
||||
state->resumetime = resumetime;
|
||||
|
||||
if (prinst->edicttable_length)
|
||||
{
|
||||
ed = PROG_TO_EDICT(prinst, world->g.self?*world->g.self:0);
|
||||
state->self = NUM_FOR_EDICT(prinst, ed);
|
||||
state->selfid = (prinst==svprogfuncs&&ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
|
||||
ed = PROG_TO_EDICT(prinst, world->g.self?*world->g.self:0);
|
||||
state->other = NUM_FOR_EDICT(prinst, ed);
|
||||
state->otherid = (prinst==svprogfuncs&&ed->ereftype==ER_ENTITY)?ed->xv->uniquespawnid:0;
|
||||
}
|
||||
else //allows us to call this during init().
|
||||
state->self = state->other = state->selfid = state->otherid = 0;
|
||||
state->thread = prinst->Fork(prinst);
|
||||
state->waiting = wait;
|
||||
state->returnval = retval;
|
||||
return state;
|
||||
}
|
||||
void PR_RunThreads(world_t *world)
|
||||
{
|
||||
struct globalvars_s *pr_globals;
|
||||
edict_t *ed;
|
||||
|
||||
qcstate_t *state = world->qcthreads, *next;
|
||||
world->qcthreads = NULL;
|
||||
while(state)
|
||||
{
|
||||
pubprogfuncs_t *prinst = world->progs;
|
||||
next = state->next;
|
||||
|
||||
if (state->resumetime > (world->g.time?*world->g.time:0) || state->waiting)
|
||||
{ //not time yet, reform original list.
|
||||
state->next = world->qcthreads;
|
||||
world->qcthreads = state;
|
||||
}
|
||||
else
|
||||
{ //call it and forget it ever happened. The Sleep biltin will recreate if needed.
|
||||
pr_globals = PR_globals(prinst, PR_CURRENT);
|
||||
|
||||
if (world->g.self)
|
||||
{
|
||||
//restore the thread's self variable, if applicable.
|
||||
ed = PROG_TO_EDICT(prinst, state->self);
|
||||
if ((prinst==svprogfuncs?ed->xv->uniquespawnid:0) != state->selfid)
|
||||
ed = prinst->edicttable[0];
|
||||
*world->g.self = EDICT_TO_PROG(prinst, ed);
|
||||
}
|
||||
|
||||
if (world->g.other)
|
||||
{
|
||||
//restore the thread's other variable, if applicable
|
||||
ed = PROG_TO_EDICT(prinst, state->other);
|
||||
if ((prinst==svprogfuncs?ed->xv->uniquespawnid:0) != state->otherid)
|
||||
ed = prinst->edicttable[0];
|
||||
*world->g.other = EDICT_TO_PROG(prinst, ed);
|
||||
}
|
||||
|
||||
G_FLOAT(OFS_RETURN) = state->returnval; //return value of fork or sleep
|
||||
|
||||
prinst->RunThread(prinst, state->thread);
|
||||
prinst->parms->memfree(state->thread);
|
||||
prinst->parms->memfree(state);
|
||||
}
|
||||
|
||||
state = next;
|
||||
}
|
||||
}
|
||||
void PR_ClearThreads(pubprogfuncs_t *prinst)
|
||||
{
|
||||
world_t *world;
|
||||
qcstate_t *state, *next;
|
||||
if (!prinst)
|
||||
return; //shoo!
|
||||
world = prinst->parms->user;
|
||||
state = world->qcthreads;
|
||||
world->qcthreads = NULL;
|
||||
while(state)
|
||||
{
|
||||
next = state->next;
|
||||
|
||||
//free the memory.
|
||||
prinst->parms->memfree(state->thread);
|
||||
prinst->parms->memfree(state);
|
||||
|
||||
state = next;
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_Abort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
prinst->AbortStack(prinst);
|
||||
}
|
||||
void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
world_t *world = prinst->parms->user;
|
||||
float sleeptime;
|
||||
|
||||
//this func calls a function in annother progs
|
||||
sleeptime = G_FLOAT(OFS_PARM0);
|
||||
|
||||
PR_CreateThread(prinst, 1, (world->g.time?*world->g.time:0) + sleeptime, false);
|
||||
|
||||
prinst->AbortStack(prinst);
|
||||
}
|
||||
void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
world_t *world = prinst->parms->user;
|
||||
float sleeptime;
|
||||
|
||||
if (svprogfuncs->callargc >= 1)
|
||||
sleeptime = G_FLOAT(OFS_PARM0);
|
||||
else
|
||||
sleeptime = 0;
|
||||
|
||||
PR_CreateThread(prinst, 1, (world->g.time?*world->g.time:0) + sleeptime, false);
|
||||
|
||||
// PRSV_RunThreads();
|
||||
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
}
|
||||
|
||||
//this func calls a function in another progs
|
||||
//it works in the same way as the above func, except that it calls by reference to a function, as opposed to by it's name
|
||||
//used for entity function variables - not actually needed anymore
|
||||
void QCBUILTIN PF_externrefcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
|
@ -6868,20 +7054,28 @@ void QCBUILTIN PF_externrefcall (pubprogfuncs_t *prinst, struct globalvars_s *pr
|
|||
PR_ExecuteProgram(prinst, f);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_externset (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //set a value in annother progs
|
||||
void QCBUILTIN PF_externset (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //set a value in another progs
|
||||
{
|
||||
int n = G_PROG(OFS_PARM0);
|
||||
int v = G_INT(OFS_PARM1);
|
||||
eval_t *v = (eval_t*)&G_INT(OFS_PARM1);
|
||||
const char *varname = PF_VarString(prinst, 2, pr_globals);
|
||||
eval_t *var;
|
||||
etype_t t = ev_void;
|
||||
|
||||
var = PR_FindGlobal(prinst, varname, n, NULL);
|
||||
var = PR_FindGlobal(prinst, varname, n, &t);
|
||||
|
||||
if (var)
|
||||
var->_int = v;
|
||||
{
|
||||
if (t == ev_vector)
|
||||
VectorCopy(v->_vector, var->_vector);
|
||||
else if (t == ev_int64 || t == ev_uint64 || t == ev_double)
|
||||
var->i64 = v->i64;
|
||||
else
|
||||
var->_int = v->_int;
|
||||
}
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //return a value in annother progs
|
||||
void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //return a value in another progs
|
||||
{
|
||||
int n = G_PROG(OFS_PARM0);
|
||||
const char *varname = PF_VarString(prinst, 1, pr_globals);
|
||||
|
@ -6895,6 +7089,8 @@ void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
G_INT(OFS_RETURN) = (char*)var - prinst->stringtable;
|
||||
else
|
||||
G_INT(OFS_RETURN) = 0;
|
||||
G_INT(OFS_RETURN+1) = 0;
|
||||
G_INT(OFS_RETURN+2) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6910,11 +7106,13 @@ void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
{
|
||||
n = prinst->FindFunction(prinst, varname, n);
|
||||
G_INT(OFS_RETURN) = n;
|
||||
G_INT(OFS_RETURN+1) = 0;
|
||||
G_INT(OFS_RETURN+2) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //this func calls a function in annother progs (by name)
|
||||
void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) //this func calls a function in another progs (by name)
|
||||
{
|
||||
int progsnum;
|
||||
const char *funcname;
|
||||
|
@ -6950,6 +7148,26 @@ void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
}
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_setwatchpoint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
const char *desc = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
int type = G_FLOAT(OFS_PARM1);
|
||||
int qcptr = G_INT(OFS_PARM2);
|
||||
char variable[64];
|
||||
|
||||
if (type == ev_float)
|
||||
Q_snprintfz(variable,sizeof(variable), "*(float*)%#x", qcptr);
|
||||
else if (type == ev_string)
|
||||
Q_snprintfz(variable,sizeof(variable), "*(string*)%#x", qcptr);
|
||||
else
|
||||
Q_snprintfz(variable,sizeof(variable), "*(int*)%#x", qcptr);
|
||||
|
||||
if (prinst->SetWatchPoint(prinst, desc, variable))
|
||||
Con_DPrintf("Watchpoint set\n");
|
||||
else
|
||||
Con_Printf("Watchpoint failure\n");
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
prinst->debug_trace = DEBUG_TRACE_INTO;
|
||||
|
@ -7031,28 +7249,34 @@ void QCBUILTIN PF_localcmd (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
Cbuf_AddText (str, RESTRICT_INSECURE);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
int timer = (prinst->callargc > 0)?G_FLOAT(OFS_PARM0):0;
|
||||
void QCBUILTIN PF_gettimed (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{ //usng doubles is for longer uptimes rather than extra precision. we artificially limit precision to reduce spectre sidebands, though I'm not sure how useful it'd be.
|
||||
int timer = (prinst->callargc > 0)?G_INT(OFS_PARM0):0;
|
||||
switch(timer)
|
||||
{
|
||||
default:
|
||||
case 0: //cached time at start of frame
|
||||
G_FLOAT(OFS_RETURN) = realtime;
|
||||
G_DOUBLE(OFS_RETURN) = realtime;
|
||||
break;
|
||||
case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure
|
||||
G_FLOAT(OFS_RETURN) = (qint64_t)Sys_Milliseconds()/1000.0;
|
||||
G_DOUBLE(OFS_RETURN) = (qint64_t)Sys_Milliseconds()/1000.0;
|
||||
break;
|
||||
//case 2: //highres.. looks like time into the frame
|
||||
//case 3: //uptime
|
||||
//case 4: //cd track
|
||||
#ifndef SERVERONLY
|
||||
case 5: //sim time
|
||||
G_FLOAT(OFS_RETURN) = cl.time;
|
||||
G_DOUBLE(OFS_RETURN) = cl.time;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void QCBUILTIN PF_gettimef (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
G_INT(OFS_PARM0) = G_FLOAT(OFS_PARM0);
|
||||
PF_gettimed (prinst, pr_globals);
|
||||
G_FLOAT(OFS_RETURN) = G_DOUBLE(OFS_RETURN);
|
||||
}
|
||||
|
||||
void QCBUILTIN PF_calltimeofday (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
@ -7097,7 +7321,7 @@ void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s
|
|||
formatbuf[0] = '%';
|
||||
|
||||
#define GETARG_FLOAT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
|
||||
#define GETARG_DOUBLE(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
|
||||
#define GETARG_DOUBLE(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_DOUBLE(OFS_PARM0 + 3 * (a))) : 0)
|
||||
#define GETARG_VECTOR(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
|
||||
#define GETARG_INT(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_INT(OFS_PARM0 + 3 * (a))) : 0)
|
||||
#define GETARG_INT64(a) (((a)>=firstarg && (a)<prinst->callargc) ? (G_INT64(OFS_PARM0 + 3 * (a))) : 0)
|
||||
|
@ -7707,6 +7931,7 @@ void QCBUILTIN PF_pushmove (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
|
|||
|
||||
void PR_Common_Shutdown(pubprogfuncs_t *progs, qboolean errored)
|
||||
{
|
||||
PR_ClearThreads(progs);
|
||||
#if defined(SKELETALOBJECTS) || defined(RAGDOLLS)
|
||||
skel_reset(progs->parms->user);
|
||||
#endif
|
||||
|
@ -8092,7 +8317,7 @@ qc_extension_t QSG_Extensions[] = {
|
|||
{"DP_QC_TRACETOSS"},
|
||||
{"DP_QC_TRACE_MOVETYPE_HITMODEL"},
|
||||
{"DP_QC_TRACE_MOVETYPE_WORLDONLY"},
|
||||
{"DP_QC_TRACE_MOVETYPES"}, //this one is just a lame excuse to add annother extension...
|
||||
{"DP_QC_TRACE_MOVETYPES"}, //this one is just a lame excuse to add another extension...
|
||||
{"DP_QC_UNLIMITEDTEMPSTRINGS", NULL, 0,{NULL}, "Supersedes DP_QC_MULTIPLETEMPSTRINGS, superseded by FTE_QC_PERSISTENTTEMPSTRINGS. Specifies that all temp strings will be valid at least until the QCVM returns."},
|
||||
{"DP_QC_URI_ESCAPE", NULL, 2,{"uri_escape", "uri_unescape"}},
|
||||
#ifdef WEBCLIENT
|
||||
|
|
|
@ -181,8 +181,10 @@ void QCBUILTIN PF_fputs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
|
|||
void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fwrite (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fread (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fseek32 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fsize32 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fseek64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_fsize64 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_normalize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_vlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -195,6 +197,7 @@ void QCBUILTIN PF_rotatevectorsbymatrix (pubprogfuncs_t *prinst, struct globalva
|
|||
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_setwatchpoint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_eprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -237,6 +240,8 @@ void QCBUILTIN PF_stoh (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
void QCBUILTIN PF_htos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_ftoi (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_itof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_ftou (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_utof (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void PR_fclose_progs (pubprogfuncs_t *prinst);
|
||||
const char *PF_VarString (pubprogfuncs_t *prinst, int first, struct globalvars_s *pr_globals);
|
||||
void PR_ProgsAdded(pubprogfuncs_t *prinst, int newprogs, const char *modulename);
|
||||
|
@ -275,6 +280,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_
|
|||
#define PF_frameduration PF_Fixme
|
||||
#define PF_modelframecount PF_Fixme
|
||||
#define PF_frameforname PF_Fixme
|
||||
#define PF_frameforaction PF_Fixme
|
||||
#define PF_skel_delete PF_Fixme
|
||||
#define PF_skel_copybones PF_Fixme
|
||||
#define PF_skel_premul_bones PF_Fixme
|
||||
|
@ -370,7 +376,6 @@ void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s
|
|||
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);
|
||||
void QCBUILTIN PF_randomvec (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_strreplace (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_strireplace (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_randomvector (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -392,7 +397,12 @@ void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_bitshift(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
||||
struct qcstate_s *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait);
|
||||
void PR_ClearThreads(pubprogfuncs_t *prinst);
|
||||
void PR_RunThreads(world_t *world);
|
||||
void QCBUILTIN PF_Abort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_externcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_externrefcall (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_externvalue (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -505,6 +515,7 @@ void QCBUILTIN PF_cl_playingdemo (pubprogfuncs_t *prinst, struct globalvars_s *p
|
|||
void QCBUILTIN PF_cl_runningserver (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_getgamedirinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_getpackagemanagerinfo (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_addprogs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cs_media_create (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cs_media_destroy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cs_media_command (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -535,6 +546,8 @@ void QCBUILTIN PF_cl_sprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
void QCBUILTIN PF_cl_bprint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_clientcount (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_queueaudio(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_getqueuedaudiotime(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_getlocaluserinfoblob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_cl_getlocaluserinfostring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -594,6 +607,7 @@ void QCBUILTIN PF_base64encode(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
void QCBUILTIN PF_base64decode(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
||||
void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_memrealloc(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_memcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
@ -605,7 +619,8 @@ void QCBUILTIN PF_memstrsize(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
|
|||
|
||||
void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_calltimeofday (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_gettimef (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
void QCBUILTIN PF_gettimed (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
||||
void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
|
||||
|
||||
|
@ -1094,6 +1109,8 @@ enum
|
|||
globalfunction(CSQC_Parse_TempEntity, "float()")/*EXT_CSQC_ABSOLUTLY_VILE*/ \
|
||||
\
|
||||
globalfunction(CSQC_MapEntityEdited, "void(int entidx, string newentdata)")\
|
||||
globalfunction(StartFrame, "void()")\
|
||||
globalfunction(EndFrame, "void()")\
|
||||
\
|
||||
/*These are pointers to the csqc's globals.*/ \
|
||||
globalfloat (time) /*float The simulation(aka: smoothed server) time, speed drifts based upon latency*/ \
|
||||
|
@ -1273,6 +1290,19 @@ typedef struct csqcedict_s
|
|||
int skinobject;
|
||||
} csqcedict_t;
|
||||
|
||||
typedef struct qcstate_s
|
||||
{
|
||||
float resumetime;
|
||||
qboolean waiting;
|
||||
struct qcthread_s *thread;
|
||||
int self;
|
||||
int selfid;
|
||||
int other;
|
||||
int otherid;
|
||||
float returnval;
|
||||
|
||||
struct qcstate_s *next;
|
||||
} qcstate_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
|
|
@ -206,6 +206,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#define C2M_MASTER_REQUEST 'c'
|
||||
#define M2C_MASTER_REPLY 'd' // + \n + qw server port list
|
||||
|
||||
//for S2C 'status' packets.
|
||||
#define STATUS_OLDSTYLE 0 //equivelent to STATUS_SERVERINFO|STATUS_PLAYERS
|
||||
#define STATUS_SERVERINFO 1
|
||||
#define STATUS_PLAYERS 2
|
||||
#define STATUS_SPECTATORS 4
|
||||
#define STATUS_SPECTATORS_AS_PLAYERS 8 //for ASE - change only frags: show as "S"
|
||||
#define STATUS_SHOWTEAMS 16
|
||||
#define STATUS_QTVLIST 32 //qtv destid "name" "streamid@host:port" numviewers
|
||||
#define STATUS_LOGININFO 64
|
||||
|
||||
//==================
|
||||
// note that there are some defs.qc that mirror to these numbers
|
||||
// also related to svc_strings[] in cl_parse
|
||||
|
@ -1170,7 +1181,9 @@ enum {
|
|||
==========================================================
|
||||
*/
|
||||
|
||||
#ifndef MAX_CLIENTS
|
||||
#define MAX_CLIENTS 255 /*max 255, min 32*/
|
||||
#endif
|
||||
#define QWMAX_CLIENTS 32 /*QW's standard max. clients might have issues above this value*/
|
||||
#define NQMAX_CLIENTS 16 /*NQ's standard max. clients might have issues above this value*/
|
||||
|
||||
|
|
|
@ -108,14 +108,17 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres
|
|||
#define qatomic32_t qint32_t
|
||||
#define FTE_Atomic32_Inc(ptr) __sync_add_and_fetch(ptr, 1) //returns the AFTER the operation.
|
||||
#define FTE_Atomic32_Dec(ptr) __sync_add_and_fetch(ptr, -1) //returns the AFTER the operation.
|
||||
#define FTE_Atomic_Insert(head, newnode, newnodenext) do newnodenext = head; while(!__sync_bool_compare_and_swap(&head, newnodenext, newnode)) //atomically insert into a linked list, being sure to not corrupt the pointers
|
||||
#elif defined(_WIN32)
|
||||
#define qatomic32_t long
|
||||
#define FTE_Atomic32_Inc(ptr) _InterlockedIncrement(ptr)
|
||||
#define FTE_Atomic32_Dec(ptr) _InterlockedDecrement(ptr)
|
||||
#define FTE_Atomic_Insert(head, newnode, newnodenext) do newnodenext = head; while(newnodenext != _InterlockedCompareExchangePointer(&head, newnode, newnodenext))
|
||||
#else
|
||||
#define qatomic32_t qint32_t
|
||||
#define FTE_Atomic32_Inc(ptr) FTE_Atomic32Mutex_Add(ptr, 1)
|
||||
#define FTE_Atomic32_Dec(ptr) FTE_Atomic32Mutex_Add(ptr, -1)
|
||||
#define FTE_Atomic_Insert(head, newnode, newnodenext) do newnodenext = head; while(!FTE_AtomicPtr_ConditionalReplace(&head, newnodenext, newnode))
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "quakedef.h"
|
||||
#include <wctype.h>
|
||||
|
||||
//#define COLOURMISSINGSTRINGS //for english people to more easily see what's not translatable (text still white)
|
||||
//#define COLOURUNTRANSLATEDSTRINGS //show empty translations as alt-text versions of the original string
|
||||
|
@ -27,8 +28,9 @@ cvar_t language = CVARAFCD("lang", sys_language, "prvm_language", CVAR_USERINFO|
|
|||
|
||||
static void Filter_Reload_f(void)
|
||||
{
|
||||
|
||||
// FilterInit(
|
||||
char *file = FS_MallocFile("filter.txt", FS_ROOT, NULL);
|
||||
FilterInit(file?file:"");
|
||||
FS_FreeFile(file);
|
||||
}
|
||||
void TranslateInit(void)
|
||||
{
|
||||
|
@ -630,6 +632,7 @@ void TL_Reformat(int language, char *out, size_t outsize, size_t numargs, const
|
|||
const char *fmt;
|
||||
const char *a;
|
||||
size_t alen;
|
||||
unsigned int lastindex = 0;
|
||||
|
||||
fmt = (numargs>0&&arg[0])?arg[0]:"";
|
||||
fmt = TL_Translate(language, fmt);
|
||||
|
@ -645,8 +648,11 @@ void TL_Reformat(int language, char *out, size_t outsize, size_t numargs, const
|
|||
*out++ = '}', fmt+=2, outsize--;
|
||||
else if (*fmt == '{')
|
||||
{
|
||||
unsigned int index = strtoul(fmt+1, (char**)&fmt, 10)+1;
|
||||
const char *idxstr = fmt+1;
|
||||
unsigned int index = strtoul(idxstr, (char**)&fmt, 10)+1;
|
||||
int size = 0;
|
||||
if (idxstr == fmt) //when no index value was specified, just go for the next one
|
||||
index = lastindex+1;
|
||||
if (*fmt == ',')
|
||||
size = strtol(fmt+1, (char**)&fmt, 10);
|
||||
if (*fmt == ':')
|
||||
|
@ -665,6 +671,8 @@ void TL_Reformat(int language, char *out, size_t outsize, size_t numargs, const
|
|||
else
|
||||
a = TL_Translate(language, arg[index]);
|
||||
|
||||
lastindex = index;
|
||||
|
||||
alen = strlen(a);
|
||||
if (alen > outsize)
|
||||
alen = outsize;
|
||||
|
@ -708,8 +716,8 @@ static void FilterPurge(void)
|
|||
}
|
||||
static void FilterInit(const char *file)
|
||||
{
|
||||
qbyte *tempmem = malloc(strlen(file)+1);
|
||||
qbyte *tempmemstart = tempmem;
|
||||
qbyte *tempmemstart = malloc(strlen(file)+1);
|
||||
qbyte *tempmem = tempmemstart;
|
||||
const char **words;
|
||||
size_t count = 1, i, l;
|
||||
size_t bytes;
|
||||
|
@ -737,28 +745,29 @@ static void FilterInit(const char *file)
|
|||
*tempmem++ = tolower(*c);
|
||||
}
|
||||
*tempmem++ = 0;
|
||||
count++;
|
||||
if (*words[count])
|
||||
count++;
|
||||
}
|
||||
qsort(words, count, sizeof(words[0]), FilterCompareWords); //sort by lead byte... and longest first...
|
||||
i = 0;
|
||||
for (i = 0, bytes = 0; i < count; i++)
|
||||
bytes += strlen(words[i]);
|
||||
bytes += strlen(words[i])+1;
|
||||
bytes += countof(filter);
|
||||
filtermem = malloc(bytes);
|
||||
filtermem = tempmem = malloc(bytes);
|
||||
|
||||
for (l = countof(filter), i = 0; l-- > 0; )
|
||||
{
|
||||
if (i < count && words[i][0] == l)
|
||||
{
|
||||
filter[l] = filtermem;
|
||||
filter[l] = tempmem;
|
||||
while (i < count && *words[i] == l)
|
||||
{ //second copy... urgh. can forget the first char and replace with a length.
|
||||
*filtermem++ = strlen(words[i]+1);
|
||||
memcpy(filtermem, words[i]+1, filtermem[-1]); //just the text, no null needed. tighly packed.
|
||||
filtermem += filtermem[-1];
|
||||
*tempmem++ = strlen(words[i]+1);
|
||||
memcpy(tempmem, words[i]+1, tempmem[-1]); //just the text, no null needed. tighly packed.
|
||||
tempmem += tempmem[-1];
|
||||
i++;
|
||||
}
|
||||
*filtermem++ = 0;
|
||||
*tempmem++ = 0;
|
||||
}
|
||||
else
|
||||
filter[l] = NULL;
|
||||
|
@ -772,6 +781,8 @@ char *FilterObsceneString(const qbyte *in, char *outbuf, size_t bufsize)
|
|||
char *ret = outbuf;
|
||||
if (strlen(in) >= bufsize)
|
||||
Sys_Error("output buffer too small!");
|
||||
if (!filtermem)
|
||||
Filter_Reload_f();
|
||||
restart:
|
||||
while (*in)
|
||||
{
|
||||
|
@ -827,3 +838,75 @@ restart:
|
|||
*outbuf++ = 0; //make sure its null terminated.
|
||||
return ret;
|
||||
}
|
||||
qboolean TL_FilterObsceneCCStringInplace(conchar_t *in, conchar_t *end)
|
||||
{ //FIXME: filters are meant to be utf-8, but our strings are not.
|
||||
qboolean obscene = false;
|
||||
// conchar_t *start = in;
|
||||
conchar_t *next;
|
||||
if (!filtermem)
|
||||
Filter_Reload_f();
|
||||
restart:
|
||||
while(in < end)
|
||||
{
|
||||
unsigned int c, cflags;
|
||||
next = Font_Decode(in, &cflags, &c);
|
||||
c = towlower(c);
|
||||
if (c < 255 && filter[c])
|
||||
{
|
||||
qbyte *m = filter[c];
|
||||
while (*m)
|
||||
{ //for each word starting with this letter...
|
||||
conchar_t *test = next;
|
||||
qbyte len = *m;
|
||||
const qbyte *match = m+1;
|
||||
int err;
|
||||
m += 1+len;
|
||||
while(*match && test < end)
|
||||
{ //don't let 'foo bar' through when 'foobar' is a bad word.
|
||||
test = Font_Decode(test, &cflags, &c);
|
||||
if (whiteish(c))
|
||||
continue;
|
||||
|
||||
if (towlower(c) == utf8_decode(&err, match, (char const**)&match))
|
||||
{
|
||||
if (--len == 0)
|
||||
{ //a match.
|
||||
|
||||
//peek the next and reject it if we're still mid word
|
||||
if (test < end)
|
||||
Font_Decode(test, &cflags, &c);
|
||||
else
|
||||
c = 0;
|
||||
if (c && !whiteish(c))
|
||||
break; //assassinate!
|
||||
|
||||
//okay, not mid-word, obuscate the swears.
|
||||
while (test > in)
|
||||
{ //censor it.
|
||||
if (*in & CON_LONGCHAR && !(*in & CON_RICHFORECOLOUR))
|
||||
*in = CON_LONGCHAR; //no other flags here.
|
||||
else
|
||||
{
|
||||
//*in = "#@*$"[(in-start)&3] | CON_WHITEMASK;
|
||||
*in = 0x26a0 | CON_WHITEMASK | (*in&CON_HIDDEN);
|
||||
obscene = true;
|
||||
}
|
||||
in++;
|
||||
}
|
||||
goto restart; //double breaks suck
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(; next < end; next = Font_Decode(next, &cflags, &c))
|
||||
{
|
||||
if (whiteish(c))
|
||||
break;
|
||||
}
|
||||
in = next;
|
||||
}
|
||||
return obscene;
|
||||
}
|
||||
|
|
|
@ -21,4 +21,6 @@ extern cvar_t language;
|
|||
#define localtext(t) PO_GetText(languages[com_language].po, t)
|
||||
int TL_FindLanguage(const char *lang);
|
||||
|
||||
qboolean TL_FilterObsceneCCStringInplace(conchar_t *in, conchar_t *end);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -130,7 +130,7 @@ typedef struct q2trace_s
|
|||
#define MOVE_WORLDONLY (MOVE_NOMONSTERS|MOVE_MISSILE) //use MOVE_OTHERONLY instead
|
||||
#endif
|
||||
#define MOVE_HITMODEL (1<<2)
|
||||
#define MOVE_RESERVED (1<<3) //so we are less likly to get into tricky situations when we want to steal annother future DP extension.
|
||||
#define MOVE_RESERVED (1<<3) //so we are less likly to get into tricky situations when we want to steal another future DP extension.
|
||||
#define MOVE_TRIGGERS (1<<4) //triggers must be marked with FINDABLE_NONSOLID (an alternative to solid-corpse)
|
||||
#define MOVE_EVERYTHING (1<<5) //can return triggers and non-solid items if they're marked with FINDABLE_NONSOLID (works even if the items are not properly linked)
|
||||
#define MOVE_LAGGED (1<<6) //trace touches current last-known-state, instead of actual ents (just affects players for now)
|
||||
|
@ -263,6 +263,7 @@ struct world_s
|
|||
pvec_t *drawfont;
|
||||
pvec_t *drawfontscale;
|
||||
} g;
|
||||
struct qcstate_s *qcthreads;
|
||||
|
||||
#ifdef USERBE
|
||||
qboolean rbe_hasphysicsents;
|
||||
|
|
|
@ -1393,7 +1393,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
if ((clmodel->engineflags & MDLF_FLAME) || //stuff on fire should generally have enough light...
|
||||
r_fullbright.ival || //vanila cheat
|
||||
(e->flags & RF_FULLBRIGHT) || //DP feature
|
||||
(r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch)) //ezquake cheat
|
||||
(r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch && cls.allow_fbskins>0)) //ezquake cheat
|
||||
{
|
||||
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;
|
||||
e->light_range[0] = e->light_range[1] = e->light_range[2] = 0;
|
||||
|
@ -1453,7 +1453,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
// VectorMA(vec3_origin, 0.5, shadelight, ambientlight);
|
||||
// VectorCopy(ambientlight, shadelight);
|
||||
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
if (!r_vertexdlights.ival && r_dlightlightmaps)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
|
@ -1500,7 +1500,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
if (!r_vertexdlights.ival && r_dlightlightmaps)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
|
|
|
@ -1307,6 +1307,18 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
|
|||
else
|
||||
t = r_whiteimage;
|
||||
break;
|
||||
case T_GEN_TRANSMISSION:
|
||||
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->transmission))
|
||||
t = shaderstate.curtexnums->transmission;
|
||||
else
|
||||
t = r_whiteimage;
|
||||
break;
|
||||
case T_GEN_THICKNESS:
|
||||
if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->thickness))
|
||||
t = shaderstate.curtexnums->thickness;
|
||||
else
|
||||
t = r_whiteimage;
|
||||
break;
|
||||
case T_GEN_SHADOWMAP:
|
||||
t = shaderstate.curshadowmap;
|
||||
break;
|
||||
|
|
|
@ -387,13 +387,12 @@ void R_BloomBlend (texid_t source, int x, int y, int w, int h)
|
|||
|
||||
intex = pingtex[0][i];
|
||||
}
|
||||
r_worldentity.glowmod[0] = 0;
|
||||
r_worldentity.glowmod[1] = 0;
|
||||
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
GL_Set2D(false);
|
||||
r_worldentity.glowmod[0] = 0;
|
||||
r_worldentity.glowmod[1] = 0;
|
||||
|
||||
bloomfinal->defaulttextures->base = intex;
|
||||
bloomfinal->defaulttextures->loweroverlay = (i >= 2)?pingtex[0][i-2]:0;
|
||||
|
@ -402,6 +401,7 @@ void R_BloomBlend (texid_t source, int x, int y, int w, int h)
|
|||
/*combine them onto the screen*/
|
||||
GLBE_FBO_Pop(oldfbo);
|
||||
GLBE_FBO_Sources(source, r_nulltex);
|
||||
GL_Set2D(false);
|
||||
R2D_ScalePic(x, y + h, w, -h, bloomfinal);
|
||||
}
|
||||
void R_BloomShutdown(void)
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
fmt=k -- quake-style raster font with koi8-u codepage (apparently its somewhat common in the quake community)
|
||||
fmt=h -- halflife-style all-on-one-line raster font
|
||||
aspect=0.5 -- raster font is squished horizontally
|
||||
style -- list of modifiets for inexact family font matching for system fonts
|
||||
style -- list of modifiers for inexact family font matching for system fonts
|
||||
*/
|
||||
|
||||
void Font_Init(void);
|
||||
|
@ -404,6 +404,7 @@ static struct
|
|||
} trackerimages[256];
|
||||
static int numtrackerimages;
|
||||
#define TRACKERFIRST 0xe200
|
||||
#define TRACKERCOUNT 0x100 //an upper bound. so misused codepoints won't go weird.
|
||||
int Font_RegisterTrackerImage(const char *image)
|
||||
{
|
||||
int i;
|
||||
|
@ -412,7 +413,7 @@ int Font_RegisterTrackerImage(const char *image)
|
|||
if (!strcmp(trackerimages[i].name, image))
|
||||
return TRACKERFIRST + i;
|
||||
}
|
||||
if (numtrackerimages == 256)
|
||||
if (numtrackerimages == TRACKERCOUNT)
|
||||
return 0;
|
||||
trackerimages[i].image = NULL; //actually load it elsewhere, because we're lazy.
|
||||
Q_strncpyz(trackerimages[i].name, image, sizeof(trackerimages[i].name));
|
||||
|
@ -1546,7 +1547,7 @@ static struct charcache_s *Font_GetChar(font_t *f, unsigned int codepoint)
|
|||
c = Font_GetCharIfLoaded(f, charidx);
|
||||
if (!c)
|
||||
{
|
||||
if (charidx >= TRACKERFIRST && charidx < TRACKERFIRST+100)
|
||||
if (charidx >= TRACKERFIRST && charidx < TRACKERFIRST+TRACKERCOUNT)
|
||||
{
|
||||
static struct charcache_s tc;
|
||||
tc.texplane = TRACKERIMAGE;
|
||||
|
|
|
@ -5873,7 +5873,7 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
|
|||
{
|
||||
for (s = 0; s < br->faces[j].lmextents[0]; s++)
|
||||
{
|
||||
*(unsigned int*)out = (0x3<<30) | (in[2]<<22) | (in[1]<<12) | (in[0]<<2);
|
||||
*(unsigned int*)out = (0x3u<<30) | (in[2]<<22) | (in[1]<<12) | (in[0]<<2);
|
||||
out+=4;
|
||||
in+=3;
|
||||
}
|
||||
|
@ -6709,6 +6709,9 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br, void *mem)
|
|||
br->faces[i].stdir[1][1] = MSG_ReadFloat();
|
||||
br->faces[i].stdir[1][2] = MSG_ReadFloat();
|
||||
br->faces[i].stdir[1][3] = MSG_ReadFloat();
|
||||
|
||||
br->faces[i].surfaceflags = 0; //used by q2
|
||||
br->faces[i].surfacevalue = 0; //used by q2 (generally light levels)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,31 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize)
|
|||
model->bonectls = bonectls;
|
||||
|
||||
#ifndef SERVERONLY
|
||||
model->compatbones = ZG_Malloc(&mod->memgroup, header->numbones * sizeof(*model->compatbones));
|
||||
for (i = 0; i < header->numbones; i++)
|
||||
{
|
||||
float matrix[12];
|
||||
Q_strncpyz(model->compatbones[i].name, model->bones[i].name, sizeof(model->bones[i].name));
|
||||
model->compatbones[i].parent = model->bones[i].parent;
|
||||
model->compatbones[i].ref.org[0] = model->bones[i].value[0];
|
||||
model->compatbones[i].ref.org[1] = model->bones[i].value[1];
|
||||
model->compatbones[i].ref.org[2] = model->bones[i].value[2];
|
||||
QuaternionGLAngle(model->bones[i].value+3, model->compatbones[i].ref.quat);
|
||||
model->compatbones[i].ref.scale[0] = 1.0f;
|
||||
model->compatbones[i].ref.scale[1] = 1.0f;
|
||||
model->compatbones[i].ref.scale[2] = 1.0f;
|
||||
|
||||
//compute rel matrix
|
||||
GenMatrixPosQuat4Scale(model->compatbones[i].ref.org, model->compatbones[i].ref.quat, model->compatbones[i].ref.scale, matrix);
|
||||
//compute abs matrix.
|
||||
if(model->bones[i].parent>=0)
|
||||
R_ConcatTransforms((void*)transform_matrix[model->bones[i].parent], (void*)matrix, transform_matrix[i]);
|
||||
else
|
||||
memcpy(transform_matrix[i], matrix, 12 * sizeof(float));
|
||||
//keep the ragdoll code happy with its insistance on using inverses.
|
||||
Matrix3x4_Invert_Simple((const float*)transform_matrix[i], model->compatbones[i].inverse);
|
||||
}
|
||||
|
||||
tex = (hlmdl_tex_t *) ((qbyte *) texheader + texheader->textures);
|
||||
|
||||
shaders = ZG_Malloc(&mod->memgroup, texheader->numtextures*sizeof(shader_t));
|
||||
|
@ -1192,7 +1217,7 @@ static int HLMDL_GetBoneData_Internal(hlmodel_t *model, int firstbone, int lastb
|
|||
lastbone = model->header->numbones;
|
||||
if (cbone >= lastbone)
|
||||
continue;
|
||||
HL_SetupBones(model, fstate->g[bgroup].frame[0], cbone, lastbone, fstate->g[bgroup].subblendfrac, fstate->g[bgroup].subblend2frac, fstate->g[bgroup].frametime[0], result); /* Setup the bones */
|
||||
HL_SetupBones(model, fstate->g[bgroup].frame[0] & ~0x8000, cbone, lastbone, fstate->g[bgroup].subblendfrac, fstate->g[bgroup].subblend2frac, fstate->g[bgroup].frametime[0], result); /* Setup the bones */
|
||||
cbone = lastbone;
|
||||
}
|
||||
return cbone;
|
||||
|
|
|
@ -1031,27 +1031,28 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b)
|
|||
{
|
||||
if (qrenderer != QR_NONE)
|
||||
Mod_LoadAliasShaders(mod);
|
||||
|
||||
}
|
||||
|
||||
#ifdef RAGDOLL
|
||||
if (mod->type == mod_alias || mod->type == mod_halflife)
|
||||
{
|
||||
int numbones = Mod_GetNumBones(mod, false);
|
||||
if (numbones)
|
||||
{
|
||||
int numbones = Mod_GetNumBones(mod, false);
|
||||
if (numbones)
|
||||
size_t filesize;
|
||||
char *buf;
|
||||
char dollname[MAX_QPATH];
|
||||
Q_snprintfz(dollname, sizeof(dollname), "%s.doll", mod->name);
|
||||
buf = FS_LoadMallocFile(dollname, &filesize);
|
||||
if (buf)
|
||||
{
|
||||
size_t filesize;
|
||||
char *buf;
|
||||
char dollname[MAX_QPATH];
|
||||
Q_snprintfz(dollname, sizeof(dollname), "%s.doll", mod->name);
|
||||
buf = FS_LoadMallocFile(dollname, &filesize);
|
||||
if (buf)
|
||||
{
|
||||
mod->dollinfo = rag_createdollfromstring(mod, dollname, numbones, buf);
|
||||
BZ_Free(buf);
|
||||
}
|
||||
mod->dollinfo = rag_createdollfromstring(mod, dollname, numbones, buf);
|
||||
BZ_Free(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
switch(verbose)
|
||||
|
@ -3595,8 +3596,8 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, int
|
|||
mt->offsets[3] == mt->offsets[2]+(mt->width>>2)*(mt->height>>2))
|
||||
{
|
||||
extofs = mt->offsets[3]+(mt->width>>3)*(mt->height>>3);
|
||||
if (loadmodel->fromgame == fg_halflife && *(short*)(ptr + mt->offsets[3] + (mt->width>>3)*(mt->height>>3)) == 256)
|
||||
{
|
||||
if (extofs + 2+256*3 <= miptexsize && *(short*)(ptr + extofs) == 256)
|
||||
{ //space for a halflife paletted texture, with the right signature (note: usually padded).
|
||||
pal = ptr + extofs+2;
|
||||
extofs += 2+256*3;
|
||||
}
|
||||
|
@ -4313,6 +4314,59 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m
|
|||
loadmodel->surfaces = out;
|
||||
loadmodel->numsurfaces = count;
|
||||
|
||||
//dodgy guesses time...
|
||||
if (loadmodel->fromgame == fg_quake //some halflife maps are misidentified as quake...
|
||||
&& loadmodel->submodels[0].headnode[3] /*these do have crouch hulls. this'll save a LOT of modulo expense*/
|
||||
&& subbsp == sb_none/*don't bother with bsp2... maybe halflife will get a remaster that uses/supports it?*/
|
||||
&& ins && count /*yeah... just in case*/
|
||||
&& !overrides.shifts /*would break expectations. fix your maps.*/
|
||||
&& lightlump->filelen%3==0 /*hlbsp has rgb lighting so MUST be a multiple of 3*/
|
||||
)
|
||||
{
|
||||
for (surfnum=0; surfnum<count; surfnum++)
|
||||
{
|
||||
lofs = LittleLong(ins[surfnum].lightofs);
|
||||
if (lofs%3)
|
||||
break; //not a byte offset within rgb data
|
||||
if (lofs != (unsigned int)-1 && ins[surfnum].styles[0]!=255)
|
||||
{
|
||||
//count styles
|
||||
for (i = 0; i < countof(ins[surfnum].styles); i++)
|
||||
if (ins[surfnum].styles[i] == 255)
|
||||
break;
|
||||
if (!i)
|
||||
continue; //no lightmap data here...
|
||||
|
||||
tn = LittleShort (ins->texinfo);
|
||||
if (tn < 0 || tn >= loadmodel->numtexinfo)
|
||||
break;
|
||||
out->texinfo = loadmodel->texinfo + tn;
|
||||
out->firstedge = LittleLong(ins->firstedge);
|
||||
out->numedges = LittleShort(ins->numedges);
|
||||
out->lmshift = lmshift;
|
||||
CalcSurfaceExtents (loadmodel, out);
|
||||
i *= (out->extents[0]>>out->lmshift)+1; //width
|
||||
i *= (out->extents[1]>>out->lmshift)+1; //height
|
||||
i *= 3; //for rgb
|
||||
//'i' is now the size of our lightmap data, in bytes. phew.
|
||||
lend = lofs + i;
|
||||
|
||||
//we now have a reference surface.
|
||||
for (surfnum++; surfnum<count; surfnum++)
|
||||
{
|
||||
unsigned int checklofs = LittleLong(ins[surfnum].lightofs);
|
||||
if (checklofs%3)
|
||||
break; //can't be hl
|
||||
if (checklofs > lofs && checklofs < lend)
|
||||
break; //started before reference surf ended... reference surface can't have been using RGB lighting. so not a mislabled hlbsp.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (surfnum==count)
|
||||
loadmodel->fromgame = fg_halflife;
|
||||
}
|
||||
|
||||
Mod_LoadVertexNormals(loadmodel, bspx, mod_base, NULL);
|
||||
Mod_LoadLighting (loadmodel, bspx, mod_base, lightlump, false, &overrides, subbsp);
|
||||
|
||||
|
|
|
@ -35,20 +35,24 @@ typedef struct bspx_header_s bspx_header_t;
|
|||
|
||||
typedef enum {
|
||||
SHADER_SORT_NONE,
|
||||
SHADER_SORT_RIPPLE,
|
||||
SHADER_SORT_DEFERREDLIGHT,
|
||||
SHADER_SORT_RIPPLE, //new
|
||||
SHADER_SORT_DEFERREDLIGHT, //new
|
||||
SHADER_SORT_PORTAL,
|
||||
SHADER_SORT_SKY,
|
||||
SHADER_SORT_SKY, //aka environment
|
||||
SHADER_SORT_OPAQUE,
|
||||
//fixme: occlusion tests
|
||||
SHADER_SORT_DECAL,
|
||||
SHADER_SORT_SEETHROUGH,
|
||||
//then rtlights are drawn
|
||||
SHADER_SORT_UNLITDECAL,
|
||||
SHADER_SORT_UNLITDECAL, //new
|
||||
SHADER_SORT_BANNER,
|
||||
//fog
|
||||
SHADER_SORT_UNDERWATER,
|
||||
SHADER_SORT_BLEND,
|
||||
SHADER_SORT_ADDITIVE,
|
||||
//blend2,3,6
|
||||
//stencilshadow
|
||||
//almostnearest
|
||||
SHADER_SORT_NEAREST,
|
||||
|
||||
|
||||
|
@ -894,7 +898,7 @@ typedef struct {
|
|||
//
|
||||
|
||||
typedef enum {mod_brush, mod_sprite, mod_alias, mod_dummy, mod_halflife, mod_heightmap} modtype_t;
|
||||
typedef enum {fg_quake, fg_quake2, fg_quake3, fg_halflife, fg_new, fg_doom, fg_doom3} fromgame_t; //useful when we have very similar model types. (eg quake/halflife bsps)
|
||||
typedef enum {fg_quake, fg_quake2, fg_quake3, fg_halflife, fg_new, fg_doom} fromgame_t; //useful when we have very similar model types. (eg quake/halflife bsps)
|
||||
typedef enum {sb_none, sb_quake64, sb_long1, sb_long2} subbsp_t; // used to denote bsp specifics for load processing only (no runtime changes)
|
||||
|
||||
#define MF_ROCKET (1u<<0) // leave a trail
|
||||
|
|
|
@ -735,7 +735,7 @@ void R_PushDlights (void)
|
|||
return;
|
||||
#endif
|
||||
|
||||
if (r_dynamic.ival <= 0|| !r_worldentity.model)
|
||||
if (!r_dlightlightmaps || !r_worldentity.model)
|
||||
return;
|
||||
|
||||
if (r_worldentity.model->loadstate != MLS_LOADED)
|
||||
|
|
|
@ -1165,6 +1165,21 @@ static void Shader_SurfaceParm (parsestate_t *ps, const char **ptr)
|
|||
Con_DLPrintf(2, "Shader %s, Unknown surface parm \"%s\"\n", ps->s->name, token); //note that there are game-specific names used to override mod surfaceflags+contents
|
||||
}
|
||||
|
||||
static void Shader_DP_Sort (parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
shader_t *shader = ps->s;
|
||||
char *token;
|
||||
|
||||
token = Shader_ParseString ( ptr );
|
||||
|
||||
if (!Q_stricmp(token, "sky"))
|
||||
shader->sort = SHADER_SORT_SKY;
|
||||
else if (!Q_stricmp(token, "hud"))
|
||||
shader->sort = SHADER_SORT_NEAREST;
|
||||
// else if (!Q_stricmp(token, "distance"))
|
||||
// shader->sort = SHADER_SORT_NONE; //not really immplemented, could maybe force v_depthsortentities. just let q3 rules take over.
|
||||
}
|
||||
|
||||
static void Shader_Sort (parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
shader_t *shader = ps->s;
|
||||
|
@ -1176,13 +1191,19 @@ static void Shader_Sort (parsestate_t *ps, const char **ptr)
|
|||
Con_DPrintf("Shader %s, ignoring 'sort %s'\n", ps->s->name, token);
|
||||
return; //dp ignores 'sort' entirely.
|
||||
}
|
||||
// else if ( !Q_stricmp( token, "none" ) )
|
||||
// shader->sort = SHADER_SORT_NONE; //default, overwritten with an automatic choice.
|
||||
else if ( !Q_stricmp( token, "ripple" ) ) //fte, weird. drawn only to the ripplemap.
|
||||
shader->sort = SHADER_SORT_RIPPLE;
|
||||
else if ( !Q_stricmp( token, "deferredlight" ) ) //fte, weird. drawn only to prelight buffer.
|
||||
shader->sort = SHADER_SORT_DEFERREDLIGHT;
|
||||
else if ( !Q_stricmp( token, "portal" ) )
|
||||
shader->sort = SHADER_SORT_PORTAL;
|
||||
else if( !Q_stricmp( token, "sky" ) )
|
||||
shader->sort = SHADER_SORT_SKY;
|
||||
else if( !Q_stricmp( token, "opaque" ) )
|
||||
shader->sort = SHADER_SORT_OPAQUE;
|
||||
else if( !Q_stricmp( token, "decal" ) || !Q_stricmp( token, "litdecal" ) )
|
||||
else if( !Q_stricmp( token, "decal" ) || !Q_stricmp( token, "litdecal" ) )
|
||||
shader->sort = SHADER_SORT_DECAL;
|
||||
else if( !Q_stricmp( token, "seethrough" ) )
|
||||
shader->sort = SHADER_SORT_SEETHROUGH;
|
||||
|
@ -1190,21 +1211,41 @@ static void Shader_Sort (parsestate_t *ps, const char **ptr)
|
|||
shader->sort = SHADER_SORT_UNLITDECAL;
|
||||
else if( !Q_stricmp( token, "banner" ) )
|
||||
shader->sort = SHADER_SORT_BANNER;
|
||||
else if( !Q_stricmp( token, "additive" ) )
|
||||
shader->sort = SHADER_SORT_ADDITIVE;
|
||||
else if( !Q_stricmp( token, "underwater" ) )
|
||||
shader->sort = SHADER_SORT_UNDERWATER;
|
||||
else if( !Q_stricmp( token, "blend" ))
|
||||
shader->sort = SHADER_SORT_BLEND;
|
||||
else if( !Q_stricmp( token, "additive" ) )
|
||||
shader->sort = SHADER_SORT_ADDITIVE;
|
||||
else if( !Q_stricmp( token, "nearest" ) )
|
||||
shader->sort = SHADER_SORT_NEAREST;
|
||||
else if( !Q_stricmp( token, "blend" ) )
|
||||
shader->sort = SHADER_SORT_BLEND;
|
||||
else if ( !Q_stricmp( token, "deferredlight" ) )
|
||||
shader->sort = SHADER_SORT_DEFERREDLIGHT;
|
||||
else if ( !Q_stricmp( token, "ripple" ) )
|
||||
shader->sort = SHADER_SORT_RIPPLE;
|
||||
else
|
||||
{
|
||||
shader->sort = atoi ( token );
|
||||
int q3 = atoi ( token );
|
||||
shadersort_t q3sorttofte[] =
|
||||
{
|
||||
/* 0*/SHADER_SORT_NONE,
|
||||
/* 1*/SHADER_SORT_PORTAL,
|
||||
/* 2*/SHADER_SORT_SKY, //aka environment in q3
|
||||
/* 3*/SHADER_SORT_OPAQUE,
|
||||
/* 4*/SHADER_SORT_DECAL,
|
||||
/* 5*/SHADER_SORT_SEETHROUGH,
|
||||
/* 6*/SHADER_SORT_BANNER,
|
||||
/* 7*/SHADER_SORT_UNDERWATER/*SHADER_SORT_FOG*/,
|
||||
/* 8*/SHADER_SORT_UNDERWATER,
|
||||
/* 9*/SHADER_SORT_BLEND, //blend0 in q3
|
||||
/*10*/SHADER_SORT_ADDITIVE, //blend1 in q3
|
||||
/*11*/SHADER_SORT_ADDITIVE/*SHADER_SORT_BLEND2*/,
|
||||
/*12*/SHADER_SORT_ADDITIVE/*SHADER_SORT_BLEND3*/,
|
||||
/*13*/SHADER_SORT_ADDITIVE/*SHADER_SORT_BLEND6*/, //yes, 4+5 missing in q3...
|
||||
/*14*/SHADER_SORT_ADDITIVE/*SHADER_SORT_STENCIL*/,
|
||||
/*15*/SHADER_SORT_NEAREST/*SHADER_SORT_ALMOSTNEAREST*/,
|
||||
/*16*/SHADER_SORT_NEAREST
|
||||
};
|
||||
if (q3 >= 0 && q3 < countof(q3sorttofte))
|
||||
shader->sort = q3sorttofte[q3];
|
||||
else
|
||||
shader->sort = SHADER_SORT_NONE; // :(
|
||||
clamp ( shader->sort, SHADER_SORT_NONE, SHADER_SORT_NEAREST );
|
||||
}
|
||||
}
|
||||
|
@ -1374,6 +1415,8 @@ const struct sh_defaultsamplers_s sh_defaultsamplers[] =
|
|||
{"s_reflectmask", 1u<<S_REFLECTMASK},
|
||||
{"s_displacement", 1u<<S_DISPLACEMENT},
|
||||
{"s_occlusion", 1u<<S_OCCLUSION},
|
||||
{"s_transmission", 1u<<S_TRANSMISSION},
|
||||
{"s_thickness", 1u<<S_THICKNESS},
|
||||
{"s_lightmap", 1u<<S_LIGHTMAP0},
|
||||
{"s_deluxemap", 1u<<S_DELUXEMAP0},
|
||||
#if MAXRLIGHTMAPS > 1
|
||||
|
@ -2007,12 +2050,12 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
|
|||
nopermutation |= PERMUTATION_SKELETAL;
|
||||
|
||||
//multiple lightmaps is kinda hacky. if any are set, all must be.
|
||||
#define ALTLIGHTMAPSAMP 14
|
||||
if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))))
|
||||
prog->defaulttextures |=((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2)));
|
||||
#define ALTDELUXMAPSAMP 17
|
||||
if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))))
|
||||
prog->defaulttextures |=((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2)));
|
||||
#if MAXRLIGHTMAPS > 1
|
||||
if (prog->defaulttextures & ((1u<<S_LIGHTMAP1 ) | (1u<<S_LIGHTMAP2 ) | (1u<<S_LIGHTMAP3 )))
|
||||
prog->defaulttextures |=((1u<<S_LIGHTMAP1 ) | (1u<<S_LIGHTMAP2 ) | (1u<<S_LIGHTMAP3 ));
|
||||
if (prog->defaulttextures & ((1u<<S_DELUXEMAP1) | (1u<<S_DELUXEMAP2) | (1u<<S_DELUXEMAP3)))
|
||||
prog->defaulttextures |=((1u<<S_DELUXEMAP1) | (1u<<S_DELUXEMAP2) | (1u<<S_DELUXEMAP3));
|
||||
#endif
|
||||
|
||||
for (end = *name?strchr(name+1, '#'):NULL; end && *end; )
|
||||
{
|
||||
|
@ -2169,6 +2212,11 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
|
|||
if (strchr(basicname, '/') || strchr(basicname, '.'))
|
||||
{ //explicit path
|
||||
FS_LoadFile(basicname, &file);
|
||||
if (!file)
|
||||
{ //well that failed. try fixing up the extension in case they omitted that.
|
||||
Q_snprintfz(blobname, sizeof(blobname), COM_SkipPath(sh_config.progpath), basicname);
|
||||
FS_LoadFile(blobname, &file);
|
||||
}
|
||||
*blobname = 0;
|
||||
}
|
||||
else if (ruleset_allow_shaders.ival)
|
||||
|
@ -2581,7 +2629,7 @@ static void Shader_ReflectCube(parsestate_t *ps, const char **ptr)
|
|||
static void Shader_ReflectMask(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
char *token = Shader_ParseSensString(ptr);
|
||||
unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0);
|
||||
unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB);
|
||||
ps->s->defaulttextures->reflectmask = Shader_FindImage(ps, token, flags);
|
||||
}
|
||||
|
||||
|
@ -2629,6 +2677,18 @@ static void Shader_DisplacementMap(parsestate_t *ps, const char **ptr)
|
|||
unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB);
|
||||
ps->s->defaulttextures->displacement = Shader_FindImage(ps, token, flags);
|
||||
}
|
||||
static void Shader_TransmissionMap(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
char *token = Shader_ParseSensString(ptr);
|
||||
unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB);
|
||||
ps->s->defaulttextures->transmission = Shader_FindImage(ps, token, flags);
|
||||
}
|
||||
static void Shader_ThicknessMap(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
char *token = Shader_ParseSensString(ptr);
|
||||
unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB);
|
||||
ps->s->defaulttextures->thickness = Shader_FindImage(ps, token, flags);
|
||||
}
|
||||
|
||||
static void Shaderpass_QF_Material(parsestate_t *ps, const char **ptr)
|
||||
{ //qf_material BASETEXTURE NORMALMAP SPECULARMAP
|
||||
|
@ -2789,6 +2849,23 @@ static void Shader_FactorEmit(parsestate_t *ps, const char **ptr)
|
|||
shader->factors[MATERIAL_FACTOR_EMIT][2] = Shader_ParseFloat(shader, ptr, 1);
|
||||
shader->factors[MATERIAL_FACTOR_EMIT][3] = Shader_ParseFloat(shader, ptr, 1);
|
||||
}
|
||||
static void Shader_FactorTransmission(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
shader_t *shader = ps->s;
|
||||
shader->factors[MATERIAL_FACTOR_TRANSMISSION][0] = Shader_ParseFloat(shader, ptr, 1);
|
||||
// shader->factors[MATERIAL_FACTOR_TRANSMISSION][1] = the volume distance;
|
||||
shader->factors[MATERIAL_FACTOR_TRANSMISSION][2] = 0;
|
||||
shader->factors[MATERIAL_FACTOR_TRANSMISSION][3] = 0;
|
||||
}
|
||||
static void Shader_FactorVolume(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
shader_t *shader = ps->s;
|
||||
shader->factors[MATERIAL_FACTOR_VOLUME][0] = Shader_ParseFloat(shader, ptr, 1); //r
|
||||
shader->factors[MATERIAL_FACTOR_VOLUME][1] = Shader_ParseFloat(shader, ptr, 1); //g
|
||||
shader->factors[MATERIAL_FACTOR_VOLUME][2] = Shader_ParseFloat(shader, ptr, 1); //b
|
||||
shader->factors[MATERIAL_FACTOR_VOLUME][3] = Shader_ParseFloat(shader, ptr, 1); //factor
|
||||
shader->factors[MATERIAL_FACTOR_TRANSMISSION][1] = Shader_ParseFloat(shader, ptr, 1); //distance
|
||||
}
|
||||
|
||||
static void Shader_BEMode(parsestate_t *ps, const char **ptr)
|
||||
{
|
||||
|
@ -2919,11 +2996,15 @@ static shaderkey_t shaderkeys[] =
|
|||
{"lowermap", Shader_LowerMap, "fte"},
|
||||
{"reflectmask", Shader_ReflectMask, "fte"},
|
||||
{"displacementmap", Shader_DisplacementMap, "fte"},
|
||||
{"transmissionmap", Shader_TransmissionMap, "fte"},
|
||||
{"thicknessmap", Shader_ThicknessMap, "fte"},
|
||||
|
||||
{"portalfboscale", Shader_PortalFBOScale, "fte"}, //portal/mirror/refraction/reflection FBOs are resized by this scale
|
||||
{"basefactor", Shader_FactorBase, "fte"}, //material scalers for glsl
|
||||
{"specularfactor", Shader_FactorSpec, "fte"}, //material scalers for glsl
|
||||
{"fullbrightfactor", Shader_FactorEmit, "fte"}, //material scalers for glsl
|
||||
{"fte_transmissionfactor",Shader_FactorTransmission,"fte"}, //material scalers for glsl
|
||||
{"fte_volumefactor", Shader_FactorVolume, "fte"}, //material scalers for glsl
|
||||
|
||||
//TODO: PBR textures...
|
||||
// {"albedomap", Shader_DiffuseMap, "fte"}, //rgb(a)
|
||||
|
@ -2952,6 +3033,7 @@ static shaderkey_t shaderkeys[] =
|
|||
{"polygonoffset", NULL, "dp"},
|
||||
{"glossintensitymod", Shader_DP_GlossScale, "dp"}, //scales r_shadow_glossintensity(=1), aka: gl_specular
|
||||
{"glossexponentmod", Shader_DP_GlossExponent, "dp"}, //scales r_shadow_glossexponent(=32)
|
||||
{"transparentsort", Shader_DP_Sort, "dp"}, //urgh...
|
||||
|
||||
/*doom3 compat*/
|
||||
{"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap <map>\n}"
|
||||
|
@ -3940,7 +4022,7 @@ static void Shaderpass_Scroll (parsestate_t *ps, const char **ptr)
|
|||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("Bad shader scale\n");
|
||||
Con_DPrintf("Bad shader scroll value\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3952,7 +4034,7 @@ static void Shaderpass_Scroll (parsestate_t *ps, const char **ptr)
|
|||
}
|
||||
else
|
||||
{
|
||||
Con_Printf("Bad shader scale\n");
|
||||
Con_DPrintf("Bad shader scroll value\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4307,7 +4389,9 @@ qboolean Shader_Init (void)
|
|||
#ifdef FTE_TARGET_WEB
|
||||
sh_config.max_gpu_bones = 0; //webgl tends to crap out if this is too high, so 32 is a good enough value to play safe. some browsers have really shitty uniform performance too, so lets just default to pure-cpu transforms. in javascript. yes, its that bad.
|
||||
#else
|
||||
sh_config.max_gpu_bones = 64; //ATI drivers bug out and start to crash if you put this at 128.
|
||||
//some of our APIs will set their own guesses from queries. don't stomp on that.
|
||||
if (!sh_config.max_gpu_bones)
|
||||
sh_config.max_gpu_bones = 64; //ATI drivers bug out and start to crash if you put this at 128.
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -4726,16 +4810,18 @@ static void Shader_FixupProgPasses(parsestate_t *ps, shaderpass_t *pass)
|
|||
{T_GEN_REFLECTMASK, 0}, //10
|
||||
{T_GEN_DISPLACEMENT, SHADER_HASDISPLACEMENT},//11
|
||||
{T_GEN_OCCLUSION, 0}, //12
|
||||
{T_GEN_TRANSMISSION, 0}, //13
|
||||
{T_GEN_THICKNESS, 0}, //14
|
||||
// {T_GEN_REFLECTION, SHADER_HASREFLECT}, //
|
||||
// {T_GEN_REFRACTION, SHADER_HASREFRACT}, //
|
||||
// {T_GEN_REFRACTIONDEPTH, SHADER_HASREFRACTDEPTH},//
|
||||
// {T_GEN_RIPPLEMAP, SHADER_HASRIPPLEMAP}, //
|
||||
|
||||
//batch
|
||||
{T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //13
|
||||
{T_GEN_DELUXMAP, 0}, //14
|
||||
//more lightmaps //15,16,17
|
||||
//mode deluxemaps //18,19,20
|
||||
{T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //15
|
||||
{T_GEN_DELUXMAP, 0}, //16
|
||||
//more lightmaps //17,18,19
|
||||
//mode deluxemaps //20,21,22
|
||||
};
|
||||
|
||||
#ifdef HAVE_MEDIA_DECODER
|
||||
|
@ -4815,7 +4901,9 @@ struct scondinfo_s
|
|||
static qboolean Shader_Conditional_Read(parsestate_t *ps, struct scondinfo_s *cond, const char *token, const char **ptr)
|
||||
{
|
||||
shader_t *shader = ps->s;
|
||||
if (!Q_stricmp(token, "if"))
|
||||
if (ps->parseflags & SPF_DOOM3)
|
||||
return false; //doom materials have conditionals that remove passes, without endifs. don't misparse here.
|
||||
else if (!Q_stricmp(token, "if"))
|
||||
{
|
||||
if (cond->depth+1 == countof(cond->level))
|
||||
{
|
||||
|
@ -5925,16 +6013,18 @@ done:;
|
|||
{T_GEN_REFLECTMASK, 0}, //10
|
||||
{T_GEN_DISPLACEMENT, SHADER_HASDISPLACEMENT},//11
|
||||
{T_GEN_OCCLUSION, 0}, //12
|
||||
{T_GEN_TRANSMISSION, 0}, //13
|
||||
{T_GEN_THICKNESS, 0}, //14
|
||||
// {T_GEN_REFLECTION, SHADER_HASREFLECT}, //
|
||||
// {T_GEN_REFRACTION, SHADER_HASREFRACT}, //
|
||||
// {T_GEN_REFRACTIONDEPTH, SHADER_HASREFRACTDEPTH},//
|
||||
// {T_GEN_RIPPLEMAP, SHADER_HASRIPPLEMAP}, //
|
||||
|
||||
//batch
|
||||
{T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //13
|
||||
{T_GEN_DELUXMAP, 0}, //14
|
||||
//more lightmaps //15,16,17
|
||||
//mode deluxemaps //18,19,20
|
||||
{T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //15
|
||||
{T_GEN_DELUXMAP, 0}, //16
|
||||
//more lightmaps //17,18,19
|
||||
//mode deluxemaps //20,21,22
|
||||
};
|
||||
|
||||
#ifdef HAVE_MEDIA_DECODER
|
||||
|
@ -8035,6 +8125,8 @@ static char *Shader_DecomposeSubPass(char *o, shader_t *s, shaderpass_t *p, qboo
|
|||
case T_GEN_REFLECTMASK: Shader_DecomposeSubPassMap(o, s, "map $reflectmask", s->defaulttextures[0].reflectmask); break;
|
||||
case T_GEN_DISPLACEMENT: Shader_DecomposeSubPassMap(o, s, "map $displacement", s->defaulttextures[0].displacement); break;
|
||||
case T_GEN_OCCLUSION: Shader_DecomposeSubPassMap(o, s, "map $occlusion", s->defaulttextures[0].occlusion); break;
|
||||
case T_GEN_TRANSMISSION: Shader_DecomposeSubPassMap(o, s, "map $transmission", s->defaulttextures[0].transmission); break;
|
||||
case T_GEN_THICKNESS: Shader_DecomposeSubPassMap(o, s, "map $thickness", s->defaulttextures[0].thickness); break;
|
||||
case T_GEN_CURRENTRENDER: sprintf(o, "map $currentrender "); break;
|
||||
case T_GEN_SOURCECOLOUR: sprintf(o, "map $sourcecolour"); break;
|
||||
case T_GEN_SOURCEDEPTH: sprintf(o, "map $sourcedepth"); break;
|
||||
|
|
|
@ -3847,7 +3847,7 @@ void Sh_PreGenerateLights(void)
|
|||
{
|
||||
r_shadow_realtime_world_lightmaps.value = 1;
|
||||
if (!r_shadow_realtime_world_importlightentitiesfrommap.ival)
|
||||
Con_Printf(CON_WARNING "No lights detected in map.\n");
|
||||
Con_Printf(CON_WARNING "No lights detected in map, ^[[and importing is disabled]\\type\\r_shadow_realtime_world_importlightentitiesfrommap 1^].\n");
|
||||
else
|
||||
Con_DPrintf("No lights detected in map.\n");
|
||||
}
|
||||
|
@ -4098,7 +4098,8 @@ void Sh_DrawLights(qbyte *vis)
|
|||
r_shadow_realtime_world_importlightentitiesfrommap.modified ||
|
||||
r_shadow_realtime_dlight.modified ||
|
||||
r_shadow_realtime_dlight_shadows.modified ||
|
||||
r_shadow_shadowmapping.modified || r_shadows.modified)
|
||||
r_shadow_shadowmapping.modified || r_shadows.modified ||
|
||||
r_shadow_raytrace.modified)
|
||||
{
|
||||
r_shadow_realtime_world.modified =
|
||||
r_shadow_realtime_world_shadows.modified =
|
||||
|
@ -4106,6 +4107,7 @@ void Sh_DrawLights(qbyte *vis)
|
|||
r_shadow_realtime_dlight_shadows.modified =
|
||||
r_shadow_shadowmapping.modified =
|
||||
r_shadows.modified =
|
||||
r_shadow_raytrace.modified =
|
||||
false;
|
||||
Sh_CheckSettings();
|
||||
//make sure the lighting is reloaded
|
||||
|
@ -4116,9 +4118,8 @@ void Sh_DrawLights(qbyte *vis)
|
|||
return;
|
||||
|
||||
ignoreflags = (r_shadow_realtime_world.ival?LFLAG_REALTIMEMODE:0)
|
||||
| (r_shadow_realtime_dlight.ival?LFLAG_NORMALMODE:0);
|
||||
if (r_dynamic.ival == -1 && r_dynamic.value > 0)
|
||||
ignoreflags |= LFLAG_LIGHTMAP; //if we're using scenecache then we cannot use lightmap hacks for dlights, so draw them via rtlight code instead.
|
||||
| (r_shadow_realtime_dlight.ival?LFLAG_NORMALMODE:0)
|
||||
| ((r_dynamic.ival&&!r_dlightlightmaps)?LFLAG_LIGHTMAP:0); //if we're using scenecache and won't be updating lightmaps then we should still respect r_dynamic.
|
||||
if (!ignoreflags)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1491,14 +1491,24 @@ static const char *glsl_hdrs[] =
|
|||
#endif
|
||||
#endif
|
||||
"#if defined(ORM) || defined(SG)\n"
|
||||
"uniform vec4 factors[3];\n"
|
||||
"uniform vec4 factors[5];\n"
|
||||
"#define factor_base factors[0]\n"
|
||||
"#define factor_spec factors[1]\n"
|
||||
"#define factor_emit factors[2]\n"
|
||||
"#define factor_transmission factors[3].r\n"
|
||||
"#define factor_volume_distance factors[3].g\n"
|
||||
// "#define factor_? factors[3].b\n"
|
||||
// "#define factor_? factors[3].a\n"
|
||||
"#define factor_volume_rgb factors[4].rgb\n"
|
||||
"#define factor_volume_thickness factors[4].a\n"
|
||||
"#else\n"
|
||||
"#define factor_base vec4(1.0)\n"
|
||||
"#define factor_spec vec4(1.0)\n"
|
||||
"#define factor_emit vec4(1.0)\n"
|
||||
/*"#define factor_transmission 0.0\n"
|
||||
"#define factor_volume_distance 0.0\n"
|
||||
"#define factor_volume_rgb vec3(1.0)\n"
|
||||
"#define factor_volume_thickness 0.0\n"*/
|
||||
"#endif\n"
|
||||
"#ifdef USEUBOS\n"
|
||||
"layout(std140) uniform u_lightinfo\n"
|
||||
|
@ -1541,7 +1551,7 @@ static const char *glsl_hdrs[] =
|
|||
"float e_time;"
|
||||
"};\n"
|
||||
"#ifdef SKELETAL\n"
|
||||
"layout(std140) unform u_bones\n"
|
||||
"layout(std140) uniform u_bones\n"
|
||||
"{\n"
|
||||
"#ifdef PACKEDBONES\n"
|
||||
"vec4 m_bones_packed[3*MAX_GPU_BONES];\n"
|
||||
|
@ -1648,7 +1658,7 @@ static const char *glsl_hdrs[] =
|
|||
"wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
|
||||
"wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
|
||||
"wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
|
||||
"wmat[3] = vec4(0.0,0.0,0.0,1.0);\n"
|
||||
"wmat[3] = vec4(0.0,0.0,0.0,1.0);"
|
||||
"return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);"
|
||||
"}\n"
|
||||
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
|
||||
|
@ -2422,6 +2432,8 @@ static GLuint GLSlang_CreateShader (program_t *prog, const char *name, int ver,
|
|||
"uniform sampler2D s_reflectmask;\n",
|
||||
"uniform sampler2D s_displacement;\n",
|
||||
"uniform sampler2D s_occlusion;\n",
|
||||
"uniform sampler2D s_transmission;\n",
|
||||
"uniform sampler2D s_thickness;\n",
|
||||
"uniform sampler2D s_lightmap;\n#define s_lightmap0 s_lightmap\n",
|
||||
"uniform sampler2D s_deluxemap;\n#define s_deluxemap0 s_deluxemap\n",
|
||||
|
||||
|
@ -3664,6 +3676,21 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
|
|||
sh_config.progs_supported = gl_config.arb_shader_objects;
|
||||
sh_config.progs_required = gl_config_nofixedfunc;
|
||||
|
||||
if (gl_config.glversion >= 4.1)
|
||||
{
|
||||
GLint maxuniformvecs = 256; //minimum value... or 128 on webgl1(grr)
|
||||
if (gl_config.glversion >= 4.1)
|
||||
qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxuniformvecs);
|
||||
else if (gl_config.glversion >= 2.0)
|
||||
{
|
||||
qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &maxuniformvecs); //at least 1024, supposedly.
|
||||
maxuniformvecs /= 4;
|
||||
}
|
||||
|
||||
sh_config.max_gpu_bones = (maxuniformvecs-64)/3; //we don't know how many we're actually going to use for any specific bit of glsl, so make a generous guess and throw in a bit more for drivers that lie. we need 3 per bone matrix.
|
||||
sh_config.max_gpu_bones = bound(0, sh_config.max_gpu_bones, MAX_BONES); //o.O
|
||||
}
|
||||
|
||||
if (sh_config.progs_supported)
|
||||
{
|
||||
sh_config.pDeleteProg = GLSlang_DeleteProg;
|
||||
|
|
|
@ -582,7 +582,7 @@ static qboolean EGLHeadless_Init (rendererstate_t *info, unsigned char *palette)
|
|||
|
||||
if (GL_Init(info, &EGL_Proc))
|
||||
return true;
|
||||
Con_Printf(CON_ERROR "Unable to initialise opengl-on-wayland.\n");
|
||||
Con_Printf(CON_ERROR "Unable to initialise egl_headless.\n");
|
||||
return false;
|
||||
}
|
||||
static void EGLHeadless_DeInit(void)
|
||||
|
|
|
@ -311,7 +311,7 @@ static void SDLVID_EnumerateVideoModes (const char *driver, const char *output,
|
|||
static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qrenderer_t qrenderer)
|
||||
{
|
||||
int flags = 0;
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
#if SDL_VERSION_ATLEAST(2,0,0)
|
||||
int display = -1;
|
||||
SDL_DisplayMode modeinfo, *usemode;
|
||||
|
||||
|
@ -361,7 +361,6 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr
|
|||
if (info->stereo)
|
||||
SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
|
||||
|
||||
#if SDL_MAJOR_VERSION >= 2
|
||||
if (info->srgb)
|
||||
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
|
||||
|
||||
|
@ -393,7 +392,6 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr
|
|||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
else
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
#endif
|
||||
if (info->multisample)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, info->multisample);
|
||||
|
|
|
@ -398,8 +398,6 @@ void R_DoomWorld();
|
|||
#endif
|
||||
#ifdef MAP_PROC
|
||||
qboolean QDECL D3_LoadMap_CollisionMap(model_t *mod, void *buf, size_t bufsize);
|
||||
unsigned char *D3_CalcVis(model_t *mod, vec3_t org);
|
||||
void D3_GenerateAreas(model_t *mod);
|
||||
#endif
|
||||
|
||||
//gl_bloom.c
|
||||
|
|
|
@ -349,9 +349,12 @@ typedef void (APIENTRY * PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef GL_VERSION_4_1
|
||||
#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
|
||||
#endif
|
||||
#ifndef GL_VERSION_2_0
|
||||
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GL_ARB_vertex_program
|
||||
|
|
|
@ -298,6 +298,7 @@ typedef struct //this is stored as the cache. an hlmodel_t is generated when dra
|
|||
|
||||
hlmdl_header_t *header;
|
||||
hlmdl_bone_t *bones;
|
||||
struct galiasbone_s *compatbones;
|
||||
hlmdl_bonecontroller_t *bonectls;
|
||||
hlmdl_sequencefile_t *animcache[MAX_ANIM_GROUPS];
|
||||
zonegroup_t *memgroup;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -274,6 +274,8 @@ typedef struct shaderpass_s {
|
|||
T_GEN_REFLECTMASK, //dpreflectcube mask
|
||||
T_GEN_DISPLACEMENT, //displacement texture (probably half-float or something so higher precision than normalmap.a)
|
||||
T_GEN_OCCLUSION, //occlusion mask (instead of baking it into the texture itself, required for correct pbr)
|
||||
T_GEN_TRANSMISSION, //.r fancy opacity mask (still contributes its own colour over the top, for KHR_materials_transmission)
|
||||
T_GEN_THICKNESS, //.g depth mask (could be replaced with raytracing, for KHR_materials_volume)
|
||||
|
||||
T_GEN_CURRENTRENDER,//copy the current screen to a texture, and draw that
|
||||
|
||||
|
@ -698,7 +700,9 @@ struct shader_s
|
|||
#define MATERIAL_FACTOR_BASE 0
|
||||
#define MATERIAL_FACTOR_SPEC 1
|
||||
#define MATERIAL_FACTOR_EMIT 2
|
||||
#define MATERIAL_FACTOR_COUNT 3
|
||||
#define MATERIAL_FACTOR_TRANSMISSION 3
|
||||
#define MATERIAL_FACTOR_VOLUME 4
|
||||
#define MATERIAL_FACTOR_COUNT 5
|
||||
vec4_t factors[MATERIAL_FACTOR_COUNT];
|
||||
|
||||
//arranged as a series of vec4s
|
||||
|
@ -877,15 +881,17 @@ enum
|
|||
S_REFLECTMASK = 10,
|
||||
S_DISPLACEMENT = 11,
|
||||
S_OCCLUSION = 12,
|
||||
S_LIGHTMAP0 = 13,
|
||||
S_DELUXEMAP0 = 14,
|
||||
S_TRANSMISSION = 13,
|
||||
S_THICKNESS = 14,
|
||||
S_LIGHTMAP0 = 15,
|
||||
S_DELUXEMAP0 = 16,
|
||||
#if MAXRLIGHTMAPS > 1
|
||||
S_LIGHTMAP1 = 15,
|
||||
S_LIGHTMAP2 = 16,
|
||||
S_LIGHTMAP3 = 17,
|
||||
S_DELUXEMAP1 = 18,
|
||||
S_DELUXEMAP2 = 19,
|
||||
S_DELUXEMAP3 = 20,
|
||||
S_LIGHTMAP1 = 17,
|
||||
S_LIGHTMAP2 = 18,
|
||||
S_LIGHTMAP3 = 19,
|
||||
S_DELUXEMAP1 = 20,
|
||||
S_DELUXEMAP2 = 21,
|
||||
S_DELUXEMAP3 = 22,
|
||||
#endif
|
||||
};
|
||||
extern const struct sh_defaultsamplers_s
|
||||
|
|
|
@ -36,10 +36,6 @@ struct sockaddr;
|
|||
struct sockaddr_qstorage;
|
||||
int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s);
|
||||
|
||||
#if defined(__unix__) && !defined(__CYGWIN__)
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
typedef qboolean iwboolean;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -201,7 +201,7 @@ int COM_CheckParm(const char *parm)
|
|||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_EPOLL
|
||||
struct stun_ctx
|
||||
{
|
||||
struct epollctx_s pub;
|
||||
|
@ -338,7 +338,9 @@ int main(int argc, char **argv)
|
|||
WSADATA pointlesscrap;
|
||||
WSAStartup(2, &pointlesscrap);
|
||||
#else
|
||||
#ifdef HAVE_EPOLL
|
||||
int ep = epoll_create1(0);
|
||||
#endif
|
||||
signal(SIGPIPE, SIG_IGN); //so we don't crash out if a peer closes the socket half way through.
|
||||
#endif
|
||||
|
||||
|
@ -416,7 +418,7 @@ int main(int argc, char **argv)
|
|||
else
|
||||
printf("Server is read only\n");
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef HAVE_EPOLL
|
||||
while(1)
|
||||
{
|
||||
if (ftpport)
|
||||
|
@ -430,7 +432,6 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
}
|
||||
#else
|
||||
|
||||
while (!HTTP_ServerInit(ep, httpport))
|
||||
sleep(5);
|
||||
PrepareStun(ep, httpport);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
COMMON_OBJS=comprout.o hash.o qcc_cmdlib.o qcd_main.o
|
||||
QCC_OBJS=qccmain.o qcc_pr_comp.o qcc_pr_lex.o packager.o
|
||||
QCC_OBJS=qccmain.o qcc_pr_comp.o qcc_pr_lex.o packager.o decomp.o
|
||||
VM_OBJS=pr_exec.o pr_edict.o pr_multi.o initlib.o qcdecomp.o
|
||||
GTKGUI_OBJS=qcc_gtk.o qccguistuff.o
|
||||
WIN32GUI_OBJS=qccgui.o qccguistuff.o packager.o
|
||||
|
@ -102,10 +102,10 @@ qcvm.a: $(QCC_OBJS) $(VM_OBJS) $(COMMON_OBJS)
|
|||
test.o: test.c
|
||||
$(DO_CC)
|
||||
|
||||
testapp.bin: test.o qcvm.a
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -o testapp.bin -O3 $(BASE_LDFLAGS) $^ -lm -lz
|
||||
qcvm: test.o qcvm.a
|
||||
$(CC) $(BASE_CFLAGS) $(CFLAGS) -o qcvm -O3 $(BASE_LDFLAGS) $^ -lm -lz -ggdb
|
||||
|
||||
tests: testapp.bin
|
||||
tests: qcvm
|
||||
@echo Running Tests...
|
||||
@$(foreach a,$(wildcard tests/*.src), echo TEST: $a; rm progs.dat; ./testapp.bin progs.dat -srcfile $a; echo; echo)
|
||||
@echo Tests run.
|
||||
|
|
|
@ -65,6 +65,7 @@ void *qccHunkAlloc(size_t mem)
|
|||
void qccClearHunk(void)
|
||||
{
|
||||
struct qcchunk_s *t;
|
||||
QCC_PurgeTemps();
|
||||
while (qcc_hunk)
|
||||
{
|
||||
t = qcc_hunk;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,6 +40,8 @@
|
|||
#define QCFAULT return (prinst.pr_xstatement=(st-pr_statements)-1),PR_HandleFault
|
||||
#define EVAL_FLOATISTRUE(ev) ((ev)->_int & 0x7fffffff) //mask away sign bit. This avoids using denormalized floats.
|
||||
|
||||
#define A_RSHIFT_I(x,y) ((x < 0) ? ~(~(x) >> (y)) : ((x) >> (y))) //C leaves it undefined whether signed rshift is arithmatic or logical. gcc should be smart enough to fold this to the proper signed instruction at least on x86.
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define errorif(x) if(__builtin_expect(x,0))
|
||||
#else
|
||||
|
@ -57,9 +59,9 @@
|
|||
//this will fire on the next instruction after the variable got changed.
|
||||
prinst.pr_xstatement = s;
|
||||
if (current_progstate->linenums)
|
||||
externs->Printf("Watch point hit in %s:%u, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), current_progstate->linenums[s-1], prinst.watch_name);
|
||||
externs->Printf("^b^3Watch point hit in %s:%u, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), current_progstate->linenums[s-1], prinst.watch_name);
|
||||
else
|
||||
externs->Printf("Watch point hit in %s, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), prinst.watch_name);
|
||||
externs->Printf("^b^3Watch point hit in %s, \"%s\" changed", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), prinst.watch_name);
|
||||
switch(prinst.watch_type)
|
||||
{
|
||||
case ev_float:
|
||||
|
@ -468,7 +470,7 @@ reeval:
|
|||
ptr = QCPOINTERM(i);
|
||||
*(unsigned char *)ptr = (char)OPA->_float;
|
||||
break;
|
||||
case OP_STOREP_B: //store (byte) character in a string
|
||||
case OP_STOREP_I8: //store (byte) character in a string
|
||||
i = OPB->_int + (OPC->_int)*sizeof(pbyte);
|
||||
errorif (QCPOINTERWRITEFAIL(i, sizeof(pbyte)))
|
||||
{
|
||||
|
@ -483,6 +485,21 @@ reeval:
|
|||
ptr = QCPOINTERM(i);
|
||||
*(pbyte *)ptr = (pbyte)OPA->_int;
|
||||
break;
|
||||
case OP_STOREP_I16: //store short to a pointer
|
||||
i = OPB->_int + (OPC->_int)*sizeof(short);
|
||||
errorif (QCPOINTERWRITEFAIL(i, sizeof(short)))
|
||||
{
|
||||
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(short), sizeof(short))))
|
||||
{
|
||||
if (i == -1)
|
||||
break;
|
||||
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
|
||||
}
|
||||
}
|
||||
else
|
||||
ptr = QCPOINTERM(i);
|
||||
*(short *)ptr = (short)OPA->_int;
|
||||
break;
|
||||
|
||||
case OP_STOREF_F:
|
||||
case OP_STOREF_I:
|
||||
|
@ -860,7 +877,6 @@ reeval:
|
|||
case OP_CALL1:
|
||||
case OP_CALL0:
|
||||
{
|
||||
int callerprogs;
|
||||
int newpr;
|
||||
unsigned int fnum;
|
||||
RUNAWAYCHECK();
|
||||
|
@ -874,7 +890,7 @@ reeval:
|
|||
|
||||
glob = NULL; //try to derestrict it.
|
||||
|
||||
callerprogs=prinst.pr_typecurrent; //so we can revert to the right caller.
|
||||
progfuncs->funcs.callprogs=prinst.pr_typecurrent; //so we can revert to the right caller.
|
||||
newpr = (fnum & 0xff000000)>>24; //this is the progs index of the callee
|
||||
fnum &= ~0xff000000; //the callee's function index.
|
||||
|
||||
|
@ -882,7 +898,7 @@ reeval:
|
|||
errorif (!PR_SwitchProgsParms(progfuncs, newpr) || !fnum || fnum > pr_progs->numfunctions)
|
||||
{
|
||||
char *msg = fnum?"OP_CALL references invalid function in %s\n":"NULL function from qc (inside %s).\n";
|
||||
PR_SwitchProgsParms(progfuncs, callerprogs);
|
||||
PR_SwitchProgsParms(progfuncs, progfuncs->funcs.callprogs);
|
||||
|
||||
glob = pr_globals;
|
||||
if (!progfuncs->funcs.debug_trace)
|
||||
|
@ -922,12 +938,12 @@ reeval:
|
|||
}
|
||||
else
|
||||
PR_RunError (&progfuncs->funcs, "Bad builtin call number - %i", -newf->first_statement);
|
||||
PR_SwitchProgsParms(progfuncs, (progsnum_t)callerprogs);
|
||||
PR_SwitchProgsParms(progfuncs, (progsnum_t)progfuncs->funcs.callprogs);
|
||||
|
||||
//decide weather non debugger wants to start debugging.
|
||||
return prinst.pr_xstatement;
|
||||
}
|
||||
s = PR_EnterFunction (progfuncs, newf, callerprogs);
|
||||
s = PR_EnterFunction (progfuncs, newf, progfuncs->funcs.callprogs);
|
||||
st = &pr_statements[s];
|
||||
}
|
||||
|
||||
|
@ -1018,6 +1034,8 @@ reeval:
|
|||
case OP_DIV_I:
|
||||
if (OPB->_int == 0) //no division by zero allowed...
|
||||
OPC->_int = 0;
|
||||
else if (OPB->_int == -1 && OPA->_int==(int)0x80000000)
|
||||
OPC->_int = 0x7fffffff;
|
||||
else
|
||||
OPC->_int = OPA->_int / OPB->_int;
|
||||
break;
|
||||
|
@ -1106,7 +1124,7 @@ reeval:
|
|||
ptr = QCPOINTERM(i);
|
||||
OPC->_float = *(unsigned char *)ptr;
|
||||
break;
|
||||
case OP_LOADP_B: //load character from a string/pointer
|
||||
case OP_LOADP_U8: //load character from a string/pointer
|
||||
i = (unsigned int)OPA->_int + (int)OPB->_int;
|
||||
errorif (QCPOINTERREADFAIL(i, sizeof(pbyte)))
|
||||
{
|
||||
|
@ -1124,6 +1142,60 @@ reeval:
|
|||
ptr = QCPOINTERM(i);
|
||||
OPC->_int = *(pbyte *)ptr;
|
||||
break;
|
||||
case OP_LOADP_I8: //load character from a string/pointer
|
||||
i = (unsigned int)OPA->_int + (int)OPB->_int;
|
||||
errorif (QCPOINTERREADFAIL(i, sizeof(pbyte)))
|
||||
{
|
||||
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int, sizeof(pbyte))))
|
||||
{
|
||||
if (i == -1)
|
||||
{
|
||||
OPC->_int = 0;
|
||||
break;
|
||||
}
|
||||
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
ptr = QCPOINTERM(i);
|
||||
OPC->_int = *(char *)ptr;
|
||||
break;
|
||||
case OP_LOADP_U16: //load character from a string/pointer
|
||||
i = (unsigned int)OPA->_int + (int)OPB->_int*2;
|
||||
errorif (QCPOINTERREADFAIL(i, sizeof(short)))
|
||||
{
|
||||
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int*2, sizeof(short))))
|
||||
{
|
||||
if (i == -1)
|
||||
{
|
||||
OPC->_int = 0;
|
||||
break;
|
||||
}
|
||||
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
ptr = QCPOINTERM(i);
|
||||
OPC->_int = *(unsigned short *)ptr;
|
||||
break;
|
||||
case OP_LOADP_I16: //load character from a string/pointer
|
||||
i = (unsigned int)OPA->_int + (int)OPB->_int*2;
|
||||
errorif (QCPOINTERREADFAIL(i, sizeof(short)))
|
||||
{
|
||||
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int*2, sizeof(short))))
|
||||
{
|
||||
if (i == -1)
|
||||
{
|
||||
OPC->_int = 0;
|
||||
break;
|
||||
}
|
||||
QCFAULT(&progfuncs->funcs, "bad pointer read in %s (%i bytes into %s)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, ptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
ptr = QCPOINTERM(i);
|
||||
OPC->_int = *(short *)ptr;
|
||||
break;
|
||||
case OP_LOADP_I:
|
||||
case OP_LOADP_F:
|
||||
case OP_LOADP_FLD:
|
||||
|
@ -1194,7 +1266,7 @@ reeval:
|
|||
OPC->_int = OPA->_int ^ OPB->_int;
|
||||
break;
|
||||
case OP_RSHIFT_I:
|
||||
OPC->_int = OPA->_int >> OPB->_int;
|
||||
OPC->_int = A_RSHIFT_I(OPA->_int, OPB->_int);
|
||||
break;
|
||||
case OP_RSHIFT_U:
|
||||
OPC->_uint = OPA->_uint >> OPB->_uint;
|
||||
|
@ -1602,18 +1674,19 @@ reeval:
|
|||
return s;
|
||||
*/ }
|
||||
break;
|
||||
case OP_PUSH:
|
||||
case OP_PUSH: //note: OPA is words, not bytes.
|
||||
OPC->_int = ENGINEPOINTER(&prinst.localstack[prinst.localstack_used+prinst.spushed]);
|
||||
prinst.spushed += OPA->_int;
|
||||
prinst.spushed += OPA->_uint;
|
||||
if (prinst.spushed + prinst.localstack_used >= LOCALSTACK_SIZE)
|
||||
{
|
||||
i = prinst.spushed;
|
||||
prinst.spushed = 0;
|
||||
prinst.pr_xstatement = st-pr_statements;
|
||||
PR_RunError(&progfuncs->funcs, "Progs pushed too much");
|
||||
PR_RunError(&progfuncs->funcs, "Progs pushed too much (%i bytes, %i parents, max %i)", i, prinst.localstack_used, LOCALSTACK_SIZE);
|
||||
}
|
||||
break;
|
||||
/* case OP_POP:
|
||||
pr_spushed -= OPA->_int;
|
||||
pr_spushed -= OPA->_uint;
|
||||
if (pr_spushed < 0)
|
||||
{
|
||||
pr_spushed = 0;
|
||||
|
@ -1633,7 +1706,7 @@ reeval:
|
|||
case OP_BITOR_I64: OPC->i64 = OPA->i64 | OPB->i64; break;
|
||||
case OP_BITXOR_I64: OPC->i64 = OPA->i64 ^ OPB->i64; break;
|
||||
case OP_LSHIFT_I64I: OPC->i64 = OPA->i64 << OPB->_int; break;
|
||||
case OP_RSHIFT_I64I: OPC->i64 = OPA->i64 >> OPB->_int; break;
|
||||
case OP_RSHIFT_I64I: OPC->i64 = A_RSHIFT_I(OPA->i64, OPB->_int); break;
|
||||
case OP_LT_I64: OPC->_int = OPA->i64 < OPB->i64; break;
|
||||
case OP_LE_I64: OPC->_int = OPA->i64 <= OPB->i64; break;
|
||||
case OP_EQ_I64: OPC->_int = OPA->i64 == OPB->i64; break;
|
||||
|
@ -1652,6 +1725,10 @@ reeval:
|
|||
case OP_CONV_FI64: OPC->i64 = OPA->_float; break;
|
||||
case OP_CONV_I64D: OPC->_double = OPA->i64; break;
|
||||
case OP_CONV_DI64: OPC->i64 = OPA->_double; break;
|
||||
case OP_CONV_U64D: OPC->_double = OPA->u64; break;
|
||||
case OP_CONV_DU64: OPC->u64 = OPA->_double; break;
|
||||
case OP_CONV_U64F: OPC->_float = OPA->u64; break;
|
||||
case OP_CONV_FU64: OPC->u64 = OPA->_float; break;
|
||||
case OP_ADD_D: OPC->_double = OPA->_double + OPB->_double; break;
|
||||
case OP_SUB_D: OPC->_double = OPA->_double - OPB->_double; break;
|
||||
case OP_MUL_D: OPC->_double = OPA->_double * OPB->_double; break;
|
||||
|
@ -1661,8 +1738,11 @@ reeval:
|
|||
case OP_EQ_D: OPC->_int = OPA->_double == OPB->_double; break;
|
||||
case OP_NE_D: OPC->_int = OPA->_double != OPB->_double; break;
|
||||
|
||||
|
||||
|
||||
case OP_BITEXTEND_I: OPC->_int = A_RSHIFT_I(( signed int)(OPA->_int << (32-(OPB->_uint&0xff)-(OPB->_uint>>8))), (signed)(32-(OPB->_uint&0xff))); break; //shift it up and down. should sign extend.
|
||||
case OP_BITEXTEND_U: OPC->_uint = (unsigned int)(OPA->_uint << (32-(OPB->_uint&0xff)-(OPB->_uint>>8))) >> (32-(OPB->_uint&0xff)); break; //shift it up and down. should clear the bits.
|
||||
case OP_BITCOPY_I: i=((1<<(OPB->_uint&0xff))-1);OPC->_uint=(OPC->_uint&~(i<<(OPB->_uint>>8)))|(((OPA->_uint&i)<<(OPB->_uint>>8)));break; //replaces the specified bits (uses the same format bitextend uses to select its input to extend)
|
||||
case OP_CONV_UF: OPC->_float = OPA->_uint; break;
|
||||
case OP_CONV_FU: OPC->_uint = OPA->_float; break;
|
||||
|
||||
case OP_UNUSED:
|
||||
case OP_POP:
|
||||
|
|
|
@ -3,7 +3,7 @@ int Grep(const char *filename, const char *string);
|
|||
void EditFile(const char *name, int line, pbool setcontrol);
|
||||
|
||||
void GUI_SetDefaultOpts(void);
|
||||
int GUI_BuildParms(const char *args, const char **argv, pbool quick);
|
||||
int GUI_BuildParms(const char *args, const char **argv, int argv_size, pbool quick);
|
||||
|
||||
//unsigned char *PDECL QCC_ReadFile (const char *fname, void *buffer, int len, size_t *sz);
|
||||
int QCC_RawFileSize (const char *fname);
|
||||
|
|
|
@ -445,6 +445,56 @@ static void PDECL PR_memfree (pubprogfuncs_t *ppf, void *memptr)
|
|||
PR_memvalidate(progfuncs);
|
||||
}
|
||||
|
||||
static void *PDECL PR_memrealloc (pubprogfuncs_t *ppf, void *memptr, unsigned int newsize)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
qcmemusedblock_t *ub;
|
||||
unsigned int ptr = memptr?((char*)memptr - progfuncs->funcs.stringtable):0;
|
||||
void *newptr;
|
||||
unsigned int oldsize;
|
||||
|
||||
/*freeing NULL is ignored*/
|
||||
if (!ptr) //realloc instead of malloc is accepted.
|
||||
return PR_memalloc(ppf, newsize);
|
||||
PR_memvalidate(progfuncs);
|
||||
ptr -= sizeof(qcmemusedblock_t);
|
||||
if (/*ptr < 0 ||*/ ptr >= prinst.addressableused)
|
||||
{
|
||||
ptr += sizeof(qcmemusedblock_t);
|
||||
if (ptr < prinst.addressableused && !*(char*)memptr)
|
||||
{
|
||||
//the empty string is a point of contention. while we can detect it from fteqcc, its best to not give any special favours (other than nicer debugging, where possible)
|
||||
//we might not actually spot it from other qccs, so warning about it where possible is probably a very good thing.
|
||||
externs->Printf("PR_memrealloc: unable to free the non-null empty string constant at %x\n", ptr);
|
||||
}
|
||||
else
|
||||
externs->Printf("PR_memrealloc: pointer invalid - out of range (%x >= %x)\n", ptr, (unsigned int)prinst.addressableused);
|
||||
PR_StackTrace(&progfuncs->funcs, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//this is the used block that we're trying to free
|
||||
ub = (qcmemusedblock_t*)(progfuncs->funcs.stringtable + ptr);
|
||||
if (ub->marker != MARKER_USED || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst.addressableused)
|
||||
{
|
||||
externs->Printf("PR_memrealloc: pointer lacks marker - double-freed?\n");
|
||||
PR_StackTrace(&progfuncs->funcs, false);
|
||||
return NULL;
|
||||
}
|
||||
oldsize = ub->size;
|
||||
oldsize -= sizeof(qcmemusedblock_t); //ignore the header.
|
||||
|
||||
newptr = PR_memalloc(ppf, newsize);
|
||||
if (oldsize > newsize)
|
||||
oldsize = newsize; //don't copy it all.
|
||||
memcpy(newptr, memptr, oldsize);
|
||||
newsize -= oldsize;
|
||||
memset((char*)newptr+oldsize, 0, newsize); //clear out any extended part.
|
||||
PR_memfree(ppf, memptr); //free the old.
|
||||
|
||||
return newptr;
|
||||
}
|
||||
|
||||
void PRAddressableFlush(progfuncs_t *progfuncs, size_t totalammount)
|
||||
{
|
||||
prinst.addressableused = 0;
|
||||
|
@ -1169,7 +1219,7 @@ void *PR_PointerToNative_MoInvalidate(pubprogfuncs_t *inst, pint_t ptr, size_t o
|
|||
else
|
||||
{ //regular pointer
|
||||
offset += ptr;
|
||||
if (datasize > inst->stringtablesize || offset >= inst->stringtablesize-datasize || !offset)
|
||||
if (datasize > inst->stringtablesize || offset >= inst->stringtablesize-datasize || (!offset && datasize>1))
|
||||
return NULL; //can't autoresize these. just fail.
|
||||
return inst->stringtable + ptr;
|
||||
}
|
||||
|
@ -1375,6 +1425,8 @@ static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str,
|
|||
prinst.nexttempstring = i;
|
||||
prinst.livetemps++;
|
||||
|
||||
len = ((len+3)&~3); //round up, primarily so its safe to use loadp_i to read the last few chars of the string
|
||||
|
||||
prinst.tempstrings[i] = progfuncs->funcs.parms->memalloc(sizeof(tempstr_t) - sizeof(((tempstr_t*)NULL)->value) + len);
|
||||
prinst.tempstrings[i]->size = len;
|
||||
*str = prinst.tempstrings[i]->value;
|
||||
|
@ -1667,6 +1719,7 @@ static pubprogfuncs_t deffuncs = {
|
|||
QC_Decompile,
|
||||
#endif
|
||||
0, //callargc
|
||||
0,
|
||||
|
||||
0, //string table(pointer base address)
|
||||
0, //string table size
|
||||
|
@ -1685,6 +1738,7 @@ static pubprogfuncs_t deffuncs = {
|
|||
ED_NewString,
|
||||
QC_HunkAlloc,
|
||||
PR_memalloc,
|
||||
PR_memrealloc,
|
||||
PR_memfree,
|
||||
PR_AllocTempString,
|
||||
PR_AllocTempStringLen,
|
||||
|
|
|
@ -247,7 +247,7 @@ enum qcop_e {
|
|||
OP_LOADA_FNC, //150
|
||||
OP_LOADA_I,
|
||||
|
||||
OP_STORE_P, //152... erm.. wait...
|
||||
OP_STORE_P,
|
||||
OP_LOAD_P,
|
||||
|
||||
OP_LOADP_F,
|
||||
|
@ -339,13 +339,13 @@ enum qcop_e {
|
|||
OP_STOREF_I, //1 non-string reference/int
|
||||
|
||||
//r5744+
|
||||
OP_STOREP_B,//((char*)b)[(int)c] = (int)a
|
||||
OP_LOADP_B, //(int)c = *(char*)
|
||||
OP_STOREP_I8, //((char*)b)[(int)c] = (int)a
|
||||
OP_LOADP_U8, //(int)c = *(unsigned char*)
|
||||
|
||||
//r5768+
|
||||
//opcodes for 32bit uints
|
||||
OP_LE_U, //aka GT
|
||||
OP_LT_U, //aka GE
|
||||
OP_LE_U, //aka GE
|
||||
OP_LT_U, //aka GT
|
||||
OP_DIV_U, //don't need mul+add+sub
|
||||
OP_RSHIFT_U, //lshift is the same for signed+unsigned
|
||||
|
||||
|
@ -359,13 +359,13 @@ enum qcop_e {
|
|||
OP_BITXOR_I64,
|
||||
OP_LSHIFT_I64I,
|
||||
OP_RSHIFT_I64I,
|
||||
OP_LE_I64, //aka GT
|
||||
OP_LT_I64, //aka GE
|
||||
OP_LE_I64, //aka GE
|
||||
OP_LT_I64, //aka GT
|
||||
OP_EQ_I64,
|
||||
OP_NE_I64,
|
||||
//extra opcodes for 64bit uints
|
||||
OP_LE_U64, //aka GT
|
||||
OP_LT_U64, //aka GE
|
||||
OP_LE_U64, //aka GE
|
||||
OP_LT_U64, //aka GT
|
||||
OP_DIV_U64,
|
||||
OP_RSHIFT_U64I,
|
||||
|
||||
|
@ -397,6 +397,20 @@ enum qcop_e {
|
|||
OP_EQ_D,
|
||||
OP_NE_D,
|
||||
|
||||
//r6614+
|
||||
OP_STOREP_I16, //((short*)b)[(int)c] = (int)a
|
||||
OP_LOADP_I16, //(int)c = *(signed short*)a (sign extends)
|
||||
OP_LOADP_U16, //(unsigned int)c = *(unsigned short*)a
|
||||
OP_LOADP_I8, //(unsigned int)c = *(signed char*)a (sign extends)
|
||||
OP_BITEXTEND_I, //sign extend (for signed bitfields)
|
||||
OP_BITEXTEND_U, //zero extend (for unsigned bitfields)
|
||||
OP_BITCOPY_I, //copy lower bits from the input to some part of the output
|
||||
OP_CONV_UF, //OPC.f=(float)OPA.i -- 0xffffffffu*0.5=0 otherwise.
|
||||
OP_CONV_FU, //OPC.i=(int)OPA.f
|
||||
OP_CONV_U64D, //OPC.d=(double)OPA.u64 -- useful mostly so decompilers don't do weird stuff.
|
||||
OP_CONV_DU64, //OPC.u64=(uint64_t)OPA.d
|
||||
OP_CONV_U64F, //OPC.f=(float)OPA.u64 -- useful mostly so decompilers don't do weird stuff.
|
||||
OP_CONV_FU64, //OPC.u64=(uint64_t)OPA.f
|
||||
|
||||
OP_NUMREALOPS,
|
||||
|
||||
|
@ -463,10 +477,13 @@ enum qcop_e {
|
|||
OP_ADD_FP,
|
||||
OP_ADD_PI,
|
||||
OP_ADD_IP,
|
||||
OP_ADD_PU,
|
||||
OP_ADD_UP,
|
||||
|
||||
OP_SUB_SI,
|
||||
OP_SUB_PF,
|
||||
OP_SUB_PI,
|
||||
OP_SUB_PU,
|
||||
|
||||
OP_SUB_PP,
|
||||
|
||||
|
@ -531,8 +548,8 @@ enum qcop_e {
|
|||
//uint64 opcodes. they match the int32 ones so emulation is basically swapping them over.
|
||||
OP_BITNOT_I64, //BITXOR ~0
|
||||
OP_BITCLR_I64,
|
||||
OP_GE_I64, //LT_I64
|
||||
OP_GT_I64, //LE_I64
|
||||
OP_GE_I64, //LE_I64
|
||||
OP_GT_I64, //LT_I64
|
||||
|
||||
OP_ADD_U64,
|
||||
OP_SUB_U64,
|
||||
|
@ -544,8 +561,8 @@ enum qcop_e {
|
|||
OP_BITNOT_U64, //BITXOR ~0
|
||||
OP_BITCLR_U64,
|
||||
OP_LSHIFT_U64I,
|
||||
OP_GE_U64, //LT_U64
|
||||
OP_GT_U64, //LE_U64
|
||||
OP_GE_U64, //LE_U64
|
||||
OP_GT_U64, //LT_U64
|
||||
OP_EQ_U64,
|
||||
OP_NE_U64,
|
||||
|
||||
|
@ -557,6 +574,8 @@ enum qcop_e {
|
|||
OP_BITCLR_D,
|
||||
OP_LSHIFT_DI,
|
||||
OP_RSHIFT_DI,
|
||||
OP_GE_D, //LE_D
|
||||
OP_GT_D, //LT_D
|
||||
|
||||
OP_WSTATE, //for the 'w' part of CWSTATE. will probably never be used, but hey, hexen2...
|
||||
|
||||
|
@ -618,13 +637,19 @@ typedef struct statement32_s
|
|||
typedef struct
|
||||
{
|
||||
struct QCC_def_s *sym;
|
||||
unsigned int ofs;
|
||||
union
|
||||
{
|
||||
unsigned int ofs;
|
||||
// unsigned int bofs;
|
||||
signed int jumpofs;
|
||||
};
|
||||
struct QCC_type_s *cast; //the entire sref is considered null if there is no cast, although it *MAY* have an ofs specified if its part of a jump instruction
|
||||
} QCC_sref_t;
|
||||
typedef struct qcc_statement_s
|
||||
{
|
||||
unsigned short op;
|
||||
#define STF_LOGICOP (1u<<0) //do not bother following when looking for uninitialised variables.
|
||||
#define STF_NOFOLD (1u<<1) //do not allow changing its var_c to fold the following store.
|
||||
unsigned short flags;
|
||||
QCC_sref_t a, b, c;
|
||||
unsigned int linenum;
|
||||
|
|
|
@ -1036,6 +1036,20 @@ char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs)
|
|||
return line;
|
||||
}
|
||||
|
||||
char *PR_GlobalStringImmediate (progfuncs_t *progfuncs, int ofs)
|
||||
{
|
||||
int i;
|
||||
static char line[128];
|
||||
sprintf (line,"%i", ofs);
|
||||
|
||||
i = strlen(line);
|
||||
for ( ; i<20 ; i++)
|
||||
strcat (line," ");
|
||||
strcat (line," ");
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
ED_Print
|
||||
|
@ -2742,6 +2756,7 @@ pbool PR_ReallyLoadProgs (progfuncs_t *progfuncs, const char *filename, progstat
|
|||
int reorg = prinst.reorganisefields || prinst.numfields;
|
||||
|
||||
int stringadjust;
|
||||
int pointeradjust;
|
||||
|
||||
int *basictypetable;
|
||||
|
||||
|
@ -3027,9 +3042,15 @@ retry:
|
|||
glob = pr_globals = (float *)s;
|
||||
|
||||
if (progfuncs->funcs.stringtable)
|
||||
{
|
||||
stringadjust = pr_strings - progfuncs->funcs.stringtable;
|
||||
pointeradjust = (char*)glob - progfuncs->funcs.stringtable;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringadjust = 0;
|
||||
pointeradjust = (char*)glob - pr_strings;
|
||||
}
|
||||
|
||||
if (!pr_linenums)
|
||||
{
|
||||
|
@ -3531,12 +3552,20 @@ retry:
|
|||
if (reorg && !basictypetable)
|
||||
QC_AddSharedFieldVar(&progfuncs->funcs, i, pr_strings - stringadjust);
|
||||
break;
|
||||
case ev_pointer:
|
||||
if (((int *)glob)[gd16[i].ofs] & 0x80000000)
|
||||
{
|
||||
((int *)glob)[gd16[i].ofs] &= ~0x80000000;
|
||||
((int *)glob)[gd16[i].ofs] += pointeradjust;
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH
|
||||
case ev_string:
|
||||
if (((unsigned int *)glob)[gd16[i].ofs]>=progstate->progs->numstrings)
|
||||
externs->Printf("PR_LoadProgs: invalid string value (%x >= %x) in '%s'\n", ((unsigned int *)glob)[gd16[i].ofs], progstate->progs->numstrings, gd16[i].s_name+pr_strings-stringadjust);
|
||||
else if (isfriked != -1)
|
||||
{
|
||||
if (pr_strings[((int *)glob)[gd16[i].ofs]]) //quakec uses string tables. 0 must remain null, or 'if (s)' can break.
|
||||
if (((int *)glob)[gd16[i].ofs]) //quakec uses string tables. 0 must remain null, or 'if (s)' can break.
|
||||
{
|
||||
((int *)glob)[gd16[i].ofs] += stringadjust;
|
||||
isfriked = false;
|
||||
|
@ -3578,8 +3607,18 @@ retry:
|
|||
case ev_field:
|
||||
QC_AddSharedFieldVar(&progfuncs->funcs, i, pr_strings - stringadjust);
|
||||
break;
|
||||
case ev_pointer:
|
||||
if (((int *)glob)[pr_globaldefs32[i].ofs] & 0x80000000)
|
||||
{
|
||||
((int *)glob)[pr_globaldefs32[i].ofs] &= ~0x80000000;
|
||||
((int *)glob)[pr_globaldefs32[i].ofs] += pointeradjust;
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH
|
||||
case ev_string:
|
||||
if (pr_strings[((int *)glob)[pr_globaldefs32[i].ofs]]) //quakec uses string tables. 0 must remain null, or 'if (s)' can break.
|
||||
if (((unsigned int *)glob)[pr_globaldefs32[i].ofs]>=progstate->progs->numstrings)
|
||||
externs->Printf("PR_LoadProgs: invalid string value (%x >= %x) in '%s'\n", ((unsigned int *)glob)[pr_globaldefs32[i].ofs], progstate->progs->numstrings, pr_globaldefs32[i].s_name+pr_strings-stringadjust);
|
||||
else if (((int *)glob)[pr_globaldefs32[i].ofs]) //quakec uses string tables. 0 must remain null, or 'if (s)' can break.
|
||||
{
|
||||
((int *)glob)[pr_globaldefs32[i].ofs] += stringadjust;
|
||||
isfriked = false;
|
||||
|
@ -3628,6 +3667,10 @@ retry:
|
|||
if (progfuncs->funcs.stringtablesize + progfuncs->funcs.stringtable < pr_strings + pr_progs->numstrings)
|
||||
progfuncs->funcs.stringtablesize = (pr_strings + pr_progs->numstrings) - progfuncs->funcs.stringtable;
|
||||
|
||||
//make sure the localstack is addressable to the qc, so we can OP_PUSH okay.
|
||||
if (!prinst.localstack)
|
||||
prinst.localstack = PRAddressableExtend(progfuncs, NULL, 0, sizeof(float)*LOCALSTACK_SIZE);
|
||||
|
||||
if (externs->MapNamedBuiltin)
|
||||
{
|
||||
for (i=0,fnc2=pr_cp_functions; i<pr_progs->numfunctions; i++, fnc2++)
|
||||
|
|
|
@ -128,8 +128,8 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
|
|||
if ( (unsigned)op < OP_NUMOPS)
|
||||
{
|
||||
int i;
|
||||
externs->Printf ("%s ", pr_opcodes[op].name);
|
||||
i = strlen(pr_opcodes[op].name);
|
||||
externs->Printf ("%s ", pr_opcodes[op].opname);
|
||||
i = strlen(pr_opcodes[op].opname);
|
||||
for ( ; i<10 ; i++)
|
||||
externs->Printf (" ");
|
||||
}
|
||||
|
@ -141,16 +141,22 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
|
|||
#define TYPEHINT(a) NULL
|
||||
#endif
|
||||
|
||||
if (op == OP_IF_F || op == OP_IFNOT_F)
|
||||
if (op == OP_IF_F || op == OP_IFNOT_F || op == OP_IF_I || op == OP_IFNOT_I || op == OP_IF_S || op == OP_IFNOT_S)
|
||||
externs->Printf ("%sbranch %i",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)),arg[1]);
|
||||
else if (op == OP_GOTO)
|
||||
{
|
||||
externs->Printf ("branch %i",arg[0]);
|
||||
}
|
||||
else if (op == OP_BOUNDCHECK)
|
||||
{
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
externs->Printf ("%s",PR_GlobalStringImmediate(progfuncs, arg[1]));
|
||||
externs->Printf ("%s",PR_GlobalStringImmediate(progfuncs, arg[2]));
|
||||
}
|
||||
else if ( (unsigned)(op - OP_STORE_F) < 6)
|
||||
{
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[0], TYPEHINT(a)));
|
||||
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[1]));
|
||||
externs->Printf ("%s",PR_GlobalStringNoContents(progfuncs, arg[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -159,7 +165,7 @@ static void PR_PrintStatement (progfuncs_t *progfuncs, int statementnum)
|
|||
if (arg[1])
|
||||
externs->Printf ("%s",PR_GlobalString(progfuncs, arg[1], TYPEHINT(b)));
|
||||
if (arg[2])
|
||||
externs->Printf ("%s", PR_GlobalStringNoContents(progfuncs, arg[2]));
|
||||
externs->Printf ("%s",PR_GlobalStringNoContents(progfuncs, arg[2]));
|
||||
}
|
||||
externs->Printf ("\n");
|
||||
}
|
||||
|
@ -363,9 +369,9 @@ static void PDECL PR_PrintRelevantLocals(progfuncs_t *progfuncs)
|
|||
else
|
||||
fdef = ED_FieldAtOfs(progfuncs, ((eval_t *)&pr_globals[st16[st].b])->_int);
|
||||
if (fdef)
|
||||
externs->Printf(" %s.%s: %s\n", PR_StringToNative(&progfuncs->funcs, ent->s_name), PR_StringToNative(&progfuncs->funcs, fld->s_name), PR_ValueString(progfuncs, fdef->type, ptr, false));
|
||||
externs->Printf(" %s.%s: %s\n", PR_StringToNative(&progfuncs->funcs, ent->s_name), PR_StringToNative(&progfuncs->funcs, fld->s_name), PR_ValueString(progfuncs, fdef->type, ptr, false));
|
||||
else
|
||||
externs->Printf(" %s.%s: BAD FIELD DEF - %#x\n", PR_StringToNative(&progfuncs->funcs, ent->s_name), PR_StringToNative(&progfuncs->funcs, fld->s_name), ptr->_int);
|
||||
externs->Printf(" %s.%s: BAD FIELD DEF - %#x\n", PR_StringToNative(&progfuncs->funcs, ent->s_name), PR_StringToNative(&progfuncs->funcs, fld->s_name), ptr->_int);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -454,20 +460,20 @@ void PDECL PR_StackTrace (pubprogfuncs_t *ppf, int showlocals)
|
|||
{
|
||||
if (f->parm_size[arg] == 3)
|
||||
{ //looks like a vector. print it as such
|
||||
externs->Printf(" arg%i(%i): [%g, %g, %g]\n", arg, f->parm_start+ofs, *(float *)(globalbase+ofs), *(float *)(globalbase+ofs+1), *(float *)(globalbase+ofs+2));
|
||||
externs->Printf(" arg%i(%i): [%g, %g, %g]\n", arg, f->parm_start+ofs, *(float *)(globalbase+ofs), *(float *)(globalbase+ofs+1), *(float *)(globalbase+ofs+2));
|
||||
ofs += 2;
|
||||
}
|
||||
else
|
||||
externs->Printf(" arg%i(%i): %g===%i\n", arg, f->parm_start+ofs, *(float *)(globalbase+ofs), *(int *)(globalbase+ofs) );
|
||||
externs->Printf(" arg%i(%i): %g===%i\n", arg, f->parm_start+ofs, *(float *)(globalbase+ofs), *(int *)(globalbase+ofs) );
|
||||
}
|
||||
else
|
||||
{
|
||||
externs->Printf(" unk(%i): %g===%i\n", f->parm_start+ofs, *(float *)(globalbase+ofs), *(int *)(globalbase+ofs) );
|
||||
externs->Printf(" unk(%i): %g===%i\n", f->parm_start+ofs, *(float *)(globalbase+ofs), *(int *)(globalbase+ofs) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
externs->Printf(" %s: %s\n", PR_StringToNative(ppf, local->s_name), PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+ofs), false));
|
||||
externs->Printf(" %s: %s\n", PR_StringToNative(ppf, local->s_name), PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase+ofs), false));
|
||||
if (local->type == ev_vector)
|
||||
ofs+=2;
|
||||
}
|
||||
|
@ -556,6 +562,7 @@ static int ASMCALL PR_EnterFunction (progfuncs_t *progfuncs, mfunction_t *f, int
|
|||
}
|
||||
|
||||
prinst.pr_xfunction = f;
|
||||
prinst.spushed = 0;
|
||||
return f->first_statement - 1; // offset the s++
|
||||
}
|
||||
|
||||
|
@ -708,6 +715,34 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, const char *key, eval_t **result,
|
|||
struct edictrun_s *ed;
|
||||
// etype_t ptrtype = ev_void;
|
||||
|
||||
if (!strncmp(key, "*(float*)", 9))
|
||||
{
|
||||
fofs = strtoul(key+9, NULL, 0);
|
||||
if (fofs < 0 || fofs+3 >= prinst.addressableused)
|
||||
return false;
|
||||
*result = (eval_t*)(pr_strings + fofs);
|
||||
*rettype = ev_float;
|
||||
return true;
|
||||
}
|
||||
if (!strncmp(key, "*(int*)", 7))
|
||||
{
|
||||
fofs = strtoul(key+7, NULL, 0);
|
||||
if (fofs < 0 || fofs+3 >= prinst.addressableused)
|
||||
return false;
|
||||
*result = (eval_t*)(pr_strings + fofs);
|
||||
*rettype = ev_integer;
|
||||
return true;
|
||||
}
|
||||
if (!strncmp(key, "*(string*)", 7))
|
||||
{
|
||||
fofs = strtoul(key+7, NULL, 0);
|
||||
if (fofs < 0 || fofs+3 >= prinst.addressableused)
|
||||
return false;
|
||||
*result = (eval_t*)(pr_strings + fofs);
|
||||
*rettype = ev_string;
|
||||
return true;
|
||||
}
|
||||
|
||||
c = strchr(key, '.');
|
||||
if (c) *c = '\0';
|
||||
def = ED_FindLocalOrGlobal(progfuncs, key, &val);
|
||||
|
@ -790,14 +825,14 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, const char *key, eval_t **result,
|
|||
return true;
|
||||
}
|
||||
|
||||
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key)
|
||||
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *desc, const char *location)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t *)ppf;
|
||||
eval_t *val;
|
||||
eval_t fakeval;
|
||||
etype_t type;
|
||||
|
||||
if (!key)
|
||||
if (!location)
|
||||
{
|
||||
free(prinst.watch_name);
|
||||
prinst.watch_name = NULL;
|
||||
|
@ -805,9 +840,9 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key)
|
|||
prinst.watch_type = ev_void;
|
||||
return false;
|
||||
}
|
||||
if (!LocateDebugTerm(progfuncs, key, &val, &type, &fakeval))
|
||||
if (!LocateDebugTerm(progfuncs, location, &val, &type, &fakeval))
|
||||
{
|
||||
externs->Printf("Unable to evaluate watch term \"%s\"\n", key);
|
||||
externs->Printf("Unable to evaluate watch term \"%s\"\n", location);
|
||||
return false;
|
||||
}
|
||||
if (val == &fakeval)
|
||||
|
@ -822,7 +857,7 @@ pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *ppf, const char *key)
|
|||
}
|
||||
|
||||
free(prinst.watch_name);
|
||||
prinst.watch_name = strdup(key);
|
||||
prinst.watch_name = strdup(desc);
|
||||
prinst.watch_ptr = val;
|
||||
prinst.watch_old = *prinst.watch_ptr;
|
||||
prinst.watch_type = type &~ DEF_SAVEGLOBAL;
|
||||
|
@ -1354,7 +1389,10 @@ static const char *lastfile = NULL;
|
|||
{
|
||||
PR_PrintStatement(progfuncs, statement);
|
||||
if (fatal)
|
||||
{
|
||||
progfuncs->funcs.debug_trace = DEBUG_TRACE_ABORTERROR;
|
||||
progfuncs->funcs.parms->Abort ("%s", fault?fault:"Debugger Abort");
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
|
@ -1602,20 +1640,20 @@ static casecmprange_t casecmprange[] =
|
|||
casecmprange_i //func
|
||||
};
|
||||
|
||||
#define RUNAWAYCHECK() \
|
||||
#define RUNAWAYCHECK() \
|
||||
if (!--*runaway) \
|
||||
{ \
|
||||
prinst.pr_xstatement = st-pr_statements; \
|
||||
{ \
|
||||
prinst.pr_xstatement = st-pr_statements; \
|
||||
PR_RunError (&progfuncs->funcs, "runaway loop error\n");\
|
||||
PR_StackTrace(&progfuncs->funcs,false); \
|
||||
externs->Printf ("runaway loop error\n"); \
|
||||
while(prinst.pr_depth > prinst.exitdepth) \
|
||||
PR_LeaveFunction(progfuncs); \
|
||||
PR_StackTrace(&progfuncs->funcs,false); \
|
||||
externs->Printf ("runaway loop error\n"); \
|
||||
while(prinst.pr_depth > prinst.exitdepth) \
|
||||
PR_LeaveFunction(progfuncs); \
|
||||
prinst.spushed = 0; \
|
||||
return -1; \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#if defined(FTE_TARGET_WEB) || defined(SIMPLE_QCVM)
|
||||
#if defined(SIMPLE_QCVM)
|
||||
static int PR_NoDebugVM(progfuncs_t *fte_restrict progfuncs)
|
||||
{
|
||||
char stack[4*1024];
|
||||
|
@ -1653,7 +1691,7 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft
|
|||
st = &pr_statements16[s];
|
||||
while (progfuncs->funcs.debug_trace || prinst.watch_ptr || prinst.profiling)
|
||||
{
|
||||
#if defined(FTE_TARGET_WEB) || defined(SIMPLE_QCVM)
|
||||
#if defined(SIMPLE_QCVM)
|
||||
reeval16:
|
||||
//this can generate huge functions, so disable it on systems that can't realiably cope with such things (IE initiates an unwanted denial-of-service attack when pointed our javascript, and firefox prints a warning too)
|
||||
prinst.pr_xstatement = st-pr_statements16;
|
||||
|
@ -1678,7 +1716,7 @@ static int PR_ExecuteCode16 (progfuncs_t *fte_restrict progfuncs, int s, int *ft
|
|||
|
||||
static int PR_ExecuteCode32 (progfuncs_t *fte_restrict progfuncs, int s, int *fte_restrict runaway)
|
||||
{
|
||||
#if defined(FTE_TARGET_WEB) ||defined(SIMPLE_QCVM)
|
||||
#if defined(SIMPLE_QCVM)
|
||||
//this can generate huge functions, so disable it on systems that can't realiably cope with such things (IE initiates an unwanted denial-of-service attack when pointed our javascript, and firefox prints a warning too)
|
||||
prinst.pr_xstatement = s;
|
||||
PR_RunError (&progfuncs->funcs, "32bit qc statement support was disabled for this platform.\n");
|
||||
|
@ -1801,6 +1839,10 @@ static void PR_ExecuteCode (progfuncs_t *progfuncs, int s)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && defined(__GLIBC__)
|
||||
#define __USE_GNU
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
|
||||
{
|
||||
|
@ -1833,7 +1875,12 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
|
|||
{
|
||||
// if (pr_global_struct->self)
|
||||
// ED_Print (PROG_TO_EDICT(pr_global_struct->self));
|
||||
#if defined(__GNUC__) && !defined(FTE_TARGET_WEB)
|
||||
#if defined(__GNUC__) && defined(__GLIBC__)
|
||||
Dl_info info;
|
||||
void *caller = __builtin_return_address(0);
|
||||
dladdr(caller, &info);
|
||||
externs->Printf("PR_ExecuteProgram: NULL function from %s+%p(%s)\n", info.dli_fname, (void*)((intptr_t)caller - (intptr_t)info.dli_fbase), info.dli_sname?info.dli_sname:"<function not known>");
|
||||
#elif defined(__GNUC__) && !defined(FTE_TARGET_WEB)
|
||||
externs->Printf("PR_ExecuteProgram: NULL function from exe (address %p)\n", __builtin_return_address(0));
|
||||
#else
|
||||
externs->Printf("PR_ExecuteProgram: NULL function from exe\n");
|
||||
|
@ -1902,104 +1949,138 @@ typedef struct {
|
|||
int fnum;
|
||||
int progsnum;
|
||||
int statement;
|
||||
int spushed;
|
||||
} qcthreadstack_t;
|
||||
typedef struct qcthread_s {
|
||||
int fstackdepth;
|
||||
qcthreadstack_t fstack[MAX_STACK_DEPTH];
|
||||
int lstackused;
|
||||
int lstack[LOCALSTACK_SIZE];
|
||||
int xstatement;
|
||||
int xfunction;
|
||||
progsnum_t xprogs;
|
||||
} qcthread_t;
|
||||
|
||||
struct qcthread_s *PDECL PR_ForkStack(pubprogfuncs_t *ppf)
|
||||
{ //QC code can call builtins that call qc code.
|
||||
//to get around the problems of restoring the builtins we simply don't save the thread over the builtin.
|
||||
//this may be an error when OP_PUSH has been used.
|
||||
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
int i, l;
|
||||
int i, pushed;
|
||||
int ed = prinst.exitdepth;
|
||||
int localsoffset, baselocalsoffset;
|
||||
qcthread_t *thread = externs->memalloc(sizeof(qcthread_t));
|
||||
const mfunction_t *f;
|
||||
int curprogs = ppf->callprogs;
|
||||
|
||||
//notes:
|
||||
//pr_stack[prinst.exitdepth] is a dummy entry, with null function refs. we don't care about it.
|
||||
//pr_stack[pr_depth] is technically invalid but logically required - it refers to the current function instead. stoopid extra indirection.
|
||||
//[pr_depth] is the qc function that called whichever builtin we're executing right now so we want that (logical) one. [0] is irrelevant though.
|
||||
//entering a function copys its locals into the local stack for restoration on return, any OP_PUSHED stuff within the frame is then after that.
|
||||
//OP_PUSH/'pushed' is the PARENT function's pushes. f->locals stuff is the CHILD function's pushes.
|
||||
|
||||
//copy out the functions stack.
|
||||
for (i = 0,localsoffset=0; i < ed; i++)
|
||||
for (i = 1,localsoffset=0; i <= ed; i++)
|
||||
{
|
||||
if (i+1 == prinst.pr_depth)
|
||||
if (i == prinst.pr_depth)
|
||||
{
|
||||
localsoffset += prinst.spushed;
|
||||
|
||||
f = prinst.pr_xfunction;
|
||||
localsoffset += f->locals;
|
||||
}
|
||||
else
|
||||
f = prinst.pr_stack[i+1].f;
|
||||
localsoffset += f->locals; //this is where it crashes
|
||||
{
|
||||
localsoffset += prinst.pr_stack[i].pushed;
|
||||
|
||||
f = prinst.pr_stack[i].f;
|
||||
if (f)
|
||||
localsoffset += f->locals;
|
||||
}
|
||||
}
|
||||
//now we can start copying the stack.
|
||||
baselocalsoffset = localsoffset;
|
||||
for (i = ed; i < prinst.pr_depth; i++)
|
||||
thread->fstackdepth = 0;
|
||||
for (; i <= prinst.pr_depth; i++)
|
||||
{
|
||||
thread->fstack[i-ed].fnum = prinst.pr_stack[i].f - pr_progstate[prinst.pr_stack[i].progsnum].functions;
|
||||
thread->fstack[i-ed].progsnum = prinst.pr_stack[i].progsnum;
|
||||
thread->fstack[i-ed].statement = prinst.pr_stack[i].s;
|
||||
if (i == prinst.pr_depth)
|
||||
{ //top of the stack. whichever function called the builtin we're executing.
|
||||
thread->fstack[thread->fstackdepth].fnum = prinst.pr_xfunction - pr_progstate[curprogs].functions;
|
||||
thread->fstack[thread->fstackdepth].progsnum = curprogs;
|
||||
thread->fstack[thread->fstackdepth].statement = prinst.pr_xstatement;
|
||||
thread->fstack[thread->fstackdepth].spushed = prinst.spushed;
|
||||
thread->fstackdepth++;
|
||||
|
||||
if (i+1 == prinst.pr_depth)
|
||||
localsoffset += prinst.spushed;
|
||||
f = prinst.pr_xfunction;
|
||||
localsoffset += f->locals;
|
||||
}
|
||||
else
|
||||
f = prinst.pr_stack[i+1].f;
|
||||
localsoffset += f->locals;
|
||||
{
|
||||
thread->fstack[thread->fstackdepth].fnum = prinst.pr_stack[i].f - pr_progstate[prinst.pr_stack[i].progsnum].functions;
|
||||
thread->fstack[thread->fstackdepth].progsnum = prinst.pr_stack[i].progsnum;
|
||||
thread->fstack[thread->fstackdepth].statement = prinst.pr_stack[i].s;
|
||||
thread->fstack[thread->fstackdepth].spushed = prinst.pr_stack[i].pushed;
|
||||
thread->fstackdepth++;
|
||||
|
||||
localsoffset += prinst.pr_stack[i].pushed;
|
||||
f = prinst.pr_stack[i].f;
|
||||
localsoffset += f->locals;
|
||||
}
|
||||
}
|
||||
thread->fstackdepth = prinst.pr_depth - ed;
|
||||
|
||||
for (i = prinst.pr_depth - 1; i >= ed ; i--)
|
||||
//we now know how many locals we need... but life is not easy.
|
||||
//preserving on entry means the definitive location is the pr_globals - and they'll have been 'corrupted' by any child functions.
|
||||
//so we need to unwind(rewind) them here to find their proper 'current' values, so that resumption can rebuild the execution stack on resume to revert them properly to their prior values. messy.
|
||||
for (i = prinst.pr_depth; i > ed ; i--)
|
||||
{
|
||||
if (i+1 == prinst.pr_depth)
|
||||
f = prinst.pr_xfunction;
|
||||
if (i == prinst.pr_depth)
|
||||
f = prinst.pr_xfunction, pushed = prinst.spushed;
|
||||
else
|
||||
f = prinst.pr_stack[i+1].f;
|
||||
f = prinst.pr_stack[i].f, pushed = prinst.pr_stack[i].pushed;
|
||||
|
||||
//preseve any OP_PUSH stuff
|
||||
localsoffset -= pushed;
|
||||
memcpy(&thread->lstack[localsoffset-baselocalsoffset], prinst.localstack+localsoffset, pushed*sizeof(int));
|
||||
|
||||
//preserve the current locals
|
||||
localsoffset -= f->locals;
|
||||
for (l = 0; l < f->locals; l++)
|
||||
{
|
||||
thread->lstack[localsoffset-baselocalsoffset + l ] = ((int *)pr_globals)[f->parm_start + l];
|
||||
((int *)pr_globals)[f->parm_start + l] = prinst.localstack[localsoffset+l]; //copy the old value into the globals (so the older functions have the correct locals.
|
||||
}
|
||||
memcpy(&thread->lstack[localsoffset-baselocalsoffset], ((int *)pr_globals)+f->parm_start, f->locals*sizeof(int));
|
||||
//unwind the locals so parent functions we preserve have the proper current values.
|
||||
memcpy(((int *)pr_globals)+f->parm_start, prinst.localstack+localsoffset, f->locals*sizeof(int));
|
||||
}
|
||||
|
||||
for (i = ed; i < prinst.pr_depth ; i++) //we need to get the locals back to how they were.
|
||||
//rewind the locals so they don't get corrupt when returning from fork etc.
|
||||
for (i = ed+1; i <= prinst.pr_depth ; i++) //we need to get the locals back to how they were.
|
||||
{
|
||||
if (i+1 == prinst.pr_depth)
|
||||
f = prinst.pr_xfunction;
|
||||
if (i == prinst.pr_depth)
|
||||
f = prinst.pr_xfunction, pushed = prinst.spushed;
|
||||
else
|
||||
f = prinst.pr_stack[i+1].f;
|
||||
f = prinst.pr_stack[i].f, pushed = prinst.pr_stack[i].pushed;
|
||||
|
||||
for (l = 0; l < f->locals; l++)
|
||||
{
|
||||
((int *)pr_globals)[f->parm_start + l] = thread->lstack[localsoffset-baselocalsoffset + l];
|
||||
}
|
||||
memcpy(((int *)pr_globals)+f->parm_start, &thread->lstack[localsoffset-baselocalsoffset], f->locals*sizeof(int));
|
||||
localsoffset += f->locals;
|
||||
|
||||
localsoffset += pushed; //we didn't need to clobber this, just skip it to avoid corrupting.
|
||||
}
|
||||
thread->lstackused = localsoffset - baselocalsoffset;
|
||||
|
||||
thread->xstatement = prinst.pr_xstatement;
|
||||
thread->xfunction = prinst.pr_xfunction - current_progstate->functions;
|
||||
thread->xprogs = prinst.pr_typecurrent;
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
|
||||
{
|
||||
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
|
||||
mfunction_t *f, *oldf;
|
||||
int i,l,ls, olds;
|
||||
progsnum_t initial_progs;
|
||||
mfunction_t *f;
|
||||
int i;
|
||||
progsnum_t initial_progs = prinst.pr_typecurrent;
|
||||
unsigned int initial_stack;
|
||||
int oldexitdepth;
|
||||
int *glob;
|
||||
|
||||
int s;
|
||||
#ifndef QCGC
|
||||
int tempdepth;
|
||||
#endif
|
||||
|
||||
progsnum_t prnum = thread->xprogs;
|
||||
int fnum = thread->xfunction;
|
||||
|
||||
if (prinst.localstack_used + thread->lstackused > LOCALSTACK_SIZE)
|
||||
PR_RunError(&progfuncs->funcs, "Too many locals on resumtion of QC thread\n");
|
||||
|
||||
|
@ -2008,87 +2089,57 @@ void PDECL PR_ResumeThread (pubprogfuncs_t *ppf, struct qcthread_s *thread)
|
|||
|
||||
|
||||
//do progs switching stuff as appropriate. (fteqw only)
|
||||
initial_progs = prinst.pr_typecurrent;
|
||||
PR_SwitchProgsParms(progfuncs, prnum);
|
||||
|
||||
|
||||
oldexitdepth = prinst.exitdepth;
|
||||
prinst.exitdepth = prinst.pr_depth;
|
||||
|
||||
ls = 0;
|
||||
initial_stack = prinst.localstack_used;
|
||||
//add on the callstack.
|
||||
for (i = 0; i < thread->fstackdepth; i++)
|
||||
{
|
||||
if (prinst.pr_depth == prinst.exitdepth)
|
||||
{
|
||||
prinst.pr_stack[prinst.pr_depth].f = prinst.pr_xfunction;
|
||||
prinst.pr_stack[prinst.pr_depth].s = prinst.pr_xstatement;
|
||||
prinst.pr_stack[prinst.pr_depth].progsnum = initial_progs;
|
||||
}
|
||||
else
|
||||
{
|
||||
prinst.pr_stack[prinst.pr_depth].progsnum = thread->fstack[i].progsnum;
|
||||
prinst.pr_stack[prinst.pr_depth].f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
|
||||
prinst.pr_stack[prinst.pr_depth].s = thread->fstack[i].statement;
|
||||
}
|
||||
|
||||
if (i+1 == thread->fstackdepth)
|
||||
{
|
||||
f = &pr_cp_functions[fnum];
|
||||
glob = (int*)pr_globals;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = pr_progstate[thread->fstack[i+1].progsnum].functions + thread->fstack[i+1].fnum;
|
||||
glob = (int*)pr_progstate[thread->fstack[i+1].progsnum].globals;
|
||||
}
|
||||
for (l = 0; l < f->locals; l++)
|
||||
{
|
||||
prinst.localstack[prinst.localstack_used++] = glob[f->parm_start + l];
|
||||
glob[f->parm_start + l] = thread->lstack[ls++];
|
||||
}
|
||||
|
||||
//make the new stack frame from the working values so stuff gets restored properly...
|
||||
prinst.pr_stack[prinst.pr_depth].f = prinst.pr_xfunction;
|
||||
prinst.pr_stack[prinst.pr_depth].s = prinst.pr_xstatement;
|
||||
prinst.pr_stack[prinst.pr_depth].progsnum = prinst.pr_typecurrent;
|
||||
prinst.pr_stack[prinst.pr_depth].pushed = prinst.spushed;
|
||||
prinst.pr_depth++;
|
||||
|
||||
//restore the OP_PUSH data
|
||||
memcpy(&prinst.localstack[prinst.localstack_used], &thread->lstack[prinst.localstack_used-initial_stack], prinst.spushed*sizeof(int));
|
||||
prinst.localstack_used += prinst.spushed;
|
||||
|
||||
//and refill the working values from the inbound stack
|
||||
PR_SwitchProgs(progfuncs, thread->fstack[i].progsnum);
|
||||
prinst.pr_xfunction = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
|
||||
prinst.pr_xstatement = thread->fstack[i].statement;
|
||||
prinst.spushed = thread->fstack[i].spushed;
|
||||
|
||||
f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum;
|
||||
glob = (int*)pr_progstate[thread->fstack[i].progsnum].globals;
|
||||
|
||||
//copy the 'new' function's current globals into the local stack for restoration
|
||||
memcpy(&prinst.localstack[prinst.localstack_used], &glob[f->parm_start], sizeof(int)*f->locals);
|
||||
//and overwrite them with the saved values.
|
||||
memcpy(&glob[f->parm_start], &thread->lstack[prinst.localstack_used-initial_stack], sizeof(int)*f->locals);
|
||||
prinst.localstack_used += f->locals;
|
||||
}
|
||||
|
||||
if (ls != thread->lstackused)
|
||||
if (prinst.localstack_used-initial_stack != thread->lstackused)
|
||||
PR_RunError(&progfuncs->funcs, "Thread stores incorrect locals count\n");
|
||||
|
||||
|
||||
f = &pr_cp_functions[fnum];
|
||||
|
||||
// thread->lstackused -= f->locals; //the current function is the odd one out.
|
||||
|
||||
//add on the locals stack
|
||||
memcpy(prinst.localstack+prinst.localstack_used, thread->lstack, sizeof(int)*thread->lstackused);
|
||||
prinst.localstack_used += thread->lstackused;
|
||||
|
||||
//bung the locals of the current function on the stack.
|
||||
// for (i=0 ; i < f->locals ; i++)
|
||||
// ((int *)pr_globals)[f->parm_start + i] = 0xff00ff00;//thread->lstack[thread->lstackused+i];
|
||||
|
||||
|
||||
// PR_EnterFunction (progfuncs, f, initial_progs);
|
||||
oldf = prinst.pr_xfunction;
|
||||
olds = prinst.pr_xstatement;
|
||||
prinst.pr_xfunction = f;
|
||||
s = thread->xstatement;
|
||||
|
||||
#ifndef QCGC
|
||||
tempdepth = prinst.numtempstringsstack;
|
||||
#endif
|
||||
PR_ExecuteCode(progfuncs, s);
|
||||
PR_ExecuteCode(progfuncs, prinst.pr_xstatement);
|
||||
|
||||
|
||||
PR_SwitchProgsParms(progfuncs, initial_progs);
|
||||
PR_SwitchProgsParms(progfuncs, initial_progs); //just in case
|
||||
#ifndef QCGC
|
||||
PR_FreeTemps(progfuncs, tempdepth);
|
||||
prinst.numtempstringsstack = tempdepth;
|
||||
#endif
|
||||
|
||||
prinst.exitdepth = oldexitdepth;
|
||||
prinst.pr_xfunction = oldf;
|
||||
prinst.pr_xstatement = olds;
|
||||
}
|
||||
|
||||
void PDECL PR_AbortStack (pubprogfuncs_t *ppf)
|
||||
|
|
|
@ -331,7 +331,7 @@ int PDECL QC_RegisterFieldVar(pubprogfuncs_t *ppf, unsigned int type, const char
|
|||
{ //we just found a new fieldname inside a progs
|
||||
prinst.field[fnum].ofs = ofs = prinst.fields_size/sizeof(pvec_t); //add on the end
|
||||
|
||||
//if the progs field offset matches annother offset in the same progs, make it match up with the earlier one.
|
||||
//if the progs field offset matches another offset in the same progs, make it match up with the earlier one.
|
||||
if (progsofs>=0)
|
||||
{
|
||||
unsigned otherofs;
|
||||
|
|
|
@ -167,12 +167,12 @@ typedef struct prinst_s
|
|||
#define MAX_STACK_DEPTH 1024 //insanely high value requried for xonotic.
|
||||
prstack_t pr_stack[MAX_STACK_DEPTH];
|
||||
int pr_depth;
|
||||
int spushed;
|
||||
|
||||
//locals
|
||||
#define LOCALSTACK_SIZE 16384
|
||||
int localstack[LOCALSTACK_SIZE];
|
||||
#define LOCALSTACK_SIZE (65536*16) //in words
|
||||
int *localstack;
|
||||
int localstack_used;
|
||||
int spushed; //extra
|
||||
|
||||
//step-by-step debug state
|
||||
int debugstatement;
|
||||
|
@ -328,7 +328,7 @@ typedef struct edictrun_s
|
|||
int PDECL Comp_Begin(pubprogfuncs_t *progfuncs, int nump, const char **parms);
|
||||
int PDECL Comp_Continue(pubprogfuncs_t *progfuncs);
|
||||
|
||||
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, const char *key);
|
||||
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, const char *desc, const char *location);
|
||||
char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *progfuncs, const char *key);
|
||||
char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, size_t *size, size_t maxsize, int mode);
|
||||
int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, const char *file, void *ctx, void (PDECL *memoryreset) (pubprogfuncs_t *progfuncs, void *ctx), void (PDECL *entspawned) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend), pbool(PDECL *extendedterm)(pubprogfuncs_t *progfuncs, void *ctx, const char **extline));
|
||||
|
@ -557,6 +557,7 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *inst, string_t str);
|
|||
|
||||
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs, struct QCC_type_s **typehint);
|
||||
char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs);
|
||||
char *PR_GlobalStringImmediate (progfuncs_t *progfuncs, int ofs);
|
||||
|
||||
pbool CompileFile(progfuncs_t *progfuncs, const char *filename);
|
||||
|
||||
|
|
|
@ -26,6 +26,16 @@
|
|||
#define VARGS
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 202311L // c23
|
||||
#define FALLTHROUGH [[fallthrough]];
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 7
|
||||
#define FALLTHROUGH __attribute__((fallthrough));
|
||||
#elif defined(__clang__) && __clang_major__ >= 7
|
||||
#define FALLTHROUGH __attribute__((fallthrough));
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(__i386__) //supported arch
|
||||
#if defined(__GNUC__) || defined(_MSC_VER) //supported compilers (yay for inline asm)
|
||||
//#define QCJIT
|
||||
|
@ -95,7 +105,8 @@ ev_union, //not really sure why this is separate from struct
|
|||
ev_accessor,//some weird type to provide class-like functions over a basic type.
|
||||
ev_enum, //just a numeric type
|
||||
ev_typedef, //so typedefs can refer to their original type (primarily for structs).
|
||||
ev_boolean, //exists to optimise if(-0) workarounds. engine just sees int/float.
|
||||
ev_boolean, //exists to optimise if(-0) workarounds. engine just sees int/float. uses parentclass
|
||||
ev_bitfld, //erk... structs only... converted to their parentclass on read.
|
||||
} etype_t;
|
||||
enum {
|
||||
DEBUG_TRACE_OFF, //debugging should be off.
|
||||
|
@ -180,6 +191,7 @@ struct pubprogfuncs_s
|
|||
pbool (PDECL *Decompile) (pubprogfuncs_t *prinst, const char *fname);
|
||||
|
||||
int callargc; //number of args of built-in call
|
||||
int callprogs; //which progs it was called from...
|
||||
|
||||
char *stringtable; //qc strings are all relative. add to a qc string. this is required for support of frikqcc progs that strip string immediates.
|
||||
unsigned int stringtablesize;
|
||||
|
@ -200,6 +212,7 @@ struct pubprogfuncs_s
|
|||
char *(PDECL *AddString) (pubprogfuncs_t *prinst, const char *val, int minlength, pbool demarkup); //dump a string into the progs memory (for setting globals and whatnot)
|
||||
void *(PDECL *Tempmem) (pubprogfuncs_t *prinst, int ammount, char *whatfor); //grab some mem for as long as the progs stays loaded
|
||||
void *(PDECL *AddressableAlloc) (pubprogfuncs_t *progfuncs, unsigned int ammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/
|
||||
void *(PDECL *AddressableRealloc) (pubprogfuncs_t *progfuncs, void *oldptr, unsigned int newammount); /*returns memory within the qc block, use stringtoprogs to get a usable qc pointer/string*/
|
||||
void (PDECL *AddressableFree) (pubprogfuncs_t *progfuncs, void *mem); /*frees a block of addressable memory*/
|
||||
string_t (PDECL *TempString) (pubprogfuncs_t *prinst, const char *str);
|
||||
string_t (PDECL *AllocTempString) (pubprogfuncs_t *prinst, char **str, unsigned int len);
|
||||
|
@ -211,7 +224,7 @@ struct pubprogfuncs_s
|
|||
void (PDECL *EntClear) (pubprogfuncs_t *progfuncs, struct edict_s *e);
|
||||
void (PDECL *FindPrefixGlobals) (pubprogfuncs_t *progfuncs, int prnum, char *prefix, void (PDECL *found) (pubprogfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type, void *ctx), void *ctx); //calls the callback for each named global found
|
||||
|
||||
pbool (PDECL *SetWatchPoint) (pubprogfuncs_t *prinst, const char *key);
|
||||
pbool (PDECL *SetWatchPoint) (pubprogfuncs_t *prinst, const char *desc, const char *location);
|
||||
|
||||
void (PDECL *AddSharedVar) (pubprogfuncs_t *progfuncs, int start, int size);
|
||||
void (PDECL *AddSharedFieldVar) (pubprogfuncs_t *progfuncs, int num, char *relstringtable);
|
||||
|
@ -244,7 +257,7 @@ typedef struct progexterns_s {
|
|||
int (VARGS *Printf) (const char *, ...) LIKEPRINTF(1);
|
||||
int (VARGS *DPrintf) (const char *, ...) LIKEPRINTF(1);
|
||||
void (VARGS *Sys_Error) (const char *, ...) LIKEPRINTF(1);
|
||||
void (VARGS *Abort) (char *, ...) LIKEPRINTF(1);
|
||||
void (VARGS *Abort) (const char *, ...) LIKEPRINTF(1);
|
||||
pbool (PDECL *CheckHeaderCrc) (pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename);
|
||||
|
||||
void (PDECL *entspawn) (struct edict_s *ent, int loading); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue