forked from fte/fteqw
1
0
Fork 0

Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.

Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
This commit is contained in:
Shpoike 2024-04-09 18:13:59 +01:00
parent ea0509805b
commit 8dadfb4878
199 changed files with 10060 additions and 3764 deletions

View File

@ -174,6 +174,19 @@ IF(JPEG_FOUND)
ELSE()
MESSAGE(WARNING "libjpeg library NOT available. Who cares?")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_JPEG)
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?")
ENDIF()
SET(FTE_DEP_PNG true CACHE BOOL "Link against libpng.")
@ -187,6 +200,7 @@ IF(PNG_FOUND)
ELSE()
MESSAGE(WARNING "libpng library NOT available. Good luck with screenshots.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_PNG)
SET(PNG_LIBRARIES)
ENDIF()
SET(FTE_DEP_FREETYPE true CACHE BOOL "Link against libfreetype.")
@ -221,7 +235,7 @@ ELSE()
ENDIF()
SET(FTE_DEP_VORBISFILE true CACHE BOOL "Link against libvorbisfile.")
IF(FTE_DEP_VROBISFILE)
IF(FTE_DEP_VORBISFILE)
FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile)
ENDIF()
IF(NOT VORBISFILE_LIBRARY)
@ -230,18 +244,30 @@ IF(NOT VORBISFILE_LIBRARY)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_OGG)
ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
SET(FTE_WERROR true CACHE BOOL "Warnings as errors.")
ELSE()
SET(FTE_WERROR false CACHE BOOL "Warnings as errors.")
ENDIF()
IF(FTE_WERROR)
SET(FTE_WERROR_ARG "-Werror")
ELSE()
SET(FTE_WERROR_ARG "")
ENDIF()
IF(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign")
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall ${FTE_WERROR_ARG} -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
ELSE()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 ${FTE_WERROR_ARG}")
ENDIF()
endif()
IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") #
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-definition") #k&r c is weird and can't cope with 64bit types.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-parameter-type") #k&r c is weird and can't cope with 64bit types.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-declaration") #
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") #void* stuff
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") #msvc doesn't support vla
@ -254,9 +280,9 @@ IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
#might as well do this, public builds use the regular Makefile.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall ${FTE_WERROR_} -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
ELSE()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 ${FTE_WERROR_}")
ENDIF()
IF (NOT FTE_USE_SDL)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--warn-common")
@ -266,8 +292,8 @@ ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
IF(NOT ${WIN32})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEBUG")
ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FILE_OFFSET_BITS=64")
@ -289,6 +315,32 @@ FUNCTION(EMBED_PLUGIN_META PLUGNAME PLUGTITLE PLUGDESC)
VERBATIM)
ENDFUNCTION()
SET(FTE_DEP_GNUTLS true CACHE BOOL "Link against gnutls")
IF(FTE_DEP_GNUTLS)
FIND_PACKAGE(GnuTLS)
IF(NOT GNUTLS_FOUND)
MESSAGE(WARNING "gnutls library NOT available. HTTPS/DTLS will not be available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_GNUTLS)
ELSE()
IF(WIN32)
SET(GNUTLS_STATIC true CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
ELSE()
SET(GNUTLS_STATIC false CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
ENDIF()
IF(GNUTLS_STATIC)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};GNUTLS_STATIC)
SET(FTE_LIBS ${FTE_LIBS} ${GNUTLS_LIBRARY})
SET(FTESV_LIBS ${FTESV_LIBS} ${GNUTLS_LIBRARY})
ENDIF()
ENDIF()
ENDIF()
IF(WIN32)
SET(FTE_DEP_WINSSPI true CACHE BOOL "Link against winsspi(schannel)")
IF(NOT FTE_DEP_WINSSPI)
SET(FTE_DEFINES ${FTE_DEFINES};NO_WINSSPI)
ENDIF()
ENDIF()
IF(${ANDROID})
# FIND_PACKAGE(Freetype REQUIRED)
@ -315,6 +367,7 @@ ELSEIF(WIN32 AND NOT FTE_USE_SDL)
engine/client/winquake.rc
engine/common/sys_win_threads.c
engine/common/net_ssl_winsspi.c
engine/common/net_ssl_gnutls.c
engine/common/fs_win32.c
engine/client/cd_win.c
engine/client/in_win.c
@ -345,25 +398,13 @@ ELSEIF(WIN32 AND NOT FTE_USE_SDL)
engine/client/winquake.rc
engine/common/sys_win_threads.c
engine/common/net_ssl_winsspi.c
engine/common/net_ssl_gnutls.c
engine/common/fs_win32.c
engine/server/sv_sys_win.c
)
ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
#openbsd will have issues with snd_linux.c
FIND_PACKAGE(GnuTLS)
IF(NOT GNUTLS_FOUND)
MESSAGE(WARNING "gnutls library NOT available. HTTPS/DTLS will not be available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_GNUTLS)
ELSE()
SET(GNUTLS_STATIC false CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
IF(GNUTLS_STATIC)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};GNUTLS_STATIC)
SET(FTE_LIBS ${FTE_LIBS} ${GNUTLS_LIBRARY})
SET(FTESV_LIBS ${FTESV_LIBS} ${GNUTLS_LIBRARY})
ENDIF()
ENDIF()
#linux-only packages
FIND_PACKAGE(ALSA)
IF(ALSA_FOUND)
@ -382,6 +423,10 @@ ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_RANDR)
MESSAGE(WARNING "Xrandr library NOT available.")
ENDIF()
IF (NOT X11_Xscreensaver_FOUND)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_XSS)
MESSAGE(WARNING "Xss library NOT available.")
ENDIF()
ELSE()
MESSAGE(WARNING "x11 library NOT available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11)
@ -450,7 +495,7 @@ ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
ENDIF()
ENDIF()
SET(FTESV_DEFINES MULTITHREAD)
SET(FTESV_DEFINES ${FTESV_DEFINES};MULTITHREAD)
SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES}
engine/server/sv_sys_unix.c
engine/common/sys_linux_threads.c
@ -481,7 +526,7 @@ ELSEIF(1) #SDL
engine/gl/gl_vidsdl.c
)
SET(FTESV_DEFINES FTE_SDL)
SET(FTESV_DEFINES ${FTESV_DEFINES};MULTITHREAD)
SET(FTESV_LIBS ${FTESV_LIBS} ${SYS_LIBS} ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES})
IF(WIN32)
@ -505,6 +550,7 @@ ELSEIF(1) #SDL
engine/common/sys_linux_threads.c
engine/server/sv_sys_unix.c
)
SET(FTESV_LIBS ${FTESV_LIBS} pthread)
ENDIF()
ELSE()
# engine/common/sys_linux_threads.c
@ -862,7 +908,7 @@ SET(FTE_Q3_FILES
)
#For annoying compressed gltf2 files.
SET(FTE_DEP_DRACO false CACHE BOOL "Link against libdraco.")
SET(FTE_DEP_DRACO false CACHE BOOL "Link against libdraco (apache2).")
IF(FTE_DEP_DRACO)
FIND_LIBRARY(
DRACO_LIBRARY
@ -1052,8 +1098,8 @@ ELSE()
imgtool.c
iqm/iqm.h
)
SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${DRACO_CFLAGS};${FTE_REVISON}")
TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS} ${DRACO_LIBRARY})
SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${DRACO_CFLAGS};${FTE_LIB_DEFINES};${FTE_REVISON}")
TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS} ${DRACO_LIBRARY} ${JPEG_LIBRARIES} ${PNG_LIBRARIES})
SET(INSTALLTARGS ${INSTALLTARGS} iqmtool)
ENDIF()
@ -1151,6 +1197,7 @@ ELSE()
engine/qclib/qcc_pr_lex.c
engine/qclib/qccmain.c
engine/qclib/qcd_main.c
engine/qclib/decomp.c
engine/qclib/packager.c
)
SET_TARGET_PROPERTIES(fteqcc PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON}")
@ -1260,6 +1307,8 @@ SET(FTE_PLUG_OPENSSL false CACHE BOOL "Compile OpenSSL.")
IF(FTE_PLUG_OPENSSL)
#the openssl license is incompatible with the GPL, so while we have code to use it distributing the binaries built with it is not a (legal) option.
#note that openssl 3.0.0 upwards are apache-2 licensed, which IS gpl-3 compatible (though not gpl-2). debian has not caught up with that yet, however.
#Crosscompile linux->win64: sudo ln -s ${pwd}/engine/libs-x86_64-w64-mingw32/openssl-openssl-3.0.1/ /usr/x86_64-w64-mingw32/OpenSSL
SET(OPENSSL_USE_STATIC_LIBS true CACHE BOOL "Link openssl statically.") #usually as an .so though. :/)
FIND_PACKAGE(OpenSSL)
IF(OPENSSL_VERSION_MAJOR LESS 3)
SET(FTE_PRIVATE_USE_ONLY false CACHE BOOL "Ignore license violations.")
@ -1275,11 +1324,15 @@ IF(FTE_PLUG_OPENSSL)
MESSAGE(WARNING "Using openssl. Resulting plugin must be licensed as GPLv3.")
ENDIF()
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES})
if (WIN32)
SET(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ws2_32)
ENDIF()
ADD_LIBRARY(plug_openssl MODULE
plugins/plugin.c
plugins/net_ssl_openssl.c
)
TARGET_INCLUDE_DIRECTORIES(plug_openssl PRIVATE ${OPENSSL_INCLUDE_DIR})
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
TARGET_LINK_LIBRARIES(plug_openssl ${SYS_LIBS} ${OPENSSL_LIBRARIES})
@ -1291,7 +1344,7 @@ ENDIF()
#IF(FTE_PLUG_GNUTLS)
# FIND_PACKAGE(GnuTLS)
# IF(NOT GNUTLS_FOUND)
# MESSAGE(WARNING "openssl library NOT available. you'll have to use some other library.")
# MESSAGE(WARNING "gnutls library NOT available. you'll have to use some other library.")
# ELSE()
# SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES})
#
@ -1628,7 +1681,8 @@ IF(FTE_MENU_SYS)
DEPENDS fteqcc
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/menusys/"
COMMAND fteqcc -srcfile "menu.src" -o "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" -DREVISION="${SVNREVISION}" -DDATE="${FTE_DATE}" -DBRANCH="${FTE_BRANCH}"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" "${CMAKE_CURRENT_BINARY_DIR}/menu.lno"
COMMAND /bin/echo -e "{\\n package fte_menusys\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"Replacement Menus\"\\n gamedir \"id1\"\\n desc \"Modern menus to replace the ancient quake ones\"\\n}" | zip -j -q -9 -fz- "${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3" - "${CMAKE_CURRENT_BINARY_DIR}/menu.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" "${CMAKE_CURRENT_BINARY_DIR}/menu.lno" "${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3"
SOURCES
quakec/menusys/menu.src
quakec/menusys/fteextensions.qc
@ -1665,12 +1719,8 @@ IF(FTE_MENU_SYS)
quakec/menusys/menu/quit.qc
)
ADD_CUSTOM_COMMAND(
TARGET menusys POST_BUILD
COMMAND /bin/echo -e "{\\n package fte_menusys\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"Replacement Menus\"\\n gamedir \"id1\"\\n desc \"Modern menus to replace the ancient quake ones\"\\n}" | zip -q -9 -fz- menusys.pk3 - menu.dat
VERBATIM)
INSTALL(FILES
menusys.pk3
${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/")
ENDIF()
@ -1681,7 +1731,8 @@ IF(FTE_CSADDON)
DEPENDS fteqcc
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/csaddon/src/"
COMMAND fteqcc -srcfile "csaddon.src" -o "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.lno"
COMMAND /bin/echo -e "{\\n package fte_csaddon\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"${PLUGTITLE}\"\\n gamedir \"id1\"\\n desc \"${PLUGDESC}\"\\n}" | zip -j -q -9 -fz- "${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3" - "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.lno" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3"
SOURCES
quakec/csaddon/src/csaddon.src
@ -1704,11 +1755,7 @@ IF(FTE_CSADDON)
quakec/csaddon/src/csaddon.qc
)
ADD_CUSTOM_COMMAND(
TARGET csaddon POST_BUILD
COMMAND /bin/echo -e "{\\n package fte_csaddon\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"${PLUGTITLE}\"\\n gamedir \"id1\"\\n desc \"${PLUGDESC}\"\\n}" | zip -q -9 -fz- csaddon.pk3 - csaddon.dat
VERBATIM)
INSTALL(FILES
csaddon.pk3
${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/")
ENDIF()

View File

@ -137,14 +137,10 @@ endif
ifneq (,$(findstring DLINK_QUAKE3,$(FTE_CONFIG_EXTRA)))
LINK_QUAKE3=1
endif
ifeq ($(findstring web,$(FTE_TARGET)),) #the web target uses javascript/browser loaders for common audio+image files instead of needing to embed our own, which keeps sizes down slightly.
ifeq (,$(findstring DNO_VORBISFILE,$(FTE_CONFIG_EXTRA)))
USE_VORBISFILE=1
endif
ifneq (,$(findstring DLINK_FREETYPE,$(FTE_CONFIG_EXTRA)))
LINK_FREETYPE=1
LINK_ZLIB=1
LINK_PNG=1
endif
ifneq (,$(findstring DLINK_JPEG,$(FTE_CONFIG_EXTRA)))
LINK_JPEG=1
endif
@ -152,6 +148,12 @@ ifneq (,$(findstring DLINK_PNG,$(FTE_CONFIG_EXTRA)))
LINK_ZLIB=1
LINK_PNG=1
endif
endif
ifneq (,$(findstring DLINK_FREETYPE,$(FTE_CONFIG_EXTRA)))
LINK_FREETYPE=1
LINK_ZLIB=1
LINK_PNG=1
endif
ifneq (,$(findstring -Os,$(FTE_CONFIG_EXTRA)))
CPUOPTIMIZATIONS+=-Os
BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS))
@ -164,6 +166,12 @@ ifneq (,$(findstring DLINK_INTERNAL_BULLET,$(FTE_CONFIG_EXTRA)))
#bullet plugin will be built into the exe itself
INTERNAL_BULLET=1
endif
ifneq (,$(findstring DLINK_EZHUD,$(FTE_CONFIG_EXTRA)))
LINK_EZHUD=1
endif
ifneq (,$(findstring DLINK_OPENSSL,$(FTE_CONFIG_EXTRA)))
LINK_OPENSSL=1
endif
ifeq ($(BITS),64)
CC:=$(CC) -m64
@ -249,8 +257,9 @@ DO_CMAKE=cmake -DCMAKE_C_COMPILER="$(firstword $(CC))" -DCMAKE_C_FLAGS="$(wordli
ifeq ($(DROID_ARCH),)
#armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64
DROID_ARCH=armeabi-v7a
DROID_ARCH+=x86
DROID_ARCH+=armeabi-v7a #old 32bit android. yucky.
DROID_ARCH+=arm64-v8a #modern android devices are 64bit-only. urgh.
DROID_ARCH+=x86 #mostly for testing...
#DROID_ARCH+=x86_64 #starting with DROID_API_LEVEL 21
endif
ifeq ($(FTE_TARGET),droid)
@ -632,8 +641,6 @@ ifeq (win,$(findstring cyg,$(FTE_TARGET))$(findstring win,$(FTE_TARGET)))
# OGGVORBISLDFLAGS=$(MINGW_LIBS_DIR)/libvorbisfile.a $(MINGW_LIBS_DIR)/libvorbis.a $(MINGW_LIBS_DIR)/libogg.a
endif
OGGVORBISLDFLAGS ?= -lvorbisfile -lvorbis -logg
#BASELDFLAGS=-lm -lz
XLDFLAGS=-L$(ARCHLIBS) $(IMAGELDFLAGS)
@ -987,8 +994,8 @@ ifeq (1,$(LINK_QUAKE3))
l_struct.o
endif
COMMONLIBFLAGS=
COMMONLDDEPS=
COMMONLIBFLAGS?=
COMMONLDDEPS?=
CLIENTLIBFLAGS=$(COMMONLIBFLAGS) $(LIBOPUS_STATIC) $(LIBSPEEX_STATIC) $(OGGVORBISFILE_STATIC)
SERVERLIBFLAGS=$(COMMONLIBFLAGS)
CLIENTLDDEPS=$(COMMONLDDEPS) $(LIBOPUS_LDFLAGS) $(LIBSPEEX_LDFLAGS) $(OGGVORBISLDFLAGS)
@ -997,14 +1004,17 @@ ifeq (1,$(USE_OPUS))
LIBOPUS_STATIC=-DOPUS_STATIC
LIBOPUS_LDFLAGS=-lopus
ALL_CFLAGS+=-I/usr/include/opus
MAKELIBS+=libs-$(ARCH)/libopus.a
endif
ifeq (1,$(USE_SPEEX))
LIBSPEEX_STATIC=-DSPEEX_STATIC
LIBSPEEX_LDFLAGS=-lspeex -lspeexdsp
MAKELIBS+=libs-$(ARCH)/libspeex.a libs-$(ARCH)/libspeexdsp.a
endif
ifeq (1,$(USE_VORBISFILE))
OGGVORBISFILE_STATIC=-DLIBVORBISFILE_STATIC
OGGVORBISLDFLAGS ?= -lvorbisfile -lvorbis -logg
else
OGGVORBISLDFLAGS=
OGGVORBISFILE_STATIC=
@ -1062,6 +1072,34 @@ ifeq (1,$(strip $(INTERNAL_BULLET)))
LDCC=$(CXX)
MAKELIBS+=libs-$(ARCH)/libBulletDynamics.a
endif
ifeq (1,$(LINK_EZHUD))
VPATH := $(VPATH) : $(BASE_DIR)/../plugins/ezhud
ALL_CFLAGS+=-DSTATIC_EZHUD #let the plugins code know it needs to add the appropriate entry.
CLIENT_OBJS += \
ezquakeisms.o \
hud.o \
hud_common.o \
hud_editor.o
endif
ifeq (1,$(LINK_OPENSSL))
ifeq (1,$(shell $(PKGCONFIG) --version-atleast 3 openssl && echo 1)) #must exist... and if its not openssl3 then its not gpl3-compatible so refuse to use it.
VPATH := $(VPATH) : $(BASE_DIR)/../plugins
ALL_CFLAGS+=-DSTATIC_OPENSSL #let the plugins code know it needs to add the appropriate entry.
COMMON_OBJS += \
net_ssl_openssl.o
ALL_DFLAGS+=$(shell $(PKGCONFIG) openssl --cflags --silence-errors)
COMMONLDDEPS+=$(shell $(PKGCONFIG) openssl --libs --silence-errors)
endif
endif
ifeq (1,$(shell $(PKGCONFIG) --exists gnutls && echo 1))
ALL_CFLAGS+=$(shell $(PKGCONFIG) gnutls --cflags --silence-errors)
#ALL_CFLAGS+=-DGNUTLS_STATIC
#COMMONLDDEPS+=$(shell $(PKGCONFIG) gnutls --static --libs --silence-errors) #we soft-link, so we don't need the -lgnutls stuff.
else
ALL_CFLAGS+=-DNO_GNUTLS
endif
#the defaults for sdl come first
#CC_MACHINE:=$(shell $(CC) -dumpmachine)
@ -1761,13 +1799,14 @@ ifeq ($(FTE_TARGET),web)
#GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) cd_null.o
#GL_LDFLAGS=$(GLLDFLAGS)
GLB_DIR=gl_web
GLCL_DIR=glcl_web
GL_EXE_NAME=../ftewebgl.js
GLCL_EXE_NAME=../ftewebglcl.js
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS)
GL_CFLAGS=$(GLCFLAGS)
GL_CFLAGS=$(GLCFLAGS) $(CLIENTLIBFLAGS)
IMAGELDFLAGS=
CLIENTLDDEPS=
SERVERLDDEPS=
#generate deps properly
@ -2074,17 +2113,24 @@ qccgui-scintilla: scintilla$(BITS)_static
@LTO= $(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
ifdef windir
debugdir:
@-mkdir -p "$(subst /,\, $(OUT_DIR))"
reldir:
outdir:
ifneq "$(OUT_DIR)" ""
@-mkdir -p "$(subst /,\, $(OUT_DIR))"
endif
debugdir: outdir
@-mkdir -p "$(subst /,\, $(RELEASE_DIR))"
reldir: outdir
@-mkdir -p "$(subst /,\, $(DEBUG_DIR))"
else
reldir:
outdir:
ifneq "$(OUT_DIR)" ""
@-mkdir -p "$(OUT_DIR)"
endif
debugdir: outdir
reldir: outdir
@-mkdir -p "$(RELEASE_DIR)"
@-mkdir -p "$(OUT_DIR)"
debugdir:
debugdir: outdir
@-mkdir -p "$(DEBUG_DIR)"
@-mkdir -p "$(OUT_DIR)"
endif
plugins-dbg:
@ -2172,15 +2218,23 @@ else
endif
web-rel:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-rel FTE_TARGET=web CC="$(EMCC)"
cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebgl.html
@PATH="$(EMSCRIPTENPATH)" $(MAKE) makelibs FTE_TARGET=web CC="$(EMCC)" && PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-rel FTE_TARGET=web CC="$(EMCC)"
@cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebgl.html
@gzip -kf $(RELEASE_DIR)/ftewebgl.html
@gzip -kf $(RELEASE_DIR)/ftewebgl.js
@gzip -kf $(RELEASE_DIR)/ftewebgl.wasm
webcl-rel:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) makelibs FTE_TARGET=web CC="$(EMCC)" && PATH="$(EMSCRIPTENPATH)" $(MAKE) glcl-rel FTE_TARGET=web CC="$(EMCC)"
@cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebglcl.html
@sed -i 's/ftewebgl.js/ftewebglcl.js/g' release/ftewebglcl.html #swap out the .js filename for the client-only one.
@gzip -kf $(RELEASE_DIR)/ftewebglcl.html
@gzip -kf $(RELEASE_DIR)/ftewebglcl.js
@gzip -kf $(RELEASE_DIR)/ftewebglcl.wasm
web-dbg:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-dbg FTE_TARGET=web CC="$(EMCC)"
cp $(BASE_DIR)/web/fteshell.html $(DEBUG_DIR)/ftewebgl.html
@cp $(BASE_DIR)/web/fteshell.html $(DEBUG_DIR)/ftewebgl.html
@gzip -kf $(DEBUG_DIR)/ftewebgl.html
@gzip -kf $(DEBUG_DIR)/ftewebgl.js
@gzip -kf $(DEBUG_DIR)/ftewebgl.wasm
@ -2288,23 +2342,26 @@ AR?=$(ARCH)-ar
CONFIGARGS+= -host=$(ARCH) --enable-shared=no CC="$(CC)"
CONFIGARGS:= $(CONFIGARGS)
#--disable-silent-rules
OPUSCONFIGARGS=$(CONFIGARGS)
TOOLOVERRIDES+=CFLAGS="$$CFLAGS -Os"
TOOLCONGIGUREOVERRIDES=$(TOOLOVERRIDES)
TOOLMAKEOVERRIDES=$(TOOLOVERRIDES)
ifeq (web,$(FTE_TARGET))
TOOLCONFIGUREOVERRIDES=emconfigure
TOOLMAKEOVERRIDES=emmake
OPUSCONFIGARGS=--disable-rtcd --disable-hardening --enable-stack-protector=no --enable-shared=no
CONFIGARGS=--enable-shared=no
endif
libs-$(ARCH)/libjpeg.a:
test -f jpegsrc.v$(JPEGVER).tar.gz || wget http://www.ijg.org/files/jpegsrc.v$(JPEGVER).tar.gz
-test -f libs-$(ARCH)/libjpeg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../jpegsrc.v$(JPEGVER).tar.gz && cd jpeg-$(JPEGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libjpeg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libjpeg.a && cp jconfig.h jerror.h jmorecfg.h jpeglib.h jversion.h ../ )
test -f libs-$(ARCH)/libjpeg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../jpegsrc.v$(JPEGVER).tar.gz && cd jpeg-$(JPEGVER) && $(CONFIGUREOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libjpeg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libjpeg.a && cp jconfig.h jerror.h jmorecfg.h jpeglib.h jversion.h ../ )
ifeq ($(FTE_TARGET),web)
libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc:
test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/fossils/zlib-$(ZLIBVER).tar.gz
-test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && emconfigure ./configure --static && emmake $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ )
else
libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc:
test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/fossils/zlib-$(ZLIBVER).tar.gz
-test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && $(TOOLOVERRIDES) ./configure --static && $(TOOLOVERRIDES) $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ )
endif
test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && $(TOOLCONFIGUREOVERRIDES) ./configure --static && $(TOOLMAKEOVERRIDES) $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ )
libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a
(cd libs-$(ARCH)/zlib-$(ZLIBVER) && \
$(CC) -o contrib/infback9/infback9.o -c contrib/infback9/infback9.c -I. && \
@ -2315,35 +2372,35 @@ libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a
libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc: libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc
test -f libpng-$(PNGVER).tar.gz || wget http://prdownloads.sourceforge.net/libpng/libpng-$(PNGVER).tar.gz?download -O libpng-$(PNGVER).tar.gz
-test -f libs-$(ARCH)/libpng.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libpng-$(PNGVER).tar.gz && cd libpng-$(PNGVER) && $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --enable-static && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libpng16.a ../libpng.a && cp libpng.pc png*.h ../ )
test -f libs-$(ARCH)/libpng.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libpng-$(PNGVER).tar.gz && cd libpng-$(PNGVER) && $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --enable-static && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libpng16.a ../libpng.a && cp libpng.pc png*.h ../ )
libs-$(ARCH)/libogg.a:
test -f libogg-$(OGGVER).tar.gz || wget http://downloads.xiph.org/releases/ogg/libogg-$(OGGVER).tar.gz
-test -f libs-$(ARCH)/libogg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libogg-$(OGGVER).tar.gz && cd libogg-$(OGGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp src/.libs/libogg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libogg.a && mkdir ../ogg && cp include/ogg/*.h ../ogg)
test -f libs-$(ARCH)/libogg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libogg-$(OGGVER).tar.gz && cd libogg-$(OGGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp src/.libs/libogg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libogg.a && mkdir ../ogg && cp include/ogg/*.h ../ogg)
libs-$(ARCH)/libvorbis.a: libs-$(ARCH)/libogg.a
test -f libvorbis-$(VORBISVER).tar.gz || wget http://downloads.xiph.org/releases/vorbis/libvorbis-$(VORBISVER).tar.gz
-test -f libs-$(ARCH)/libvorbisfile.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libvorbis-$(VORBISVER).tar.gz && cd libvorbis-$(VORBISVER) && $(TOOLOVERRIDES) ./configure PKG_CONFIG= $(CONFIGARGS) --disable-oggtest --with-ogg-libraries=.. --with-ogg-includes=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/libogg-$(OGGVER)/include && $(TOOLOVERRIDES) $(MAKE) && cp lib/.libs/libvorbis.a ../ && cp lib/.libs/libvorbisfile.a ../ && mkdir ../vorbis && cp include/vorbis/*.h ../vorbis)
test -f libs-$(ARCH)/libvorbisfile.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libvorbis-$(VORBISVER).tar.gz && cd libvorbis-$(VORBISVER) && $(TOOLOVERRIDES) ./configure PKG_CONFIG= $(CONFIGARGS) --disable-oggtest --with-ogg-libraries=.. --with-ogg-includes=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/libogg-$(OGGVER)/include && $(TOOLOVERRIDES) $(MAKE) && cp lib/.libs/libvorbis.a ../ && cp lib/.libs/libvorbisfile.a ../ && mkdir ../vorbis && cp include/vorbis/*.h ../vorbis)
libs-$(ARCH)/libopus.a:
test -f opus-$(OPUSVER).tar.gz || wget https://archive.mozilla.org/pub/opus/opus-$(OPUSVER).tar.gz
-test -f libs-$(ARCH)/libopus.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../opus-$(OPUSVER).tar.gz && cd opus-$(OPUSVER) && CFLAGS="-D_FORTIFY_SOURCE=0 $(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libopus.a ../ && cp include/opus*.h ../)
test -f libs-$(ARCH)/libopus.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../opus-$(OPUSVER).tar.gz && cd opus-$(OPUSVER) && CFLAGS="-D_FORTIFY_SOURCE=0 $(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(OPUSCONFIGARGS) --disable-extra-programs && $(TOOLMAKEOVERRIDES) $(MAKE) && cp .libs/libopus.a ../ && cp include/opus*.h ../)
libs-$(ARCH)/libspeex.a:
test -f speex-$(SPEEXVER).tar.gz || wget http://downloads.us.xiph.org/releases/speex/speex-$(SPEEXVER).tar.gz
-test -f libs-$(ARCH)/libspeex.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speex-$(SPEEXVER).tar.gz && cd speex-$(SPEEXVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp libspeex/.libs/libspeex.a ../ && cp -r include/speex/*.h ../speex/)
test -f libs-$(ARCH)/libspeex.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speex-$(SPEEXVER).tar.gz && cd speex-$(SPEEXVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(CONFIGARGS) --disable-binaries && $(TOOLMAKEOVERRIDES) $(MAKE) && cp libspeex/.libs/libspeex.a ../ && cp -r include/speex/*.h ../speex/)
libs-$(ARCH)/libspeexdsp.a:
test -f speexdsp-$(SPEEXDSPVER).tar.gz || wget http://downloads.xiph.org/releases/speex/speexdsp-$(SPEEXDSPVER).tar.gz
-test -f libs-$(ARCH)/libspeexdsp.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speexdsp-$(SPEEXDSPVER).tar.gz && cd speexdsp-$(SPEEXDSPVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp libspeexdsp/.libs/libspeexdsp.a ../ && cp -r include/speex/*.h ../speex/)
test -f libs-$(ARCH)/libspeexdsp.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speexdsp-$(SPEEXDSPVER).tar.gz && cd speexdsp-$(SPEEXDSPVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLMAKEOVERRIDES) $(MAKE) && cp libspeexdsp/.libs/libspeexdsp.a ../ && cp -r include/speex/*.h ../speex/)
libs-$(ARCH)/libfreetype.a libs-$(ARCH)/ft2build.h: libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc
test -f freetype-$(FREETYPEVER).tar.gz || wget https://download-mirror.savannah.gnu.org/releases/freetype/freetype-$(FREETYPEVER).tar.gz
-test -f libs-$(ARCH)/libfreetype.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../freetype-$(FREETYPEVER).tar.gz && cd freetype-$(FREETYPEVER) && PKG_CONFIG_LIBDIR=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --with-zlib=yes --with-png=yes --with-bzip2=no --with-harfbuzz=no && $(TOOLOVERRIDES) $(MAKE) && cp objs/.libs/libfreetype.a ../ && cp -r include/* ../)
test -f libs-$(ARCH)/libfreetype.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../freetype-$(FREETYPEVER).tar.gz && cd freetype-$(FREETYPEVER) && PKG_CONFIG_LIBDIR=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --with-zlib=yes --with-png=yes --with-bzip2=no --with-harfbuzz=no && $(TOOLOVERRIDES) $(MAKE) && cp objs/.libs/libfreetype.a ../ && cp -r include/* ../)
libs-$(ARCH)/libBulletDynamics.a:
test -f bullet3-$(BULLETVER).tar.gz || wget https://github.com/bulletphysics/bullet3/archive/$(BULLETVER).tar.gz -O bullet3-$(BULLETVER).tar.gz
-test -f libs-$(ARCH)/libBulletDynamics.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../bullet3-$(BULLETVER).tar.gz && cd bullet3-$(BULLETVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) $(DO_CMAKE) . && $(TOOLOVERRIDES) $(MAKE) LinearMath BulletDynamics BulletCollision && cp src/LinearMath/libLinearMath.a src/BulletDynamics/libBulletDynamics.a src/BulletCollision/libBulletCollision.a src/btBulletCollisionCommon.h src/btBulletDynamicsCommon.h ..)
test -f libs-$(ARCH)/libBulletDynamics.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../bullet3-$(BULLETVER).tar.gz && cd bullet3-$(BULLETVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) $(DO_CMAKE) . && $(TOOLOVERRIDES) $(MAKE) LinearMath BulletDynamics BulletCollision && cp src/LinearMath/libLinearMath.a src/BulletDynamics/libBulletDynamics.a src/BulletCollision/libBulletCollision.a src/btBulletCollisionCommon.h src/btBulletDynamicsCommon.h ..)
libs-$(ARCH)/vulkan/vulkan.h:
test -f vulkan-sdk-$(VULKANVER).tar.gz || wget https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$(VULKANVER).tar.gz
@ -2380,13 +2437,13 @@ $(RELEASE_DIR)/imgtool$(BITS)$(EXEPOSTFIX): $(IMGTOOL_OBJECTS)
imgtool-rel: $(RELEASE_DIR)/imgtool$(BITS)$(EXEPOSTFIX)
imgtool: imgtool-rel
MASTER_OBJECTS=server/sv_sys_unix.c common/sys_linux_threads.c common/net_ssl_gnutls.c server/sv_master.c common/net_wins.c common/net_ice.c common/cvar.c common/cmd.c common/sha1.c http/httpclient.c common/log.c common/fs.c common/fs_stdio.c common/common.c common/translate.c common/zone.c qclib/hash.c
MASTER_OBJECTS=server/sv_sys_unix.c common/sys_linux_threads.c common/net_ssl_gnutls.c server/sv_master.c common/net_wins.c common/net_ice.c common/cvar.c common/cmd.c common/sha1.c common/sha2.c http/httpclient.c common/log.c common/fs.c common/fs_stdio.c common/common.c common/translate.c common/zone.c qclib/hash.c
$(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS)
$(CC) -o $@ $(MASTER_OBJECTS) -flto=jobserver -fvisibility=hidden -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(RELEASE_CFLAGS) $(RELEASE_LDFLAGS)
$(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS)
$(CC) -o $@ $(MASTER_OBJECTS) -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(DEBUG_CFLAGS) $(DEBUG_LDFLAGS)
master-rel: $(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master-dbg: $(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master-rel: reldir $(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master-dbg: dbgdir $(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master: master-rel
QTV_OBJECTS= \

View File

@ -68,7 +68,7 @@ void Cam_AutoTrack_Update(const char *mode)
autotrack_statsrule = NULL;
if (!*mode || !Q_strcasecmp(mode, "auto"))
{
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
autotrackmode = TM_STATS;
autotrack_statsrule = Z_StrDup(""); //default
@ -501,7 +501,7 @@ static int CL_AutoTrack_Choose(int seat)
best = cl.autotrack_killer;
if (autotrackmode == TM_MODHINTS && seat == 0 && cl.autotrack_hint >= 0)
best = cl.autotrack_hint;
if (autotrackmode == TM_STATS && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
if (autotrackmode == TM_STATS && cls.demoplayback == DPB_MVD)
best = CL_FindHighTrack(seat, autotrack_statsrule);
if (autotrackmode == TM_HIGHTRACK || best == -1)
best = CL_FindHighTrack(seat, "%f");
@ -578,7 +578,7 @@ void Cam_Lock(playerview_t *pv, int playernum)
Skin_FlushPlayers();
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
memcpy(&pv->stats, cl.players[playernum].stats, sizeof(pv->stats));
// pv->cam_state = CAM_;
@ -1001,13 +1001,13 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
if (cls.state != ca_active)
return;
if (!pv->spectator && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) // only in spectator mode
if (!pv->spectator && cls.demoplayback != DPB_MVD) // only in spectator mode
return;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
int nb;
nb = (cmd->sidemove<0)?4:0;
int nb = 0;
nb |= (cmd->sidemove<0)?4:0;
nb |= (cmd->sidemove>0)?8:0;
nb |= (cmd->forwardmove<0)?16:0;
nb |= (cmd->forwardmove>0)?32:0;
@ -1015,18 +1015,21 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
nb |= (cmd->upmove>0)?128:0;
if (Cam_TrackNum(pv) >= 0)
{
if (nb & (nb ^ pv->cam_oldbuttons) & 4)
Cvar_SetValue(&cl_demospeed, max(cl_demospeed.value - 0.1, 0));
if (nb & (nb ^ pv->cam_oldbuttons) & 8)
Cvar_SetValue(&cl_demospeed, min(cl_demospeed.value + 0.1, 10));
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
if (nb & (nb ^ pv->cam_oldbuttons) & 16)
Cbuf_AddText("demo_jump +10", RESTRICT_LOCAL);
if (nb & (nb ^ pv->cam_oldbuttons) & 32)
Cbuf_AddText("demo_jump -10", RESTRICT_LOCAL);
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
if (*cls.lastdemoname)
{ //changing rates or jumping doesn't make sense with mvds.
if (nb & (nb ^ pv->cam_oldbuttons) & 4)
Cvar_SetValue(&cl_demospeed, max(cl_demospeed.value - 0.1, 0));
if (nb & (nb ^ pv->cam_oldbuttons) & 8)
Cvar_SetValue(&cl_demospeed, min(cl_demospeed.value + 0.1, 10));
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
if (nb & (nb ^ pv->cam_oldbuttons) & 16)
Cbuf_AddText("demo_jump +10", RESTRICT_LOCAL);
if (nb & (nb ^ pv->cam_oldbuttons) & 32)
Cbuf_AddText("demo_jump -10", RESTRICT_LOCAL);
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
}
if (nb & (nb ^ pv->cam_oldbuttons) & 64)
Cvar_SetValue(&cl_splitscreen, max(cl_splitscreen.ival - 1, 0));
if (nb & (nb ^ pv->cam_oldbuttons) & 128)

View File

@ -78,6 +78,7 @@ void CL_StopPlayback (void)
cls.demoplayback = DPB_NONE;
cls.demoseeking = false; //just in case
cls.demotrack = -1;
cls.demoeztv_ext = 0;
if (cls.timedemo)
CL_FinishTimeDemo ();
@ -215,7 +216,7 @@ int demo_preparsedemo(unsigned char *buffer, int bytes)
int ofs;
unsigned int length;
#define dem_mask 7
if (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)
if (cls.demoplayback != DPB_MVD)
return bytes; //no need if its not an mvd (this simplifies it a little)
while (bytes>2)
@ -407,6 +408,12 @@ void CL_DemoJump_f(void)
return;
}
if (!*cls.lastdemoname)
{
Con_Printf("unable to seak in qtv streams.\n");
return; //can't seek live streams...
}
if (*s == '+' || *s == '-')
{
if (colon)
@ -465,6 +472,12 @@ void CL_DemoNudge_f(void)
return;
}
if (!*cls.lastdemoname)
{
Con_Printf("unable to seak in qtv streams.\n");
return; //can't seek live streams...
}
if (!move)
move = 1;
@ -519,6 +532,7 @@ qboolean CL_GetDemoMessage (void)
q1usercmd_t q1cmd;
int demopos = 0;
int msglength;
static float throttle;
if (endofdemo)
{
@ -667,7 +681,7 @@ readnext:
}
// read the time from the packet
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
if (demtime < 0)
{
@ -681,7 +695,9 @@ readnext:
if (readdemobytes(&demopos, &msecsadded, sizeof(msecsadded)) != sizeof(msecsadded))
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
demotime = olddemotime;
nextdemotime = demotime;
return 0;
@ -696,7 +712,7 @@ readnext:
{
if (readdemobytes(&demopos, &demotime, sizeof(demotime)) != sizeof(demotime))
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime; //if we ran out of buffered demo, delay the demo parsing a little
return 0;
}
@ -763,15 +779,10 @@ readnext:
else
demtime = demotime; // we're warping
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime)
{
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
}
cls.netchan.frame_latency = 0;
cls.netchan.last_received = realtime; // just to happy timeout check
}
@ -783,7 +794,7 @@ readnext:
// get the msg type
if (readdemobytes (&demopos, &c, sizeof(c)) != sizeof(c))
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
return 0;
}
@ -805,7 +816,7 @@ readnext:
r = readdemobytes (&demopos, &q1cmd, sizeof(q1cmd));
if (r != sizeof(q1cmd))
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
CL_StopPlayback ();
return 0;
@ -843,7 +854,7 @@ readit:
// get the next message
if (readdemobytes (&demopos, &msglength, 4) != 4)
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
return 0;
}
@ -857,20 +868,27 @@ readit:
}
if (readdemobytes (&demopos, net_message.data, msglength) != msglength)
{
Con_DPrintf("Not enough buffered\n");
Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
return 0;
}
NET_UpdateRates(cls.sockets, true, msglength); //keep any rate calcs sane
net_message.cursize = msglength;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
int seat;
cl.defaultnetsplit = 0;
switch(cls_lasttype)
{
case dem_multiple:
if (!cls_lastto && (cls.ezprotocolextensions1 & EZPEXT1_HIDDEN_MESSAGES))
{ //an 'mvdsv hidden message' packet.
MSG_BeginReading(&net_message, cls.netchan.netprim);
CLEZ_ParseHiddenDemoMessage();
olddemotime = demotime;
goto readnext;
}
for (seat = 0; seat < cl.splitclients; seat++)
{
tracknum = cl.playerview[seat].cam_spec_track;
@ -939,7 +957,7 @@ readit:
NET_UpdateRates(cls.sockets, false, demopos); //keep any rate calcs sane
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
cls.netchan.incoming_acknowledged = cls.netchan.incoming_sequence;
goto readnext;
@ -975,8 +993,21 @@ readit:
}
demo_flushbytes(demopos);
olddemotime = demotime;
if (cls.demoplayback == DPB_MVD)
{
if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime)
{
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
}
cls.netchan.frame_latency = 0;
cls.netchan.last_received = realtime; // just to happy timeout check
}
}
olddemotime = demotime;
net_from.type = NA_INVALID;
return 1;
}
@ -1009,6 +1040,7 @@ void CL_Stop_f (void)
}
else
#endif
if (cls.demorecording == DPB_QUAKEWORLD)
{
SZ_Clear (&net_message);
MSG_WriteLong (&net_message, -1); // -1 sequence means out of band
@ -1139,12 +1171,16 @@ void CL_RecordMap_f (void)
CL_Disconnect_f();
SV_SpawnServer (mapname, NULL, false, false, 0);
if (!sv.state)
return;
#ifdef MVD_RECORDING
COM_DefaultExtension(demoname, ".mvd", sizeof(demoname));
#else
COM_DefaultExtension(demoname, ".dem", sizeof(demoname));
if (svs.allocated_client_slots > 1)
COM_DefaultExtension(demoname, ".mvd", sizeof(demoname));
else
#endif
COM_DefaultExtension(demoname, ".qwd", sizeof(demoname));
COM_FileExtension(demoname, demoext, sizeof(demoext));
#if defined(AVAIL_GZDEC) && !defined(CLIENTONLY)
@ -1166,6 +1202,19 @@ void CL_RecordMap_f (void)
else
#endif
{
#ifdef NQPROT
if (!strcmp(demoext, "dem"))
cls.demorecording = DPB_NETQUAKE;
else
#endif
if (!strcmp(demoext, "qwd"))
cls.demorecording = DPB_QUAKEWORLD;
else
{
CL_Disconnect_f();
return;
}
cls.demooutfile = FS_OpenVFS (demoname, "wb", FS_GAME);
if (!cls.demooutfile)
{
@ -1176,16 +1225,10 @@ void CL_RecordMap_f (void)
if (!Q_strcasecmp(".gz", COM_GetFileExtension(demoname, NULL)))
cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true);
#endif
#ifdef NQPROT
if (!strcmp(demoext, "dem"))
{
cls.demorecording = DPB_NETQUAKE;
if (cls.demorecording == DPB_NETQUAKE)
VFS_PUTS(cls.demooutfile, "-1\n");
}
else
#endif
cls.demorecording = DPB_QUAKEWORLD;
CL_WriteSetDemoMessage();
}
}
@ -1384,11 +1427,11 @@ void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
MSG_WriteByte (buf, cl.deathmatch?GAME_DEATHMATCH:GAME_COOP);
MSG_WriteString (buf, cl.levelname);
for (i = 1; *cl.model_name[i] && i < MAX_PRECACHE_MODELS; i++)
for (i = 1; cl.model_name[i] && i < MAX_PRECACHE_MODELS; i++)
MSG_WriteString (buf, cl.model_name[i]);
MSG_WriteByte (buf, 0);
for (i = 1; *cl.sound_name[i] && i < MAX_PRECACHE_SOUNDS ; i++)
for (i = 1; cl.sound_name[i] && i < MAX_PRECACHE_SOUNDS ; i++)
MSG_WriteString (buf, cl.sound_name[i]);
MSG_WriteByte (buf, 0);
}
@ -2284,7 +2327,7 @@ void CL_PlayDemo_f (void)
}
//dl is provided so that we can receive files via chunked/gziped http downloads and on systems that don't provide sockets etc. its tracked so we can cancel the download if the client aborts playback early.
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay)
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay, unsigned int eztv_ext)
{
int protocol = CP_UNKNOWN;
@ -2295,7 +2338,6 @@ void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int
switch(demotype)
{
case DPB_EZTV:
case DPB_MVD:
case DPB_QUAKEWORLD:
protocol = CP_QUAKEWORLD;
@ -2345,13 +2387,14 @@ void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int
Con_Printf ("Playing demo from %s.\n", filename);
}
cls.findtrack = (demotype == DPB_MVD || demotype == DPB_EZTV);
cls.findtrack = (demotype == DPB_MVD);
cls.demoplayback = demotype;
cls.demoeztv_ext = eztv_ext;
cls.protocol = protocol;
cls.state = ca_demostart;
net_message.packing = SZ_RAWBYTES;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, 0);
Netchan_Setup (NCF_CLIENT, &cls.netchan, &net_from, 0, 0);
demtime = -bufferdelay;
cls.demostarttime = 0;
@ -2391,20 +2434,20 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "dm2") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "dm2.gz"))
{
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0, 0);
return;
}
#endif
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz"))
{
CL_PlayDemoStream(f, demoname, issyspath, DPB_MVD, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_MVD, 0, 0);
return;
}
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "qwd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "qwd.gz"))
{
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0, 0);
return;
}
@ -2436,7 +2479,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
else
cls.demotrack = -1;
CL_PlayDemoStream(f, demoname, issyspath, DPB_NETQUAKE, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_NETQUAKE, 0, 0);
return;
}
VFS_SEEK(f, start);
@ -2477,7 +2520,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
if (protocol >= PROTOCOL_VERSION_Q2_DEMO_MIN && protocol <= PROTOCOL_VERSION_Q2_DEMO_MAX)
{
VFS_SEEK(f, start);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0, 0);
return;
}
break;
@ -2493,7 +2536,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
//could also be .qwz or .dmz or whatever that nq extension is. we don't support either.
//mvd and qwd have no identifying markers, other than the extension.
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0, 0);
}
#ifdef WEBCLIENT
void CL_PlayDownloadedDemo(struct dl_download *dl)
@ -2566,7 +2609,7 @@ void CL_Demo_ClientCommand(char *commandtext)
#ifdef warningmsg
#pragma warningmsg("this needs buffering safely")
#endif
if (cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD && cls.demoeztv_ext)
{
VFS_WRITE(cls.demoinfile, &len, sizeof(len));
VFS_WRITE(cls.demoinfile, &b, sizeof(b));
@ -2947,8 +2990,9 @@ fail:
//eztv extensions to v1.0
else if (!strcmp(s, "QTV_EZQUAKE_EXT"))
{
iseztv = true;
Con_Printf("Warning: eztv extensions %s\n", colon);
iseztv = atoi(colon);
if (iseztv & ~(EZTV_DOWNLOAD|EZTV_SETINFO|EZTV_QTVUSERLIST))
Con_Printf(CON_WARNING"Warning: unknown eztv extensions %s\n", colon);
}
//v1.1 sourcelist response includes SRCSRV, SRCHOST, SRCPLYRS, SRCVIEWS, SRCID
@ -3013,7 +3057,7 @@ fail:
Con_Printf("streaming \"%s\" from qtv\n", streamavailable);
else
Con_Printf("qtv connection established to %s\n", qtv->hostname);
CL_PlayDemoStream(qtv->stream, NULL, false, iseztv?DPB_EZTV:DPB_MVD, BUFFERTIME);
CL_PlayDemoStream(qtv->stream, NULL, false, DPB_MVD, BUFFERTIME, iseztv);
qtv->stream = NULL;
demo_resetcache(qtv->requestsize - (tail-qtv->requestbuffer), tail);
*link = qtv->next;
@ -3194,8 +3238,8 @@ void CL_QTVPlay_f (void)
if (qtvcl_eztvextensions.ival)
{
Q_snprintfz(msg+msglen, sizeof(msg)-msglen,
"QTV_EZQUAKE_EXT: 3\n"
"USERINFO: ");
"QTV_EZQUAKE_EXT: %u\n"
"USERINFO: ", EZTV_DOWNLOAD|EZTV_SETINFO|EZTV_QTVUSERLIST);
msglen += strlen(msg+msglen);
InfoBuf_ToString(&cls.userinfo[0], msg+msglen, sizeof(msg)-msglen-1, basicuserinfos, NULL, NULL, NULL, NULL);
msglen += strlen(msg+msglen);

View File

@ -925,7 +925,7 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
if (bits & UF_DRAWFLAGS)
{
news->hexen2flags = MSG_ReadByte();
if ((news->hexen2flags & MLS_MASK) == MLS_ABSLIGHT)
if ((news->hexen2flags & MLS_MASK) >= MLS_ADDLIGHT)
news->abslight = MSG_ReadByte();
else
news->abslight = 0;
@ -1052,7 +1052,7 @@ void CLFTE_ParseEntities(void)
// Con_Printf("CL: Dropped %i\n", i);
// }
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
@ -1291,7 +1291,7 @@ void CLQW_ParsePacketEntities (qboolean delta)
cl.inframes[newpacket].frameid = cls.netchan.incoming_sequence;
cl.inframes[newpacket].receivedtime = realtime;
if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
{
extern float olddemotime; //time from the most recent demo packet
cl.oldgametime = cl.gametime;
@ -1317,7 +1317,7 @@ void CLQW_ParsePacketEntities (qboolean delta)
from = MSG_ReadByte ();
// Con_Printf("%i %i from %i\n", cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence, from);
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
from = oldpacket = cls.netchan.incoming_sequence - 1;
oldpacket = cl.inframes[from & UPDATE_MASK].frameid;
@ -1851,6 +1851,209 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
}
}
#ifdef HEXEN2
#define UH2_MOREBITS (1u<<0)
#define UH2_ORIGIN1 (1u<<1)
#define UH2_ORIGIN2 (1u<<2)
#define UH2_ORIGIN3 (1u<<3)
#define UH2_ANGLE2 (1u<<4)
#define UH2_STEP (1u<<5)
#define UH2_FRAME (1u<<6)
#define UH2_SIGNAL (1u<<7)
#define UH2_ANGLE1 (1u<<8)
#define UH2_ANGLE3 (1u<<9)
#define UH2_MODEL (1u<<10)
//#define UH2_ (1u<<11)
//#define UH2_ (1u<<12)
//#define UH2_ (1u<<13)
#define UH2_LONGENTITY (1u<<14)
#define UH2_EVENMORE (1u<<15)
#define UH2_SKIN (1u<<16)
#define UH2_EFFECTS (1u<<17)
#define UH2_SCALE (1u<<18)
#define UH2_COLORMAP (1u<<19)
void CLH2_ParseEntities(void)
{
//h2mp apparently uses some sort of delta compression
//there's three parts to this, the start, the updates, and the removes at the end.
//so we can be a bit lazy and parse the 'fast updates' here and assert they end with a final clear.
//entities are ordered.
packet_entities_t *oldpack, *newpack;
entity_state_t *to, *from;
unsigned int read, bits;
int oldi;
unsigned int removecount;
int frame = MSG_ReadByte();
int seq = MSG_ReadByte();
//not really sure what to do with this.
(void)frame;
(void)seq;
//server->client sequence
// if (cl.numackframes == sizeof(cl.ackframes)/sizeof(cl.ackframes[0]))
// cl.numackframes--;
// cl.ackframes[cl.numackframes++] = MSG_ReadLong(); /*server sequence to be acked*/
//client->server sequence ack
// if (cls.protocol_nq >= CPNQ_DP7)
// CL_AckedInputFrame(cls.netchan.incoming_sequence, MSG_ReadLong(), true); /*client input sequence which has been acked*/
if (cl.validsequence)
oldpack = &cl.inframes[(cl.validsequence)&UPDATE_MASK].packet_entities;
else
oldpack = NULL;
cl.validsequence = cls.netchan.incoming_sequence;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].receivedtime = realtime;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].frameid = cls.netchan.incoming_sequence;
newpack = &cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].packet_entities;
newpack->servertime = cl.gametime;
//copy old state to new state
if (newpack != oldpack)
{
if (oldpack)
{
newpack->num_entities = oldpack->num_entities;
newpack->max_entities = newpack->num_entities+16; //for slop for new ents, to reduce reallocs
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
memcpy(newpack->entities, oldpack->entities, sizeof(entity_state_t)*newpack->num_entities);
}
else
newpack->num_entities = 0;
newpack->bonedatacur = 0;
//flag them all as having old bones
//they'll be renewed after parsing
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
newpack->entities[oldi].boneoffset |= 0x80000000;
}
for (;;)
{
bits = MSG_ReadByte();
if ((bits&0x80) == 0)
break; //no fast-update bit!
if (bits & UH2_MOREBITS)
bits |= MSG_ReadByte()<<8;
if (bits & UH2_EVENMORE)
bits |= MSG_ReadByte()<<16;
if (bits & UH2_LONGENTITY)
read = MSG_ReadUInt16();
else
read = MSG_ReadByte();
if (msg_badread)
Host_EndGame("Corrupt entity message packet\n");
if (!read)
break; //remove world signals end of packet.
if (read >= MAX_EDICTS)
Host_EndGame("Too many entities.\n");
if (!CL_CheckBaselines(read))
Host_EndGame("CLNQ_ParseEntity: check baselines failed with size %i", read);
from = &cl_baselines[read];
to = NULL;
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
{
if (read == newpack->entities[oldi].number)
{
from = &newpack->entities[oldi];
to = &newpack->entities[oldi];
break;
}
}
if (!to)
{ //okay, so this is new
if (newpack->num_entities==newpack->max_entities)
{
newpack->max_entities = newpack->num_entities+16;
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
}
to = &newpack->entities[newpack->num_entities];
newpack->num_entities++;
if (cl_shownet.ival >= 3)
Con_Printf("%3i: New %i %x\n", MSG_GetReadCount(), to->number, bits);
}
else if (cl_shownet.ival >= 3)
Con_Printf("%3i: Update %i %x\n", MSG_GetReadCount(), to->number, bits);
memcpy(to, from, sizeof(*to));
to->number = read;
if (bits & UH2_MODEL) to->modelindex = MSG_ReadShort();
if (bits & UH2_FRAME) to->frame = MSG_ReadByte();
if (bits & UH2_COLORMAP)to->colormap = MSG_ReadByte();
if (bits & UH2_SKIN) to->skinnum = MSG_ReadByte();
if (bits & UH2_SKIN) to->hexen2flags = MSG_ReadByte(); //yes, shared with skin
if (bits & UH2_EFFECTS) to->effects = MSG_ReadByte();
if (bits & UH2_ORIGIN1) to->origin[0] = MSG_ReadCoord();
if (bits & UH2_ANGLE1) to->angles[0] = MSG_ReadAngle();
if (bits & UH2_ORIGIN2) to->origin[1] = MSG_ReadCoord();
if (bits & UH2_ANGLE2) to->angles[1] = MSG_ReadAngle();
if (bits & UH2_ORIGIN3) to->origin[2] = MSG_ReadCoord();
if (bits & UH2_ANGLE3) to->angles[2] = MSG_ReadAngle();
if (bits & UH2_SCALE) to->scale = MSG_ReadByte()*(16.0/100);
if (bits & UH2_SCALE) to->abslight = MSG_ReadByte();
to->sequence = cls.netchan.incoming_sequence;
to->inactiveflag = 0;
}
//handle the removes
if (bits != 48)
Host_EndGame("Corrupt entity message packet\n");
removecount = (qbyte)MSG_ReadByte();
while (removecount --> 0)
{
read = MSG_ReadUInt16();
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
{
if (read == newpack->entities[oldi].number)
{
newpack->entities[oldi].inactiveflag = true;
break;
}
}
}
//sort them, just in case. the removes will bubble to the end.
qsort(newpack->entities, newpack->num_entities, sizeof(entity_state_t), CLDP_SortEntities);
while (newpack->num_entities)
{ //pop those removes.
if (newpack->entities[newpack->num_entities-1].inactiveflag)
newpack->num_entities--;
else
break;
}
//make sure any bone states are refreshed
for (oldi=0, to = newpack->entities; oldi<newpack->num_entities ; oldi++, to++)
{
if (to->bonecount && (to->boneoffset & 0x80000000))
{
unsigned int oldoffset = to->boneoffset & 0x7fffffff;
void *dest = AllocateBoneSpace(newpack, to->bonecount, &to->boneoffset);
void *src = GetBoneSpace(oldpack, oldoffset);
memcpy(dest, src, to->bonecount * sizeof(short)*7);
}
}
}
#endif
void CLNQ_ParseEntity(unsigned int bits)
{
int i;
@ -3934,7 +4137,7 @@ static qboolean CL_ChooseInterpolationFrames(int *newf, int *oldf, float servert
qboolean CL_MayLerp(void)
{
//force lerping when playing low-framerate demos.
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
return true;
#ifdef NQPROT
if (cls.demoplayback == DPB_NETQUAKE)
@ -3956,13 +4159,13 @@ void CL_TransitionEntities (void)
qboolean nolerp;
float servertime, frac;
if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
{
nolerp = false;
}
else
{
nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV;
nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD;
}
if (cl.demonudge < 0)
@ -4825,8 +5028,26 @@ void CLQW_ParsePlayerinfo (void)
oldstate = &cl.inframes[oldparsecountmod].playerstate[num];
state = &cl.inframes[parsecountmod].playerstate[num];
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
#ifdef QUAKESTATS
int i;
const char *viewmodel = NULL;
static struct {
const char *vmdl;
const char *vwep;
} haxx[] =
{
{"progs/v_axe.mdl", "w_axe"},
{"progs/v_shot.mdl", "w_shot"},
{"progs/v_shot2.mdl", "w_shot2"},
{"progs/v_nail.mdl", "w_nail"},
{"progs/v_nail2.mdl", "w_nail2"},
{"progs/v_rock.mdl", "w_rock"},
{"progs/v_rock2.mdl", "w_rock2"},
{"progs/v_light.mdl", "w_light"},
};
#endif
player_state_t dummy;
if (!cl.parsecount || info->prevcount > cl.parsecount || cl.parsecount - info->prevcount >= UPDATE_BACKUP - 1)
{
@ -4853,11 +5074,38 @@ void CLQW_ParsePlayerinfo (void)
state->messagenum = cl.parsecount;
state->command.msec = 0;
state->command.impulse = 0;
#ifdef QUAKESTATS
i = cl.players[num].stats[STAT_WEAPONMODELI];
if (i>0&&i<MAX_PRECACHE_MODELS && cl.model_name_vwep[0])
viewmodel = cl.model_name[i];
if(viewmodel)
{
for (i = 0; i < countof(haxx); i++)
{
if (!strcmp(viewmodel, haxx[i].vmdl))
{
viewmodel = haxx[i].vwep;
for (i = 1; i < countof(cl.model_name_vwep); i++)
{
if (!cl.model_name_vwep[i])
break;
if (!strcmp(viewmodel, cl.model_name_vwep[i]))
{
state->command.impulse = i;
break;
}
}
break;
}
}
}
#endif
state->frame = MSG_ReadByte ();
state->state_time = parsecounttime;
state->command.msec = 0;
for (i = 0; i < 3; i++)
{
@ -5365,7 +5613,7 @@ void CL_LinkPlayers (void)
frame = &cl.inframes[displayseq&UPDATE_MASK];
predictplayers = cl_predict_players.ival;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
predictplayers = false;
for (j=0, info=cl.players, state=frame->playerstate ; j < cl.allocated_client_slots

View File

@ -1332,6 +1332,8 @@ void CL_AdjustAngles (int pnum, double frametime)
if (!cl_instantrotate.ival)
quant *= speed*frametime;
in_rotate -= quant;
if (r_xflip.ival)
quant *= -1;
if (ruleset_allow_frj.ival)
cl.playerview[pnum].viewanglechange[YAW] += quant;
}
@ -1342,6 +1344,8 @@ void CL_AdjustAngles (int pnum, double frametime)
if ((cl.fpd & FPD_LIMIT_YAW) || !ruleset_allow_frj.ival)
quant = bound(-900, quant, 900);
quant *= frametime;
if (r_xflip.ival)
quant *= -1;
cl.playerview[pnum].viewanglechange[YAW] -= quant * CL_KeyState (&in_right, pnum, false);
cl.playerview[pnum].viewanglechange[YAW] += quant * CL_KeyState (&in_left, pnum, false);
}
@ -1410,6 +1414,9 @@ static void CL_BaseMove (vec3_t moves, int pnum)
if ((in_speed.state[pnum] & 1) ^ cl_run.ival)
scale *= cl_movespeedkey.value;
if (r_xflip.ival)
sidespeed *= -1;
moves[0] = 0;
if (! (in_klook.state[pnum] & 1) )
{
@ -1819,7 +1826,7 @@ static qboolean CLFTE_SendVRCmd (sizebuf_t *buf, unsigned int seats)
if (flags & VRM_LOSS)
MSG_WriteByte (buf, (qbyte)lost);
if (flags & VRM_DELAY)
MSG_WriteByte (buf, bound(0,cldelay,255)); //a byte should always be enough for any framerate above 40.
MSG_WriteByte (buf, bound(0,cldelay,255)); //a byte should always be enough for any framerate above 40, and we don't want peole to be able to lie so easily.
if (flags & VRM_ACKS)
{
MSG_WriteUInt64(buf, cl.numackframes);
@ -2122,7 +2129,7 @@ void VARGS CL_SendSeatClientCommand(qboolean reliable, unsigned int seat, char *
char string[2048];
clcmdbuf_t *buf, *prev;
if (cls.demoplayback && cls.demoplayback != DPB_EZTV)
if (cls.demoplayback && !(cls.demoplayback == DPB_MVD && cls.demoeztv_ext))
return; //no point.
va_start (argptr, format);
@ -2783,7 +2790,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cls.demoplayback != DPB_NONE || cls.state <= ca_demostart)
{
cursor_active = false;
if (!cls.state || cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (!cls.state || cls.demoplayback == DPB_MVD)
{
extern cvar_t cl_splitscreen;
cl.ackedmovesequence = cl.movesequence;

View File

@ -73,7 +73,8 @@ cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, miss
cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this.");
static cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, ^1so this will not function there^7. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly.");
#endif
static cvar_t cl_forcevrui = CVARD("cl_forcevrui", "0", "Force the use of VR UIs, even with no VR headset active.");
static cvar_t cl_vrui_force = CVARD("cl_vrui_force", "0", "Force the use of VR UIs, even with no VR headset active.");
cvar_t cl_vrui_lock = CVARD("cl_vrui_lock", "1", "Controls how the UI is positioned when using VR/XR. 0: Repositioned infront of the head when the console/menus are toggled. 1: Locked infront of the reference position (which may require the user to turn around to find it).");
cvar_t *hud_tracking_show;
cvar_t *hud_miniscores_show;
extern cvar_t net_compress;
@ -119,14 +120,18 @@ cvar_t cl_noblink = CVARD("cl_noblink", "0", "Disable the ^^b text blinking feat
cvar_t cl_servername = CVARFD("cl_servername", "", CVAR_NOSET, "The hostname of the last server you connected to");
cvar_t cl_serveraddress = CVARD("cl_serveraddress", "none", "The address of the last server you connected to");
cvar_t qtvcl_forceversion1 = CVAR("qtvcl_forceversion1", "0");
cvar_t qtvcl_eztvextensions = CVAR("qtvcl_eztvextensions", "0");
cvar_t qtvcl_eztvextensions = CVAR("qtvcl_eztvextensions", "1");
cvar_t record_flush = CVARD("record_flush", "0", "If set, explicitly flushes demo data to disk while recording. This may be inefficient, depending on how your operating system is configured.");
cvar_t cl_demospeed = CVARF("cl_demospeed", "1", 0);
cvar_t cl_demoreel = CVARFD("cl_demoreel", "0", CVAR_SAVE, "When enabled, the engine will begin playing a demo loop on startup.");
cvar_t cl_loopbackprotocol = CVARD("cl_loopbackprotocol", "qw", "Which protocol to use for single-player/the internal client. Should be one of: qw, qwid, nqid, nq, fitz, bjp3, dp6, dp7, auto. If 'auto', will use qw protocols for qw mods, and nq protocols for nq mods.");
#ifdef FTE_TARGET_WEB
static cvar_t cl_verify_urischeme = CVARAFD("cl_verify_urischeme", "2", "cl_verify_qwprotocol"/*ezquake, inappropriate for misc schemes*/, CVAR_NOSAVE/*checked at startup, so its only really default.cfg that sets it*/, "0: Do nothing.\n1: Check whether our protocol scheme is registered and prompt the user to register associations.\n2: Always re-register on every startup, without prompting. Sledgehammer style.");
#else
static cvar_t cl_verify_urischeme = CVARAFD("cl_verify_urischeme", "0", "cl_verify_qwprotocol"/*ezquake, inappropriate for misc schemes*/, CVAR_NOSAVE/*checked at startup, so its only really default.cfg that sets it*/, "0: Do nothing.\n1: Check whether our protocol scheme is registered and prompt the user to register associations.\n2: Always re-register on every startup, without prompting. Sledgehammer style.");
#endif
cvar_t cl_threadedphysics = CVARD("cl_threadedphysics", "0", "When set, client input frames are generated and sent on a worker thread");
@ -192,7 +197,6 @@ cvar_t cl_sendguid = CVARD("cl_sendguid", "", "Send a randomly generated 'glo
cvar_t cl_downloads = CVARAFD("cl_downloads", "1", /*q3*/"cl_allowDownload", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Allows you to block all automatic downloads.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer.");
cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://example.com/path/gamemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARAFD("cl_download_wait", "1", /*old*/"requiredownloads", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
cvar_t mod_precache = CVARD("mod_precache","1", "Controls when models are loaded.\n0: Load them only when they're actually needed.\n1: Load them upfront.\n2: Lazily load them to shorten load times at the risk of brief stuttering during only the start of the map.");
@ -302,7 +306,7 @@ static struct
} ext;
int qport;
int challenge; //tracked as part of guesswork based upon what replies we get.
int clchallenge;
int clchallenge; //generated by the client, to ensure the response wasn't spoofed/spammed.
double time; //for connection retransmits
qboolean clogged; //ignore time...
enum coninfomode_e
@ -361,7 +365,10 @@ void VRUI_SnapAngle(void)
{
// VectorCopy(cl.playerview[0].viewangles, vrui.angles);
vrui.angles[0] = 0;
vrui.angles[1] = cl.playerview[0].aimangles[1];
if (cl_vrui_lock.ival) //if its locked, then its locked infront of the unpitched player entity
vrui.angles[1] = cl.playerview[0].viewangles[1];
else //otherwise its moved to infront of the player's head any time the menu is displayed.
vrui.angles[1] = cl.playerview[0].aimangles[1];
vrui.angles[2] = 0;
}
@ -796,6 +803,8 @@ static void CL_SendConnectPacket (netadr_t *to)
//cl.splitclients = 1;
if (q3)
q3->cl.SendConnectPacket(cls.sockets, to, connectinfo.challenge, connectinfo.qport, cls.userinfo);
else
CL_ConnectAbort("Q3 plugin not loaded, cannot connect to q3 servers without it.\n");
return;
}
#endif
@ -926,7 +935,7 @@ char *CL_TryingToConnect(void)
return cls.servername;
}
#ifdef NQPROT
#if defined(NQPROT) && defined(HAVE_SERVER)
static void CL_NullReadPacket(void)
{ //just drop it all
}
@ -942,9 +951,7 @@ struct resolvectx_s
};
static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
{
#ifdef HAVE_DTLS
size_t i;
#endif
struct resolvectx_s *ctx = vctx;
//something screwed us over...
@ -971,7 +978,7 @@ static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
if (connectinfo.mode == CIM_Q2EONLY)
{
for (i = 0; i < ctx->found; i++)
{ //if we've already established a dtls connection, stick with it
{ //if we've already established a dtls connection, stick with it, otherwise 'upgrade' from udp to 'kexlan' transport layer.
if (ctx->adr[i].prot == NP_DGRAM)
ctx->adr[i].prot = NP_KEXLAN;
}
@ -986,8 +993,12 @@ static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
static void CL_ResolveServer(void *vctx, void *data, size_t a, size_t b)
{
struct resolvectx_s *ctx = vctx;
//stupid logic for targ@prox2@prox1 chaining. just disable it if there's weird ws:// or whatever in there.
//FIXME: really shouldn't be in there
const char *res = strrchr(ctx->servername, '/');
const char *host = strrchr(ctx->servername+1, '@');
if (host)
if (host && !res)
host++;
else
host = ctx->servername;
@ -1464,8 +1475,10 @@ void CL_CheckForResend (void)
if (contype & 1)
{
char tmp[256];
//vanilla: Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge %i %s\n", 255, 255, 255, 255, connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false));
if (strrchr(cls.servername, '@')) //if we're apparently using qwfwd then strictly adhere to vanilla's protocol so that qwfwd does not bug out. this will pollute gamedirs if stuff starts autodownloading from the wrong type of server, and probably show up vanilla-vs-rerelease glitches everywhere..
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
else
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge %i %s\n", 255, 255, 255, 255, connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false));
switch(NET_SendPacket (cls.sockets, strlen(data), data, to))
{
case NETERR_CLOGGED: //temporary failure
@ -1511,7 +1524,7 @@ void CL_CheckForResend (void)
if (*e)
pwd = CalcHashInt(&hash_md4, password.string, strlen(password.string));
}
MSG_WriteByte(&sb, 1); /*'mod'*/
MSG_WriteByte(&sb, MOD_PROQUAKE); /*'mod'*/
MSG_WriteByte(&sb, 34); /*'mod' version*/
MSG_WriteByte(&sb, 0); /*flags*/
MSG_WriteLong(&sb, pwd); /*password*/
@ -1584,9 +1597,9 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
//the scheme is either a network scheme in which case we use it directly, or a game-specific scheme.
scheme = NET_IsURIScheme(schemestart);
if (scheme->prot == NP_INVALID)
if (scheme && scheme->prot == NP_INVALID)
scheme = NULL; //qw:// or q3:// something that's just noise here.
if (scheme->flags&URISCHEME_NEEDSRESOURCE)
if (scheme && scheme->flags&URISCHEME_NEEDSRESOURCE)
{
Q_strncpyz (cls.servername, schemestart, sizeof(cls.servername)); //oh. will probably be okay then
arglist = NULL;
@ -1612,6 +1625,13 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
Con_Printf("Ignoring 'join'\n");
memmove(sl, sl+5, strlen(sl+5)+1);
}
else if (!strncmp(sl, "/qtvplay", 5))
{
char buf[256];
*sl = 0;
Cmd_ExecuteString(va("qtvplay %s\n", COM_QuotedString(schemeend+3, buf,sizeof(buf), false)), RESTRICT_LOCAL);
return;
}
else if (!strncmp(sl, "/", 1) && (sl[1] == 0 || sl[1]=='?'))
{
//current spectator mode
@ -1649,6 +1669,7 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
connectinfo.protocol = CP_UNKNOWN;
connectinfo.mode = mode;
connectinfo.spec = spec;
connectinfo.clchallenge = rand()^(rand()<<16);
connectinfo.peercred.name = cls.servername;
if (arglist)
@ -1716,6 +1737,7 @@ void CL_BeginServerReconnect(void)
connectinfo.time = 0;
connectinfo.tries = 0; //re-ensure routes.
connectinfo.nextadr = 0; //should at least be consistent, other than packetloss. yay.
connectinfo.clchallenge = rand()^(rand()<<16);
NET_InitClient(false);
}
@ -1785,11 +1807,11 @@ static void CL_Connect_f (void)
server = Cmd_Argv (1);
server = strcpy(alloca(strlen(server)+1), server);
#ifdef HAVE_SERVER
/*#ifdef HAVE_SERVER
if (sv.state == ss_clustermode)
CL_Disconnect (NULL);
else
#endif
#endif*/
CL_Disconnect_f ();
CL_BeginServerConnect(server, 0, false, CIM_DEFAULT, CIS_DEFAULT);
@ -1821,11 +1843,11 @@ static void CL_ConnectBestRoute_f (void)
else
Con_TPrintf ("Routing table favours chaining through %i proxies (%ims vs %ims)\n", proxies, chainedcost, directcost);
#ifdef HAVE_SERVER
/*#ifdef HAVE_SERVER
if (sv.state == ss_clustermode)
CL_Disconnect (NULL);
else
#endif
#endif*/
CL_Disconnect_f ();
CL_BeginServerConnect(server, 0, true, CIM_DEFAULT, CIS_DEFAULT);
}
@ -2265,6 +2287,17 @@ void CL_ClearState (qboolean gamestart)
if (cl.particle_csname[i])
free(cl.particle_csname[i]);
}
for (i = 0; i < countof(cl.model_name); i++)
if (cl.model_name[i])
BZ_Free(cl.model_name[i]);
#ifdef HAVE_LEGACY
for (i = 0; i < countof(cl.model_name_vwep); i++)
if (cl.model_name_vwep[i])
BZ_Free(cl.model_name_vwep[i]);
#endif
for (i = 0; i < countof(cl.sound_name); i++)
if (cl.sound_name[i])
BZ_Free(cl.sound_name[i]);
#ifdef Q2CLIENT
for (i = 0; i < Q2MAX_IMAGES; i++)
if (cl.image_name[i])
@ -2521,6 +2554,13 @@ void CL_Disconnect (const char *reason)
cls.findtrack = false;
cls.realserverip.type = NA_INVALID;
while (cls.qtvviewers)
{
struct qtvviewers_s *v = cls.qtvviewers;
cls.qtvviewers = v->next;
Z_Free(v);
}
#ifdef TCPCONNECT
//disconnects it, without disconnecting the others.
FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, NP_DGRAM);
@ -2618,6 +2658,7 @@ void CL_Users_f (void)
{
int i;
int c;
struct qtvviewers_s *v;
c = 0;
Con_TPrintf ("userid frags name\n");
@ -2631,6 +2672,11 @@ void CL_Users_f (void)
}
}
for (v = cls.qtvviewers; v; v = v->next)
{
Con_Printf ("%6s %4s ^[%s^]\n", "", "-", v->name);
}
Con_TPrintf ("%i total users\n", c);
}
@ -2927,7 +2973,7 @@ void CL_PakDownloads(int mode)
mode&4 download even packages that are not referenced.
*/
char local[256];
char *pname;
char *pname, *sep;
char *s = cl.serverpackhashes;
int i;
@ -2946,6 +2992,10 @@ void CL_PakDownloads(int mode)
else if (!(mode & 4))
continue;
sep = strchr(pname, '/');
if (!sep || strchr(sep+1, '/'))
continue; //don't try downloading weird ones here... paks inside paks is screwy stuff!
if ((mode&3) != 2)
{
/*if we already have such a file, this is a no-op*/
@ -3773,6 +3823,7 @@ void CL_Reconnect_f (void)
static void CL_ConnectionlessPacket_Connection(char *tokens)
{
unsigned int ncflags;
int qportsize = -1;
if (net_from.type == NA_INVALID)
return; //I've found a qizmo demo that contains one of these. its best left ignored.
@ -3848,19 +3899,16 @@ static void CL_ConnectionlessPacket_Connection(char *tokens)
cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1;
cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
ncflags = NCF_CLIENT;
if (connectinfo.ext.mtu)
ncflags |= NCF_FRAGABLE;
if (connectinfo.ext.fte2&PEXT2_STUNAWARE)
ncflags |= NCF_STUNAWARE;
Netchan_Setup (ncflags, &cls.netchan, &net_from, connectinfo.qport, connectinfo.ext.mtu);
cls.protocol_q2 = (cls.protocol == CP_QUAKE2)?connectinfo.subprotocol:0;
if (qportsize>=0)
cls.netchan.qportsize = qportsize;
cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false;
cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE);
if (connectinfo.ext.mtu >= 64)
{
cls.netchan.mtu = connectinfo.ext.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.ext.compresscrc);
#else
@ -4069,7 +4117,7 @@ void CL_ConnectionlessPacket (void)
if (!strcmp(com_token, "hallengeResponse"))
{
/*Quake3*/
/*Quake3 - "\xff\xff\xff\xffchallengeResponse challenge [clchallenge protover]" (no \n)*/
#ifdef Q3CLIENT
if (connectinfo.protocol == CP_QUAKE3 || connectinfo.protocol == CP_UNKNOWN)
{
@ -4262,12 +4310,12 @@ void CL_ConnectionlessPacket (void)
#ifdef HAVE_DTLS
if ((candtls && net_enable_dtls.ival) && net_from.prot == NP_DGRAM && (net_enable_dtls.ival>1 || candtls > 1) && !NET_IsEncrypted(&net_from))
{
//c2s getchallenge <no client details
//c2s getchallenge <no client details, only leaks that its quakelike, something you can maybe guess from port numbers>
//s2c c%u\0DTLS=$candtls <may leak server details>
//<<YOU ARE HERE>>
//c2s dtlsconnect %u [REALTARGET] <FIXME: target server is plain text, not entirely unlike tls1.2, but still worse than a vpn and could be improved>
//s2c dtlsopened <no details at all, other than that the server is now willing to accept dtls handshakes etc>
//c2s DTLS(getchallenge)
//c2s DTLS(getchallenge) <start here if you're using dtls:// scheme>
//DTLS(etc)
//NOTE: the dtlsconnect/dtlsopened parts are redundant and the non-dtls parts are now entirely optional (and should be skipped if the client requries/knows the server supports dtls)
@ -4284,7 +4332,7 @@ void CL_ConnectionlessPacket (void)
char *pkt;
//qwfwd proxy routing. it doesn't support it yet, but hey, if its willing to forward the dtls packets its all good.
char *at;
if ((at = strrchr(cls.servername, '@')))
if ((at = strrchr(cls.servername, '@')) && !strchr(cls.servername, '/'))
{
*at = 0;
pkt = va("%c%c%c%c""dtlsconnect %i %s", 255, 255, 255, 255, connectinfo.challenge, cls.servername);
@ -4391,7 +4439,7 @@ void CL_ConnectionlessPacket (void)
}
Validation_Apply_Ruleset();
Netchan_Setup(NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
Netchan_Setup(NCF_CLIENT, &cls.netchan, &net_from, connectinfo.qport, 0);
CL_ParseEstablished();
cls.netchan.isnqprotocol = true;
@ -4674,7 +4722,7 @@ void CLNQ_ConnectionlessPacket(void)
cls.fteprotocolextensions = connectinfo.ext.fte1;
cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
Netchan_Setup (NCF_CLIENT, &cls.netchan, &net_from, connectinfo.qport, 0);
CL_ParseEstablished();
cls.netchan.isnqprotocol = true;
cls.netchan.compresstable = NULL;
@ -4767,7 +4815,7 @@ void CL_ReadPacket(void)
return; //ignore it. We arn't connected.
}
if (net_message.cursize < 6 && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) //MVDs don't have the whole sequence header thing going on
if (net_message.cursize < 6 && cls.demoplayback != DPB_MVD) //MVDs don't have the whole sequence header thing going on
{
char adr[MAX_ADR_SIZE];
if (net_message.cursize == 1 && net_message.data[0] == A2A_ACK)
@ -4791,7 +4839,7 @@ void CL_ReadPacket(void)
return;
}
if (cls.netchan.pext_stunaware) //should be safe to do this here.
if (cls.netchan.flags&NCF_STUNAWARE) //should be safe to do this here.
if (NET_WasSpecialPacket(cls.sockets))
return;
@ -4836,7 +4884,7 @@ void CL_ReadPacket(void)
#endif
break;
case CP_QUAKEWORLD:
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
MSG_BeginReading(&net_message, cls.netchan.netprim);
cls.netchan.last_received = realtime;
@ -4891,7 +4939,7 @@ void CL_ReadPackets (void)
}
}
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
CL_MVDUpdateSpectator();
}
@ -4908,7 +4956,7 @@ qboolean CL_AllowArbitaryDownload(const char *oldname, const char *localfile)
strstr(localfile, "\\") || strstr(localfile, "..") || strstr(localfile, "./") || strstr(localfile, ":") || strstr(localfile, "//") || //certain path patterns are just bad
Q_strcasestr(localfile, ".qvm") || Q_strcasestr(localfile, ".dll") || Q_strcasestr(localfile, ".so") || Q_strcasestr(localfile, ".dylib")) //disallow any native code
{ //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar)
Con_Printf("Ignoring arbitary download to \"%s\" due to possible security risk\n", localfile);
Con_Printf("Ignoring arbitrary download to \"%s\" due to possible security risk\n", localfile);
return false;
}
allow = cl_download_redirection.ival;
@ -4941,10 +4989,12 @@ static void CL_Curl_f(void)
int i, argc = Cmd_Argc();
const char *arg, *gamedir, *localterse/*no dlcache*/= NULL;
char localname[MAX_QPATH];
char localnametmp[MAX_QPATH];
int usage = 0;
qboolean alreadyhave = false;
extern char *cl_dp_packagenames;
unsigned int dlflags = DLLF_VERBOSE|DLLF_ALLOWWEB;
const char *ext;
if (argc < 2)
{
Con_Printf("%s: No args\n", Cmd_Argv(0));
@ -5015,12 +5065,29 @@ static void CL_Curl_f(void)
}
arg = Cmd_Argv(argc-1);
if (!localterse)
{
char *t;
localterse = strrchr(arg, '/');
if (!localterse)
localterse = arg;
t = strchr(localterse, '?');
if (t)
*t = 0;
if (t-localterse < countof(localnametmp))
{
memcpy(localnametmp, localterse, t-localterse);
localnametmp[t-localterse] = 0;
localterse = localnametmp;
}
}
if (!localterse)
{
//for compat, we should look for the last / and truncate on a ?.
Con_Printf("%s: skipping download of %s, as the local name was not explicitly given\n", Cmd_Argv(0), arg);
return;
}
if (usage == 1)
ext = COM_GetFileExtension(localterse, NULL);
if (usage == 1 && (!strcmp(ext, ".pk3") || !strcmp(ext, ".pak")))
{
dlflags |= DLLF_NONGAME;
gamedir = FS_GetGamedir(true);
@ -5084,7 +5151,7 @@ void CL_Download_f (void)
if (!*localname)
localname = url;
if ((cls.state == ca_disconnected || cls.demoplayback) && cls.demoplayback != DPB_EZTV)
if ((cls.state == ca_disconnected || cls.demoplayback) && !(cls.demoplayback == DPB_MVD && (cls.demoeztv_ext&EZTV_DOWNLOAD)))
{
Con_TPrintf ("Must be connected.\n");
return;
@ -5134,14 +5201,14 @@ void CL_DownloadSize_f(void)
size = Cmd_Argv(2);
if (!strcmp(size, "e"))
{
Con_Printf("Download of \"%s\" failed. Not found.\n", rname);
Con_Printf(CON_ERROR"Download of \"%s\" failed. Not found.\n", rname);
CL_DownloadFailed(rname, NULL, DLFAIL_SERVERFILE);
}
else if (!strcmp(size, "p"))
{
if (cls.download && stricmp(cls.download->remotename, rname))
{
Con_Printf("Download of \"%s\" failed. Not allowed.\n", rname);
Con_Printf(CON_ERROR"Download of \"%s\" failed. Not allowed.\n", rname);
CL_DownloadFailed(rname, NULL, DLFAIL_SERVERCVAR);
}
}
@ -5359,21 +5426,11 @@ void CL_Fog_f(void)
#ifdef _DEBUG
void CL_FreeSpace_f(void)
{
char buf[32];
quint64_t freespace;
const char *freepath = Cmd_Argv(1);
if (Sys_GetFreeDiskSpace(freepath, &freespace))
{
if (freespace > 512.0*1024*1024*1024)
Con_Printf("%s: %g tb available\n", freepath, freespace/(1024.0*1024*1024*1024));
else if (freespace > 512.0*1024*1024)
Con_Printf("%s: %g gb available\n", freepath, freespace/(1024.0*1024*1024));
else if (freespace > 512.0*1024)
Con_Printf("%s: %g mb available\n", freepath, freespace/(1024.0*1024));
else if (freespace > 512.0)
Con_Printf("%s: %g kb available\n", freepath, freespace/1024.0);
else
Con_Printf("%s: %"PRIu64" bytes available\n", freepath, freespace);
}
Con_Printf("%s: %s available\n", freepath, FS_AbbreviateSize(buf,sizeof(buf),freespace));
else
Con_Printf("%s: disk free not queryable\n", freepath);
}
@ -5434,7 +5491,24 @@ void CL_Status_f(void)
if (cls.state)
{
char cert[8192];
qbyte fp[DIGEST_MAXSIZE+1];
char b64[(DIGEST_MAXSIZE*4)/3+1];
if (NET_GetConnectionCertificate(cls.sockets, &cls.netchan.remote_address, QCERT_ISENCRYPTED, NULL, 0))
Q_strncpyz(b64, "<UNENCRYPTED>", sizeof(b64));
else
{
int sz = NET_GetConnectionCertificate(cls.sockets, &cls.netchan.remote_address, QCERT_PEERCERTIFICATE, cert, sizeof(cert));
if (sz<0)
Q_strncpyz(b64, "<UNAVAILABLE>", sizeof(b64));
else
{
sz = Base64_EncodeBlockURI(fp, CalcHash(&hash_certfp, fp,sizeof(fp), cert, sz), b64, sizeof(b64));
b64[sz] = 0;
}
}
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.
switch(cls.protocol)
{
default:
@ -5466,6 +5540,9 @@ void CL_Status_f(void)
case CPNQ_BJP3:
Con_Printf("Network Protocol : BJP3\n");
break;
case CPNQ_H2MP:
Con_Printf("Network Protocol : H2MP\n");
break;
case CPNQ_FITZ666:
Con_Printf("Network Protocol : FitzQuake\n");
break;
@ -5555,10 +5632,10 @@ void CL_Status_f(void)
count++;
}
Con_Printf("csqc entities : %i/%i/%i (mem: %.1f%%)\n", count, csqc_world.num_edicts, csqc_world.max_edicts, 100*(float)(csqc_world.progs->stringtablesize/(double)csqc_world.progs->stringtablemaxsize));
for (count = 1; count < MAX_PRECACHE_MODELS; count++)
for (count = 1; count < MAX_CSMODELS; count++)
if (!*cl.model_csqcname[count])
break;
Con_Printf("csqc models : %i/%i\n", count, MAX_PRECACHE_MODELS);
Con_Printf("csqc models : %i/%i\n", count, MAX_CSMODELS);
Con_Printf("client sounds : %i\n", num_sfx); //there is a limit, its just private. :(
for (count = 1; count < MAX_SSPARTICLESPRE; count++)
@ -5678,7 +5755,8 @@ void CL_Init (void)
Cvar_Register (&cl_idlefps, cl_screengroup);
Cvar_Register (&cl_yieldcpu, cl_screengroup);
Cvar_Register (&cl_timeout, cl_controlgroup);
Cvar_Register (&cl_forcevrui, cl_controlgroup);
Cvar_Register (&cl_vrui_force, cl_controlgroup);
Cvar_Register (&cl_vrui_lock, cl_controlgroup);
Cvar_Register (&lookspring, cl_inputgroup);
Cvar_Register (&lookstrafe, cl_inputgroup);
Cvar_Register (&sensitivity, cl_inputgroup);
@ -5794,7 +5872,6 @@ void CL_Init (void)
Cvar_Register (&cl_threadedphysics, cl_controlgroup);
hud_tracking_show = Cvar_Get("hud_tracking_show", "1", 0, "statusbar");
hud_miniscores_show = Cvar_Get("hud_miniscores_show", "1", 0, "statusbar");
Cvar_Register (&cl_download_mapsrc, cl_controlgroup);
Cvar_Register (&cl_dlemptyterminate, cl_controlgroup);
@ -5863,7 +5940,6 @@ void CL_Init (void)
Cmd_AddCommandAD ("connectbr", CL_ConnectBestRoute_f, CL_Connect_c, "connect address:port\nConnect to a qw server using the best route we can detect.");
#endif
Cmd_AddCommandAD("connect", CL_Connect_f, CL_Connect_c, "connect scheme://address:port\nConnect to a server. "
#if defined(FTE_TARGET_WEB)
"Use a scheme of rtc[s]://broker/gamename to connect via a webrtc broker."
"Use a scheme of ws[s]://server to connect via websockets."
@ -5896,16 +5972,22 @@ void CL_Init (void)
Cmd_AddCommandD ("cl_transfer", CL_Transfer_f, "Connect to a different server, disconnecting from the current server only when the new server replies.");
#ifdef TCPCONNECT
Cmd_AddCommandAD ("connecttcp", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix");
Cmd_AddCommandAD ("tcpconnect", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix");
#endif
#ifdef IRCCONNECT
Cmd_AddCommand ("connectirc", CL_IRCConnect_f);
#endif
#ifdef NQPROT
Cmd_AddCommandD ("connectnq", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also disables QW/Q2/Q3/DP handshakes preventing them from being favoured, so should only be used when you actually want NQ protocols specifically.");
#ifdef HAVE_DTLS
Cmd_AddCommandD ("connectqe", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also forces the use of DTLS and QE-specific handshakes. You will also need to ensure the dtls_psk_* cvars are set properly or the server will refuse the connection.");
#endif
#endif
#ifdef Q2CLIENT
Cmd_AddCommandD ("connectq2e", CLQ2E_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_Q2ESERVER)".");
Cmd_AddCommandD ("connectq2e", CLQ2E_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_Q2EXSERVER)".");
#endif
#ifdef HAVE_LEGACY
Cmd_AddCommandAD("qwurl", CL_Connect_f, CL_Connect_c, "For compat with ezquake.");
#endif
Cmd_AddCommand ("reconnect", CL_Reconnect_f);
Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server.");
@ -5924,7 +6006,7 @@ void CL_Init (void)
Cmd_AddCommandAD ("color", CL_Color_f, CL_Color_c, NULL);
#if defined(NQPROT) && defined(HAVE_LEGACY)
Cmd_AddCommand ("curl", CL_Curl_f);
Cmd_AddCommandD ("curl", CL_Curl_f, "For use by xonotic.");
#endif
Cmd_AddCommand ("download", CL_Download_f);
Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use");
@ -6074,7 +6156,7 @@ void Host_WriteConfiguration (void)
f = FS_OpenVFS(savename, "wb", FS_GAMEONLY);
if (!f)
{
FS_NativePath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
FS_DisplayPath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_TPrintf (CON_ERROR "Couldn't write %s.\n", sysname);
return;
}
@ -6084,7 +6166,7 @@ void Host_WriteConfiguration (void)
VFS_CLOSE (f);
FS_NativePath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
FS_DisplayPath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf("Wrote %s\n", savename);
}
}
@ -6118,15 +6200,6 @@ qboolean Host_SimulationTime(float time)
}
#endif
void Host_RunFileNotify(struct dl_download *dl)
{
if (dl->file)
{
Host_RunFile(dl->url, strlen(dl->url), dl->file);
dl->file = NULL;
}
}
#include "fs.h"
#define HRF_OVERWRITE (1<<0)
#define HRF_NOOVERWRITE (1<<1)
@ -6136,7 +6209,7 @@ void Host_RunFileNotify(struct dl_download *dl)
#define HRF_OPENED (1<<4)
#define HRF_DOWNLOADED (1<<5) //file was actually downloaded, and not from the local system
#define HRF_WAITING (1<<6) //file looks important enough that we should wait for it to start to download or something before we try doing other stuff.
// (1<<7)
#define HRF_DECOMPRESS (1<<7) //need to degzip it, which prevents streaming.
#define HRF_DEMO_MVD (1<<8)
#define HRF_DEMO_QWD (1<<9)
@ -6165,7 +6238,7 @@ typedef struct {
extern int waitingformanifest;
void Host_DoRunFile(hrf_t *f);
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay);
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay, unsigned int eztv_ext);
void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name);
//guesses the file type based upon its file extension. mdl/md3/iqm distinctions are not important, so we can usually get away with this in the context of quake.
@ -6201,13 +6274,13 @@ unsigned int Host_GuessFileType(const char *mimetype, const char *filename)
{
//demo formats
{HRF_DEMO_QWD, "qwd"},
{HRF_DEMO_QWD, "qwd.gz"},
{HRF_DEMO_QWD|HRF_DECOMPRESS, "qwd.gz"},
{HRF_DEMO_MVD, "mvd"},
{HRF_DEMO_MVD, "mvd.gz"},
{HRF_DEMO_MVD|HRF_DECOMPRESS, "mvd.gz"},
{HRF_DEMO_DM2, "dm2"},
{HRF_DEMO_DM2, "dm2.gz"},
{HRF_DEMO_DM2|HRF_DECOMPRESS, "dm2.gz"},
{HRF_DEMO_DEM, "dem"},
{HRF_DEMO_DEM, "dem.gz"},
{HRF_DEMO_DEM|HRF_DECOMPRESS, "dem.gz"},
{HRF_QTVINFO, "qtv"},
//other stuff
{HRF_MANIFEST, "fmf"},
@ -6215,6 +6288,7 @@ unsigned int Host_GuessFileType(const char *mimetype, const char *filename)
{HRF_BSP, "map"},
{HRF_CONFIG, "cfg"},
{HRF_CONFIG, "rc"},
{HRF_PACKAGE, "kpf"},
{HRF_PACKAGE, "pak"},
{HRF_PACKAGE, "pk3"},
{HRF_PACKAGE, "pk4"},
@ -6319,20 +6393,29 @@ qboolean Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
}
}
#ifdef AVAIL_GZDEC
//seeking means we can rewind
if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKEWORLD, 0);
if (f->flags & HRF_DECOMPRESS)
{ //if its a gzip, we'll probably need to decompress it ourselves... in case the server doesn't use content-encoding:gzip
//our demo playback should decompress it when its fin ally available.
dl->file = VFSPIPE_Open(1, true);
return true;
}
else
#endif
if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKEWORLD, 0, 0);
else if (f->flags & HRF_DEMO_MVD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_MVD, 0);
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_MVD, 0, 0);
#ifdef Q2CLIENT
else if (f->flags & HRF_DEMO_DM2)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKE2, 0);
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKE2, 0, 0);
#endif
#ifdef NQPROT
else if (f->flags & HRF_DEMO_DEM)
{ //fixme: the demo code can't handle the cd track with streamed/missing-so-far writes.
dl->file = VFSPIPE_Open(1, true); //make sure the reader will be seekable, so we can rewind.
// CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, DPB_NETQUAKE, 0);
// CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, DPB_NETQUAKE, 0, 0);
}
#endif
else if (f->flags & (HRF_MANIFEST | HRF_QTVINFO))
@ -6402,6 +6485,7 @@ static qboolean isurl(char *url)
#endif
qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnamelen);
void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath);
void Host_DoRunFile(hrf_t *f)
{
@ -6466,7 +6550,7 @@ done:
//if we still don't know what it is, give up.
if (!(f->flags & HRF_FILETYPES))
{
Con_Printf("Host_DoRunFile: unknown filetype\n");
Con_Printf("Host_DoRunFile: unknown filetype for \"%s\"\n", f->fname);
goto done;
}
@ -6485,18 +6569,22 @@ done:
if (f->srcfile)
{
VFS_SEEK(f->srcfile, 0);
#ifdef AVAIL_GZDEC
f->srcfile = FS_DecompressGZip(f->srcfile, NULL);
#endif
if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKEWORLD, 0);
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKEWORLD, 0, 0);
#ifdef Q2CLIENT
else if (f->flags & HRF_DEMO_DM2)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKE2, 0);
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKE2, 0, 0);
#endif
#ifdef NQPROT
else if (f->flags & HRF_DEMO_DEM)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_NETQUAKE, 0);
CL_PlayDemoFile(f->srcfile, f->fname, true); //should be able to handle the cd-track header.
#endif
else //if (f->flags & HRF_DEMO_MVD)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_MVD, 0);
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_MVD, 0, 0);
f->srcfile = NULL;
}
else
@ -6657,8 +6745,12 @@ done:
if (f->flags & HRF_PACKAGE)
{
#ifdef PACKAGEMANAGER
Z_Free(f->packageinfo);
if (f->packageinfo)
Z_Free(f->packageinfo); //sucks that we have to do this again, to recompute the proper qname+qroot
Q_strncpyz(qname, COM_SkipPath(f->fname), sizeof(qname));
f->packageinfo = PM_GeneratePackageFromMeta(f->srcfile, qname,sizeof(qname), &qroot);
if (!f->packageinfo)
goto done;
#endif
}
else if (f->flags & HRF_MANIFEST)
@ -6718,7 +6810,10 @@ done:
}
else if (isnew)
{
Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"), displayname), "Install!", "", "Cancel", true);
if (f->packageinfo && strstr(f->packageinfo, "\nguessed"))
Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"CON_ERROR"File contains no metadata so will be installed to\n%s"), displayname, qname), "Install!", "", "Cancel", true);
else
Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"), displayname), "Install!", "", "Cancel", true);
return;
}
else
@ -6729,9 +6824,9 @@ done:
}
else if (f->flags & HRF_OVERWRITE)
{
char buffer[8192];
char buffer[65536];
int len;
f->dstfile = FS_OpenVFS(qname, "wb", qroot);
f->dstfile = FS_OpenVFS(qname, (f->flags & HRF_PACKAGE)?"wbp":"wb", qroot);
if (f->dstfile)
{
#ifdef FTE_TARGET_WEB
@ -6753,10 +6848,13 @@ done:
#ifdef PACKAGEMANAGER
if (f->flags & HRF_PACKAGE)
PM_FileInstalled(COM_SkipPath(f->fname), qroot, f->packageinfo, true);
PM_FileInstalled(qname, qroot, f->packageinfo, true);
#endif
Cbuf_AddText(loadcommand, RESTRICT_LOCAL);
if (!strcmp(loadcommand, "fs_restart\n"))
FS_ReloadPackFiles();
else
Cbuf_AddText(loadcommand, RESTRICT_LOCAL);
}
goto done;
@ -6779,6 +6877,8 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
if (!Sys_ResolveFileURL(fname, nlen, utf8, sizeof(utf8)))
{
Con_Printf("Cannot resolve file url\n");
if(file)
VFS_CLOSE(file);
return false;
}
fname = utf8;
@ -6892,7 +6992,11 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
if (file)
f->flags |= HRF_OPENED;
Con_TPrintf("Opening external file: %s\n", f->fname);
{
char dpath[MAX_OSPATH];
FS_DisplayPath(f->fname, FS_SYSTEM, dpath,sizeof(dpath));
Con_TPrintf("Opening external file: %s\n", dpath);
}
Host_DoRunFile(f);
return true;
@ -6924,7 +7028,7 @@ double Host_Frame (double time)
qboolean idle;
extern int r_blockvidrestart;
static qboolean hadwork;
qboolean vrsync;
unsigned int vrflags;
qboolean mustrenderbeforeread;
RSpeedLocals();
@ -6934,7 +7038,7 @@ double Host_Frame (double time)
return 0; // something bad happened, or the server disconnected
}
vrsync = vid.vr?vid.vr->SyncFrame(&time):false; //fiddle with frame timings
vrflags = vid.vr?vid.vr->SyncFrame(&time):0; //fiddle with frame timings
newrealtime = Media_TweekCaptureFrameTime(realtime, time); //fiddle with time some more
time = newrealtime - realtime;
@ -6978,7 +7082,7 @@ double Host_Frame (double time)
if (!cls.timedemo)
CL_ReadPackets ();
if (idle && cl_idlefps.value > 0 && !vrsync)
if (idle && cl_idlefps.value > 0 && !(vrflags&VRF_OVERRIDEFRAMETIME))
{
double idlesec = 1.0 / cl_idlefps.value;
if (idlesec > 0.1)
@ -7053,7 +7157,7 @@ double Host_Frame (double time)
#ifdef HAVE_MEDIA_ENCODER
&& Media_Capturing() != 2
#endif
&& !vrsync)
&& !(vrflags&VRF_OVERRIDEFRAMETIME))
{
spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, 1.5, maxfpsignoreserver);
if (!spare)
@ -7128,7 +7232,7 @@ double Host_Frame (double time)
CL_UseIndepPhysics(cls.state != ca_disconnected && !!cl_threadedphysics.ival); //starts/stops the input frame thread.
cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo);
cl.do_lerp_players = cl_lerp_players.ival || cls.demoplayback==DPB_MVD || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo);
CL_AllowIndependantSendCmd(false);
mustrenderbeforeread = cls.protocol == CP_QUAKE2; //FIXME: quake2 MUST render a frame (or a later one) before it can read any acks from the server, otherwise its prediction screws up. I'm too lazy to rewrite that right now.
@ -7213,6 +7317,8 @@ double Host_Frame (double time)
Con_Printf("R2D_Flush was set outside of SCR_UpdateScreen\n");
}
cl.mouseplayerview = NULL;
cl.mousenewtrackplayer = -1;
for (i = 0; i < MAX_SPLITS; i++)
{
cl.playerview[i].audio.defaulted = true;
@ -7235,7 +7341,7 @@ double Host_Frame (double time)
{
RSpeedMark();
vid.ime_allow = false;
vrui.enabled = cl_forcevrui.ival;
vrui.enabled |= cl_vrui_force.ival || (vrflags&VRF_UIACTIVE);
if (SCR_UpdateScreen())
fps_count++;
if (R2D_Flush)
@ -7350,6 +7456,7 @@ void CL_StartCinematicOrMenu(void)
startuppending = true;
return;
}
Cmd_StuffCmds();
if (startuppending)
{
if (startuppending == 2) //installer finished.
@ -7379,7 +7486,7 @@ void CL_StartCinematicOrMenu(void)
}
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername)
{
{ //this is so default.cfg can define startup commands to exec if the engine starts up with no +connect / +map etc arg
TP_ExecTrigger("f_startup", true);
Cbuf_Execute ();
}
@ -7590,6 +7697,7 @@ static void Host_URIPrompt(void *ctx, promptbutton_t btn)
void Host_FinishLoading(void)
{
int i;
extern qboolean r_forceheadless;
extern int r_blockvidrestart;
if (r_blockvidrestart == true)
@ -7615,8 +7723,7 @@ void Host_FinishLoading(void)
Con_History_Load();
Cmd_StuffCmds();
Cbuf_Execute ();
r_blockvidrestart = 2;
CL_ArgumentOverrides();
#ifdef HAVE_SERVER
@ -7641,14 +7748,15 @@ void Host_FinishLoading(void)
Sys_Quit();
#endif
r_blockvidrestart = 2;
Menu_Download_Update();
#ifdef IPLOG
IPLog_Merge_File("iplog.txt");
IPLog_Merge_File("iplog.dat"); //legacy crap, for compat with proquake
#endif
if (!PM_IsApplying())
Cmd_StuffCmds();
}
if (PM_IsApplying() == 1)
@ -7659,6 +7767,16 @@ void Host_FinishLoading(void)
return;
}
//open any files specified on the commandline (urls, paks, models, I dunno).
for (i = 1; i < com_argc; i++)
{
if (!com_argv[i])
continue;
if (*com_argv[i] == '+' || *com_argv[i] == '-')
break;
Host_RunFile(com_argv[i], strlen(com_argv[i]), NULL);
}
//android may find that it has no renderer at various points.
if (r_forceheadless)
return;

File diff suppressed because it is too large Load Diff

View File

@ -638,7 +638,6 @@ static void QDECL Plug_GetServerInfoRaw(char *outptr, size_t outlen)
case DPB_NONE:
break;
case DPB_MVD:
case DPB_EZTV:
Q_strncatz(outptr, "\\demotype\\mvd", outlen);
break;
case DPB_QUAKEWORLD:
@ -692,7 +691,6 @@ static size_t QDECL Plug_GetServerInfoBlob(const char *key, void *outptr, size_t
case DPB_NONE:
break;
case DPB_MVD:
case DPB_EZTV:
blob = "mvd";
break;
case DPB_QUAKEWORLD:
@ -888,7 +886,7 @@ static size_t QDECL Plug_GetTeamInfo(teamplayerinfo_t *players, size_t maxplayer
players->health = cl.playerview[seat].statsf[STAT_HEALTH];
Q_strncpyz(players->nick, "", sizeof(players->nick));
}
else if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
else if (cls.demoplayback == DPB_MVD)
{ //scrape it from the mvd (assuming there is one...
players->items = cl.players[i].stats[STAT_ITEMS];
players->armor = cl.players[i].statsf[STAT_ARMOR];

View File

@ -633,7 +633,7 @@ void CL_CalcClientTime(void)
//qw code can drift (but oh noes! my latency!)
//FIXME: nq code should be able to drift, but is apparently buggy somewhere and ends up uncomfortably stuttery right now.
//default is to drift in demos+SP but not live (oh noes! added latency!)
if (cls.protocol == CP_QUAKE2 || cls.protocol==CP_NETQUAKE/*FIXME*/ || (cls.protocol != CP_QUAKE3 && (!cl_lerp_smooth.ival || (cl_lerp_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback != DPB_MVD))
if (cls.protocol == CP_QUAKE2 || cls.protocol==CP_NETQUAKE/*FIXME*/ || (cls.protocol != CP_QUAKE3 && (!cl_lerp_smooth.ival || (cl_lerp_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1 || cl.playerview[0].spectator))) && cls.demoplayback!=DPB_MVD))
{ //no drift logic
double f;
extern cvar_t cl_demospeed;
@ -1018,7 +1018,7 @@ void CL_PredictMovePNum (int seat)
}
#endif
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && pv->cam_state == CAM_FREECAM)
if (cl.paused && !(cls.demoplayback!=DPB_MVD) && pv->cam_state == CAM_FREECAM)
return;
if (!cl.validsequence)
@ -1086,7 +1086,7 @@ void CL_PredictMovePNum (int seat)
nopred = true;
//these things also force-disable prediction
if ((cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) ||
if (cls.demoplayback==DPB_MVD ||
cl.intermissionmode != IM_NONE || cl.paused || pv->pmovetype == PM_NONE || pv->pmovetype == PM_FREEZE || CAM_ISLOCKED(pv))
{
nopred = true;
@ -1169,7 +1169,7 @@ void CL_PredictMovePNum (int seat)
}
else
{
if (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback==DPB_MVD)
{
pv->nolocalplayer = false;
from.state = &cl.inframes[cl.ackedmovesequence & UPDATE_MASK].playerstate[pv->playernum];

View File

@ -2445,7 +2445,7 @@ void SCR_ImageName (const char *mapname)
strcpy(levelshotname, "levelshots/");
COM_FileBase(mapname, levelshotname + strlen(levelshotname), sizeof(levelshotname)-strlen(levelshotname));
if (qrenderer && scr_loadingscreen_aspect.ival >= 0)
if (qrenderer && scr_loadingscreen_aspect.ival >= 0 && *mapname)
{
R_LoadHiResTexture(levelshotname, NULL, IF_NOWORKER|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP);
@ -2624,7 +2624,7 @@ SCR_ScreenShot_f
*/
static void SCR_ScreenShot_f (void)
{
char sysname[1024];
char displayname[1024];
char pcxname[MAX_QPATH];
int i;
vfsfile_t *vfs;
@ -2672,7 +2672,7 @@ static void SCR_ScreenShot_f (void)
}
}
FS_NativePath(pcxname, FS_GAMEONLY, sysname, sizeof(sysname));
FS_DisplayPath(pcxname, FS_GAMEONLY, displayname, sizeof(displayname));
rgbbuffer = VID_GetRGBInfo(&stride, &width, &height, &fmt);
if (rgbbuffer)
@ -2680,12 +2680,12 @@ static void SCR_ScreenShot_f (void)
//regarding metadata - we don't really know what's on the screen, so don't write something that may be wrong (eg: if there's only a console, don't claim that its a 360 image)
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, &rgbbuffer, 1, stride, width, height, fmt, false))
{
Con_Printf ("Wrote %s\n", sysname);
Con_Printf ("Wrote %s\n", displayname);
BZ_Free(rgbbuffer);
return;
}
BZ_Free(rgbbuffer);
Con_Printf (CON_ERROR "Couldn't write %s\n", sysname);
Con_Printf (CON_ERROR "Couldn't write %s\n", displayname);
}
else
Con_Printf (CON_ERROR "Couldn't get colour buffer for screenshot\n");
@ -2881,9 +2881,9 @@ static void SCR_ScreenShot_Mega_f(void)
{
if (SCR_ScreenShot(filename, FS_GAMEONLY, buffers, numbuffers, stride[0], width[0], height[0], fmt[0], true))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
char displayname[1024];
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", displayname);
}
}
else
@ -3040,9 +3040,9 @@ static void SCR_ScreenShot_VR_f(void)
Con_Printf ("Unable to capture suitable screen image\n");
else if (SCR_ScreenShot(filename, FS_GAMEONLY, buffer, (stereo?2:1), stride, width, height*(stereo?1:2), TF_BGRX32, true))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
char displayname[1024];
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", displayname);
}
BZ_Free(buffer[0]);
@ -3058,7 +3058,7 @@ void SCR_ScreenShot_Cubemap_f(void)
int stride, fbwidth, fbheight;
uploadfmt_t fmt;
char filename[MAX_QPATH];
char sysname[1024];
char displayname[1024];
char *fname = Cmd_Argv(1);
int i, firstside;
char olddrawviewmodel[64]; //hack, so we can set r_drawviewmodel to 0 so that it doesn't appear in screenshots even if the csqc is generating new data.
@ -3189,8 +3189,8 @@ void SCR_ScreenShot_Cubemap_f(void)
{
if (Image_WriteDDSFile(filename, FS_GAMEONLY, &mips))
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", displayname);
}
}
#endif
@ -3199,8 +3199,8 @@ void SCR_ScreenShot_Cubemap_f(void)
{
if (Image_WriteKTXFile(filename, FS_GAMEONLY, &mips))
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", displayname);
}
}
#endif
@ -3249,13 +3249,13 @@ void SCR_ScreenShot_Cubemap_f(void)
if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, fbwidth, fbheight, fmt, false))
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", displayname);
}
else
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Failed to write %s\n", sysname);
FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Failed to write %s\n", displayname);
}
BZ_Free(buffer);
}

View File

@ -475,6 +475,7 @@ typedef struct
CPNQ_BJP1, //16bit models, strict 8bit sounds (otherwise based on nehahra)
CPNQ_BJP2, //16bit models, strict 16bit sounds
CPNQ_BJP3, //16bit models, flagged 16bit sounds, 8bit static sounds.
CPNQ_H2MP, //urgh
CPNQ_FITZ666, /*and rmqe999 protocol, which is a strict superset*/
CPNQ_DP5,
CPNQ_DP6,
@ -519,7 +520,7 @@ typedef struct
// entering a map (and clearing client_state_t)
vfsfile_t *demooutfile;
enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,DPB_EZTV,
enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,
#ifdef NQPROT
DPB_NETQUAKE,
#endif
@ -527,12 +528,16 @@ typedef struct
DPB_QUAKE2
#endif
} demoplayback, demorecording;
unsigned int demoeztv_ext;
#define EZTV_DOWNLOAD (1u<<0) //also changes modellist/soundlist stuff to keep things synced
#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;
float demoseektime;
int demotrack;
qboolean timedemo;
char lastdemoname[MAX_OSPATH];
char lastdemoname[MAX_OSPATH]; //empty if is a qtv stream
qboolean lastdemowassystempath;
vfsfile_t *demoinfile;
float td_lastframe; // to meter out one message a frame
@ -540,6 +545,13 @@ typedef struct
float td_starttime; // realtime at second frame of timedemo
float demostarttime; // the time of the first frame, so we don't get weird results with qw demos
struct qtvviewers_s
{ //(other) people on a qtv. in case people give a damn.
struct qtvviewers_s *next;
int userid;
char name[128];
} *qtvviewers;
int challenge;
float latency; // rolling average
@ -904,12 +916,12 @@ typedef struct
// information that is static for the entire time connected to a server
//
#ifdef HAVE_LEGACY
char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH];
char *model_name_vwep[MAX_VWEP_MODELS];
struct model_s *model_precache_vwep[MAX_VWEP_MODELS];
#endif
char model_name[MAX_PRECACHE_MODELS][MAX_QPATH];
char *model_name[MAX_PRECACHE_MODELS];
struct model_s *model_precache[MAX_PRECACHE_MODELS];
char sound_name[MAX_PRECACHE_SOUNDS][MAX_QPATH];
char *sound_name[MAX_PRECACHE_SOUNDS];
struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS];
char *particle_ssname[MAX_SSPARTICLESPRE];
int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat.
@ -994,6 +1006,8 @@ typedef struct
float currentpacktime;
qboolean do_lerp_players;
playerview_t *mouseplayerview; //for mouse/scoreboard interaction when playing mvds.
int mousenewtrackplayer;
int teamplay;
int deathmatch;
@ -1363,6 +1377,7 @@ void CL_Parse_Disconnected(void);
void CL_DumpPacket(void);
void CL_ParseEstablished(void);
void CLQW_ParseServerMessage (void);
void CLEZ_ParseHiddenDemoMessage (void);
void CLNQ_ParseServerMessage (void);
#ifdef Q2CLIENT
void CLQ2_ParseServerMessage (void);

View File

@ -1956,7 +1956,8 @@ static int Con_DrawProgress(int left, int right, int y)
sprintf(progresspercenttext, " (%ukB/s)", CL_DownloadRate()/1000);
else
{
sprintf(progresspercenttext, " (%u%sKiB)", (int)(total/1024), extra?"+":"");
char tmp[64];
sprintf(progresspercenttext, " (%s%s)", FS_AbbreviateSize(tmp,sizeof(tmp), total), extra?"+":"");
}
//do some marquee thing, so the user gets the impression that SOMETHING is happening.

View File

@ -1792,7 +1792,7 @@ error:
int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, qintptr_t bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata)
{
char name[MAX_OSPATH];
char systemname[MAX_OSPATH]; //FIXME: replace with png_set_write_fn
int i;
FILE *fp;
png_structp png_ptr;
@ -1882,7 +1882,7 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
}
Image_BlockSizeForEncoding(fmt, &pxsize, &bw, &bh, &bd);
if (!FS_NativePath(filename, fsroot, name, sizeof(name)))
if (!FS_SystemPath(filename, fsroot, systemname, sizeof(systemname)))
return false;
if (numbuffers == 2)
@ -1898,10 +1898,10 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
if (!LibPNG_Init())
return false;
if (!(fp = fopen (name, "wb")))
if (!(fp = fopen (systemname, "wb")))
{
FS_CreatePath (filename, FS_GAMEONLY);
if (!(fp = fopen (name, "wb")))
FS_CreatePath (systemname, FS_SYSTEM);
if (!(fp = fopen (systemname, "wb")))
return false;
}
@ -7176,6 +7176,7 @@ static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, const ch
//This is for the version command
void Image_PrintInputFormatVersions(void)
{
int i;
#ifndef S_COLOR_YELLOW
#define S_COLOR_YELLOW ""
#define S_COLOR_WHITE ""
@ -7185,6 +7186,9 @@ void Image_PrintInputFormatVersions(void)
#ifdef IMAGEFMT_DDS
Con_Printf(" dds");
#ifndef DECOMPRESS_S3TC
Con_Printf("(hw-only)");
#endif
#endif
#ifdef IMAGEFMT_KTX
Con_Printf(" ktx");
@ -7231,6 +7235,9 @@ void Image_PrintInputFormatVersions(void)
#endif
#ifdef IMAGEFMT_ASTC
Con_Printf(" astc");
#ifndef DECOMPRESS_ASTC
Con_Printf("(hw-only)");
#endif
#endif
#ifdef IMAGEFMT_PKM
Con_Printf(" pkm");
@ -7278,6 +7285,10 @@ void Image_PrintInputFormatVersions(void)
Con_Printf(" lmp");
#endif
//now properly registered ones.
for (i = 0; i < imageloader_count; i++)
Con_Printf(" ^[%s^]", imageloader[i].funcs->loadername);
Con_Printf("\n");
}
@ -13757,10 +13768,10 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
{
COM_FileExtension(altname, nicename, sizeof(nicename));
e = 0;
if (strcmp(nicename, "lmp") && strcmp(nicename, "wal"))
if (Q_strcasecmp(nicename, "lmp") && Q_strcasecmp(nicename, "wal"))
for (; e < tex_extensions_count; e++)
{
if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name))
if (!Q_strcasecmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name))
break;
}
}
@ -13844,7 +13855,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
for (e = firstex; e < tex_extensions_count; e++)
{
if (tex->flags & IF_NOPCX)
if (!strcmp(tex_extensions[e].name, ".pcx"))
if (!Q_strcasecmp(tex_extensions[e].name, ".pcx"))
continue;
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, subpath, basename, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc);
@ -13863,7 +13874,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
for (e = firstex; e < tex_extensions_count; e++)
{
if (tex->flags & IF_NOPCX)
if (!strcmp(tex_extensions[e].name, ".pcx"))
if (!Q_strcasecmp(tex_extensions[e].name, ".pcx"))
continue;
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, nicename, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc);
@ -13906,7 +13917,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
*b = 0;
for (e = firstex; e < tex_extensions_count; e++)
{
if (!strcmp(tex_extensions[e].name, ".tga"))
if (!Q_strcasecmp(tex_extensions[e].name, ".tga"))
{
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, bumpname, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc);
@ -14747,7 +14758,10 @@ void Image_Formats_f(void)
}
Image_BlockSizeForEncoding(i, &blockbytes, &blockwidth, &blockheight, &blockdepth);
bpp = blockbytes*8.0/(blockwidth*blockheight*blockdepth);
Con_Printf("%20s: %s"S_COLOR_GRAY" (%s%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", (blockdepth!=1)?"3d, ":"", bpp);
if (blockbytes)
Con_Printf("%20s: %s"S_COLOR_GRAY" (%s%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", (blockdepth!=1)?"3d, ":"", bpp);
else
Con_Printf("%20s: %s\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled");
}
}

View File

@ -491,7 +491,7 @@ void IN_Commands(void)
Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, true);
break;
case IEV_JOYAXIS:
if (ev->devid < MAXJOYSTICKS && ev->joy.axis < MAXJOYAXIS)
if (ev->devid < MAXJOYSTICKS && ev->joy.axis>=0 && ev->joy.axis<MAXJOYAXIS)
{
if (topmenu && topmenu->joyaxis && topmenu->joyaxis(topmenu, ev->devid, ev->joy.axis, ev->joy.value))
joy[ev->devid].axis[ev->joy.axis] = 0;
@ -884,6 +884,9 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
return;
}
if (r_xflip.ival)
mouse_x *= -1;
// add mouse X/Y movement to cmd
if (strafe_x)
movements[1] += m_side.value * mouse_x;
@ -1040,6 +1043,8 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet
VectorClear(jlook);
VectorClear(jstrafe);
}
if (r_xflip.ival)
jlook[0] *= -1, jstrafe[0] *= -1;
if (in_speed.state[pnum] & 1)
{

View File

@ -394,6 +394,44 @@ static void J_JoystickButton(SDL_JoystickID jid, int button, qboolean pressed)
}
}
int INS_GetControllerType(int id)
{
#if SDL_VERSION_ATLEAST(2,0,12)
int i;
for (i = 0; i < MAX_JOYSTICKS; i++)
{
if (sdljoy[i].qdevid == id)
{
switch(SDL_GameControllerTypeForIndex(sdljoy[i].id))
{
default: //for the future...
#if SDL_VERSION_ATLEAST(2,0,14)
case SDL_CONTROLLER_TYPE_VIRTUAL: //don't really know... assume steaminput and thus steamdeck and thus xbox-like.
#endif
return 1;
case SDL_CONTROLLER_TYPE_UNKNOWN:
return 0;
case SDL_CONTROLLER_TYPE_XBOX360:
case SDL_CONTROLLER_TYPE_XBOXONE:
#if SDL_VERSION_ATLEAST(2,0,16)
case SDL_CONTROLLER_TYPE_GOOGLE_STADIA: //close enough
case SDL_CONTROLLER_TYPE_AMAZON_LUNA: //it'll do. I guess we're starting to see a standard here.
#endif
return 1; //a on bottom, b('cancel') to right
case SDL_CONTROLLER_TYPE_PS3:
case SDL_CONTROLLER_TYPE_PS4:
#if SDL_VERSION_ATLEAST(2,0,14)
case SDL_CONTROLLER_TYPE_PS5:
#endif
return 2; //weird indecipherable shapes.
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
return 3; //b on bottom, a('cancel') to right
}
}
}
#endif
return 0;
}
void INS_Rumble(int id, quint16_t amp_low, quint16_t amp_high, quint32_t duration)
{
#if SDL_VERSION_ATLEAST(2,0,9)
@ -459,7 +497,8 @@ void INS_SetLEDColor(int id, vec3_t color)
void INS_SetTriggerFX(int id, const void *data, size_t size)
{
#if SDL_VERSION_ATLEAST(2,0,15)
for (int i = 0; i < MAX_JOYSTICKS; i++)
int i;
for (i = 0; i < MAX_JOYSTICKS; i++)
{
if (sdljoy[i].qdevid == id)
{

View File

@ -34,8 +34,6 @@ void INS_Accumulate (void);
#define AVAIL_XINPUT
#ifdef AVAIL_XINPUT
//#define AVAIL_XINPUT_DLL "xinput9_1_0.dll"
#define AVAIL_XINPUT_DLL "xinput1_3.dll"
typedef struct _XINPUT_GAMEPAD {
WORD wButtons;
BYTE bLeftTrigger;
@ -55,7 +53,9 @@ typedef struct _XINPUT_VIBRATION {
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
DWORD (WINAPI *pXInputGetState)(DWORD dwUserIndex, XINPUT_STATE *pState);
DWORD (WINAPI *pXInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pState);
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid);
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid); //xi 1.3
DWORD (WINAPI *pXInputGetAudioDeviceIds)(DWORD dwUserIndex, LPWSTR pRenderDeviceId, UINT *pRenderCount, LPWSTR pCaptureDeviceId, UINT *pCaptureCount); //xi 1.4
enum
{
XINPUT_GAMEPAD_DPAD_UP = 0x0001,
@ -382,6 +382,51 @@ static const int mmjbuttons[32] =
K_JOY8
};
static HANDLE powercontext = INVALID_HANDLE_VALUE;
static qboolean powersaveblocked = false;
static HANDLE (WINAPI *pPowerCreateRequest) (REASON_CONTEXT *Context);
static BOOL (WINAPI *pPowerSetRequest) (HANDLE Context, POWER_REQUEST_TYPE RequestType);
static BOOL (WINAPI *pPowerClearRequest) (HANDLE Context, POWER_REQUEST_TYPE RequestType);
static void INS_ScreenSaver_Init(void)
{
dllfunction_t functable[] =
{
{(void*)&pPowerCreateRequest, "PowerCreateRequest"},
{(void*)&pPowerSetRequest, "PowerSetRequest"},
{(void*)&pPowerClearRequest, "PowerClearRequest"},
{NULL}
};
if (Sys_LoadLibrary("kernel32.dll", functable))
{ //we don't do microsoft's interpretation of localisation, so this is lame.
REASON_CONTEXT reason = {POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING};
reason.Reason.SimpleReasonString = L"Demo Playback";
powercontext = pPowerCreateRequest(&reason);
//FIXME: be prepared to regenerate the reason when our lang changes...
}
}
static void INS_ScreenSaver_UpdateBlock(qboolean block)
{
if (powercontext != INVALID_HANDLE_VALUE && block != powersaveblocked)
{
powersaveblocked = block;
if (block)
{
pPowerSetRequest(powercontext, PowerRequestDisplayRequired); //keep the screen on...
pPowerSetRequest(powercontext, PowerRequestSystemRequired); //and don't go to sleep mid-video, too...
}
else
{
pPowerClearRequest(powercontext, PowerRequestSystemRequired);
pPowerClearRequest(powercontext, PowerRequestDisplayRequired);
}
}
}
// forward-referenced functions
void INS_StartupJoystick (void);
void INS_JoyMove (void);
@ -706,6 +751,8 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
{
int grabmouse;
INS_ScreenSaver_UpdateBlock(cls.demoplayback && activeapp);
if (!activeapp)
grabmouse = false;
else if (fullscreen || in_simulatemultitouch.ival || in_windowed_mouse.value)
@ -1376,6 +1423,8 @@ void INS_Init (void)
Cvar_Register (&in_rawinput_keyboard, "Input Controls");
Cvar_Register (&in_rawinput_rdp, "Input Controls");
#endif
INS_ScreenSaver_Init();
}
/*
@ -1854,16 +1903,29 @@ static void IN_XInput_SetupAudio(struct wjoy_s *joy)
if (joy->devid == DEVID_UNSET)
return;
if (pXInputGetDSoundAudioDeviceGuids(joy->id, &gplayback, &gcapture) != ERROR_SUCCESS)
return; //probably not plugged in
if (pXInputGetDSoundAudioDeviceGuids)
{
if (pXInputGetDSoundAudioDeviceGuids(joy->id, &gplayback, &gcapture) != ERROR_SUCCESS)
return; //probably not plugged in
if (!memcmp(&gplayback, &GUID_NULL, sizeof(gplayback)))
return; //we have a controller, but no headset.
if (!memcmp(&gplayback, &GUID_NULL, sizeof(gplayback)))
return; //we have a controller, but no headset.
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses audio device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("DirectSound", audiodevicename, joy->devid);
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses directsound device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("DirectSound", audiodevicename, joy->devid);
}
else if (pXInputGetAudioDeviceIds)
{
UINT wccount = countof(mssuck);
if (!FAILED(pXInputGetAudioDeviceIds(joy->id, mssuck, &wccount, NULL,NULL/*we don't have separate mics, sadly, which also makes config awkward*/)))
{
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses xaudio2 device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("XAudio2", audiodevicename, joy->devid);
}
}
#endif
}
void INS_SetupControllerAudioDevices(qboolean enabled)
@ -1871,9 +1933,6 @@ void INS_SetupControllerAudioDevices(qboolean enabled)
#ifdef AVAIL_XINPUT
int i;
if (!pXInputGetDSoundAudioDeviceGuids)
return;
xinput_useaudio = enabled;
for (i = 0; i < joy_count; i++)
IN_XInput_SetupAudio(&wjoy[i]);
@ -1891,6 +1950,12 @@ void INS_StartupJoystick (void)
if (in_xinput.ival)
{
static dllhandle_t *xinput;
static const char *dllnames[] =
{
"xinput1_4.dll", //win8+ only. does xaudio2 instead of dsound.
"xinput1_3.dll", //dxsdk (vista+). does dsound stuff.
"xinput9_1_0.dll" //vista+. doesn't do audio stuff.
};
if (!xinput)
{
dllfunction_t funcs[] =
@ -1899,10 +1964,17 @@ void INS_StartupJoystick (void)
{(void**)&pXInputSetState, "XInputSetState"},
{NULL}
};
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs);
pXInputGetDSoundAudioDeviceGuids = NULL;
pXInputGetAudioDeviceIds = NULL;
for (id = 0; id < countof(dllnames); id++)
{
xinput = Sys_LoadLibrary(dllnames[id], funcs);
if (xinput)
break;
}
if (xinput)
pXInputGetDSoundAudioDeviceGuids = Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids");
pXInputGetDSoundAudioDeviceGuids = xinput?Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids"):NULL;
pXInputGetAudioDeviceIds = xinput?Sys_GetAddressForName(xinput, "XInputGetAudioDeviceIds"):NULL;
}
if (pXInputGetState)
{
@ -1925,7 +1997,7 @@ void INS_StartupJoystick (void)
Con_DPrintf("XInput is enabled (%i controllers found)\n", numdevs);
}
else
Con_Printf("XInput not installed\n");
Con_Printf("XInput (%s) not installed\n", dllnames[1]);
}
#endif

View File

@ -944,7 +944,7 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
if (*cl.players[player].ip)
Con_Footerf(con, true, "\n%s", cl.players[player].ip);
if (cl.playerview[0].spectator || cls.demoplayback==DPB_MVD||cls.demoplayback==DPB_EZTV)
if (cl.playerview[0].spectator || cls.demoplayback==DPB_MVD)
{
//we're spectating, or an mvd
Con_Footerf(con, true, " ^[Spectate\\player\\%i\\action\\spec^]", player);
@ -3079,7 +3079,7 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
//
// during demo playback, most keys bring up the main menu
//
if (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV && conkey && !Key_Dest_Has(~kdm_game))
if (cls.demoplayback && cls.demoplayback != DPB_MVD && conkey && !Key_Dest_Has(~kdm_game))
{
switch (key)
{ //these keys don't force the menu to appear while playing the demo reel
@ -3243,6 +3243,8 @@ defaultedbind:
if (key == K_TOUCH || (key == K_MOUSE1 && IN_Touch_MouseIsAbs(devid)))
{
const char *button = SCR_ShowPics_ClickCommand(mousecursor_x, mousecursor_y, key == K_TOUCH);
if (!button && cl.mouseplayerview && cl.mousenewtrackplayer>=0)
Cam_Lock(cl.mouseplayerview, cl.mousenewtrackplayer);
if (button)
{
dc = button;

File diff suppressed because it is too large Load Diff

View File

@ -480,7 +480,7 @@ static qboolean M_MouseMoved(emenu_t *menu)
if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height;
}
maxy -= vid.height-8;
maxy -= vid.height;
framescroll += option->frame.frac * maxy;
ypos -= option->frame.frac * maxy;
}
@ -682,16 +682,16 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
int maxy = option->frame.common.posy;
option->frame.common.width = 16;
option->frame.common.posx = vid.width - option->frame.common.width - xpos;
option->frame.common.height = vid.height-8-maxy - ypos;
option->frame.common.height = vid.height-maxy - ypos;
for (opt2 = option->common.next; opt2; opt2 = opt2->common.next)
{
if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height;
}
maxy -= vid.height-8;
maxy -= vid.height;
framescrollheight = maxy;
if (maxy < 0)
if (maxy <= 0)
{
option->frame.mousedown = false;
option->frame.frac = 0;
@ -892,7 +892,10 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
static void MenuDraw(emenu_t *menu)
{
if (!menu->dontexpand)
menu->xpos = ((vid.width - 320)>>1);
{
menu->width = min(vid.width,320);
menu->xpos = ((vid.width - menu->width)>>1);
}
if (menu->predraw)
menu->predraw(menu);
if (menu->selecteditem && menu->selecteditem->common.type == mt_text)
@ -1771,8 +1774,8 @@ void MC_CheckBox_Key(menucheck_t *option, emenu_t *menu, int key)
else
Cvar_SetValue(option->var, !option->var->value);
}
S_LocalSound ("misc/menu2.wav");
}
S_LocalSound ("misc/menu2.wav");
}
void MC_EditBox_Key(menuedit_t *edit, int key, unsigned int unicode)
@ -2401,10 +2404,15 @@ static int M_Main_AddExtraOptions(emenu_t *mainm, int y)
#endif
}
if (Cmd_Exists("menu_mods"))
{
MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Mods "), "menu_mods\n"); y += 20;
y += 20;
}
{MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Mods "), "menu_mods\n"); y += 20;}
if (Cmd_Exists("sys_openfile"))
{MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Open File "), "sys_openfile\n"); y += 20;}
#ifdef FTE_TARGET_WEB
if (Cmd_Exists("xr_toggle"))
{MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Toggle WebXR "), "xr_toggle\n"); y += 20;}
#endif
return y;
}
@ -2716,8 +2724,10 @@ void M_Menu_Main_f (void)
b = NULL;
if (!b && !m_preset_chosen.ival)
b = M_FindButton(mainm, "menu_options\n");
#ifdef PACKAGEMANAGER
if (!b && PM_AreSourcesNew(false))
b = M_FindButton(mainm, "menu_download\n");
#endif
if (b)
{
mainm->selecteditem = (menuoption_t*)b;

View File

@ -2958,7 +2958,7 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
else
Q_strncpyz(ctx->videonameextension, "tga", sizeof(ctx->videonameextension));
if (!FS_NativePath(va("%s", streamname), FS_GAMEONLY, ctx->videonameprefix, sizeof(ctx->videonameprefix)))
if (!FS_SystemPath(va("%s", streamname), FS_GAMEONLY, ctx->videonameprefix, sizeof(ctx->videonameprefix)))
{
Z_Free(ctx);
return NULL;
@ -2970,8 +2970,7 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
}
ctx->fsroot = FS_SYSTEM;
if (FS_NativePath(ctx->videonameprefix, ctx->fsroot, filename, sizeof(filename)))
FS_CreatePath(filename, ctx->fsroot);
FS_CreatePath(ctx->videonameprefix, ctx->fsroot);
ctx->audio = NULL;
if (*sndkhz)
@ -3012,7 +3011,7 @@ static void QDECL capture_raw_video (void *vctx, int frame, void *data, int stri
{
char base[MAX_QPATH];
Q_strncpyz(base, ctx->videonameprefix, sizeof(base));
if (FS_NativePath(base, ctx->fsroot, filename, sizeof(filename)))
if (FS_SystemPath(base, ctx->fsroot, filename, sizeof(filename)))
{
quint64_t diskfree = 0;
if (Sys_GetFreeDiskSpace(filename, &diskfree))
@ -3111,7 +3110,7 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width
COM_StripExtension(streamname, aviname, sizeof(aviname));
COM_DefaultExtension (aviname, ".avi", sizeof(aviname));
/*find the system location of that*/
FS_NativePath(aviname, FS_GAMEONLY, nativepath, sizeof(nativepath));
FS_SystemPath(aviname, FS_GAMEONLY, nativepath, sizeof(nativepath));
//wipe it.
f = fopen(nativepath, "rb");

View File

@ -407,7 +407,7 @@ qboolean MN_Init(void)
VFS_GETS,
VFS_PRINTF,
COM_EnumerateFiles,
FS_NativePath,
FS_SystemPath,
// Drawing stuff
MN_DrawSetClipArea,

View File

@ -1376,7 +1376,10 @@ void M_Menu_Preset_f (void)
emenu_t *menu;
int y;
menuoption_t *presetoption[7];
extern cvar_t r_nolerp, sv_nqplayerphysics, r_loadlits;
extern cvar_t r_nolerp, r_loadlits;
#ifdef HAVE_SERVER
extern cvar_t sv_nqplayerphysics;
#endif
#if defined(RTLIGHTS) && (defined(GLQUAKE) || defined(VKQUAKE))
extern cvar_t r_bloom, r_shadow_realtime_world_importlightentitiesfrommap;
#endif
@ -2608,7 +2611,9 @@ static const char *mapoptions_h2[] =
qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int key)
{
#ifdef HAVE_SERVER
singleplayerh2info_t *info = menu->data;
#endif
if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP)
return false;
@ -2642,21 +2647,20 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k
void M_Menu_Singleplayer_Cheats_Hexen2 (void)
{
static const char *skilloptions[] =
{
"Easy",
"Normal",
"Hard",
"Nightmare",
"None Set",
NULL
};
singleplayerh2info_t *info;
int cursorpositionY;
int currentmap;
#ifdef HAVE_SERVER
int currentmap;
int currentskill;
static const char *skilloptions[] =
{
"Easy",
"Normal",
"Hard",
"Nightmare",
"None Set",
NULL
};
extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill;
#endif
int y;
@ -3382,6 +3386,7 @@ typedef struct
char modelname[MAX_QPATH];
char skinname[MAX_QPATH];
char animname[MAX_QPATH];
char shaderfile[MAX_QPATH];
char *shadertext;
@ -3498,12 +3503,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
skinfile_t *skin;
texnums_t *texnums;
qboolean boneanimsonly;
model_t *animmodel = NULL;
if (R2D_Flush)
R2D_Flush();
memset(&pv, 0, sizeof(pv));
Alias_FlushCache(); //doesn't like us using stack...
CL_DecayLights ();
CL_ClearEntityLists();
V_ClearRefdef(&pv);
@ -3571,7 +3578,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
return; //panic!
if (ent.model->type == mod_alias) //should we even bother with this here?
{
if (*mods->animname)
animmodel = Mod_ForName(mods->animname, MLV_WARN);
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
}
else
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
VectorInverse(ent.axis[1]);
@ -3608,7 +3620,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime;
ent.framestate.g[FS_REG].endbone = 0x7fffffff;
if (*mods->skinname)
{
ent.customskin = Mod_RegisterSkinFile(mods->skinname); //explicit .skin file to use
if (!ent.customskin)
{
Con_Printf(CON_WARNING"Named skinfile not loaded\n");
*mods->skinname = 0; //don't spam.
}
}
else
{
ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum));
@ -3700,6 +3719,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
}
#endif
if (animmodel)// && Mod_GetNumBones(ent.model, false)==Mod_GetNumBones(animmodel, false))
{
int numbones = Mod_GetNumBones(ent.model, false);
galiasbone_t *boneinfo = Mod_GetBoneInfo(ent.model, &numbones);
float *bonematrix = alloca(numbones*sizeof(*bonematrix)*12);
ent.framestate.bonecount = Mod_GetBoneRelations(animmodel, 0, numbones, boneinfo, &ent.framestate, bonematrix);
ent.framestate.bonestate = bonematrix;
ent.framestate.skeltype = SKEL_RELATIVE;
}
else
animmodel = ent.model; //not using it. sorry. warn?
if (mods->mode == MV_NORMALS)
{
@ -3898,8 +3929,10 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
float duration = 0;
qboolean loop = false;
int act = -1;
if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act))
if (!Mod_FrameInfoForNum(animmodel, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act))
fname = "Unknown Sequence";
if (animmodel != ent.model)
fname = va("^[%s^] %s", animmodel->name, fname); //tag it properly if its from our animmodel
if (act != -1)
Draw_FunString(0, y, va("Frame%i[%i]: %s (%i poses, %f of %f secs, %s)", mods->framegroup, act, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped"));
else
@ -4032,17 +4065,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
char *data = NULL;
Draw_FunString(0, y, va("Events: "));
y+=8;
for (i = 0; Mod_GetModelEvent(ent.model, mods->framegroup, i, &timestamp, &code, &data); y+=8, i++)
for (i = 0; Mod_GetModelEvent(animmodel, mods->framegroup, i, &timestamp, &code, &data); y+=8, i++)
{
Draw_FunString(0, y, va("%i %f: %i %s", i, timestamp, code, data));
}
Draw_FunString(0, y, va("%f: <end of animation>", Mod_GetFrameDuration(ent.model, 0, mods->framegroup)));
Draw_FunString(0, y, va("%f: <end of animation>", Mod_GetFrameDuration(animmodel, 0, mods->framegroup)));
}
break;
case MV_SHADER:
{
if (!mods->shadertext)
{
char *cr;
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup, r_refdef.time, &texnums), mods->shaderfile, sizeof(mods->shaderfile));
if (!body)
{
@ -4052,9 +4086,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
if (*mods->shaderfile)
mods->shadertext = Z_StrDupf("\n\nPress space to view+edit the shader\n\n%s", body);
else
mods->shadertext = Z_StrDupf("{%s",body);
mods->shadertext = Z_StrDupf("{ %s",body);
while ((cr = strchr(mods->shadertext, '\r')))
*cr = ' ';
}
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+24, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
//fixme: draw the shader's textures.
}
@ -4333,6 +4370,12 @@ void M_Menu_ModelViewer_f(void)
menucustom_t *c;
emenu_t *menu;
if (!*Cmd_Argv(1))
{
Con_Printf("modelviewer <MODELNAME> [SKINFILE] [ANIMATIONFILE]\n");
return;
}
menu = M_CreateMenu(sizeof(*mv));
menu->menu.persist = true;
mv = menu->data;
@ -4345,6 +4388,7 @@ void M_Menu_ModelViewer_f(void)
mv->dist = 150;
Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname));
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;
@ -4406,42 +4450,57 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct emenu_s *m)
{
int i = c->dint;
struct modlist_s *mod = Mods_GetMod(i);
c->common.width = vid.width - x - 16;
if (!mod && !i)
{
float scale[] = {8,8};
R_DrawTextField(0, y, vid.width, vid.height - y,
m->height = vid.height;
if (y==0)
{ //just take the full screen.
y = m->ypos;
c->common.posy = 0;
c->common.height = m->height;
m->dontexpand = true;
m->xpos = x = 0;
m->width = vid.width;
}
else
{ //at least expand it.
c->common.height = m->height - c->common.posy;
}
//take the full width of the menu
x = m->xpos;
c->common.posx = 0;
c->common.width = m->width;
R_DrawTextField(x, y, c->common.width, c->common.height,
va(
"No games or mods known.\n"
#if defined(FTE_TARGET_WEB)
"Connection issue or bad server config.\n"
#ifdef FTE_TARGET_WEB
"Try providing packages/gamedirs via drag+drop.\n"
"%s", Cmd_Exists("sys_openfile")?"Or click to add a package\n":""
#else
#ifndef ANDROID
"You may need to use -basedir $PATHTOGAME on the commandline.\n"
#endif
"\nExpected data path:\n^a%s", com_gamepath
#endif
), CON_WHITEMASK, 0, font_console, scale);
), CON_WHITEMASK, 0, font_default, scale);
return;
}
c->common.height = 8;
c->common.width = vid.width - x - 16;
if (!mod)
return;
if (mod->manifest)
{
if (m->selecteditem == (menuoption_t*)c)
Draw_AltFunString(x, y, mod->manifest->formalname);
else
Draw_FunString(x, y, mod->manifest->formalname);
}
Draw_FunStringWidth(x, y, mod->manifest->formalname, c->common.width, 0, m->selecteditem == (menuoption_t*)c);
else
{
if (m->selecteditem == (menuoption_t*)c)
Draw_AltFunString(x, y, mod->gamedir);
else
Draw_FunString(x, y, mod->gamedir);
}
Draw_FunStringWidth(x, y, mod->gamedir, c->common.width, 0, m->selecteditem == (menuoption_t*)c);
}
static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode)
{
@ -4450,7 +4509,11 @@ static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, uns
{
qboolean wasgameless = !*FS_GetGamedir(false);
if (!Mods_GetMod(c->dint))
{
if (Cmd_Exists("sys_openfile"))
Cbuf_AddText("sys_openfile\n", RESTRICT_LOCAL);
return false;
}
M_RemoveMenu(m);
Cbuf_AddText(va("\nfs_changegame %u\n", gameidx+1), RESTRICT_LOCAL);
@ -4471,6 +4534,7 @@ void M_Menu_Mods_f (void)
menucustom_t *c;
emenu_t *menu;
size_t i;
int y;
//FIXME: sort by mtime?
@ -4479,20 +4543,23 @@ void M_Menu_Mods_f (void)
{
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
y = 32;
}
else
y = 0;
MC_AddFrameStart(menu, 32);
MC_AddFrameStart(menu, y);
for (i = 0; i<1 || Mods_GetMod(i); i++)
{
struct modlist_s *mod = Mods_GetMod(i);
c = MC_AddCustom(menu, 64, 32+i*8, menu->data, i, (mod&&mod->manifest)?mod->manifest->basedir:NULL);
c = MC_AddCustom(menu, 64, y+i*8, menu->data, i, (mod&&mod->manifest)?mod->manifest->basedir:NULL);
// if (!menu->selecteditem)
// menu->selecteditem = (menuoption_t*)c;
c->common.height = 8;
c->draw = Mods_Draw;
c->key = Mods_Key;
}
MC_AddFrameEnd(menu, 32);
MC_AddFrameEnd(menu, y);
}
#if 0
@ -4532,7 +4599,7 @@ static qboolean Installer_Go(menuoption_t *opt, menu_t *menu, int key)
#ifdef _WIN32
GetModuleFileNameW(NULL, exepath, sizeof(exepath));
FS_NativePath(va("%s.exe", fs_manifest->installation), FS_ROOT, newexepath, sizeof(newexepath));
FS_SystemPath(va("%s.exe", fs_manifest->installation), FS_ROOT, newexepath, sizeof(newexepath));
CopyFileW(exepath, newexepath, FALSE);
// SetHookState(false);

View File

@ -20,7 +20,7 @@ void M_Script_Option (emenu_t *menu, char *optionvalue, qboolean isexplicit)
Cbuf_AddText("wait\n", execlevel);
if (!*scriptname)
if (!scriptname || !*scriptname)
{
if (isexplicit)
Cbuf_AddText(va("%s\n", optionvalue), execlevel);

View File

@ -319,11 +319,10 @@ void M_Menu_Load_f (void)
void M_Menu_SinglePlayer_f (void)
{
emenu_t *menu;
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
menubutton_t *b;
mpic_t *p;
static menuresel_t resel;
#endif
#if MAX_SPLITS > 1
static const char *splitopts[] =
@ -344,15 +343,6 @@ void M_Menu_SinglePlayer_f (void)
};
#endif
#ifdef CLIENTONLY
menu = M_CreateMenu(0);
MC_AddWhiteText(menu, 84, 0, 12*8, "This build is unable", false);
MC_AddWhiteText(menu, 84, 0, 13*8, "to start a local game", false);
MC_AddBox (menu, 60, 11*8, 25*8, 4*8);
#else
switch(M_GameType())
{
#ifdef Q2CLIENT
@ -580,6 +570,14 @@ void M_Menu_SinglePlayer_f (void)
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
}
#else
menu = M_CreateMenu(0);
MC_AddWhiteText(menu, 84, 0, 12*8, "This build is unable", false);
MC_AddWhiteText(menu, 84, 0, 13*8, "to start a local game", false);
MC_AddBox (menu, 60, 11*8, 25*8, 4*8);
#endif
}
@ -626,9 +624,9 @@ static void M_DemoDraw(int x, int y, menucustom_t *control, emenu_t *menu)
demoitem_t *item, *lostit;
int ty;
char syspath[MAX_OSPATH];
if (FS_NativePath(info->fs->path, (info->fs->fsroot==FS_GAME)?FS_GAMEONLY:info->fs->fsroot, syspath, sizeof(syspath)))
Draw_FunString(x, y-16, syspath);
char displaypath[MAX_OSPATH];
if (FS_DisplayPath(info->fs->path, (info->fs->fsroot==FS_GAME)?FS_GAMEONLY:info->fs->fsroot, displaypath, sizeof(displaypath)))
Draw_FunString(x, y-16, displaypath);
ty = vid.height-24;
item = info->selected;
@ -1021,7 +1019,7 @@ static void ShowDemoMenu (emenu_t *menu, const char *path)
{
if (!strcmp(path, "../"))
{
FS_NativePath("", FS_ROOT, info->fs->path, sizeof(info->fs->path));
FS_SystemPath("", FS_ROOT, info->fs->path, sizeof(info->fs->path));
Q_strncatz(info->fs->path, "../", sizeof(info->fs->path));
info->fs->fsroot = FS_SYSTEM;
while((s = strchr(info->fs->path, '\\')))

View File

@ -21,6 +21,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "winquake.h"
#include "shader.h"
#include "cl_master.h"
#ifdef FTE_TARGET_WEB
#include <emscripten/emscripten.h>
#endif
menu_t *topmenu;
menu_t *promptmenu;
@ -1302,10 +1305,8 @@ void M_Menu_Quit_f (void)
switch(mode)
{
case 0:
#ifndef FTE_TARGET_WEB
CL_Disconnect (NULL);
Sys_Quit ();
#endif
break;
case 2:
Menu_Prompt (M_Menu_DoQuitSave, NULL, localtext("You have unsaved settings\nWould you like to\nsave them now?"), "Yes", "No", "Cancel", true);

View File

@ -131,7 +131,12 @@ typedef enum
PROMPT_NO = 1,
PROMPT_CANCEL = -1,
} promptbutton_t;
#ifdef HAVE_CLIENT
void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel, qboolean highpri);
#define Menu_PromptOrPrint(messages,optioncancel,highpri) Menu_Prompt(NULL, NULL, messages, NULL, NULL, optioncancel, highpri)
#else
#define Menu_PromptOrPrint(messages,optioncancel,highpri) Con_Printf("%s", messages)
#endif
#ifndef NOBUILTINMENUS

View File

@ -209,7 +209,7 @@ extern int Mod_TagNumForName (struct model_s *model, const char *name, int f
void Mod_AddSingleSurface(struct entity_s *ent, int surfaceidx, shader_t *shader, int mode);
int Mod_GetNumBones(struct model_s *model, qboolean allowtags);
int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, framestate_t *fstate, float *result);
int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, const struct galiasbone_s *boneinfo, const framestate_t *fstate, float *result);
int Mod_GetBoneParent(struct model_s *model, int bonenum);
struct galiasbone_s *Mod_GetBoneInfo(struct model_s *model, int *numbones);
const char *Mod_GetBoneName(struct model_s *model, int bonenum);
@ -222,11 +222,6 @@ void Draw_FunStringWidthFont(struct font_s *font, float x, float y, const void *
extern int r_regsequence;
#ifdef SERVERONLY
#define Mod_Q1LeafPVS Mod_LeafPVS
// qbyte *Mod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
#endif
enum
{
TEX_NOTLOADED,
@ -314,13 +309,13 @@ struct pendingtextureinfo
uploadfmt_t encoding; //PTI_* formats
void *extrafree; //avoids some memcpys
int mipcount;
unsigned int mipcount;
struct
{
void *data;
size_t datasize; //ceil(width/blockwidth)*ceil(height/blockheight)*ceil(depth/blockdepth)*blocksize - except that blockdepth is always considered 1 for now.
int width;
int height;
unsigned int width;
unsigned int height;
int depth;
qboolean needfree;
} mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture...

View File

@ -53,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
#endif
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP, ALIAS_GROUP_SWAPPED=16777216 } aliasframetype_t;
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP, ALIAS_GROUP_SWAPPED=0x01000000 } aliasframetype_t;
typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;

View File

@ -169,10 +169,10 @@ static net_masterlist_t net_masterlist[] = {
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "master.teamdamage.com:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "master.teamdamage.com"},
//Total conversions will need to define their own in defaults.cfg or whatever.
{MP_DPMASTER, CVARFC("net_masterextra1", "master.frag-net.com:27950 198.58.111.37:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Eukara
// {MP_DPMASTER, CVARFC("net_masterextra1", ""/*"ghdigital.com:27950 207.55.114.154:27950"*/, CVAR_NOSAVE, Net_Masterlist_Callback)}, //(was 69.59.212.88) admin: LordHavoc
{MP_DPMASTER, CVARFC("net_masterextra2", "dpmaster.deathmask.net:27950 107.161.23.68:27950 [2604:180::4ac:98c1]:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Willis
{MP_DPMASTER, CVARFC("net_masterextra3", "dpmaster.tchr.no:27950 92.62.40.73:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: tChr
{MP_DPMASTER, CVARFC("net_masterextra1", "master.frag-net.com:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Eukara
// {MP_DPMASTER, CVARFC("net_masterextra1", ""/*"ghdigital.com:27950"*/, CVAR_NOSAVE, Net_Masterlist_Callback)}, //(was 69.59.212.88) admin: LordHavoc
{MP_DPMASTER, CVARFC("net_masterextra2", "dpmaster.deathmask.net:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Willis
{MP_DPMASTER, CVARFC("net_masterextra3", "dpmaster.tchr.no:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: tChr
#else
{MP_DPMASTER, CVARFC("net_masterextra1", "", CVAR_NOSAVE, Net_Masterlist_Callback)},
{MP_DPMASTER, CVARFC("net_masterextra2", "", CVAR_NOSAVE, Net_Masterlist_Callback)},
@ -376,8 +376,8 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{
COM_Parse(master->cv.string);
Con_TPrintf (S_COLOR_GRAY"Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
master->announced = true;
}
master->announced = true;
}
break;
case NETERR_NOROUTE:
@ -387,8 +387,8 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{
COM_Parse(master->cv.string);
Con_TPrintf (CON_WARNING"No route for heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
master->announced = true;
}
master->announced = true;
}
break;
default:
@ -401,8 +401,8 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{
COM_Parse(master->cv.string);
Con_TPrintf (CON_ERROR"Failed to send heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
master->announced = true;
}
master->announced = true;
}
break;
}
@ -663,6 +663,17 @@ static void SV_Master_Add(int type, char *stringadr)
{
int i;
//don't do dupes...
for (i = 0; net_masterlist[i].cv.name; i++)
{
if (net_masterlist[i].protocol == type)
if (!strcmp(net_masterlist[i].cv.string, stringadr))
{
svs.last_heartbeat = -99999;
return;
}
}
for (i = 0; net_masterlist[i].cv.name; i++)
{
if (net_masterlist[i].protocol != type)
@ -680,6 +691,7 @@ static void SV_Master_Add(int type, char *stringadr)
}
Cvar_Set(&net_masterlist[i].cv, stringadr);
Con_Printf(CON_WARNING"setting %s to \"%s\"\n", net_masterlist[i].cv.name, stringadr);
svs.last_heartbeat = -99999;
}
@ -693,6 +705,8 @@ static void SV_Master_ClearType(int type)
{
if (net_masterlist[i].cv.flags & CVAR_NOSAVE)
continue; //ignore our extras
if (*net_masterlist[i].cv.string)
Con_Printf(CON_WARNING"clearing %s (was \"%s\")\n", net_masterlist[i].cv.name, net_masterlist[i].cv.string);
Cvar_Set(&net_masterlist[i].cv, "");
}
}
@ -733,7 +747,8 @@ static void SV_SetMaster_f (void)
return;
}
Cvar_Set(&sv_public, "1"); //go public.
if (sv_public.ival < 1)
Con_Printf(CON_WARNING"%s used on private server (sv_public is \"%s\")\n", Cmd_Argv(0), sv_public.string);
if (!strcmp(Cmd_Argv(1), "default"))
{
for (i = 0; net_masterlist[i].cv.name; i++)
@ -741,8 +756,12 @@ static void SV_SetMaster_f (void)
return;
}
SV_Master_ClearType(MP_QUAKEWORLD);
for (i=1 ; i<Cmd_Argc() ; i++)
i = 1;
if (!strcmp(Cmd_Argv(1), "add"))
i++;
else
SV_Master_ClearType(MP_QUAKEWORLD);
for ( ; i<Cmd_Argc() ; i++)
{
SV_Master_Add(MP_QUAKEWORLD, Cmd_Argv(i));
}
@ -2738,7 +2757,7 @@ static void MasterInfo_ProcessHTTP(struct dl_download *dl)
infostring = NULL;
if (!strncmp(s, "ice:///", 7) || !strncmp(s, "ices:///", 8) || !strncmp(s, "rtc:///", 7) || !strncmp(s, "rtcs:///", 8))
{
{ //implicitly using the ip:port of the responder, instead of that being specified (giving a consistent route to it instead of it having to guess what hostname we used).
brokerid = s+((s[4]==':')?7:6);
adr = brokeradr;
if (!*brokerid)
@ -2749,6 +2768,13 @@ static void MasterInfo_ProcessHTTP(struct dl_download *dl)
brokerid = s;
adr = brokeradr;
}
#ifndef HAVE_PACKET
else if ((*s=='[' || (*s >= '0' && *s <= '9')) && infostring)
{ //if we don't have support for udp packets here, convert any raw address to an rtc:///udp/ADDRESS one instead, via this master's brokering services... hopefully.
brokerid = va("/udp/%s", s);
adr = brokeradr;
}
#endif
else
{
if (!NET_StringToAdr2(s, 80, &adr, 1, &brokerid))
@ -3752,6 +3778,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
firstserver = last;
}
#else
void Master_QueryServer(serverinfo_t *server){}
qboolean CL_QueryServers(void)
{
master_t *mast;

View File

@ -2651,7 +2651,7 @@ static void P_ExportAllEffects_f(void)
outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
if (!outf)
{
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect));
FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_TPrintf("Unable to open file %s\n", effect);
return;
}
@ -2679,7 +2679,7 @@ static void P_ExportAllEffects_f(void)
}
VFS_CLOSE(outf);
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect));
FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_Printf("Written %s\n", effect);
}
#endif
@ -3398,7 +3398,7 @@ static void P_ConvertEffectInfo_f(void)
outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
if (!outf)
{
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect));
FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_TPrintf("Unable to open file %s\n", effect);
return;
}
@ -3435,7 +3435,7 @@ static void P_ConvertEffectInfo_f(void)
}
VFS_CLOSE(outf);
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect));
FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_Printf("Written %s\n", effect);
}
#endif
@ -3534,10 +3534,10 @@ static void PScript_Shutdown (void)
Cmd_RemoveCommand("r_exportbuiltinparticles");
Cmd_RemoveCommand("r_importeffectinfo");
#if _DEBUG
//#if _DEBUG
Cmd_RemoveCommand("r_partinfo");
Cmd_RemoveCommand("r_beaminfo");
#endif
//#endif
pe_default = P_INVALID;
pe_size2 = P_INVALID;
@ -3809,7 +3809,7 @@ static void QDECL R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue)
if (failure)
P_LoadParticleSet("high", true, true);
if (cls.state)
if (cls.state && cl.model_name[1])
{
//per-map configs. because we can.
memcpy(token, "map_", 4);

View File

@ -542,7 +542,6 @@ void QCBUILTIN PF_cl_playingdemo (pubprogfuncs_t *prinst, struct globalvars_s *p
G_FLOAT(OFS_RETURN) = 0;
break;
case DPB_MVD:
case DPB_EZTV:
G_FLOAT(OFS_RETURN) = 2;
break;
default:

View File

@ -221,15 +221,15 @@ static void CSQC_FindGlobals(qboolean nofuncs)
#undef globalstring
#undef globalfunction
#define ensurefloat(name) if (!csqcg.name) csqcg.name = &junk._float;
#define ensureint(name) if (!csqcg.name) csqcg.name = &junk._int;
#define ensurevector(name) if (!csqcg.name) csqcg.name = junk._vector;
#define ensureentity(name) if (!csqcg.name) csqcg.name = &junk.edict;
#define ensurefloat(name) do{if (!csqcg.name) csqcg.name = &junk._float;}while(0)
#define ensureint(name) do{if (!csqcg.name) csqcg.name = &junk._int; }while(0)
#define ensurevector(name) do{if (!csqcg.name) csqcg.name = junk._vector;}while(0)
#define ensureentity(name) do{if (!csqcg.name) csqcg.name = &junk.edict; }while(0)
#define ensureprivfloat(name) if (!csqcg.name) {static pvec_t f; csqcg.name = &f;}
#define ensureprivint(name) if (!csqcg.name) {static pint_t i; csqcg.name = &i;}
#define ensureprivvector(name) if (!csqcg.name) {static pvec3_t v; csqcg.name = v;}
#define ensurepriventity(name) if (!csqcg.name) {static pint_t e; csqcg.name = &e;}
#define ensureprivfloat(name) do{if (!csqcg.name) {static pvec_t f; csqcg.name = &f;}}while(0)
#define ensureprivint(name) do{if (!csqcg.name) {static pint_t i; csqcg.name = &i;}}while(0)
#define ensureprivvector(name) do{if (!csqcg.name) {static pvec3_t v; csqcg.name = v;}}while(0)
#define ensurepriventity(name) do{if (!csqcg.name) {static pint_t e; csqcg.name = &e;}}while(0)
if (csqc_nogameaccess)
{
@ -698,6 +698,8 @@ static int CS_FindModel(const char *name, int *free)
}
for (i = 1; i < MAX_PRECACHE_MODELS; i++)
{
if (!cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], name))
return i;
}
@ -2733,44 +2735,47 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
else
scissored = false;
R_DrawNameTags();
#ifdef RTLIGHTS
R_EditLights_DrawInfo();
#endif
if (r_refdef.drawsbar)
if (!vrui.enabled) //when we're using the vrui, this stuff needs to be part of the scene, drawn seperately for each eye
{
#ifdef PLUGINS
Plug_SBar (r_refdef.playerview);
#else
if (Sbar_ShouldDraw(r_refdef.playerview))
{
SCR_TileClear (sb_lines);
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard (r_refdef.playerview);
}
else
SCR_TileClear (0);
R_DrawNameTags();
#ifdef RTLIGHTS
R_EditLights_DrawInfo();
#endif
if (!Key_Dest_Has(kdm_menu|kdm_cwindows))
if (r_refdef.drawsbar)
{
if (cl.intermissionmode == IM_NQFINALE || cl.intermissionmode == IM_NQCUTSCENE || cl.intermissionmode == IM_H2FINALE)
#ifdef PLUGINS
Plug_SBar (r_refdef.playerview);
#else
if (Sbar_ShouldDraw(r_refdef.playerview))
{
SCR_CheckDrawCenterString ();
SCR_TileClear (sb_lines);
Sbar_Draw (r_refdef.playerview);
Sbar_DrawScoreboard (r_refdef.playerview);
}
else if (cl.intermissionmode != IM_NONE)
else
SCR_TileClear (0);
#endif
if (!Key_Dest_Has(kdm_menu|kdm_cwindows))
{
Sbar_IntermissionOverlay (r_refdef.playerview);
if (cl.intermissionmode == IM_NQFINALE || cl.intermissionmode == IM_NQCUTSCENE || cl.intermissionmode == IM_H2FINALE)
{
SCR_CheckDrawCenterString ();
}
else if (cl.intermissionmode != IM_NONE)
{
Sbar_IntermissionOverlay (r_refdef.playerview);
}
}
SCR_ShowPics_Draw();
}
SCR_ShowPics_Draw();
if (r_refdef.drawcrosshair)
R2D_DrawCrosshair();
}
if (r_refdef.drawcrosshair)
R2D_DrawCrosshair();
if (scissored)
{
if (R2D_Flush)
@ -3100,7 +3105,7 @@ static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int mode
}
else
{
if (modelindex >= MAX_PRECACHE_MODELS)
if (modelindex >= MAX_PRECACHE_MODELS || !cl.model_name[modelindex])
return NULL;
prinst->SetStringField(prinst, (void*)ent, &ent->v->model, cl.model_name[modelindex], true);
model = cl.model_precache[modelindex];
@ -3180,7 +3185,7 @@ static int PF_cs_PrecacheModel_Internal(pubprogfuncs_t *prinst, const char *mode
for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded..
{
if (!*cl.model_name[i])
if (!cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], modelname))
{
@ -3231,7 +3236,7 @@ static void QCBUILTIN PF_cs_getsoundindex (pubprogfuncs_t *prinst, struct global
//look for the server's names first...
for (i = 1; i < MAX_PRECACHE_SOUNDS; i++)
{
if (!*cl.sound_name[i])
if (!cl.sound_name[i])
break;
if (!strcmp(cl.sound_name[i], s))
{
@ -3265,7 +3270,7 @@ static void QCBUILTIN PF_cs_ModelnameForIndex(pubprogfuncs_t *prinst, struct glo
if (modelindex < 0 && (-modelindex) < MAX_CSMODELS)
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_csqcname[-modelindex]);
else if (modelindex >= 0 && modelindex < MAX_PRECACHE_MODELS)
else if (modelindex >= 0 && modelindex < MAX_PRECACHE_MODELS && cl.model_name[modelindex])
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_name[modelindex]);
else
G_INT(OFS_RETURN) = 0;
@ -3275,7 +3280,7 @@ static void QCBUILTIN PF_cs_SoundnameForIndex(pubprogfuncs_t *prinst, struct glo
int soundindex = G_FLOAT(OFS_PARM0);
//FIXME: no private indexes. still useful for sending sound names from the ssqc via indexes.
if (soundindex >= 0 && soundindex < MAX_PRECACHE_SOUNDS)
if (soundindex >= 0 && soundindex < MAX_PRECACHE_SOUNDS && cl.sound_name[soundindex])
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.sound_name[soundindex]);
else
G_INT(OFS_RETURN) = 0;
@ -5616,6 +5621,8 @@ static void QCBUILTIN PF_cs_registercommand (pubprogfuncs_t *prinst, struct glob
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL;
if (desc && !*desc)
desc = NULL;
if (!Cmd_Exists(str))
Cmd_AddCommandD(str, CS_ConsoleCommand_f, desc);
}
@ -6026,7 +6033,7 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s
{
for (i = 1; i < MAX_PRECACHE_MODELS; i++)
{
if (!*cl.model_name[i])
if (!cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], mname))
{
@ -6648,13 +6655,13 @@ static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvar
if (idx < 0)
{
mod = cl.model_csqcprecache[-idx];
if (!cl.model_csqcprecache[-idx] && doload)
if (!cl.model_csqcprecache[-idx] && doload && cl.model_csqcname[-idx])
mod = cl.model_csqcprecache[-idx] = Mod_ForName(Mod_FixName(cl.model_csqcname[-idx], cl.model_name[1]), MLV_WARN);
}
else if (idx > 0)
{
mod = cl.model_precache[idx];
if (!cl.model_precache[idx] && doload)
if (!cl.model_precache[idx] && doload && cl.model_name[idx])
mod = cl.model_precache[idx] = Mod_ForName(Mod_FixName(cl.model_name[idx], cl.model_name[1]), MLV_WARN);
}
else
@ -7119,8 +7126,8 @@ static struct {
{"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0},
{"getlocationname", PF_getlocationname, 0},
{"getlocationname", PF_getlocationname, 0},
{"crossproduct", PF_crossproduct, 0},
{"pushmove", PF_pushmove, 0},
#ifdef TERRAIN
@ -7312,6 +7319,7 @@ static struct {
{"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386},
{"memfill8", PF_memfill8, 387},
{"memgetval", PF_memgetval, 388},
@ -7854,6 +7862,24 @@ static void QDECL CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate
cs_getframestate(in, in->xv->renderflags, out);
}
static qboolean CSQC_GenerateMaterial(struct shaderparsestate_s *ps, const char *materialname, void (*LoadMaterialString)(struct shaderparsestate_s *ps, const char *script))
{
COM_AssertMainThread("CSQC_GenerateMaterial");
if (csqcg.CSQC_GenerateMaterial)
{
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, materialname));
PR_ExecuteProgram(csqcprogs, csqcg.CSQC_GenerateMaterial);
if (G_INT(OFS_RETURN))
{ //we got the script, now pass it to our material system to parse it.
LoadMaterialString(ps, PR_GetStringOfs(csqcprogs, OFS_RETURN));
return true;
}
}
return false;
}
static plugmaterialloaderfuncs_t csqcmaterialloader = {"csqc", CSQC_GenerateMaterial};
void CSQC_Shutdown(void)
{
int i;
@ -7862,6 +7888,8 @@ void CSQC_Shutdown(void)
if (csqcg.CSQC_Shutdown)
PR_ExecuteProgram(csqcprogs, csqcg.CSQC_Shutdown);
Material_RegisterLoader(&csqc_world, NULL);
key_dest_absolutemouse &= ~kdm_game;
CSQC_ForgetThreads();
PR_ReleaseFonts(kdm_game);
@ -7949,11 +7977,11 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check
if (!file)
{
const char *progsname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname");
const char *progsname = cls.state?InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname"):"csprogs.dat";
flocation_t loc={0};
vfsfile_t *f;
qboolean found = false;
if (!found && *progsname && cls.state)
if (!found && *progsname)
found = FS_FLocateFile(progsname, FSLF_IGNOREPURE, &loc);
if (!found && strcmp(progsname, "csprogs.dat"))
{
@ -7972,7 +8000,11 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check
if (checksum && !csprogs_promiscuous)
{
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
{ //its not a match... maybe we can get a better one from the pure paths instead...
file = COM_LoadTempFile (progsname, 0, sz);
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL;
}
//we write the csprogs into our archive if it was loaded from outside of there.
//this is to ensure that demos will play on the same machine later on...
@ -8429,6 +8461,9 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value);
if (csqcg.CSQC_GenerateMaterial)
Material_RegisterLoader(&csqc_world, &csqcmaterialloader);
//world edict becomes readonly
worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0);
worldent->ereftype = ER_ENTITY;
@ -8455,7 +8490,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
char *s = InfoBuf_ValueForKey(&cl.serverinfo, "map");
if (!*s)
s = cl.model_name[1];
if (!*s)
if (!s || !*s)
s = "unknown";
*str = PR_NewString(csqcprogs, s);
}

View File

@ -1351,6 +1351,7 @@ static struct
{
evalc_t chain;
evalc_t model;
evalc_t modelindex;
evalc_t mins;
evalc_t maxs;
evalc_t origin;
@ -1364,6 +1365,7 @@ static struct
evalc_t frame2time;
evalc_t renderflags;
evalc_t skinobject;
evalc_t skelobject;
evalc_t colourmod;
evalc_t alpha;
} menuc_eval;
@ -2034,6 +2036,23 @@ static void QCBUILTIN PF_m_precache_model(pubprogfuncs_t *prinst, struct globalv
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
Mod_ForName(modelname, MLV_WARN);
}
static model_t *QDECL MP_GetCModel(struct world_s *w, int modelindex)
{
extern int mod_numknown;
modelindex--;
if (modelindex < 0 || modelindex >= mod_numknown)
return NULL;
return &mod_known[modelindex];
}
static void QCBUILTIN PF_m_getmodelindex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
model_t *m = Mod_ForName(modelname, MLV_WARN);
if (m)
G_FLOAT(OFS_RETURN) = (m-mod_known)+1;
else
G_FLOAT(OFS_RETURN) = 0;
}
static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
@ -2041,6 +2060,7 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)ent, "model", ev_string, &menuc_eval.model);
eval_t *minsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "mins", ev_vector, &menuc_eval.mins);
eval_t *maxsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "maxs", ev_vector, &menuc_eval.maxs);
eval_t *modelidxval = prinst->GetEdictFieldValue(prinst, (void*)ent, "modelindex", ev_float, &menuc_eval.modelindex);
model_t *mod = Mod_ForName(modelname, MLV_WARN);
if (modelval)
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
@ -2050,6 +2070,8 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
if (mod)
while(mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (modelidxval)
modelidxval->_float = mod?(mod-mod_known)+1:0;
if (mod && minsval)
VectorCopy(mod->mins, minsval->_vector);
@ -2110,6 +2132,44 @@ static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_
V_CalcRefdef(&menuview); //set up the defaults
r_refdef.flags |= RDF_NOWORLDMODEL;
}
static void QDECL MP_Read_FrameState(pubprogfuncs_t *prinst, wedict_t *ent, framestate_t *fstate)
{
eval_t *frame1val = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame", ev_float, &menuc_eval.frame1);
eval_t *frame2val = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame2", ev_float, &menuc_eval.frame2);
eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)ent, "lerpfrac", ev_float, &menuc_eval.lerpfrac);
eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame1time", ev_float, &menuc_eval.frame1time);
eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame2time", ev_float, &menuc_eval.frame2time);
eval_t *skelobjectval = prinst->GetEdictFieldValue(prinst, (void*)ent, "skeletonindex", ev_float, &menuc_eval.skelobject);
fstate->g[FST_BASE].endbone = 0;
fstate->g[FS_REG].endbone = 0x7fffffff;
fstate->g[FS_REG].frame[0] = frame1val?frame1val->_float:0;
fstate->g[FS_REG].frame[1] = frame2val?frame2val->_float:0;
fstate->g[FS_REG].lerpweight[1] = lerpfracval?lerpfracval->_float:0;
fstate->g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0;
fstate->g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0;
#if FRAME_BLENDS >= 4
fstate->g[FS_REG].frame[2] = fstate->g[FS_REG].frame[0];
fstate->g[FS_REG].lerpweight[2] = 0;
fstate->g[FS_REG].frame[3] = fstate->g[FS_REG].frame[0];
fstate->g[FS_REG].lerpweight[3] = 0;
fstate->g[FS_REG].lerpweight[0] = 1-(fstate->g[FS_REG].lerpweight[1]+fstate->g[FS_REG].lerpweight[2]+fstate->g[FS_REG].lerpweight[3]);
#else
fstate->g[FS_REG].lerpweight[0] = 1-fstate->g[FS_REG].lerpweight[1];
#endif
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
fstate->bonecount = 0;
fstate->bonestate = NULL;
if (skelobjectval && skelobjectval->_float)
skel_lookup(&menu_world, skelobjectval->_float, fstate);
#endif
}
static void QDECL MP_Get_FrameState(struct world_s *w, wedict_t *ent, framestate_t *fstate)
{
MP_Read_FrameState(w->progs, ent, fstate);
}
static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, entity_t *out)
{
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)in, "model", ev_string, &menuc_eval.model);
@ -2121,6 +2181,7 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)in, "lerpfrac", ev_float, &menuc_eval.lerpfrac);
eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame1time", ev_float, &menuc_eval.frame1time);
eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame2time", ev_float, &menuc_eval.frame2time);
eval_t *skelobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skeletonindex", ev_float, &menuc_eval.skelobject);
eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap);
eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags);
eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject);
@ -2149,6 +2210,13 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
out->framestate.g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0;
out->framestate.g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0;
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
out->framestate.bonecount = 0;
out->framestate.bonestate = NULL;
if (skelobjectval && skelobjectval->_float)
skel_lookup(&menu_world, skelobjectval->_float, &out->framestate);
#endif
out->customskin = skinobjectval?skinobjectval->_float:0;
//FIXME: colourmap
@ -2285,6 +2353,8 @@ static void QCBUILTIN PF_menu_registercommand (pubprogfuncs_t *prinst, struct gl
{
const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL;
if (desc && !*desc)
desc = NULL;
if (!Cmd_Exists(str))
Cmd_AddCommandD(str, MP_ConsoleCommand_f, desc);
}
@ -2466,6 +2536,8 @@ static struct {
{"precache_model", PF_m_precache_model, 91},
{"setorigin", PF_m_setorigin, 92},
//gap
{"getmodelindex", PF_m_getmodelindex, 200},
//gap
{"abort", PF_Abort, 211},
//gap
{"strstrofs", PF_strstrofs, 221},
@ -2484,6 +2556,29 @@ static struct {
{"shaderforname", PF_shaderforname, 238},
{"sendpacket", PF_cl_SendPacket, 242},
//gap
{"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)
{"skel_build_ptr", PF_skel_build_ptr, 0},//float(float skel, int numblends, __variant *blends, int blendsize) skel_build_ptr = #0;
{"skel_get_numbones", PF_skel_get_numbones, 265},//float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_get_bonename", PF_skel_get_bonename, 266},//string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) (returns tempstring)
{"skel_get_boneparent", PF_skel_get_boneparent, 267},//float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_find_bone", PF_skel_find_bone, 268},//float(float skel, string tagname) skel_get_boneidx = #268; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_get_bonerel", PF_skel_get_bonerel, 269},//vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
{"skel_get_boneabs", PF_skel_get_boneabs, 270},//vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
{"skel_set_bone", PF_skel_set_bone, 271},//void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_premul_bone", PF_skel_premul_bone, 272},//void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_premul_bones", PF_skel_premul_bones, 273},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_postmul_bone", PF_skel_postmul_bone, 0},//void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
// {"skel_postmul_bones", PF_skel_postmul_bones, 0},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_copybones", PF_skel_copybones, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 276},//float(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 277},//float(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS)
{"frameforaction", PF_frameforaction, 0},//float(float modidx, int actionid) frameforaction = #0
{"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0},
//gap
{"hash_createtab", PF_hash_createtab, 287},
{"hash_destroytab", PF_hash_destroytab, 288},
{"hash_add", PF_hash_add, 289},
@ -2555,6 +2650,7 @@ static struct {
//gap
{"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386},
{"memfill8", PF_memfill8, 387},
{"memgetval", PF_memgetval, 388},
@ -3163,8 +3259,12 @@ qboolean MP_Init (void)
menutime = Sys_DoubleTime();
if (!menu_world.progs)
{
vec3_t fwd,rht,up;
int mprogs;
Con_DPrintf("Initializing menu.dat\n");
menu_world.Get_CModel = MP_GetCModel;
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);
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat");
@ -3193,6 +3293,10 @@ qboolean MP_Init (void)
*menu_world.g.time = Sys_DoubleTime();
menu_world.g.frametime = (float*)PR_FindGlobal(menu_world.progs, "frametime", 0, NULL);
menu_world.g.v_forward = (float*)PR_FindGlobal(menu_world.progs, "v_forward", 0, NULL); if (!menu_world.g.v_forward) menu_world.g.v_forward = fwd;
menu_world.g.v_right = (float*)PR_FindGlobal(menu_world.progs, "v_right", 0, NULL); if (!menu_world.g.v_right) menu_world.g.v_right = rht;
menu_world.g.v_up = (float*)PR_FindGlobal(menu_world.progs, "v_up", 0, NULL); if (!menu_world.g.v_up) menu_world.g.v_up = up;
menu_world.g.drawfont = (float*)PR_FindGlobal(menu_world.progs, "drawfont", 0, NULL);
menu_world.g.drawfontscale = (float*)PR_FindGlobal(menu_world.progs, "drawfontscale", 0, NULL);

View File

@ -1625,7 +1625,7 @@ void rag_updatedeltaent(world_t *w, entity_t *ent, lerpents_t *le)
sko->numanimated = 0;
else if (sko->doll)
sko->numanimated = sko->doll->numdefaultanimated;
Mod_GetBoneRelations(mod, 0, skorel.numbones, &ent->framestate, skorel.bonematrix);
Mod_GetBoneRelations(mod, 0, skorel.numbones, NULL, &ent->framestate, skorel.bonematrix);
skorel.modelindex = sko->modelindex;
skorel.model = sko->model;
if (sko->numanimated || sko->doll != mod->dollinfo)
@ -1932,6 +1932,7 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
framestate_t fstate;
skelobject_t *skelobj;
model_t *model;
galiasbone_t *boneinfo;
//default to failure
G_FLOAT(OFS_RETURN) = 0;
@ -1946,19 +1947,27 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
fstate.bonecount = 0;
fstate.bonestate = NULL;
numbones = Mod_GetNumBones(model, false);
if (!numbones)
{
return; //this isn't a skeletal model.
}
if (!skelidx)
{
numbones = Mod_GetNumBones(model, false);
if (!numbones)
{
return; //this isn't a skeletal model.
}
skelobj = skel_create(w, numbones);
}
else
skelobj = skel_get(w, skelidx);
if (!skelobj)
return; //couldn't get one, ran out of memory or something?
if (skelobj->model)
boneinfo = Mod_GetBoneInfo(skelobj->model, &numbones);
else
boneinfo = NULL;
numbones = skelobj->numbones;
if (lastbone < 0)
lastbone = numbones;
if (lastbone > numbones)
@ -1980,15 +1989,15 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
if (retainfrac == 0)
{
if (addition == 1) /*replace everything*/
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix);
else if (addition == 0) /*wipe it*/
if (addition == 0) /*wipe it*/
memset(skelobj->bonematrix + firstbone*12, 0, sizeof(float)*12*(lastbone-firstbone));
else if (addition == 1) /*replace everything*/
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, skelobj->bonematrix);
else
{
//scale new
float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++)
{
for (j = 0; j < 12; j++)
@ -1998,6 +2007,8 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
}
else
{
float relationsbuf[MAX_BONES*12];
if (retainfrac != 1)
{
//rescale the existing bones
@ -2007,22 +2018,19 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
skelobj->bonematrix[i*12+j] *= retainfrac;
}
}
//just add
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
if (addition == 1)
{
//just add
float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++)
{
for (j = 0; j < 12; j++)
skelobj->bonematrix[i*12+j] += relationsbuf[i*12+j];
}
}
else if (addition)
else
{
//add+scale
float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++)
{
for (j = 0; j < 12; j++)
@ -2068,6 +2076,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
int numbones, firstbone, lastbone;
model_t *model;
qboolean noadd;
const galiasbone_t *boneinfo = NULL;
//default to failure
G_FLOAT(OFS_RETURN) = 0;
@ -2170,7 +2179,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
}
}
else if (blends->prescale == 0) //new data only. directly replace the existing data
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix);
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, skelobj->bonematrix);
else
{
if (blends->prescale != 1)
@ -2183,7 +2192,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
}
}
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++)
{
for (j = 0; j < 12; j++)
@ -2671,10 +2680,10 @@ void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{
world_t *w = prinst->parms->user;
int modelindex = G_FLOAT(OFS_PARM0);
unsigned int skinnum = G_FLOAT(OFS_PARM1);
unsigned int animnum = G_FLOAT(OFS_PARM1);
int surfaceidx = 0;
model_t *mod = w->Get_CModel(w, modelindex);
const char *n = Mod_FrameNameForNum(mod, surfaceidx, skinnum);
const char *n = Mod_FrameNameForNum(mod, surfaceidx, animnum);
if (n)
RETURN_TSTRING(n);

View File

@ -208,7 +208,7 @@ extern "C" {
#endif
#if defined(Q3CLIENT) || defined(Q3SERVER)
#include "q3api.h"
#include "../common/q3api.h"
#endif
#ifdef __cplusplus

View File

@ -876,7 +876,7 @@ static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int
switch(lm->fmt)
{
default:
Sys_Error("Bad lightmap_fmt\n");
Sys_Error("Surf_StoreLightmap_RGB: Bad format - %s\n", Image_FormatName(lm->fmt));
break;
case PTI_A2BGR10:
stride = (lm->width-smax)<<2;
@ -1492,7 +1492,7 @@ static void Surf_BuildLightMap (model_t *model, msurface_t *surf, int map, int s
// add all the lightmaps
if (src)
{
if (model->fromgame == fg_quake3)
if (model->lightmaps.prebaked)
Sys_Error("Surf_BuildLightMap: q3bsp");
switch(model->lightmaps.fmt)
{
@ -1773,7 +1773,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh
// add all the lightmaps
if (src)
{
if (wmodel->fromgame == fg_quake3) //rgb
if (wmodel->lightmaps.prebaked) //rgb
{
/*q3 lightmaps are meant to be pre-built
this code is misguided, and ought never be executed anyway.
@ -1790,6 +1790,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh
bl+=3;
}
}
Sys_Error("Surf_BuildLightMap_Worker: q3bsp");
}
else switch(wmodel->lightmaps.fmt)
{
@ -2055,7 +2056,11 @@ dynamic:
#ifdef _DEBUG
if ((unsigned)fa->lightmaptexturenums[0] >= numlightmaps)
Sys_Error("Invalid lightmap index\n");
{
static float throttle;
Con_ThrottlePrintf(&throttle, 0, CON_WARNING"Invalid lightmap index\n");
return;
}
#endif
@ -2303,7 +2308,7 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
// calculate dynamic lighting for bmodel if it's not an
// instanced model
if (model->fromgame != fg_quake3 && model->fromgame != fg_doom3 && lightmap && !(webo_blocklightmapupdates&1))
if (!model->lightmaps.prebaked && lightmap && !(webo_blocklightmapupdates&1))
{
int k;
@ -3094,7 +3099,7 @@ void Surf_DrawWorld (void)
gennew = true; //generate an initial one, if we can.
else
{
if (!gennew && currentmodel->fromgame != fg_quake3)
if (!gennew && !currentmodel->lightmaps.prebaked)
{
int i = cl_max_lightstyles;
for (i = 0; i < cl_max_lightstyles; i++)
@ -3449,6 +3454,8 @@ uploadfmt_t Surf_NameToFormat(const char *nam)
uploadfmt_t Surf_LightmapMode(model_t *model)
{
uploadfmt_t fmt = Surf_NameToFormat(r_lightmap_format.string);
if (model && model->lightmaps.prebaked && model->lightmaps.fmt!=LM_RGB8)
fmt = PTI_INVALID; //don't let them force it away if we can't support it. this sucks.
if (!sh_config.texfmt[fmt])
{
qboolean hdr = (vid.flags&VID_SRGBAWARE), rgb = false;
@ -3755,7 +3762,7 @@ void Surf_BuildModelLightmaps (model_t *m)
R_BumpLightstyles(m->lightmaps.maxstyle); //should only really happen with lazy loading
if (m->submodelof && m->fromgame == fg_quake3) //FIXME: should be all bsp formats
if (m->submodelof && m->lightmaps.prebaked) //FIXME: should be all bsp formats
{
if (m->submodelof->loadstate != MLS_LOADED)
return;
@ -3763,7 +3770,7 @@ void Surf_BuildModelLightmaps (model_t *m)
}
else
{
if (!m->lightdata && m->lightmaps.count && m->fromgame == fg_quake3)
if (!m->lightdata && m->lightmaps.count && m->lightmaps.prebaked)
{
char pattern[MAX_QPATH];
COM_StripAllExtensions(m->name, pattern, sizeof(pattern));
@ -3787,7 +3794,7 @@ void Surf_BuildModelLightmaps (model_t *m)
}
}
if (m->fromgame == fg_quake3)
if (m->lightmaps.prebaked)
{
int j;
unsigned char *src, *stop;
@ -3817,24 +3824,38 @@ void Surf_BuildModelLightmaps (model_t *m)
if (!m->submodelof)
for (i = 0; i < m->lightmaps.count; i++)
{
if (lightmap[newfirst+i]->external)
if (lightmap[newfirst+i]->external || !m->lightdata)
continue;
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*3;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
if (m->lightdata)
if (lightmap[newfirst+i]->fmt == m->lightmaps.prebaked)
{
unsigned int bb,bw,bh,bd;
Image_BlockSizeForEncoding(m->lightmaps.prebaked, &bb,&bw,&bh,&bd);
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*bb;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*bb;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
memcpy(dst, src, stop-src);
}
//FIXME: replace with Image_ChangeFormat here. but the data may be partial for the last mip.
else switch(m->lightmaps.fmt)
{
case LM_RGB8:
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*3;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
switch(lightmap[newfirst+i]->fmt)
{
default:
Sys_Error("Bad lightmap_fmt\n");
Sys_Error("Surf_BuildModelLightmaps: Bad format - %s\n", Image_FormatName(lightmap[newfirst+i]->fmt));
break;
case PTI_A2BGR10:
for (; src < stop; dst += 4, src += 3)
*(unsigned int*)dst = (0x3<<30) | (src[2]<<22) | (src[1]<<12) | (src[0]<<2);
*(unsigned int*)dst = (0x3u<<30) | (src[2]<<22) | (src[1]<<12) | (src[0]<<2);
break;
case PTI_E5BGR9:
for (; src < stop; dst += 4, src += 3)
@ -3850,7 +3871,8 @@ void Surf_BuildModelLightmaps (model_t *m)
dst[3] = 255;
}
break;
/*case TF_RGBA32:
case PTI_RGBA8:
case PTI_RGBX8:
for (; src < stop; dst += 4, src += 3)
{
dst[0] = src[0];
@ -3859,15 +3881,15 @@ void Surf_BuildModelLightmaps (model_t *m)
dst[3] = 255;
}
break;
case TF_BGR24:
case PTI_BGR8:
for (; src < stop; dst += 3, src += 3)
{
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0];
}
break;*/
case TF_RGB24:
break;
case PTI_RGB8:
for (; src < stop; dst += 3, src += 3)
{
dst[0] = src[0];
@ -3886,6 +3908,23 @@ void Surf_BuildModelLightmaps (model_t *m)
}
break;
}
break;
case LM_E5BGR9:
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*4;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*4;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
if (lightmap[newfirst+i]->fmt == PTI_E5BGR9)
memcpy(dst, src, stop-src);
else //this can happen on older gpus...
Con_Printf(CON_WARNING"Unsupported lightmap format. set ^[/r_lightmap_format e5bgr9^]\n");
break;
default:
Con_Printf(CON_WARNING"Unsupported input lightmap format\n");
break;
}
}
}
@ -4010,7 +4049,7 @@ void Surf_NewMap (model_t *worldmodel)
//evil haxx
r_dynamic.ival = r_dynamic.value;
if (r_dynamic.ival > 0 && (!cl.worldmodel || cl.worldmodel->fromgame == fg_quake3)) //quake3 has no lightmaps, disable r_dynamic
if (r_dynamic.ival > 0 && (!cl.worldmodel || cl.worldmodel->lightmaps.prebaked)) //quake3 has no lightmaps, disable r_dynamic
r_dynamic.ival = 0;
memset (&r_worldentity, 0, sizeof(r_worldentity));

View File

@ -586,7 +586,7 @@ struct llightinfo_s;
void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, lightstyleindex_t surf_styles[MAXCPULIGHTMAPS], unsigned int *surf_expsamples, qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale); //special version that doesn't know what a face is or anything.
struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, struct model_s *model, qboolean shadows, qboolean skiplit);
void LightReloadEntities(struct relight_ctx_s *ctx, const char *entstring, qboolean ignorestyles);
void LightShutdown(struct relight_ctx_s *ctx);
void LightShutdown(struct relight_ctx_s *ctx, struct model_s *model);
extern const size_t lightthreadctxsize;
qboolean RelightSetup (struct model_s *model, size_t lightsamples, qboolean generatelit);
@ -699,9 +699,7 @@ extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar;
extern int r_lightprepass; //0=off,1=16bit,2=32bit
#ifdef R_XFLIP
extern cvar_t r_xflip;
#endif
extern cvar_t gl_mindist, gl_maxdist;
extern cvar_t r_clear;

View File

@ -161,8 +161,9 @@ cvar_t r_fb_bmodels = CVARAFD("r_fb_bmodels", "1",
"gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH, "Enables loading lumas on the map, as well as any external bsp models.");
cvar_t r_fb_models = CVARAFD ("r_fb_models", "1",
"gl_fb_models", CVAR_SEMICHEAT, "Enables the use of lumas on models. Note that if ruleset_allow_fbmodels is enabled, then all models are unconditionally fullbright in deathmatch, because cheaters would set up their models like that anyway, hurrah for beating them at their own game. QuakeWorld players suck.");
cvar_t r_skin_overlays = CVARF ("r_skin_overlays", "1",
CVAR_SEMICHEAT|CVAR_RENDERERLATCH);
cvar_t gl_overbright_models = CVARFD("gl_overbright_models", "0", CVAR_SEMICHEAT|CVAR_ARCHIVE, "Doubles the brightness of models, to match QuakeSpasm's misfeature of the same name.");
//cvar_t r_skin_overlays = CVARF ("r_skin_overlays", "1",
// CVAR_SEMICHEAT|CVAR_RENDERERLATCH);
cvar_t r_globalskin_first = CVARFD ("r_globalskin_first", "100", CVAR_RENDERERLATCH, "Specifies the first .skin value that is a global skin. Entities within this range will use the shader/image called 'gfx/skinSKIN.lmp' instead of their regular skin. See also: r_globalskin_count.");
cvar_t r_globalskin_count = CVARFD ("r_globalskin_count", "10", CVAR_RENDERERLATCH, "Specifies how many globalskins there are.");
cvar_t r_coronas = CVARFD ("r_coronas", "0", CVAR_ARCHIVE, "Draw coronas on realtime lights. Overrides glquake-esque flashblends.");
@ -323,6 +324,8 @@ cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far apar
cvar_t r_stereo_convergence = CVARD("r_stereo_convergence", "0", "Nudges the angle of each eye inwards when using stereoscopic rendering.");
cvar_t r_stereo_method = CVARFD("r_stereo_method", "0", CVAR_ARCHIVE, "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain.");
cvar_t r_xflip = CVAR("leftisright", "0");
extern cvar_t r_dodgytgafiles;
extern cvar_t r_dodgypcxfiles;
extern cvar_t r_keepimages;
@ -581,10 +584,6 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES);
#ifdef R_XFLIP
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
#endif
// Cvar_Register (&gl_lightmapmode, GLRENDEREROPTIONS);
Cvar_Register (&gl_picmip, GLRENDEREROPTIONS);
@ -943,6 +942,7 @@ void Renderer_Init(void)
Cvar_Register (&scr_allowsnap, SCREENOPTIONS);
Cvar_Register (&scr_consize, SCREENOPTIONS);
Cvar_Register (&scr_centersbar, SCREENOPTIONS);
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
Cvar_Register(&r_bloodstains, GRAPHICALNICETIES);
@ -1002,8 +1002,9 @@ void Renderer_Init(void)
Cvar_Register (&r_fb_bmodels, GRAPHICALNICETIES);
Cvar_Register (&r_fb_models, GRAPHICALNICETIES);
Cvar_Register (&gl_overbright_models, GRAPHICALNICETIES);
// Cvar_Register (&r_fullbrights, GRAPHICALNICETIES); //dpcompat: 1 if r_fb_bmodels&&r_fb_models
Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES);
// Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES);
Cvar_Register (&r_globalskin_first, GRAPHICALNICETIES);
Cvar_Register (&r_globalskin_count, GRAPHICALNICETIES);
Cvar_Register (&r_shadows, GRAPHICALNICETIES);
@ -1824,7 +1825,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
for (i=1 ; i<MAX_PRECACHE_MODELS ; i++)
{
if (!cl.model_name[i][0])
if (!cl.model_name[i])
break;
TRACE(("dbg: R_ApplyRenderer: reloading model %s\n", cl.model_name[i]));
@ -1846,7 +1847,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
#ifdef HAVE_LEGACY
for (i=0; i < MAX_VWEP_MODELS; i++)
{
if (*cl.model_name_vwep[i])
if (cl.model_name_vwep[i])
cl.model_precache_vwep[i] = Mod_ForName (cl.model_name_vwep[i], MLV_SILENT);
else
cl.model_precache_vwep[i] = NULL;
@ -2201,7 +2202,8 @@ void R_RestartRenderer (rendererstate_t *newr)
rendererstate_t oldr;
if (r_blockvidrestart)
{
Con_TPrintf("Ignoring vid_restart from config\n");
if (r_blockvidrestart != 2)
Con_TPrintf("Unable to restart renderer at this time\n");
return;
}
@ -2324,6 +2326,13 @@ void R_RestartRenderer_f (void)
double time;
rendererstate_t newr;
if (r_blockvidrestart)
{
if (r_blockvidrestart!=2)
Con_TPrintf("Ignoring vid_restart from config\n");
return;
}
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH, false);
if (!R_BuildRenderstate(&newr, vid_renderer.string))
{
@ -2558,72 +2567,6 @@ mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
return pspriteframe;
}
/*
void MYgluPerspective(double fovx, double fovy, double zNear, double zFar)
{
Matrix4_Projection_Far(r_refdef.m_projection, fovx, fovy, zNear, zFar);
}
void GL_InfinatePerspective(double fovx, double fovy,
double zNear)
{
// nudge infinity in just slightly for lsb slop
float nudge = 1;// - 1.0 / (1<<23);
double xmin, xmax, ymin, ymax;
ymax = zNear * tan( fovy * M_PI / 360.0 );
ymin = -ymax;
xmax = zNear * tan( fovx * M_PI / 360.0 );
xmin = -xmax;
r_projection_matrix[0] = (2*zNear) / (xmax - xmin);
r_projection_matrix[4] = 0;
r_projection_matrix[8] = (xmax + xmin) / (xmax - xmin);
r_projection_matrix[12] = 0;
r_projection_matrix[1] = 0;
r_projection_matrix[5] = (2*zNear) / (ymax - ymin);
r_projection_matrix[9] = (ymax + ymin) / (ymax - ymin);
r_projection_matrix[13] = 0;
r_projection_matrix[2] = 0;
r_projection_matrix[6] = 0;
r_projection_matrix[10] = -1 * nudge;
r_projection_matrix[14] = -2*zNear * nudge;
r_projection_matrix[3] = 0;
r_projection_matrix[7] = 0;
r_projection_matrix[11] = -1;
r_projection_matrix[15] = 0;
}
void GL_ParallelPerspective(double xmin, double xmax, double ymax, double ymin,
double znear, double zfar)
{
r_projection_matrix[0] = 2/(xmax-xmin);
r_projection_matrix[4] = 0;
r_projection_matrix[8] = 0;
r_projection_matrix[12] = (xmax+xmin)/(xmax-xmin);
r_projection_matrix[1] = 0;
r_projection_matrix[5] = 2/(ymax-ymin);
r_projection_matrix[9] = 0;
r_projection_matrix[13] = (ymax+ymin)/(ymax-ymin);
r_projection_matrix[2] = 0;
r_projection_matrix[6] = 0;
r_projection_matrix[10] = -2/(zfar-znear);
r_projection_matrix[14] = (zfar+znear)/(zfar-znear);
r_projection_matrix[3] = 0;
r_projection_matrix[7] = 0;
r_projection_matrix[11] = 0;
r_projection_matrix[15] = 1;
}
*/
/*
===============

View File

@ -2401,7 +2401,7 @@ void Sbar_DrawScoreboard (playerview_t *pv)
#endif
isdead = false;
if (pv->spectator && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
if (pv->spectator && cls.demoplayback == DPB_MVD)
{
int t = pv->cam_spec_track;
if (t >= 0 && CAM_ISLOCKED(pv) && cl.players[t].statsf[STAT_HEALTH] <= 0)
@ -3544,14 +3544,14 @@ ping time frags name
sprintf(num, S_COLOR_WHITE"%4i", p); \
else \
sprintf(num, S_COLOR_GREEN"%4i", p); \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
Draw_FunStringWidth(x, y, num, 4*8+4, false, highlight); \
},NOFILL)
#define COLUMN_PL COLUMN(pl, 2*8, \
{ \
int p = s->pl; \
sprintf(num, "%2i", p); \
Draw_FunStringWidth(x, y, num, 2*8, false, false); \
Draw_FunStringWidth(x, y, num, 2*8+4, false, highlight); \
},NOFILL)
#define COLUMN_TIME COLUMN(time, 4*8, \
{ \
@ -3563,14 +3563,14 @@ ping time frags name
minutes = (int)total/60; \
sprintf (num, "%4i", minutes); \
} \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \
Draw_FunStringWidth(x, y, num, 4*8+4, false, highlight); \
},NOFILL)
#define COLUMN_FRAGS COLUMN(frags, 5*8, \
{ \
int cx; int cy; \
if (s->spectator && s->spectator != 2) \
{ \
Draw_FunStringWidth(x, y, "spectator", 5*8, false, false); \
Draw_FunStringWidth(x, y, "spectator", 5*8+4, false, false); \
} \
else \
{ \
@ -3607,7 +3607,7 @@ ping time frags name
{ \
if (!s->spectator) \
{ \
Draw_FunStringWidth(x, y, s->team, 4*8, false, false); \
Draw_FunStringWidth(x, y, s->team, 4*8+4, false, highlight); \
} \
},NOFILL)
#define COLUMN_STAT(title, width, code, fill) COLUMN(title, width, { \
@ -3616,13 +3616,13 @@ ping time frags name
code \
} \
}, fill)
#define COLUMN_RULESET COLUMN(ruleset, 8*8, {Draw_FunStringWidth(x, y, s->ruleset, 8*8, false, false);},NOFILL)
#define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, false);},NOFILL)
#define COLUMN_KILLS COLUMN_STAT(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);},NOFILL)
#define COLUMN_TKILLS COLUMN_STAT(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);},NOFILL)
#define COLUMN_DEATHS COLUMN_STAT(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},NOFILL)
#define COLUMN_TOUCHES COLUMN_STAT(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},NOFILL)
#define COLUMN_CAPS COLUMN_STAT(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},NOFILL)
#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)
#define COLUMN_TKILLS COLUMN_STAT(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8+4, false, false);},NOFILL)
#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)
#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)
@ -3658,12 +3658,13 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
int pages;
int linesperpage, firstline, lastline;
int highlight;
if (!pv)
return;
// request new ping times every two second
if (realtime - cl.last_ping_request > 2 && cls.demoplayback != DPB_EZTV)
if (realtime - cl.last_ping_request > 2 && !cls.demoplayback)
{
if (cls.protocol == CP_QUAKEWORLD)
{
@ -3944,6 +3945,18 @@ if (showcolumns & (1<<COLUMN##title)) \
isme = (pv->cam_state == CAM_FREECAM && k == pv->playernum) ||
(pv->cam_state != CAM_FREECAM && k == pv->cam_spec_track);
if ((key_dest_absolutemouse & key_dest_mask & ~kdm_game) &&
!Key_Dest_Has(~kdm_game) &&
mousecursor_x >= startx && mousecursor_x < startx+rank_width &&
mousecursor_y >= y && mousecursor_y < y+skip)
{
highlight = 2;
cl.mouseplayerview = pv;
cl.mousenewtrackplayer = k;
}
else
highlight = 0;
x = startx;
#define COLUMN(title, width, code, fills) \
if (showcolumns & (1<<COLUMN##title)) \
@ -4018,6 +4031,9 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
top = Sbar_TopColour(s);
bottom = Sbar_BottomColour(s);
if (S_Voip_Speaking(k))
Sbar_FillPCDark (x, py, ((cl.teamplay && !consistentteams)?40:0)+48+MAX_DISPLAYEDNAME*8, 8, 0x00ff00, scr_scoreboard_backgroundalpha.value*scr_scoreboard_fillalpha.value);
Sbar_FillPC ( x, py+1, 40, 3, top);
Sbar_FillPC ( x, py+4, 40, 4, bottom);
py += 8;

View File

@ -488,17 +488,17 @@ void Skin_NextDownload (void)
CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", skinname), NULL, 0);
for (j = 1; j < MAX_PRECACHE_MODELS; j++)
{
if (!cl.model_name[j])
break;
if (cl.model_name[j][0] == '#')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.model_name[j]+1), NULL, 0);
if (!*cl.model_name[j])
break;
}
for (j = 1; j < MAX_PRECACHE_SOUNDS; j++)
{
if (!cl.sound_name[j])
break;
if (cl.sound_name[j][0] == '*')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.sound_name[j]+1), NULL, 0);
if (!*cl.sound_name[j])
break;
}
*slash = '/';
CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", skinname), NULL, 0);

View File

@ -53,6 +53,9 @@ We also have no doppler with WebAudio.
#ifdef OPENAL_STATIC
#include <AL/al.h> //output
#include <AL/alc.h> //context+input
#ifdef USEEFX
#include <AL/efx.h>
#endif
#ifndef AL_API
#define AL_API
@ -103,6 +106,13 @@ We also have no doppler with WebAudio.
#define palGetProcAddress alGetProcAddress
//voip stuff
#define palcCaptureOpenDevice alcCaptureOpenDevice
#define palcCaptureCloseDevice alcCaptureCloseDevice
#define palcCaptureStart alcCaptureStart
#define palcCaptureStop alcCaptureStop
#define palcCaptureSamples alcCaptureSamples
#ifdef FTE_TARGET_WEB //emscripten sucks.
AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {}
#endif
@ -115,6 +125,8 @@ AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {}
#endif
#define AL_API
#undef AL_ALEXT_PROTOTYPES
typedef int ALint;
typedef unsigned int ALuint;
@ -131,6 +143,7 @@ static qboolean openallib_tried;
static AL_API ALenum (AL_APIENTRY *palGetError)( void );
static AL_API void (AL_APIENTRY *palSourcef)( ALuint sid, ALenum param, ALfloat value );
static AL_API void (AL_APIENTRY *palSourcei)( ALuint sid, ALenum param, ALint value );
static AL_API void (AL_APIENTRY *palSource3i)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
static AL_API void (AL_APIENTRY *palSourcePlayv)( ALsizei ns, const ALuint *sids );
static AL_API void (AL_APIENTRY *palSourceStopv)( ALsizei ns, const ALuint *sids );
@ -251,19 +264,17 @@ static ALC_API void* (ALC_APIENTRY *palcGetProcAddress)(ALCdevice *dev
#if defined(VOICECHAT)
//capture-specific stuff
static ALC_API void (ALC_APIENTRY *palcGetIntegerv)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
static ALC_API ALCdevice * (ALC_APIENTRY *palcCaptureOpenDevice)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
static ALC_API ALCboolean (ALC_APIENTRY *palcCaptureCloseDevice)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureStart)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureStop)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
static void (ALC_APIENTRY *palcGetIntegerv)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
static ALCdevice * (ALC_APIENTRY *palcCaptureOpenDevice)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
static ALCboolean (ALC_APIENTRY *palcCaptureCloseDevice)( ALCdevice *device );
static void (ALC_APIENTRY *palcCaptureStart)( ALCdevice *device );
static void (ALC_APIENTRY *palcCaptureStop)( ALCdevice *device );
static void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
#define ALC_CAPTURE_SAMPLES 0x312
#endif
#endif
//efx
#ifdef USEEFX
@ -312,18 +323,32 @@ static ALC_API void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *dev
#define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
static AL_API void (AL_APIENTRY *palSource3i)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
#endif
#endif
static AL_API void (AL_APIENTRY *palAuxiliaryEffectSloti)(ALuint effectslot, ALenum param, ALint iValue);
static AL_API ALvoid (AL_APIENTRY *palGenAuxiliaryEffectSlots)(ALsizei n, ALuint *effectslots);
static AL_API ALvoid (AL_APIENTRY *palDeleteAuxiliaryEffectSlots)(ALsizei n, const ALuint *effectslots);
static AL_API ALvoid (AL_APIENTRY *palDeleteEffects)(ALsizei n, const ALuint *effects);
#ifdef USEEFX
#if defined(AL_ALEXT_PROTOTYPES) && defined(OPENAL_STATIC)
#define palAuxiliaryEffectSloti alAuxiliaryEffectSloti
#define palGenAuxiliaryEffectSlots alGenAuxiliaryEffectSlots
#define palDeleteAuxiliaryEffectSlots alDeleteAuxiliaryEffectSlots
#define palDeleteEffects alDeleteEffects
#define palGenEffects alGenEffects
#define palEffecti alEffecti
// #define palEffectiv alEffectiv
#define palEffectf alEffectf
#define palEffectfv alEffectfv
#else
static void (AL_APIENTRY *palAuxiliaryEffectSloti)(ALuint effectslot, ALenum param, ALint iValue);
static ALvoid (AL_APIENTRY *palGenAuxiliaryEffectSlots)(ALsizei n, ALuint *effectslots);
static ALvoid (AL_APIENTRY *palDeleteAuxiliaryEffectSlots)(ALsizei n, const ALuint *effectslots);
static ALvoid (AL_APIENTRY *palDeleteEffects)(ALsizei n, const ALuint *effects);
static AL_API ALvoid (AL_APIENTRY *palGenEffects)(ALsizei n, ALuint *effects);
static AL_API ALvoid (AL_APIENTRY *palEffecti)(ALuint effect, ALenum param, ALint iValue);
static AL_API ALvoid (AL_APIENTRY *palEffectiv)(ALuint effect, ALenum param, const ALint *piValues);
static AL_API ALvoid (AL_APIENTRY *palEffectf)(ALuint effect, ALenum param, ALfloat flValue);
static AL_API ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, const ALfloat *pflValues);
static ALvoid (AL_APIENTRY *palGenEffects)(ALsizei n, ALuint *effects);
static ALvoid (AL_APIENTRY *palEffecti)(ALuint effect, ALenum param, ALint iValue);
// static ALvoid (AL_APIENTRY *palEffectiv)(ALuint effect, ALenum param, const ALint *piValues);
static ALvoid (AL_APIENTRY *palEffectf)(ALuint effect, ALenum param, ALfloat flValue);
static ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, const ALfloat *pflValues);
#endif
#endif
//AL_EXT_float32
@ -1084,13 +1109,10 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
palSourcef(src, AL_PITCH, pitch);
#ifdef USEEFX
if (palSource3i)
{
if (chan->flags & CF_NOREVERB) //don't do the underwater thing on static sounds. it sounds like arse with all those sources.
palSource3i(src, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);
else
palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL);
}
if (chan->flags & CF_NOREVERB) //don't do the underwater thing on static sounds. it sounds like arse with all those sources.
palSource3i(src, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);
else
palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL);
#endif
palSourcei(src, AL_LOOPING, (!stream && ((chan->flags & CF_FORCELOOP)||(sfx->loopstart>=0&&!stream)))?AL_TRUE:AL_FALSE);
@ -1205,6 +1227,7 @@ static qboolean OpenAL_InitLibrary(void)
{(void*)&palGetError, "alGetError"},
{(void*)&palSourcef, "alSourcef"},
{(void*)&palSourcei, "alSourcei"},
{(void*)&palSource3i, "alSource3i"},
{(void*)&palSourcePlayv, "alSourcePlayv"},
{(void*)&palSourceStopv, "alSourceStopv"},
{(void*)&palSourcePlay, "alSourcePlay"},
@ -1238,6 +1261,7 @@ static qboolean OpenAL_InitLibrary(void)
{(void*)&palcMakeContextCurrent, "alcMakeContextCurrent"},
{(void*)&palcProcessContext, "alcProcessContext"},
{(void*)&palcGetString, "alcGetString"},
{(void*)&palcGetIntegerv, "alcGetIntegerv"},
{(void*)&palcIsExtensionPresent, "alcIsExtensionPresent"},
{(void*)&palcGetProcAddress, "alcGetProcAddress"},
{NULL}
@ -1854,16 +1878,17 @@ static qboolean QDECL OpenAL_InitCard2(soundcardinfo_t *sc, const char *devname,
#ifdef USEEFX
PrintALError("preeffects");
palSource3i = palGetProcAddress("alSource3i");
#ifndef AL_ALEXT_PROTOTYPES
palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti");
palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots");
palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots");
palDeleteEffects = palGetProcAddress("alDeleteEffects");
palGenEffects = palGetProcAddress("alGenEffects");
palEffecti = palGetProcAddress("alEffecti");
palEffectiv = palGetProcAddress("alEffectiv");
// palEffectiv = palGetProcAddress("alEffectiv");
palEffectf = palGetProcAddress("alEffectf");
palEffectfv = palGetProcAddress("alEffectfv");
#endif
if (palGenAuxiliaryEffectSlots && s_al_use_reverb.ival)
palGenAuxiliaryEffectSlots(1, &oali->effectslot);
@ -1915,10 +1940,11 @@ static qboolean OpenAL_InitCapture(void)
//if (!palcIsExtensionPresent(NULL, "ALC_EXT_capture"))
// return false;
#ifdef OPENAL_STATIC
return true;
#else
if(!palcCaptureOpenDevice)
{
palcGetIntegerv = Sys_GetAddressForName(openallib, "alcGetIntegerv");
palcCaptureOpenDevice = Sys_GetAddressForName(openallib, "alcCaptureOpenDevice");
palcCaptureStart = Sys_GetAddressForName(openallib, "alcCaptureStart");
palcCaptureSamples = Sys_GetAddressForName(openallib, "alcCaptureSamples");
@ -1927,6 +1953,7 @@ static qboolean OpenAL_InitCapture(void)
}
return palcGetIntegerv&&palcCaptureOpenDevice&&palcCaptureStart&&palcCaptureSamples&&palcCaptureStop&&palcCaptureCloseDevice;
#endif
}
static qboolean QDECL OPENAL_Capture_Enumerate (void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename))
{
@ -1955,8 +1982,13 @@ static void *QDECL OPENAL_Capture_Init (int samplerate, const char *device)
if (!device || !*device)
{
#if defined(FTE_TARGET_WEB) && (__EMSCRIPTEN_major__>2 || (__EMSCRIPTEN_major__==2&&__EMSCRIPTEN_tiny__>=14))
//emscripten, and recent enough to actually work. don't check s_al_disable here as we don't have dsound/alsa fallbacks and we do want to actually use it.
//older versions of emscripten are too buggy to use.
#else
if (s_al_disable.ival)
return NULL; //no default device
#endif
device = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
}

View File

@ -38,41 +38,41 @@
static void *alsasharedobject;
int (*psnd_pcm_open) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
int (*psnd_pcm_close) (snd_pcm_t *pcm);
int (*psnd_config_update_free_global)(void);
const char *(*psnd_strerror) (int errnum);
int (*psnd_pcm_hw_params_any) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*psnd_pcm_hw_params_set_access) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access);
int (*psnd_pcm_hw_params_set_format) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
int (*psnd_pcm_hw_params_set_channels) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
int (*psnd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
int (*psnd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
int (*psnd_pcm_hw_params) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*psnd_pcm_sw_params_current) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int (*psnd_pcm_sw_params_set_start_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
int (*psnd_pcm_sw_params_set_stop_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
int (*psnd_pcm_sw_params) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int (*psnd_pcm_hw_params_get_buffer_size) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
int (*psnd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
int (*psnd_pcm_set_params) (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency);
snd_pcm_sframes_t (*psnd_pcm_avail_update) (snd_pcm_t *pcm);
snd_pcm_state_t (*psnd_pcm_state) (snd_pcm_t *pcm);
int (*psnd_pcm_start) (snd_pcm_t *pcm);
int (*psnd_pcm_recover) (snd_pcm_t *pcm, int err, int silent);
static int (*psnd_pcm_open) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
static int (*psnd_pcm_close) (snd_pcm_t *pcm);
static int (*psnd_config_update_free_global)(void);
static const char *(*psnd_strerror) (int errnum);
static int (*psnd_pcm_hw_params_any) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
static int (*psnd_pcm_hw_params_set_access) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access);
static int (*psnd_pcm_hw_params_set_format) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
static int (*psnd_pcm_hw_params_set_channels) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
static int (*psnd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*psnd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
static int (*psnd_pcm_hw_params) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
static int (*psnd_pcm_sw_params_current) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
static int (*psnd_pcm_sw_params_set_start_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*psnd_pcm_sw_params_set_stop_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*psnd_pcm_sw_params) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
static int (*psnd_pcm_hw_params_get_buffer_size) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
static int (*psnd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
static int (*psnd_pcm_set_params) (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency);
static snd_pcm_sframes_t (*psnd_pcm_avail_update) (snd_pcm_t *pcm);
static snd_pcm_state_t (*psnd_pcm_state) (snd_pcm_t *pcm);
static int (*psnd_pcm_start) (snd_pcm_t *pcm);
static int (*psnd_pcm_recover) (snd_pcm_t *pcm, int err, int silent);
size_t (*psnd_pcm_hw_params_sizeof) (void);
size_t (*psnd_pcm_sw_params_sizeof) (void);
static size_t (*psnd_pcm_hw_params_sizeof) (void);
static size_t (*psnd_pcm_sw_params_sizeof) (void);
int (*psnd_pcm_mmap_begin) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames);
snd_pcm_sframes_t (*psnd_pcm_mmap_commit) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames);
static int (*psnd_pcm_mmap_begin) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames);
static snd_pcm_sframes_t (*psnd_pcm_mmap_commit) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames);
snd_pcm_sframes_t (*psnd_pcm_writei) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
int (*psnd_pcm_prepare) (snd_pcm_t *pcm);
static snd_pcm_sframes_t (*psnd_pcm_writei) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
static int (*psnd_pcm_prepare) (snd_pcm_t *pcm);
int (*psnd_device_name_hint) (int card, const char *iface, void ***hints);
char * (*psnd_device_name_get_hint) (const void *hint, const char *id);
int (*psnd_device_name_free_hint) (void **hints);
static int (*psnd_device_name_hint) (int card, const char *iface, void ***hints);
static char * (*psnd_device_name_get_hint) (const void *hint, const char *id);
static int (*psnd_device_name_free_hint) (void **hints);
static unsigned int ALSA_MMap_GetDMAPos (soundcardinfo_t *sc)

View File

@ -92,13 +92,8 @@ cvar_t snd_precache = CVARAF( "s_precache", "1",
cvar_t snd_loadas8bit = CVARAFD( "s_loadas8bit", "0",
"loadas8bit", CVAR_ARCHIVE,
"Downsample sounds on load as lower quality 8-bit sound, to save memory.");
#ifdef FTE_TARGET_WEB
cvar_t snd_loadasstereo = CVARD( "snd_loadasstereo", "1",
"Force mono sounds to load as if stereo ones, to waste memory. Used to work around stupid browser bugs.");
#else
cvar_t snd_loadasstereo = CVARD( "snd_loadasstereo", "0",
"Force mono sounds to load as if stereo ones, to waste memory. Not normally useful.");
#endif
cvar_t ambient_level = CVARAFD( "s_ambientlevel", "0.3",
"ambient_level", CVAR_ARCHIVE,
"This controls the volume levels of automatic area-based sounds (like water or sky), and is quite annoying. If you're playing deathmatch you'll definitely want this OFF.");
@ -1091,6 +1086,7 @@ static float S_Voip_Preprocess(short *start, unsigned int samples, float micamp)
}
static void S_Voip_TryInitCaptureContext(char *driver, char *device, int rate)
{
static float throttle;
int i;
s_voip.cdriver = NULL;
@ -1114,12 +1110,12 @@ static void S_Voip_TryInitCaptureContext(char *driver, char *device, int rate)
if (!s_voip.cdriver)
{
if (!driver)
Con_Printf("No microphone drivers supported\n");
Con_ThrottlePrintf(&throttle, 0, CON_ERROR"No microphone drivers supported\n");
else
Con_Printf("Microphone driver \"%s\" is not valid\n", driver);
Con_ThrottlePrintf(&throttle, 0, CON_ERROR"Microphone driver \"%s\" is not valid\n", driver);
}
else
Con_Printf("No microphone detected\n");
Con_ThrottlePrintf(&throttle, 0, CON_ERROR"No microphone detected\n");
s_voip.cdriver = NULL;
}
@ -1388,7 +1384,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
s_voip.capturepos += s_voip.cdriver->Update(s_voip.cdriverctx, (unsigned char*)s_voip.capturebuf + s_voip.capturepos, s_voip.encframesize*2, sizeof(s_voip.capturebuf) - s_voip.capturepos);
if (!s_voip.wantsend && s_voip.capturepos < s_voip.encframesize*2)
if (!voipsendenable || (!s_voip.wantsend && s_voip.capturepos < s_voip.encframesize*2))
{
s_voip.voiplevel = -1;
s_voip.capturepos = 0;
@ -1710,10 +1706,10 @@ void S_Voip_MapChange(void)
}
int S_Voip_Loudness(qboolean ignorevad)
{
if (s_voip.voiplevel > 100)
return 100;
if (!s_voip.cdriverctx || (!ignorevad && s_voip.dumps))
return -1;
if (s_voip.voiplevel > 100)
return 100;
return s_voip.voiplevel;
}
int S_Voip_ClientLoudness(unsigned int plno)
@ -1770,6 +1766,10 @@ void S_Voip_Parse(void)
bytes = MSG_ReadShort();
MSG_ReadSkip(bytes);
}
int S_Voip_ClientLoudness(unsigned int plno)
{
return -1;
}
#endif
@ -2188,7 +2188,7 @@ void S_DoRestart (qboolean onlyifneeded)
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
{
if (!cl.sound_name[i][0])
if (!cl.sound_name[i])
break;
cl.sound_precache[i] = S_FindName (cl.sound_name[i], true, false);
}
@ -2710,7 +2710,7 @@ static void SND_AccumulateSpacialization(soundcardinfo_t *sc, channel_t *ch, vec
listener_vec[1] = DotProduct(listener[seat].right, world_vec);
listener_vec[2] = DotProduct(listener[seat].up, world_vec);
if (snd_leftisright.ival)
if (snd_leftisright.ival^r_xflip.ival)
listener_vec[1] = -listener_vec[1];
for (i = 0; i < sc->sn.numchannels; i++)
@ -2859,7 +2859,7 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
listener_vec[1] = DotProduct(listener[seat].right, world_vec);
listener_vec[2] = DotProduct(listener[seat].up, world_vec);
if (snd_leftisright.ival)
if (snd_leftisright.ival^r_xflip.ival)
listener_vec[1] = -listener_vec[1];
for (i = 0; i < sc->sn.numchannels; i++)

View File

@ -37,10 +37,6 @@ typedef struct
static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
int cache_full_cycle;
qbyte *S_Alloc (int size);
#define LINEARUPSCALE(in, inrate, insamps, out, outrate, outlshift, outrshift) \
{ \
scale = inrate / (double)outrate; \
@ -822,9 +818,54 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int
return ResampleSfx (s, info.rate, info.numchannels, format, info.samples, info.loopstart, data + info.dataofs);
}
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
#ifdef FTE_TARGET_WEB
#if 1
void S_BrowserDecoded (void *ctx, void *dataptr, int frames, int channels, float rate)
{
sfx_t *sfx = ctx;
//make sure we were not restarting at the time... FIXME: make stricter?
extern sfx_t *known_sfx;
extern int num_sfx;
int id = sfx-known_sfx;
if (id < 0 || id >= num_sfx || sfx != &known_sfx[id])
return; //err... don't crash out!
sfx->loopstart = -1;
if (dataptr)
{ //okay, something loaded. woo.
Z_Free(sfx->decoder.buf);
sfx->decoder.buf = NULL;
sfx->decoder.decodedata = NULL;
ResampleSfx (sfx, rate, channels, QAF_S16, frames, -1, dataptr);
}
else
{
Con_Printf(CON_WARNING"Failed to decode %s\n", sfx->name);
sfx->loadstate = SLS_FAILED;
}
}
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
struct sfxcache_s *buf;
if (datalen > 4 && !strncmp(data, "RIFF", 4))
return false; //do NOT use this code for wav files. we have no way to read the looping flags which would break things in certain situations. we MUST fall back on our normal loader.
s->decoder.buf = buf = Z_Malloc(sizeof(*buf)+128);
//fill with a placeholder
buf->length = 128;
buf->speed = snd_speed;
buf->format = QAF_S8; //something basic
buf->numchannels=1;
buf->soundoffset = 0;
buf->data = (qbyte*)(buf+1);
s->loopstart = 0; //keep looping silence until it actually loads something.
return emscriptenfte_pcm_loadaudiofile(s, S_BrowserDecoded, data, datalen, sndspeed);
}
#else
//web browsers contain their own decoding libraries that our openal stuff can use.
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
@ -842,6 +883,9 @@ static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen,
return true;
}
#endif
#endif
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
//highest priority is last.
static struct

View File

@ -242,12 +242,12 @@ void S_ResetFailedLoad(void);
#ifdef PEXT2_VOICECHAT
void S_Voip_Parse(void);
#endif
int S_Voip_ClientLoudness(unsigned int plno);
#ifdef VOICECHAT
extern cvar_t snd_voip_showmeter;
void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf);
void S_Voip_MapChange(void);
int S_Voip_Loudness(qboolean ignorevad); //-1 for not capturing, otherwise between 0 and 100
int S_Voip_ClientLoudness(unsigned int plno);
qboolean S_Voip_Speaking(unsigned int plno);
void S_Voip_Ignore(unsigned int plno, qboolean ignore);
#else

View File

@ -452,7 +452,7 @@ static void Sys_Register_File_Associations_f(void)
if (!strcmp(iconname, "afterquake") || !strcmp(iconname, "nq")) //hacks so that we don't need to create icons.
iconname = "quake";
if (FS_NativePath("icon.png", FS_PUBBASEGAMEONLY, iconsyspath, sizeof(iconsyspath)))
if (FS_SystemPath("icon.png", FS_PUBBASEGAMEONLY, iconsyspath, sizeof(iconsyspath)))
iconname = iconsyspath;
s = va("%s/applications/fte-%s.desktop", xdgbase, fs_manifest->installation);
@ -1215,7 +1215,7 @@ static void DoSign(const char *fname, int signtype)
searchpathfuncs_t *search = FS_OpenPackByExtension(f, NULL, fname, fname, prefix);
if (search)
{
printf("%#08x", search->GeneratePureCRC(search, 0, 0));
printf("%#08x", search->GeneratePureCRC(search, NULL));
search->ClosePath(search);
}
else
@ -1551,15 +1551,6 @@ int main (int c, const char **v)
Host_Init(&parms);
for (i = 1; i < parms.argc; i++)
{
if (!parms.argv[i])
continue;
if (*parms.argv[i] == '+' || *parms.argv[i] == '-')
break;
Host_RunFile(parms.argv[i], strlen(parms.argv[i]), NULL);
}
oldtime = Sys_DoubleTime ();
while (1)
{

View File

@ -948,7 +948,6 @@ int QDECL main(int argc, char **argv)
{
float time, newtime, oldtime;
quakeparms_t parms;
int i;
memset(&parms, 0, sizeof(parms));
@ -975,15 +974,6 @@ int QDECL main(int argc, char **argv)
oldtime = Sys_DoubleTime ();
for (i = 1; i < parms.argc; i++)
{
if (!parms.argv[i])
continue;
if (*parms.argv[i] == '+' || *parms.argv[i] == '-')
break;
Host_RunFile(parms.argv[i], strlen(parms.argv[i]), NULL);
}
//client console should now be initialized.
/* main window message loop */

View File

@ -3629,7 +3629,7 @@ static qboolean Sys_DoInstall(void)
GetModuleFileNameW(NULL, wide, countof(wide));
narrowen(exepath, sizeof(exepath), wide);
FS_NativePath(va("%s.exe", fs_gamename.string), FS_ROOT, newexepath, sizeof(newexepath));
FS_SystemPath(va("%s.exe", fs_gamename.string), FS_ROOT, newexepath, sizeof(newexepath));
CopyFileU(exepath, newexepath, FALSE);
/*the game can now be run (using regular autoupdate stuff), but most installers are expected to install the data instead of just more downloaders, so lets do that with a 'nice' progress box*/
@ -4347,16 +4347,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
oldtime = Sys_DoubleTime ();
if (qtvfile)
{
if (!Host_RunFile(qtvfile, strlen(qtvfile), NULL))
{
SetHookState(false);
Host_Shutdown ();
return EXIT_FAILURE;
}
}
//client console should now be initialized.
#ifndef MINGW

View File

@ -1437,6 +1437,9 @@ void Validation_Auto_Response(int playernum, char *s)
static float cmdlineresponsetime;
static float scriptsresponsetime;
if (cls.demoplayback)
return; //noone gives a shit about qtv spectator versions that can't even play without reconnecting.
//quakeworld tends to use f_*
//netquake uses the slightly more guessable q_* form
if (!strncmp(s, "f_", 2))

View File

@ -94,8 +94,8 @@ static cvar_t v_ipitch_level = CVAR("v_ipitch_level", "0.3");
static cvar_t v_idlescale = CVARD("v_idlescale", "0", "Enable swishing of the view (whether idle or otherwise). Often used for concussion effects.");
cvar_t crosshair = CVARF("crosshair", "1", CVAR_ARCHIVE);
cvar_t crosshaircolor = CVARF("crosshaircolor", "255 255 255", CVAR_ARCHIVE);
cvar_t crosshairsize = CVARF("crosshairsize", "8", CVAR_ARCHIVE);
cvar_t crosshaircolor = CVARF("crosshaircolor", "255 255 255", CVAR_ARCHIVE); //QSSM misnamed it...
cvar_t crosshairsize = CVARF("crosshairsize", "8", CVAR_ARCHIVE); //QS has scr_crosshairscale, but its a multiplier rather than (vritual) size.
cvar_t cl_crossx = CVARF("cl_crossx", "0", CVAR_ARCHIVE);
cvar_t cl_crossy = CVARF("cl_crossy", "0", CVAR_ARCHIVE);
@ -1877,7 +1877,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
x = center[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-center[1])*r_refdef.vrect.height+r_refdef.vrect.y;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
if (cls.demoplayback == DPB_MVD)
{
health = pl->statsf[STAT_HEALTH];
armour = pl->statsf[STAT_ARMOR];
@ -2050,6 +2050,10 @@ void R_DrawNameTags(void)
vec3_t targ;
vec2_t scale = {12,12};
msurface_t *surf;
shader_t *shader;
const char *shadername;
char *body;
char fname[MAX_QPATH];
VectorMA(r_refdef.vieworg, 8192, vpn, targ);
#ifdef CSQC_DAT
if (csqc_world.progs)
@ -2063,23 +2067,53 @@ void R_DrawNameTags(void)
#endif
cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace);
surf = (trace.fraction == 1)?NULL:Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos);
if (surf)
if (trace.fraction >= 1)
str = "hit nothing";
else
{
shader_t *shader = surf->texinfo->texture->shader;
char fname[MAX_QPATH];
char *body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL;
shader = NULL;
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)))
{
shadername = surf->texinfo->texture->name;
shader = surf->texinfo->texture->shader;
}
else if (trace.surface && *trace.surface->name)
{
shadername = trace.surface->name;
shader = NULL;
}
else
{
shadername = "the unknown";
shader = NULL;
}
body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL;
if (body)
{
// Q_snprintfz(fname, sizeof(fname), "<default shader>");
str = va("^2%s^7\n%s%s\n{%s\n", fname, ruleset_allow_shaders.ival?"":CON_ERROR"WARNING: ruleset_allow_shaders disables external shaders"CON_DEFAULT"\n", surf->texinfo->texture->name, body);
int width, height;
char *cr;
const char *fl = "";
if (shader->usageflags & SUF_LIGHTMAP)
fl = S_COLOR_GRAY" (lightmapped)"S_COLOR_WHITE;
else if (shader->usageflags & SUF_2D)
fl = S_COLOR_GRAY" (2d)"S_COLOR_WHITE;
else //if (shader->usageflags & SUF_2D)
fl = S_COLOR_GRAY" (auto)"S_COLOR_WHITE;
if (R_GetShaderSizes(shader, &width, &height, false)>0)
fl = va("%s (%ix%i)", fl, width, height);
while((cr = strchr(body, '\r')))
*cr = ' ';
str = va(S_COLOR_GREEN"%s"S_COLOR_WHITE"\n%s%s%s\n{%s\n", fname, ruleset_allow_shaders.ival?"":CON_ERROR"WARNING: ruleset_allow_shaders disables external shaders"CON_DEFAULT"\n", shadername, fl, body);
Z_Free(body);
}
else
str = va("hit '%s'", surf->texinfo->texture->name);
str = va("hit '%s'", shadername);
}
else
str = "hit nothing";
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale);
}
else

View File

@ -67,14 +67,17 @@ typedef struct vrsetup_s
};
} vrsetup_t;
#define VRF_OVERRIDEFRAMETIME 1 //the vr interface is responsible for determining frame intervals instead of using regular clocks (so they can fiddle with prediction etc)
#define VRF_UIACTIVE 2 //we're actually rendering through a headset. use 3d rendering exclusively, with VR UI and stuff.
//interface registered by plugins for VR stuff.
typedef struct plugvrfuncs_s
{
const char *description;
qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init
qboolean (*Init) (vrsetup_t *setupinfo, rendererstate_t *info); //called after graphics context init
qboolean (*SyncFrame)(double *frametime); //called in the client's main loop, to block/tweak frame times. True means the game should render as fast as possible.
qboolean (*Render) (void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3_t angorg[2]));
unsigned int (*SyncFrame)(double *frametime); //called in the client's main loop, to block/tweak frame times. True means the game should render as fast as possible.
qboolean (*Render) (void(*rendereye)(texid_t tex, const pxrect_t *viewport, const vec4_t fovoverride, const float projmatrix[16], const float eyematrix[12]));
void (*Shutdown) (void);
#define plugvrfuncs_name "VR"
} plugvrfuncs_t;

View File

@ -128,7 +128,8 @@ extern qboolean mouseinitialized;
//extern HANDLE hinput, houtput;
extern HCURSOR hArrowCursor, hCustomCursor;
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale);
enum uploadfmt;
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, enum uploadfmt format, float hotx, float hoty, float scale);
qboolean WIN_SetCursor(void *cursor);
void WIN_DestroyCursor(void *cursor);
void WIN_WindowCreated(HWND window);

View File

@ -76,92 +76,92 @@ static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
#define TP_SKIN_CVARS \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVARC(enemycolor, "off", TP_EnemyColor_CB); \
TP_CVARC(teamcolor, "off", TP_TeamColor_CB);
static TP_CVARC(enemycolor, "off", TP_EnemyColor_CB); \
static TP_CVARC(teamcolor, "off", TP_TeamColor_CB);
#else
#define TP_SKIN_CVARS
#endif
#ifdef QUAKESTATS
#define TP_NAME_CVARS \
TP_CVAR(tp_name_none, ""); \
TP_CVAR(tp_name_axe, "axe"); \
TP_CVAR(tp_name_sg, "sg"); \
TP_CVAR(tp_name_ssg, "ssg"); \
TP_CVAR(tp_name_ng, "ng"); \
TP_CVAR(tp_name_sng, "sng"); \
TP_CVAR(tp_name_gl, "gl"); \
TP_CVAR(tp_name_rl, "rl"); \
TP_CVAR(tp_name_lg, "lg"); \
TP_CVAR(tp_name_ra, "ra"); \
TP_CVAR(tp_name_ya, "ya"); \
TP_CVAR(tp_name_ga, "ga"); \
TP_CVAR(tp_name_quad, "quad"); \
TP_CVAR(tp_name_pent, "pent"); \
TP_CVAR(tp_name_ring, "ring"); \
TP_CVAR(tp_name_suit, "suit"); \
TP_CVAR(tp_name_shells, "shells"); \
TP_CVAR(tp_name_nails, "nails"); \
TP_CVAR(tp_name_rockets, "rockets"); \
TP_CVAR(tp_name_cells, "cells"); \
TP_CVAR(tp_name_mh, "mega"); \
TP_CVAR(tp_name_health, "health"); \
TP_CVAR(tp_name_backpack, "pack"); \
TP_CVAR(tp_name_flag, "flag"); \
TP_CVAR(tp_name_nothing, "nothing"); \
TP_CVAR(tp_name_at, "at"); \
TP_CVAR(tp_need_ra, "50"); \
TP_CVAR(tp_need_ya, "50"); \
TP_CVAR(tp_need_ga, "50"); \
TP_CVAR(tp_need_health, "50"); \
TP_CVAR(tp_need_weapon, "35687"); \
TP_CVAR(tp_need_rl, "1"); \
TP_CVAR(tp_need_rockets, "5"); \
TP_CVAR(tp_need_cells, "20"); \
TP_CVAR(tp_need_nails, "40"); \
TP_CVAR(tp_need_shells, "10"); \
TP_CVAR(tp_name_disp, "dispenser"); \
TP_CVAR(tp_name_sentry, "sentry gun"); \
TP_CVAR(tp_name_rune_1, "resistance rune"); \
TP_CVAR(tp_name_rune_2, "strength rune"); \
TP_CVAR(tp_name_rune_3, "haste rune"); \
TP_CVAR(tp_name_rune_4, "regeneration rune"); \
static TP_CVAR(tp_name_none, ""); \
static TP_CVAR(tp_name_axe, "axe"); \
TP_CVAR(tp_name_sg, "sg"); \
TP_CVAR(tp_name_ssg, "ssg"); \
TP_CVAR(tp_name_ng, "ng"); \
TP_CVAR(tp_name_sng, "sng"); \
TP_CVAR(tp_name_gl, "gl"); \
TP_CVAR(tp_name_rl, "rl"); \
TP_CVAR(tp_name_lg, "lg"); \
static TP_CVAR(tp_name_ra, "ra"); \
static TP_CVAR(tp_name_ya, "ya"); \
static TP_CVAR(tp_name_ga, "ga"); \
static TP_CVAR(tp_name_quad, "quad"); \
static TP_CVAR(tp_name_pent, "pent"); \
static TP_CVAR(tp_name_ring, "ring"); \
static TP_CVAR(tp_name_suit, "suit"); \
static TP_CVAR(tp_name_shells, "shells"); \
static TP_CVAR(tp_name_nails, "nails"); \
static TP_CVAR(tp_name_rockets, "rockets"); \
static TP_CVAR(tp_name_cells, "cells"); \
static TP_CVAR(tp_name_mh, "mega"); \
static TP_CVAR(tp_name_health, "health"); \
static TP_CVAR(tp_name_backpack, "pack"); \
static TP_CVAR(tp_name_flag, "flag"); \
static TP_CVAR(tp_name_nothing, "nothing"); \
static TP_CVAR(tp_name_at, "at"); \
static TP_CVAR(tp_need_ra, "50"); \
static TP_CVAR(tp_need_ya, "50"); \
static TP_CVAR(tp_need_ga, "50"); \
static TP_CVAR(tp_need_health, "50"); \
static TP_CVAR(tp_need_weapon, "35687"); \
static TP_CVAR(tp_need_rl, "1"); \
static TP_CVAR(tp_need_rockets, "5"); \
static TP_CVAR(tp_need_cells, "20"); \
static TP_CVAR(tp_need_nails, "40"); \
static TP_CVAR(tp_need_shells, "10"); \
static TP_CVAR(tp_name_disp, "dispenser"); \
static TP_CVAR(tp_name_sentry, "sentry gun"); \
static TP_CVAR(tp_name_rune_1, "resistance rune"); \
static TP_CVAR(tp_name_rune_2, "strength rune"); \
static TP_CVAR(tp_name_rune_3, "haste rune"); \
static TP_CVAR(tp_name_rune_4, "regeneration rune"); \
\
TP_CVAR(tp_name_status_red, "$R"); \
TP_CVAR(tp_name_status_green, "$G"); \
TP_CVAR(tp_name_status_yellow, "$Y"); \
TP_CVAR(tp_name_status_blue, "$B"); \
static TP_CVAR(tp_name_status_red, "$R"); \
static TP_CVAR(tp_name_status_green, "$G"); \
static TP_CVAR(tp_name_status_yellow, "$Y"); \
static TP_CVAR(tp_name_status_blue, "$B"); \
\
TP_CVAR(tp_name_armortype_ga, "g"); \
TP_CVAR(tp_name_armortype_ya, "y"); \
TP_CVAR(tp_name_armortype_ra, "r"); \
TP_CVAR(tp_name_armor, "armor"); \
TP_CVAR(tp_name_weapon, "weapon"); \
TP_CVAR(tp_weapon_order, "78654321"); \
static TP_CVAR(tp_name_armortype_ga, "g"); \
static TP_CVAR(tp_name_armortype_ya, "y"); \
static TP_CVAR(tp_name_armortype_ra, "r"); \
static TP_CVAR(tp_name_armor, "armor"); \
static TP_CVAR(tp_name_weapon, "weapon"); \
static TP_CVAR(tp_weapon_order, "78654321"); \
\
TP_CVAR(tp_name_quaded, "quaded"); \
TP_CVAR(tp_name_pented, "pented"); \
TP_CVAR(tp_name_separator, "/"); \
static TP_CVAR(tp_name_quaded, "quaded"); \
static TP_CVAR(tp_name_pented, "pented"); \
static TP_CVAR(tp_name_separator, "/"); \
\
TP_CVAR(tp_name_enemy, "enemy"); \
TP_CVAR(tp_name_teammate, ""); \
TP_CVAR(tp_name_eyes, "eyes"); \
static TP_CVAR(tp_name_enemy, "enemy"); \
static TP_CVAR(tp_name_teammate, ""); \
static TP_CVAR(tp_name_eyes, "eyes"); \
\
TP_CVAR(loc_name_separator, "-"); \
TP_CVAR(loc_name_ssg, "ssg"); \
TP_CVAR(loc_name_ng, "ng"); \
TP_CVAR(loc_name_sng, "sng"); \
TP_CVAR(loc_name_gl, "gl"); \
TP_CVAR(loc_name_rl, "rl"); \
TP_CVAR(loc_name_lg, "lg"); \
TP_CVAR(loc_name_ga, "ga"); \
TP_CVAR(loc_name_ya, "ya"); \
TP_CVAR(loc_name_ra, "ra"); \
TP_CVAR(loc_name_mh, "mh"); \
TP_CVAR(loc_name_quad, "quad"); \
TP_CVAR(loc_name_pent, "pent"); \
TP_CVAR(loc_name_ring, "ring"); \
TP_CVAR(loc_name_suit, "suit");
static TP_CVAR(loc_name_separator, "-"); \
static TP_CVAR(loc_name_ssg, "ssg"); \
static TP_CVAR(loc_name_ng, "ng"); \
static TP_CVAR(loc_name_sng, "sng"); \
static TP_CVAR(loc_name_gl, "gl"); \
static TP_CVAR(loc_name_rl, "rl"); \
static TP_CVAR(loc_name_lg, "lg"); \
static TP_CVAR(loc_name_ga, "ga"); \
static TP_CVAR(loc_name_ya, "ya"); \
static TP_CVAR(loc_name_ra, "ra"); \
static TP_CVAR(loc_name_mh, "mh"); \
static TP_CVAR(loc_name_quad, "quad"); \
static TP_CVAR(loc_name_pent, "pent"); \
static TP_CVAR(loc_name_ring, "ring"); \
static TP_CVAR(loc_name_suit, "suit");
#else
#define TP_NAME_CVARS
#endif
@ -171,16 +171,16 @@ static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
#define TP_CVARS \
TP_SKIN_CVARS \
TP_NAME_CVARS \
TP_CVAR(cl_fakename, ""); \
static TP_CVAR(cl_fakename, ""); \
TP_CVAR(cl_parseSay, "1"); \
TP_CVAR(cl_parseFunChars, "1"); \
TP_CVAR(cl_triggers, "1"); \
TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \
static TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \
TP_CVAR(tp_forceTriggers, "0"); \
TP_CVAR(tp_loadlocs, "1"); \
TP_CVAR(tp_soundtrigger, "~"); \
static TP_CVAR(tp_soundtrigger, "~"); \
\
TP_CVAR(tp_name_someplace, "someplace")
static TP_CVAR(tp_name_someplace, "someplace")
//create the globals for all the TP cvars.
#define TP_CVAR(name,def) cvar_t name = CVAR(#name, def)
@ -906,10 +906,6 @@ static char *Macro_demoplayback (void)
case DPB_QUAKE2:
return "dm2playback";
#endif
//gcc will warn if we add annother playback and forget here, otherwise I'd use a default.
case DPB_EZTV:
break;
}
return "1"; //unknown.
}
@ -2311,9 +2307,9 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
// no team messages in teamplay 0, except for our own
if (pv->spectator)
{
unsigned int track = Cam_TrackNum(pv);
if (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) )
int track = Cam_TrackNum(pv);
if (track>=0 && (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) ))
{
flags |= TPM_OBSERVEDTEAM;
}
@ -3710,7 +3706,9 @@ void TP_Init (void)
#define TP_CVAR(name,def) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARC(name,def,callback) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARAC(name,def,name2,callback) Cvar_Register (&name, TEAMPLAYVARS);
#define static
TP_CVARS;
#undef static
#undef TP_CVAR
#undef TP_CVARC
#undef TP_CVARAC

View File

@ -173,10 +173,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name
#endif
#ifndef FULLENGINENAME
#define FULLENGINENAME "FTE Quake" //the posh name for the engine
#define FULLENGINENAME "FTE QW" //the posh name for the engine, note that 'Quake' is trademarked so we should not be using it here.
#endif
#ifndef ENGINEWEBSITE
#define ENGINEWEBSITE "^8http://^4fte^8.^4triptohell^8.^4info" //url for program
#define ENGINEWEBSITE "^8https://^4fte^8.^4triptohell^8.^4info" //url for program
#endif
#if !defined(_WIN32) || defined(WINRT)
@ -187,9 +187,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef AVAIL_WASAPI
#endif
#if !(defined(__linux__) || defined(__CYGWIN__)) || defined(ANDROID)
#undef HAVE_GNUTLS
#endif
//#if !(defined(__linux__) || defined(__CYGWIN__)) || defined(ANDROID)
// #undef HAVE_GNUTLS
//#endif
#if !defined(_WIN32) || (defined(_MSC_VER) && (_MSC_VER < 1300)) || defined(FTE_SDL)
#undef HAVE_WINSSPI
#endif
@ -253,7 +253,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef Q2BSPS
#undef Q3BSPS
#undef RFBSPS
#undef WEBSERVER //http server
#undef FTPSERVER //ftp server
#undef WEBCLIENT //http client.
#undef FTPCLIENT //ftp client.
@ -285,7 +284,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef HAVE_PACKET //no udp support
//try to trim the fat
#undef VOICECHAT //too lazy to compile opus
// #undef VOICECHAT //too lazy to compile opus
#undef HLCLIENT //dlls...
#undef HLSERVER //dlls...
// #undef CL_MASTER //bah. use the site to specify the servers.
@ -293,7 +292,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef RAGDOLL //no ode
#undef TCPCONNECT //err...
#undef IRCCONNECT //not happening
#undef PLUGINS //pointless
#if !defined(USE_INTERNAL_BULLET) && !defined(USE_INTERNAL_ODE) && !defined(MODELFMT_GLTF) && !defined(STATIC_EZHUD) && !defined(STATIC_OPENSSL) && !defined(STATIC_Q3)
#undef PLUGINS //pointless
#endif
#undef VM_Q1 //no dlls
#undef MAP_PROC //meh
// #undef HALFLIFEMODELS //blurgh
@ -392,15 +393,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef NO_GNUTLS
#undef HAVE_GNUTLS
#endif
#ifdef NO_WINSSPI
#undef HAVE_WINSSPI
#endif
#ifdef NO_OPENGL
#undef GLQUAKE
#undef USE_EGL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS)
#if (defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(PLUGINS)) && !defined(FTE_TARGET_WEB)
#define HAVE_SSL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS)
#if (defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(PLUGINS)) && !defined(FTE_TARGET_WEB)
//FIXME: HAVE_WINSSPI does not work as a server.
//FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade.
//FIXME: we don't cache server certs
@ -456,7 +460,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HAVE_TCP
#undef TCPCONNECT
#undef IRCCONNECT
#undef WEBSERVER //http server
#undef FTPSERVER //ftp server
#undef FTPCLIENT //ftp client.
#if !defined(FTE_TARGET_WEB)
@ -488,7 +491,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef Q2SERVER
#undef Q3SERVER
#undef HLSERVER
#undef WEBSERVER
#undef FTPSERVER
#undef SUBSERVERS
#undef VM_Q1
@ -558,6 +560,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#else
#define IFMINIMAL(x,y) y
#endif
#ifdef FTE_TARGET_WEB
#define IFWEB(x,y) x
#else
#define IFWEB(x,y) y
#endif
// defs common to client and server
@ -902,8 +909,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_NET_LIGHTSTYLES (INVALID_LIGHTSTYLE+1) // 16bit. the last index MAY be used to signify an invalid lightmap in the bsp, but is still valid for rtlights.
#define MAX_STANDARDLIGHTSTYLES 64
#define MAX_PRECACHE_MODELS 4096 // 14bit.
#define MAX_PRECACHE_SOUNDS 2048 // 14bit.
#define MAX_PRECACHE_MODELS 16384 // 14bit.
#define MAX_PRECACHE_SOUNDS 4096 // 14bit.
#define MAX_SSPARTICLESPRE 1024 // 14bit. precached particle effect names, for server-side pointparticles/trailparticles.
#define MAX_VWEP_MODELS 32

View File

@ -177,19 +177,19 @@ enum q1contents_e
Q1CONTENTS_SLIME = -4,
Q1CONTENTS_LAVA = -5,
Q1CONTENTS_SKY = -6,
//#define Q1CONTENTS_ORIGIN -7 /*not known to engine - origin or something*/
Q1CONTENTS_CLIP = -8, /*solid to players+monsters, but not tracelines*/
Q1CONTENTS_CURRENT_0 = -9, /*moves player*/
Q1CONTENTS_CURRENT_90 = -10, /*moves player*/
Q1CONTENTS_CURRENT_180 = -11, /*moves player*/
Q1CONTENTS_CURRENT_270 = -12, /*moves player*/
Q1CONTENTS_CURRENT_UP = -13, /*moves player*/
Q1CONTENTS_CURRENT_DOWN = -14, /*moves player*/
Q1CONTENTS_TRANS = -15, /*should be solid I guess*/
//#define HLCONTENTS_ORIGIN -7 /*not known to engine - origin or something*/
HLCONTENTS_CLIP = -8, /*solid to players+monsters, but not tracelines*/
HLCONTENTS_CURRENT_0 = -9, /*moves player*/
HLCONTENTS_CURRENT_90 = -10, /*moves player*/
HLCONTENTS_CURRENT_180 = -11, /*moves player*/
HLCONTENTS_CURRENT_270 = -12, /*moves player*/
HLCONTENTS_CURRENT_UP = -13, /*moves player*/
HLCONTENTS_CURRENT_DOWN = -14, /*moves player*/
HLCONTENTS_TRANS = -15, /*empty, but blocks pvs (for opaque non-solid windows, like vanilla-q1 water)*/
Q1CONTENTS_LADDER = -16, /*player can climb up/down*/
Q1CONTENTS_MONSTERCLIP = -17, /*solid to monster movement*/
Q1CONTENTS_PLAYERCLIP = -18, /*solid to player movement*/
Q1CONTENTS_CORPSE = -19, /*solid to tracelines*/
Q1CONTENTS_CORPSE = -19, /*solid to tracelines but not boxes*/
};
// !!! if this is changed, it must be changed in asm_i386.h too !!!
@ -572,7 +572,7 @@ typedef struct
#define Q2CONTENTS_ORIGIN 0x01000000 // removed before bsping an entity
#define Q2CONTENTS_MONSTER FTECONTENTS_BODY //0x02000000 // should never be on a brush, only in game
#define Q2CONTENTS_DEADMONSTER FTECONTENTS_CORPSE //0x04000000
#define Q2CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs
#define Q2CONTENTS_DETAIL FTECONTENTS_DETAIL // 0x08000000 // brushes to be added after vis leafs
#define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define Q2CONTENTS_LADDER 0x20000000
//0x40000000
@ -606,7 +606,7 @@ typedef struct
#define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000
#define Q3CONTENTS_BODY FTECONTENTS_BODY //0x02000000
#define Q3CONTENTS_CORPSE FTECONTENTS_CORPSE //0x04000000
#define Q3CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000
#define Q3CONTENTS_DETAIL FTECONTENTS_DETAIL //0x08000000
#define Q3CONTENTS_STRUCTURAL 0x10000000
#define Q3CONTENTS_TRANSLUCENT 0x20000000
#define Q3CONTENTS_TRIGGER 0x40000000
@ -649,11 +649,11 @@ typedef struct
//#define TI_KINGPIN_WNDW33 0x4000
//#define TI_KINGPIN_WNDW64 0x8000
#define TI_Q2EX_ALPHATEST (1u<<25)
#define TI_N64_UV (1u<<28)
#define TI_N64_SCROLL_X (1u<<29)
#define TI_N64_SCROLL_Y (1u<<30)
#define TI_N64_SCROLL_FLIP (1u<<31)
#define TI_Q2EX_ALPHATEST (1u<<25) //seems to be a thing in other pre q2e engines too.
#define TI_N64_UV (1u<<28) //2 qu per texel instead of 1... (still 16qu per luxel)
#define TI_N64_SCROLL_X (1u<<29) //scrolls fully right each second.
#define TI_N64_SCROLL_Y (1u<<30) //scrolls fully down each second.
#define TI_N64_SCROLL_FLIP (1u<<31) //reverses the scroll dirs.
//Surface flags
//#define Q3SURFACEFLAG_NODAMAGE 0x1 // never give falling damage

View File

@ -36,6 +36,7 @@ static const cvar_t dpcompat_console = {0};
int Cmd_ExecLevel;
qboolean cmd_didwait;
qboolean cmd_blockwait;
static qboolean cmd_stuffedcmdline;
void Cmd_ForwardToServer (void);
@ -590,68 +591,67 @@ quake -nosound +cmd amlev1
*/
void Cmd_StuffCmds (void)
{
int i, j;
int i;
int s;
char *text, *build, c;
char *text;
const char *arg;
int pluscmd = false;
if (cmd_stuffedcmdline)
return; //don't do it multiple times
// build the combined string to parse from
s = 0;
s = 2;
for (i=1 ; i<com_argc ; i++)
{
if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost
s += Q_strlen (com_argv[i]) + 3;
s += Q_strlen (com_argv[i])*2 + 4;
}
if (!s)
return;
text = (char*)Z_Malloc (s+1);
text = (char*)Z_Malloc (s+2);
text[0] = 0;
for (i=1 ; i<com_argc ; i++)
{
if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost
if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t') || strchr(com_argv[i], '@') || strchr(com_argv[i], '/') || strchr(com_argv[i], '\\'))
arg = com_argv[i];
if ((*arg == '+' || *arg == '-') && !(arg[1] >= '0' && arg[1] <= '9')) //we only really want the '+foo arg' commands, split by +/- prefixes. if its a -1 or +1 then that's a numerical parameter, not a separate command!
{
Q_strcat (text,"\"");
Q_strcat (text,com_argv[i]);
Q_strcat (text,"\"");
if (*text)
{
Q_strcat (text, "\n");
Cbuf_AddText (text, RESTRICT_LOCAL);
*text = 0;
}
pluscmd = *arg++ == '+';
}
if (pluscmd)
{
if (*text)
Q_strcat (text, " ");
if (strchr(arg, ' ') || strchr(arg, '\t') || strchr(arg, '@') || strchr(arg, '/') || strchr(arg, '\\'))
COM_QuotedString(arg, text+strlen(text),s-strlen(text), false);
else
Q_strcat (text,arg);
}
else
Q_strcat (text,com_argv[i]);
if (i != com_argc-1)
Q_strcat (text, " ");
}
// pull out the commands
build = (char*)Z_Malloc (s+1);
build[0] = 0;
for (i=0 ; i<s-1 ; i++)
if (*text)
{
if (text[i] == '+')
{
i++;
for (j=i ; ((text[j-1] != ' ') || ((text[j] != '+') && (text[j] != '-'))) && (text[j] != 0) ; j++)
;
c = text[j];
text[j] = 0;
Q_strcat (build, text+i);
Q_strcat (build, "\n");
text[j] = c;
i = j-1;
}
Q_strcat (text, "\n");
Cbuf_AddText (text, RESTRICT_LOCAL);
}
if (build[0])
Cbuf_AddText (build, RESTRICT_LOCAL);
Z_Free (text);
Z_Free (build);
cmd_stuffedcmdline = true; //don't add multiple times.
//and exec anything added.
Cbuf_Execute ();
}
#if defined(HAVE_LEGACY) && defined(HAVE_CLIENT)
@ -784,8 +784,8 @@ static void Cmd_Exec_f (void)
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
FS_DisplayPath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_DisplayPath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
}
return;
@ -802,8 +802,8 @@ static void Cmd_Exec_f (void)
char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig));
FS_DisplayPath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_DisplayPath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
}
return;
@ -4137,7 +4137,7 @@ static void Cmd_WriteConfig_f(void)
vfsfile_t *f;
char *filename;
char fname[MAX_QPATH];
char sysname[MAX_OSPATH];
char displayname[MAX_OSPATH];
qboolean all = true;
//special variation that only saves if an archived cvar was actually modified.
@ -4154,7 +4154,7 @@ static void Cmd_WriteConfig_f(void)
MasterInfo_WriteServers();
#endif
f = FS_OpenWithFriends(fname, sysname, sizeof(sysname), 4, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg", "dlcache/*.pk3*");
f = FS_OpenWithFriends(fname, displayname, sizeof(displayname), 4, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg", "dlcache/*.pk3*");
all = cfg_save_all.ival;
}
@ -4170,7 +4170,7 @@ static void Cmd_WriteConfig_f(void)
return;
}
FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname));
FS_DisplayPath(fname, FS_BASEGAMEONLY, displayname, sizeof(displayname));
FS_CreatePath(fname, FS_BASEGAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY);
@ -4192,7 +4192,7 @@ static void Cmd_WriteConfig_f(void)
Q_snprintfz(fname, sizeof(fname), "configs/%s", filename);
COM_DefaultExtension(fname, ".cfg", sizeof(fname));
FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname));
FS_DisplayPath(fname, FS_BASEGAMEONLY, displayname, sizeof(displayname));
FS_CreatePath(fname, FS_BASEGAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY);
@ -4200,7 +4200,7 @@ static void Cmd_WriteConfig_f(void)
}
if (!f)
{
Con_Printf (CON_ERROR "Couldn't write config %s\n", sysname);
Con_Printf (CON_ERROR "Couldn't write config %s\n", displayname);
return;
}
@ -4237,7 +4237,7 @@ static void Cmd_WriteConfig_f(void)
Cvar_Saved();
Con_Printf ("Wrote %s\n",sysname);
Con_Printf ("Wrote %s\n",displayname);
}
static void Cmd_Reset_f(void)
@ -4426,6 +4426,7 @@ Cmd_Init
*/
void Cmd_Init (void)
{
cmd_stuffedcmdline = false;
macro_count = 0;
//
// register our commands

View File

@ -85,7 +85,7 @@ qboolean Mod_DoCRC(model_t *mod, char *buffer, int buffersize)
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models;
extern cvar_t r_noaliasshadows;
extern cvar_t r_skin_overlays;
//extern cvar_t r_skin_overlays;
extern cvar_t mod_md3flags;
@ -1020,7 +1020,7 @@ typedef struct
float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0.
void *needsfree[FRAME_BLENDS*2];
} skellerps_t;
static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestateregion_s *fs, int numbones, const galiasinfo_t *inf)
static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestateregion_s *fs, const galiasbone_t *boneinf, int numbones, const galiasinfo_t *inf)
{
int frame1; //signed, because frametime might be negative...
int frame2;
@ -1066,7 +1066,7 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
{
lerps->frac[l] = fs->lerpweight[b];
lerps->needsfree[l] = BZ_Malloc(sizeof(float)*12*numbones);
lerps->pose[l] = g->GetRawBones(inf, g, time, lerps->needsfree[l], numbones);
lerps->pose[l] = g->GetRawBones(inf, g, time, lerps->needsfree[l], boneinf, numbones);
if (lerps->pose[l])
l++;
else
@ -1107,14 +1107,14 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
{
totalweight += lerps->frac[l];
lerps->needsfree[l] = NULL;
lerps->pose[l++] = (float*)g->boneofs + numbones*12*frame1;
lerps->pose[l++] = (float*)g->boneofs + inf->numbones*12*frame1;
}
lerps->frac[l] = (mlerp)*fs->lerpweight[b];
if (lerps->frac[l]>0)
{
totalweight += lerps->frac[l];
lerps->needsfree[l] = NULL;
lerps->pose[l++] = (float*)g->boneofs + numbones*12*frame2;
lerps->pose[l++] = (float*)g->boneofs + inf->numbones*12*frame2;
}
}
}
@ -1153,16 +1153,13 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
/*
finds the various blend info. returns number of bone blocks used.
*/
static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone)
static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone, const galiasbone_t *boneinfo)
{
int bonegroup;
int cbone = 0;
int endbone;
int numbonegroups=0;
if (lastbone > inf->numbones)
lastbone = inf->numbones;
for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++)
{
endbone = fstate->g[bonegroup].endbone;
@ -1176,7 +1173,7 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
if (lerps->firstbone == lerps->endbone)
continue;
if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], inf->numbones, inf)) //if there's no animations in this model, use the base pose instead.
if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], boneinfo, lerps->endbone, inf)) //if there's no animations in this model, use the base pose instead.
{
if (!inf->baseframeofs)
continue; //nope, not happening.
@ -1200,11 +1197,11 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
return value is the lastbone argument, or less if the model simply doesn't have that many bones.
_always_ writes into result
*/
static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *result, skeltype_t skeltype, int firstbone, int lastbone)
static int Alias_BlendBoneData(galiasinfo_t *inf, const framestate_t *fstate, float *result, skeltype_t skeltype, int firstbone, int lastbone, const galiasbone_t *boneinfo)
{
skellerps_t lerps[FS_COUNT], *lerp;
size_t bone, endbone = 0;
size_t numgroups = Alias_FindRawSkelData(inf, fstate, lerps, firstbone, lastbone);
size_t numgroups = Alias_FindRawSkelData(inf, fstate, lerps, firstbone, lastbone, boneinfo);
float *pose, *matrix;
int k, b;
@ -1219,7 +1216,7 @@ static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *r
memcpy(result+bone*12, lerp->pose[0]+bone*12, (endbone-bone)*12*sizeof(float));
else
{
//set up the identity matrix
//blend each influence
for (; bone < endbone; bone++)
{
pose = result + 12*bone;
@ -1247,7 +1244,7 @@ static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *r
only writes targetbuffer if needed. the return value is the only real buffer result.
assumes that all blended types are the same. probably buggy, but meh.
*/
static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t maxbufferbones)
static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t numbones, const galiasbone_t *boneinfo)
{
skellerps_t lerps[FS_COUNT], *lerp;
size_t numgroups;
@ -1256,7 +1253,7 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
lerps[0].skeltype = SKEL_IDENTITY; //just in case.
#ifdef SKELETALOBJECTS
if (framestate->bonestate && framestate->bonecount >= inf->numbones)
if (framestate->bonestate && framestate->bonecount >= numbones)
{
lerps[0].skeltype = framestate->skeltype;
lerps[0].firstbone = 0;
@ -1270,13 +1267,18 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
else
#endif
{
numgroups = Alias_FindRawSkelData(inf, framestate, lerps, 0, inf->numbones);
numgroups = Alias_FindRawSkelData(inf, framestate, lerps, 0, numbones, boneinfo);
}
//try to return data in-place.
if (numgroups==1 && lerps[0].lerpcount == 1)
{
ret = Alias_ConvertBoneData(lerps[0].skeltype, lerps[0].pose[0], min(lerps[0].endbone, inf->numbones), inf->ofsbones, targettype, targetbuffer, targetbufferalt, maxbufferbones);
ret = Alias_ConvertBoneData(lerps[0].skeltype, lerps[0].pose[0], min(lerps[0].endbone, inf->numbones), inf->ofsbones, targettype, targetbuffer, targetbufferalt, numbones);
if (ret == lerps[0].needsfree[0])
{ //bum
memcpy(targetbuffer, ret, sizeof(float)*min(lerps[0].endbone, numbones)*12);
ret = targetbuffer;
}
BZ_Free(lerps[0].needsfree[0]);
return ret;
}
@ -1365,7 +1367,7 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
}
}
return Alias_ConvertBoneData(lerps[0].skeltype, targetbuffer, inf->numbones, inf->ofsbones, targettype, targetbuffer, targetbufferalt, maxbufferbones);
return Alias_ConvertBoneData(lerps[0].skeltype, targetbuffer, inf->numbones, inf->ofsbones, targettype, targetbuffer, targetbufferalt, numbones);
}
static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, galiasinfo_t *inf)
@ -1375,9 +1377,9 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali
const float *morphweights;
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES);
meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
morphweights = inf->AnimateMorphs?inf->AnimateMorphs(inf, framestate):NULL;
morphweights = inf->AnimateMorphs?inf->AnimateMorphs(inf, framestate, alloca(sizeof(*morphweights)*inf->nummorphs)):NULL;
if (morphweights)
{
size_t m,v;
@ -1820,6 +1822,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
{
//if we have skeletal xyz info, but no skeletal weights, then its a partial model that cannot possibly be animated.
meshcache.usebonepose = NULL;
meshcache.bonecachetype = -1;
mesh->xyz_array = inf->ofs_skel_xyz;
mesh->xyz2_array = NULL;
mesh->normals_array = inf->ofs_skel_norm;
@ -1875,7 +1878,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);
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
#ifndef SERVERONLY
if (inf->shares_bones != surfnum && qrenderer)
Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone);
@ -1885,7 +1888,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);
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
//hardware bone animation
mesh->xyz_array = inf->ofs_skel_xyz;
@ -2632,7 +2635,7 @@ static qboolean Mod_Trace(model_t *model, int forcehullnum, const framestate_t *
if (curbonesurf != mod->shares_bones)
{
curbonesurf = mod->shares_bones;
bonepose = Alias_GetBoneInformation(mod, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES);
bonepose = Alias_GetBoneInformation(mod, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES, NULL);
}
posedata = alloca(mod->numverts*sizeof(vecV_t));
Alias_TransformVerticies_V(bonepose, mod->numverts, mod->ofs_skel_idx[0], mod->ofs_skel_weight[0], mod->ofs_skel_xyz[0], posedata[0]);
@ -3170,7 +3173,7 @@ static void Mod_GenerateMeshVBO(model_t *mod, galiasinfo_t *galias)
}
}
else
Con_DPrintf("\"%s\":\"%s\" exceeds gpu bone limit and will be software-skinned - %i > %i\n", mod->name, galias->surfacename, k, sh_config.max_gpu_bones);
Con_DPrintf(CON_WARNING"PERF: \"%s\":\"%s\" exceeds gpu bone limit and will be software-skinned - %i > %i\n", mod->name, galias->surfacename, k, sh_config.max_gpu_bones);
}
if (galias->mappedbones)
{
@ -3834,8 +3837,6 @@ static void Mod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight )
static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model_t *loadmodel, daliasskintype_t *pskintype, uploadfmt_t skintranstype)
{
skinframe_t *frames;
char skinname[MAX_QPATH];
char alttexpath[MAX_QPATH];
int i;
int s, t;
float sinter;
@ -3843,8 +3844,6 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
daliasskininterval_t *intervals;
qbyte *data, *saved;
galiasskin_t *outskin = galias->ofsskins;
const char *slash;
unsigned int texflags;
s = pq1inmodel->skinwidth*pq1inmodel->skinheight;
for (i = 0; i < pq1inmodel->numskins; i++)
@ -3857,37 +3856,15 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
//but only preload it if we have no replacement.
outskin->numframes=1;
if (1 || /*!TEXVALID(texture) ||*/ (loadmodel->engineflags & MDLF_NOTREPLACEMENTS))
{
//we're not using 24bits
frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames)+s);
saved = (qbyte*)(frames+1);
frames[0].texels = saved;
memcpy(saved, pskintype+1, s);
if (i == 0) //Vanilla bug: ONLY skin 0 is flood-filled (the vanilla code operates on a cached 'skin' variable that does NOT get updated between skins reflooding skin 0). We still don't like flood fills either. Hexen2 has the same issue.
Mod_FloodFillSkin(saved, outskin->skinwidth, outskin->skinheight);
}
else
{
frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames));
Q_snprintfz(skinname, sizeof(skinname), "%s_%i.lmp", slash, i);
frames[0].texnums.base = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, skintranstype);
if (r_fb_models.ival)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_luma.lmp", slash, i);
frames[0].texnums.fullbright = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_TRANS8_FULLBRIGHT);
}
if (r_loadbumpmapping)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_norm.lmp", slash, i);
frames[0].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP|IF_NOSRGB, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL);
}
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_shirt.lmp", slash, i);
frames[0].texnums.upperoverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_pants.lmp", slash, i);
frames[0].texnums.loweroverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
}
//the actual texture gets loaded after the shader.
frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames)+s);
saved = (qbyte*)(frames+1);
frames[0].texels = saved;
memcpy(saved, pskintype+1, s);
if (i == 0) //Vanilla bug: ONLY skin 0 is flood-filled (the vanilla code operates on a cached 'skin' variable that does NOT get updated between skins reflooding skin 0). We still don't like flood fills either. Hexen2 has the same issue.
Mod_FloodFillSkin(saved, outskin->skinwidth, outskin->skinheight);
Q_snprintfz(frames[0].shadername, sizeof(frames[0].shadername), "%s_%i.lmp", loadmodel->name, i);
frames[0].shader = NULL;
frames[0].defaultshader = NULL;
@ -5135,11 +5112,11 @@ int Mod_GetNumBones(model_t *model, qboolean allowtags)
return 0;
}
int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result)
int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, const galiasbone_t *boneinfo, const framestate_t *fstate, float *result)
{
#ifdef SKELETALMODELS
if (model && model->type == mod_alias)
return Alias_BlendBoneData(Mod_Extradata(model), fstate, result, SKEL_RELATIVE, firstbone, lastbone);
return Alias_BlendBoneData(Mod_Extradata(model), fstate, result, SKEL_RELATIVE, firstbone, lastbone, boneinfo);
#endif
#ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife)
@ -5156,7 +5133,10 @@ galiasbone_t *Mod_GetBoneInfo(model_t *model, int *numbones)
if (!model || model->type != mod_alias)
{
*numbones = 0;
return NULL;
}
inf = Mod_Extradata(model);
@ -5252,7 +5232,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
}
else //try getting the data from the frame state
{
numbones = Mod_GetBoneRelations(model, 0, tagnum+1, fstate, relatives);
numbones = Mod_GetBoneRelations(model, 0, tagnum+1, NULL, fstate, relatives);
lerps = relatives;
}
@ -5323,7 +5303,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
//try getting the data from the frame state
if (!numbonegroups)
numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones);
numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones, NULL);
//try base pose?
if (!numbonegroups && inf->baseframeofs)
@ -5677,7 +5657,7 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
while(surfaceidx-->0 && inf)
inf = inf->nextsurf;
if (!inf || num >= inf->numanimations)
if (!inf || (unsigned)num >= (unsigned)inf->numanimations)
return NULL;
group = inf->ofsanimations;
return group[num].name;

View File

@ -49,20 +49,27 @@ typedef struct galiasevent_s
char *data;
} galiasevent_t;
typedef struct galiasrefpose_s
{
vec4_t quat;
vec3_t org;
vec3_t scale;
} galiasrefpose_t;
//a frame group (aka: animation)
typedef struct galiasanimation_s
{
#ifdef SKELETALMODELS
skeltype_t skeltype; //for models with transforms, states that bones need to be transformed from their parent.
//this is actually bad, and can result in bones shortening as they interpolate.
float *(QDECL *GetRawBones)(const struct galiasinfo_s *mesh, const struct galiasanimation_s *a, float time, float *bonematrixstorage, int numbones);
float *(QDECL *GetRawBones)(const struct galiasinfo_s *mesh, const struct galiasanimation_s *a, float time, float *bonematrixstorage, const struct galiasbone_s *boneinf, int numbones);
void *boneofs; //numposes*12*numbones
#endif
qboolean loop;
int numposes;
//float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1]
float rate; //average framerate of animation.
int action;
int action; //-1 for none.
float actionweight;
#ifdef NONSKELETALMODELS
galiaspose_t *poseofs;
@ -76,9 +83,15 @@ typedef struct galiasbone_s galiasbone_t;
struct galiasbone_s
{
char name[64];
#if MAX_BONES>32767
int parent;
#else
short parent;
#endif
unsigned char group;
// float radius;
float inverse[12];
galiasrefpose_t ref;
};
typedef struct
@ -180,10 +193,10 @@ typedef struct galiasinfo_s
#ifdef SKELETALMODELS
boneidx_t *bonemap; //filled in automatically if our mesh has more gpu bones than we can support
unsigned int mappedbones;
unsigned int mappedbones; //number of private per-mesh bones.
unsigned int nummorphs; //extra data after the xyz/norm/stvect arrays
const float *(QDECL *AnimateMorphs)(const struct galiasinfo_s *surf, const framestate_t *framestate);
int meshrootbone;
const float *(QDECL *AnimateMorphs)(const struct galiasinfo_s *surf, const framestate_t *framestate, float *resultmorphs); //returns a float weight[nummorphs] array (base verts have an implicit weight of 1, so these are purely additive)
int meshrootbone; //unused by engine. for loader callbacks to (ab)use
float *baseframeofs; /*non-heirachical*/
int numbones;
@ -246,6 +259,7 @@ typedef struct modplugfuncs_s
void (QDECL *VectorAngles)(const float *forward, const float *up, float *result, qboolean meshpitch);
void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void (QDECL *GenMatrixPosQuat4Scale)(const vec3_t pos, const vec4_t quat, const vec3_t scale, float result[12]);
void (QDECL *QuaternionSlerp)(const vec4_t p, vec4_t q, float t, vec4_t qt);
//bone stuff
void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount);
@ -267,13 +281,10 @@ typedef struct modplugfuncs_s
void (*RenderDynamicLightmaps) (struct msurface_s *surf);
entity_t *(*NewSceneEntity) (void);
void (*EndSubmodelLoad)(struct model_s *submod, int modelloadstate);
#if sizeof_index_t==2
#define plugmodfuncs_name "Models"
#else
#define plugmodfuncs_name "Models_IDX" STRINGIFY(sizeof_index_t)
#endif
#define plugmodfuncs_name_idxpostfix "_IDX" STRINGIFY(sizeof_index_t)
#define plugmodfuncs_name "Models" plugmodfuncs_name_idxpostfix
} plugmodfuncs_t;
#define MODPLUGFUNCS_VERSION 3
#define MODPLUGFUNCS_VERSION 4
#ifdef SKELETALMODELS
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);

View File

@ -1273,7 +1273,7 @@ int MSG_ReadSize16 (sizebuf_t *sb)
{
int solid = (((ssolid>>7) & 0x1F8) - 32+32768)<<16; /*up can be negative*/
solid|= ((ssolid & 0x1F)<<3);
solid|= ((ssolid & 0x3E0)<<10);
solid|= ((ssolid & 0x3E0)<<6);
return solid;
}
}
@ -2192,6 +2192,20 @@ int MSG_ReadChar (void)
return c;
}
int MSG_PeekByte(void)
{
unsigned int msg_readcount;
if (msg_readmsg->packing!=SZ_RAWBYTES)
return -1;
msg_readcount = msg_readmsg->currentbit>>3;
if (msg_readcount+1 > msg_readmsg->cursize)
return -1;
return (unsigned char)msg_readmsg->data[msg_readcount];
}
int MSG_ReadByte (void)
{
unsigned char c;
@ -2625,6 +2639,7 @@ void MSGQW_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *move, int protove
}
}
#ifdef HAVE_SERVER
void MSGQ2_ReadDeltaUsercmd (client_t *cl, const usercmd_t *from, usercmd_t *move)
{
int bits;
@ -2729,6 +2744,7 @@ void MSGQ2_ReadDeltaUsercmd (client_t *cl, const usercmd_t *from, usercmd_t *mov
else
move->lightlevel = MSG_ReadByte ();
}
#endif
void MSG_ReadData (void *data, int len)
{
@ -5671,7 +5687,11 @@ static void COM_Version_f (void)
Con_Printf("Renderers:");
#ifdef GLQUAKE
#ifdef GLESONLY
Con_Printf(" OpenGLES");
#ifdef FTE_TARGET_WEB //shuld we be just asking the video code for a list?...
Con_Printf(" WebGL");
#else
Con_Printf(" OpenGLES");
#endif
#else
Con_Printf(" OpenGL");
#endif
@ -5711,6 +5731,10 @@ static void COM_Version_f (void)
Con_Printf("Compiled with Cygwin\n");
#endif
#ifdef FTE_TARGET_WEB
Con_Printf("Compiled with emscripten %i.%i.%i\n", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
#endif
#ifdef __clang__
Con_Printf("Compiled with clang version: %i.%i.%i (%s)\n",__clang_major__, __clang_minor__, __clang_patchlevel__, __VERSION__);
#elif defined(__GNUC__)
@ -5831,28 +5855,36 @@ static void COM_Version_f (void)
#if !defined(VOICECHAT)
Con_Printf(" disabled");
#else
#ifdef SPEEX_STATIC
Con_Printf(" speex");
Con_DPrintf("^h(static)");
#else
Con_Printf(" speex^h(dynamic)");
#ifdef HAVE_SPEEX
#ifdef SPEEX_STATIC
Con_Printf(" speex");
Con_DPrintf("^h(static)");
#else
Con_Printf(" speex^h(dynamic)");
#endif
#endif
#ifdef OPUS_STATIC
Con_Printf(" opus");
Con_DPrintf("^h(static)");
#else
Con_Printf(" opus^h(dynamic)");
#ifdef HAVE_OPUS
#ifdef OPUS_STATIC
Con_Printf(" opus");
Con_DPrintf("^h(static)");
#else
Con_Printf(" opus^h(dynamic)");
#endif
#endif
#endif
Con_Printf("\n");
Con_Printf("^3Audio Decoders:^7");
#ifdef FTE_TARGET_WEB
Con_DPrintf(" javascript");
#endif
#ifndef AVAIL_OGGVORBIS
Con_DPrintf(" ^h(disabled: Ogg Vorbis)^7");
#elif defined(LIBVORBISFILE_STATIC)
Con_Printf(" Ogg Vorbis");
Con_Printf(" Ogg-Vorbis");
Con_DPrintf("^h(static)");
#else
Con_Printf(" Ogg Vorbis^h(dynamic)");
Con_Printf(" Ogg-Vorbis^h(dynamic)");
#endif
#if defined(AVAIL_MP3_ACM)
Con_Printf(" mp3(system)");
@ -5893,7 +5925,12 @@ static void COM_Version_f (void)
Con_DPrintf(" ^h(disabled: freetype2)^7");
#endif
#ifdef AVAIL_OPENAL
Con_Printf(" openal^h(dynamic)");
#ifdef FTE_TARGET_WEB
Con_Printf(" WebAudio");
Con_DPrintf("^h(static)");
#else
Con_Printf(" OpenAL^h(dynamic)");
#endif
#else
Con_DPrintf(" ^h(disabled: openal)^7");
#endif
@ -5986,12 +6023,19 @@ static void COM_Version_f (void)
#ifdef FTPSERVER
Con_Printf(" FTPServer");
#endif
#ifdef HAVE_TCP
#ifdef TCPCONNECT
Con_Printf(" TCPConnect");
#if (defined(SUPPORT_ICE)&&defined(HAVE_DTLS)) || defined(FTE_TARGET_WEB)
Con_Printf(" WebRTC");
#endif
#ifdef FTE_TARGET_WEB
Con_Printf(" WebSocket/WSS");
#else
Con_Printf(" ^h(disabled: TCP)");
#if defined(HAVE_TCP)
#ifdef TCPCONNECT
Con_Printf(" TCPConnect");
#endif
#else
Con_Printf(" ^h(disabled: TCP)");
#endif
#endif
#ifdef HAVE_GNUTLS //on linux
Con_Printf(" GnuTLS");
@ -6705,9 +6749,6 @@ void COM_Init (void)
//random should be random from the start...
srand(time(0));
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
#ifdef LOADERTHREAD
COM_InitWorkerThread();
#endif

View File

@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#define VK_NO_STDINT_H //we're handling this. please don't cause conflicts. grr.
#if __STDC_VERSION__ >= 199901L || defined(__GNUC__)
#if __STDC_VERSION__ >= 199901L || defined(__GNUC__) || _MSC_VER >= 1600
//C99 has a stdint header which hopefully contains an intptr_t
//its optional... but if its not in there then its unlikely you'll actually be able to get the engine to a stage where it *can* load anything
#include <stdint.h>
@ -43,6 +43,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define quint32_t uint32_t
#define qint64_t int64_t
#define quint64_t uint64_t
#define qintmax_t intmax_t
#define quintmax_t uintmax_t
#else
#define qint8_t signed char //be explicit with this one.
#define quint8_t unsigned char
@ -85,6 +87,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define quint64_t unsigned qint64_t
#endif
#define qintmax_t qint64_t
#define quintmax_t quint64_t
#ifndef uint32_t
#define int8_t qint8_t
#define uint8_t quint8_t
@ -96,6 +101,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define uint64_t quint64_t
#define intptr_t qintptr_t
#define uintptr_t quintptr_t
#define intmax_t qintmax_t
#define uintmax_t quintmax_t
#endif
#endif
@ -345,6 +352,8 @@ void MSG_WriteDir (sizebuf_t *sb, float dir[3]);
extern qboolean msg_badread; // set if a read goes beyond end of message
extern struct netprim_s msg_nullnetprim;
int MSG_PeekByte(void);
void MSG_BeginReading (sizebuf_t *sb, struct netprim_s prim);
void MSG_ChangePrimitives(struct netprim_s prim);
int MSG_GetReadCount(void);
@ -381,7 +390,6 @@ void MSGQ2_ReadDeltaUsercmd (struct client_s *cl, const struct usercmd_s *from,
void MSG_ReadData (void *data, int len);
void MSG_ReadSkip (int len);
int MSG_ReadSize16 (sizebuf_t *sb);
void MSG_WriteSize16 (sizebuf_t *sb, unsigned int sz);
void COM_DecodeSize(int solid, float *mins, float *maxs);
@ -568,6 +576,7 @@ typedef struct searchpath_s
char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages.
char purepath[256]; //server tracks the path used to load them so it can tell the client
char prefix[MAX_QPATH]; //prefix to add to each file within the archive. may also be ".." to mean ignore the top-level path.
int crc_seed; //can skip some hashes if this is cached.
int crc_check; //client sorts packs according to this checksum
int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded.
int orderkey; //used to check to see if the paths were actually changed or not.
@ -607,6 +616,7 @@ qboolean FS_GetLocMTime(flocation_t *location, time_t *modtime);
const char *FS_GetPackageDownloadFilename(flocation_t *loc); //returns only packages (or null)
const char *FS_GetRootPackagePath(flocation_t *loc); //favours packages, but falls back on gamedirs.
searchpath_t *FS_GetPackage(const char *package); //for fancy stuff that should probably have its own helper...
qboolean FS_GetPackageDownloadable(const char *package);
char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly);
char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean ext);
@ -660,12 +670,12 @@ char *VFS_GETS(vfsfile_t *vf, char *buffer, size_t buflen);
void VARGS VFS_PRINTF(vfsfile_t *vf, const char *fmt, ...) LIKEPRINTF(2);
enum fs_relative{
//note that many of theses paths can map to multiple system locations. FS_NativePath can vary somewhat in terms of what it returns, generally favouring writable locations rather then the path that actually contains a file.
//note that many of theses paths can map to multiple system locations. FS_SystemPath/FS_DisplayPath can vary somewhat in terms of what it returns, generally favouring writable locations rather then the path that actually contains a file.
FS_BINARYPATH, //where the 'exe' is located. we'll check here for dlls too.
FS_LIBRARYPATH, //for system dlls and stuff
FS_ROOT, //./ (effectively -homedir if enabled, otherwise effectively -basedir arg)
FS_SYSTEM, //a system path. absolute paths are explicitly allowed and expected, but not required.
#define FS_RELATIVE_ISSPECIAL(r) ((r)<FS_GAME)
//after this point, all types must be relative to a gamedir
FS_GAME, //standard search (not generally valid for writing/save/rename/delete/etc)
FS_GAMEONLY, //$gamedir/
@ -676,6 +686,8 @@ enum fs_relative{
qboolean COM_WriteFile (const char *filename, enum fs_relative fsroot, const void *data, int len);
char *FS_AbbreviateSize(char *buf, size_t bufsize, qofs_t fsize); //just formats a filesize into the buffer and returns it.
void FS_FlushFSHashWritten(const char *fname);
void FS_FlushFSHashRemoved(const char *fname);
void FS_FlushFSHashFull(void); //too much/unknown changed...
@ -685,7 +697,9 @@ qboolean FS_Rename2(const char *oldf, const char *newf, enum fs_relative oldrela
qboolean FS_Remove(const char *fname, enum fs_relative relativeto); //0 on success, non-0 on error
qboolean FS_RemoveTree(searchpathfuncs_t *pathhandle, const char *fname);
qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relativesource, enum fs_relative relativedest);
qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
//qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
qboolean FS_SystemPath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
qboolean FS_DisplayPath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //retrieves a string for user display. prefixes may be masked for privacy.
qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto);
void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize);
vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
@ -964,6 +978,7 @@ extern hashfunc_t hash_sha2_384;
extern hashfunc_t hash_sha2_512;
extern hashfunc_t hash_crc16; //aka ccitt, required for qw's clc_move and various bits of dp compat
extern hashfunc_t hash_crc16_lower;
#define hash_certfp hash_sha2_256 //This is the hash function we're using to compute *fp serverinfo. we can detect 1/2-256/2-512 by sizes, but we need consistency to avoid confusion in clientside things too.
unsigned int hashfunc_terminate_uint(const hashfunc_t *hash, void *context); //terminate, except returning the digest as a uint instead of a blob. folds the digest if longer than 4 bytes.
unsigned int CalcHashInt(const hashfunc_t *hash, const void *data, size_t datasize);
size_t CalcHash(const hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datasize);
@ -1001,7 +1016,6 @@ typedef enum {
} logtype_t;
void Log_String (logtype_t lognum, const char *s);
void Con_Log (const char *s);
void Log_Logfile_f (void);
void Log_Init(void);
void Log_ShutDown(void);
#ifdef IPLOG
@ -1085,8 +1099,15 @@ json_t *JSON_FindChild(json_t *t, const char *child); //find a named child in an
json_t *JSON_GetIndexed(json_t *t, unsigned int idx); //find an indexed child in an array (or object, though slower)
double JSON_ReadFloat(json_t *t, double fallback); //read a numeric value.
size_t JSON_ReadBody(json_t *t, char *out, size_t outsize); //read a string value.
size_t JSON_GetCount(json_t *t);
//exotic fancy functions
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, const char *json, int *jsonpos, int jsonlen); //fancy parsing.
struct jsonparsectx_s
{
char const *const data;
const size_t size;
size_t pos;
};
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, struct jsonparsectx_s *ctx); //fancy parsing.
//helpers
json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx); //just a helper.
qboolean JSON_Equals(json_t *t, const char *child, const char *expected); //compares a bit faster.

View File

@ -126,10 +126,8 @@
#undef Q3SERVER //q3 server stuff.
#undef HEXEN2 //runs hexen2 gamecode, supports hexen2 file formats.
#undef NQPROT //act as an nq client/server, with nq gamecode.
////#undef WEBSERVER //sv_ftp + sv_http cvars.
#undef WEBCLIENT //uri_get+any internal downloads etc
#undef RUNTIMELIGHTING //automatic generation of .lit files
#undef R_XFLIP //old silly thing
#undef TEXTEDITOR //my funky text editor! its awesome!
#undef TCPCONNECT //support for playing over tcp sockets, instead of just udp. compatible with qizmo.
#undef IRCCONNECT //lame support for routing game packets via irc server. not a good idea.

View File

@ -36,7 +36,6 @@
#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
#define RTLIGHTS
#define RUNTIMELIGHTING //automatic generation of .lit files
#define R_XFLIP //old silly thing
//Extra misc features.
//#define CLIENTONLY //
@ -154,7 +153,7 @@
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
#define CL_MASTER //Clientside Server Browser functionality.
#define PACKAGEMANAGER //Allows the user to enable/disable/download(with WEBCLIENT) packages and plugins.
#define PACKAGEMANAGER //Allows the user to enable/disable/download(with WEBCLIENT) packages and plugins. Also handles map packages.
// Audio Drivers
#define AVAIL_OPENAL
@ -191,22 +190,23 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.
#ifdef COMPILE_OPTS
#ifdef COMPILE_OPTS //This is a block of hints for the makefile to decide which deps to link.
//things to configure qclib, which annoyingly doesn't include this file itself
//-DOMIT_QCC //disable the built-in qcc
//-DSIMPLE_QCVM //disable qc debugging and 32bit opcodes
#ifndef AVAIL_ZLIB
//-DNO_ZLIB //disable zlib
#endif
#ifdef AVAIL_PNGLIB
-DLINK_PNG
#endif
#ifdef AVAIL_JPEGLIB
-DLINK_JPEG
#ifndef FTE_TARGET_WEB
#ifdef AVAIL_PNGLIB
-DLINK_PNG
#endif
#ifdef AVAIL_JPEGLIB
-DLINK_JPEG
#endif
#endif
#if defined(PLUGINS) && (defined(Q3SERVER) || defined(Q3CLIENT))
-DLINK_QUAKE3 //ask the makefile to bake the quake3 plugin into the engine itself.
@ -217,15 +217,24 @@
#ifndef AVAIL_BOTLIB
-DNO_BOTLIB //disable static botlib
#endif
//-DNO_VORBISFILE //disable static vorbisfile
#ifndef FTE_TARGET_WEB
-DLINK_VORBISFILE //disable static vorbisfile
#endif
//enable some staticaly linked libraries
#ifndef FTE_TARGET_WEB
-DLINK_FREETYPE //international text requires international fonts.
#endif
#if defined(USE_INTERNAL_ODE) && !defined(ODE_DYNAMIC)
-DLINK_ODE
#endif
#if defined(PLUGINS)
//-DLINK_EZHUD //uncomment this line to statically link the ezhud plugin (eg for the web-rel target).
#endif
//-DLINK_OPENSSL //statically link our openssl plugin into the engine instead of being separate. NOTE: openssl<3 is a license no-go, 3 still requires gpl3 (2 prohits patent).
//-Os //optimise for size instead of speed. less cpu cache needed means that its sometimes faster anyway.
#endif

View File

@ -38,7 +38,6 @@
//#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
//#define RTLIGHTS
//#define RUNTIMELIGHTING //automatic generation of .lit files
//#define R_XFLIP //old silly thing
//Extra misc features.
//#define CLIENTONLY //
@ -193,7 +192,6 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.

View File

@ -36,7 +36,6 @@
#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
#define RTLIGHTS
//#define RUNTIMELIGHTING //automatic generation of .lit files
//#define R_XFLIP //old silly thing
//Extra misc features.
//#define CLIENTONLY //
@ -191,7 +190,6 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.

View File

@ -101,14 +101,14 @@
#define TERRAIN
/* audio */
#define AVAIL_DSOUND
#define AVAIL_DSOUND
#undef AVAIL_OPENAL
#define AVAIL_OGGVORBIS
#define HAVE_OPUS
#define VOICECHAT
/* todo: make OpenAL only */
#define HAVE_MIXER
/* todo: make OpenAL only */
#define HAVE_MIXER
/* Model formats, IQM/VVM and HLMDL for legacy maps */
#define INTERQUAKEMODELS
@ -168,9 +168,7 @@
#undef Q3SERVER /* q3 server stuff */
#undef HEXEN2 /* runs hexen2 gamecode, supports hexen2 file formats */
#undef NQPROT /* act as an nq client/server, with nq gamecode */
#undef WEBSERVER /* sv_ftp + sv_http cvars */
#undef RUNTIMELIGHTING /* automatic generation of .lit files */
#undef R_XFLIP /* old silly thing */
#undef TEXTEDITOR /* because emacs */
#undef TCPCONNECT /* support for playing over tcp sockets, instead of just udp. compatible with qizmo */
#undef IRCCONNECT /* lame support for routing game packets via irc server. not a good idea */

View File

@ -95,6 +95,9 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
#define CON_WARNING "^&E0"
#define CON_ERROR "^&C0"
#define CON_NOTICE "^&-1"
#if defined(_DEBUG) || defined(FTE_TARGET_WEB)/*urgh...*/
#define CON_DEBUG CON_WARNING __FILE__":"STRINGIFY(__LINE__)" "
#endif
#define isextendedcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || x == '-')
#define ishexcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f'))
@ -245,7 +248,7 @@ 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
void VARGS Con_DLPrintf (int level, const char *fmt, ...) LIKEPRINTF(2); //developer>=2, for spammy stuff
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...); //for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...) LIKEPRINTF(3); //for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_SafePrintf (const char *fmt, ...) LIKEPRINTF(1);
void Con_Footerf(console_t *con, qboolean append, const char *fmt, ...) LIKEPRINTF(3);
void Con_Clear_f (void);

View File

@ -474,7 +474,7 @@ showhelp:
else
col = S_COLOR_YELLOW; //cvar is changed, but won't be saved to a config so w/e.
if (cmd->flags & CVAR_NOUNSAFEEXPAND)
Con_Printf("^[%s%s\\type\\%s\\tip\\"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e.
Con_Printf("^[%s%s\\type\\%s\\tip\\<Current value is hidden>\n\n"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e.
else
Con_Printf("^[%s%s\\type\\%s %s\\tip\\Default: %s\nCurrent: %s\n\n"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name,cmd->string, cmd->defaultstr,cmd->string, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e.
total++;
@ -1066,6 +1066,10 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
}
Z_Free (latch); // free the old value string
#ifdef HAVE_SERVER
MSV_SendCvarChange(var);
#endif
}
if (var->latched_string) //we may as well have this here.

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ struct searchpathfuncs_s
void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives)
int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm);
int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, int seed, int usepure);
int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, const int *seed);
vfsfile_t * (QDECL *OpenVFS)(searchpathfuncs_t *handle, flocation_t *loc, const char *mode);
@ -73,6 +73,7 @@ void FS_UnRegisterFileSystemModule(void *module);
void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix, unsigned int packageflags);
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri);
qboolean PM_HandleRedirect(const char *package, char *url, size_t urlsize);
void PM_ManifestChanged(ftemanifest_t *man);
void *PM_GeneratePackageFromMeta(vfsfile_t *file, char *fname, size_t fnamesize, enum fs_relative *fsroot);
void PM_FileInstalled(const char *filename, enum fs_relative fsroot, void *metainfo, qboolean enable); //we finished installing a file via some other mechanism (drag+drop or from server. insert it into the updates menu.
@ -85,7 +86,7 @@ unsigned int PM_MarkUpdates (void); //mark new/updated packages as needing insta
void PM_ApplyChanges(void); //for -install/-doinstall args
qboolean PM_AreSourcesNew(qboolean doprompt);
qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running
void PM_AddManifestPackages(ftemanifest_t *man);
void PM_AddManifestPackages(ftemanifest_t *man, qboolean mayapply);
void Menu_Download_Update(void);
typedef struct
@ -107,7 +108,7 @@ enum modsourcetype_e
MST_UNKNOWN, //forgot where it came from...
};
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man, enum modsourcetype_e sourcetype), void *usr);
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man, enum modsourcetype_e sourcetype), void *usr, qboolean fixedbasedir);
struct modlist_s
{

View File

@ -1214,7 +1214,7 @@ static int QDECL FSDZ_EnumerateFiles (searchpathfuncs_t *handle, const char *mat
return true;
}
static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype)
static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{
dzarchive_t *pak = (void*)handle;
@ -1224,7 +1224,8 @@ static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int c
int i;
filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed;
if (seed)
filecrcs[numcrcs++] = *seed;
for (i = 0; i < pak->numfiles; i++)
{
@ -1234,10 +1235,7 @@ static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int c
}
}
if (crctype)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
BZ_Free(filecrcs);
return result;

View File

@ -12,7 +12,7 @@ typedef struct
fsbucket_t bucket;
char name[MAX_QPATH];
int filepos, filelen;
unsigned int filepos, filelen;
} mpackfile_t;
typedef struct pack_s
@ -24,7 +24,7 @@ typedef struct pack_s
void *mutex;
vfsfile_t *handle;
unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
qofs_t filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
qatomic32_t references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed.
} pack_t;
@ -34,27 +34,27 @@ typedef struct pack_s
typedef struct
{
char name[56];
int filepos, filelen;
unsigned int filepos, filelen;
} dpackfile_t;
typedef struct
{
int filepos, filelen;
unsigned int filepos, filelen;
char name[8];
} dwadfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
unsigned int dirofs;
unsigned int dirlen;
} dpackheader_t;
typedef struct
{
char id[4];
int dirlen;
int dirofs;
unsigned int dirlen;
unsigned int dirofs;
} dwadheader_t;
#define MAX_FILES_IN_PACK 2048
@ -129,7 +129,7 @@ static unsigned int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t *
if (loc)
{
loc->fhandle = pf;
snprintf(loc->rawname, sizeof(loc->rawname), "%s", pak->descname);
Q_snprintfz(loc->rawname, sizeof(loc->rawname), "%s", pak->descname);
loc->offset = pf->filepos;
loc->len = pf->filelen;
}
@ -155,7 +155,7 @@ static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *ma
return true;
}
static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype)
static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{ //this is really weak. :(
pack_t *pak = (void*)handle;
@ -165,7 +165,8 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
int i;
filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed;
if (seed) //so exploiters can't cache it in purity replies.
filecrcs[numcrcs++] = *seed;
for (i = 0; i < pak->numfiles; i++)
{
@ -175,10 +176,7 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
}
}
if (crctype)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
BZ_Free(filecrcs);
return result;
@ -307,7 +305,7 @@ of the list so they override previous pack files.
*/
searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix)
{
dpackheader_t header;
dpackheader_t header = {};
int i;
mpackfile_t *newfiles;
int numpackfiles;
@ -327,7 +325,8 @@ searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *
if (read < sizeof(header) || header.id[0] != 'P' || header.id[1] != 'A'
|| header.id[2] != 'C' || header.id[3] != 'K')
{
Con_Printf("%s is not a pak - %c%c%c%c\n", desc, header.id[0], header.id[1], header.id[2], header.id[3]);
header.dirofs = 0;
Con_Printf("%s is not a pak - \"%s\"\n", desc, header.id);
return NULL;
}
header.dirofs = LittleLong (header.dirofs);
@ -484,7 +483,7 @@ newsection:
newfiles[i].filelen = 4;
break;
}
if (!strncmp(filename, "gl_", 3) && ((filename[3] == 'e' && filename[5] == 'm') || !strncmp(filename+3, "map", 3)))
if (!Q_strncmp(filename, "gl_", 3) && ((filename[3] == 'e' && filename[5] == 'm') || !strncmp(filename+3, "map", 3)))
{ //this is the start of a beutiful new map
section = 5;
strcpy(sectionname, filename+3);

View File

@ -5,7 +5,7 @@
#include <sys/stat.h>
#endif
#if !defined(FTE_TARGET_WEB) && (!defined(_WIN32) || defined(FTE_SDL))
#if !defined(FTE_TARGET_WEB) && (!defined(_WIN32) || defined(FTE_SDL) || defined(WEBSVONLY))
#ifdef WEBSVONLY
#define Z_Free free

View File

@ -4,6 +4,36 @@
//#define AVAIL_BZLIB
//#define DYNAMIC_BZLIB
//supported ZIP features:
//zip64 for huge zips
//utf-8 encoding support (non-utf-8 is always ibm437)
//symlink flag
//compression mode: store
//compression mode: deflate (via zlib)
//compression mode: deflate64 (via zlib's unofficial extras)
//compression mode: bzip2 (via libbz2)
//bigendian cpus. everything misaligned.
//weak/original file encryption (set fs_zip_password)
//split archives (see specific notes)
//NOT supported:
//other compression modes
//strong/aes encryption
//if central dir is crypted/compressed, the archive will fail to open
//crc verification (if present then the local header must match the central dir, but the file data itself will not be verified in part because that'd require decoding the entire file upfront first)
//infozip utf-8 name override.
//other 'extra' fields.
//split archives:
//the central directory must be stored exclusively inside the initial zip/pk3 file.
//additional volumes will use the first letter of the extension and then at least two base-10 digits denoting the volume index (eg pak0.pk3 + pak0.p00 + pak0.p01).
//individual files must not be split over files (no rollover on truncation)
//fteqcc has a feature to generate versioned centraldir-only zips using external volumes for the actual data. This can be used to avoid downloading redundant data when connecting to servers using older revisions, but such revisions must be centrally managed.
#ifdef AVAIL_BZLIB
# include <bzlib.h>
# ifdef DYNAMIC_BZLIB
@ -47,14 +77,6 @@
# endif
# include <zlib.h>
# ifdef _MSC_VER
# ifdef _WIN64
# pragma comment(lib, MSVCLIBSPATH "zlib64.lib")
# else
# pragma comment(lib, MSVCLIBSPATH "zlib.lib")
# endif
# endif
# ifdef DYNAMIC_ZLIB
# define ZLIB_LOADED() (zlib_handle!=NULL)
void *zlib_handle;
@ -801,7 +823,7 @@ static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *ma
return true;
}
static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype)
static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{
zipfile_t *zip = (void*)handle;
@ -811,7 +833,8 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
int i;
filecrcs = BZ_Malloc((zip->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed;
if (seed)
filecrcs[numcrcs++] = *seed;
for (i = 0; i < zip->numfiles; i++)
{
@ -819,10 +842,7 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
filecrcs[numcrcs++] = zip->files[i].crc;
}
if (crctype || numcrcs < 1)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
BZ_Free(filecrcs);
return result;
@ -1609,30 +1629,6 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
return (vfsfile_t*)vfsz;
}
//ZIP features:
//zip64 for huge zips
//utf-8 encoding support (non-utf-8 is always ibm437)
//symlink flag
//compression mode: store
//compression mode: deflate (via zlib)
//bigendian cpus. everything misaligned.
//NOT supported:
//compression mode: deflate64
//other compression modes
//split archives
//if central dir is crypted/compressed, the archive will fail to open
//if a file is crypted/compressed, the file will (internally) be marked as corrupt
//crc verification
//infozip utf-8 name override.
//other 'extra' fields.
//split archives:
//central directory must be stored exclusively inside the initial zip.
//files on other parts will fail to load.
//individual files must not be split over files
struct zipinfo
{
unsigned int thisdisk; //this disk number

View File

@ -231,18 +231,6 @@ static unsigned char q2_palette[256*3];
#endif
/*
typedef struct q2csurface_s
{
char name[16];
int flags;
int value;
} q2csurface_t;
*/
typedef struct {
@ -1679,7 +1667,8 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, lump
int style;
struct decoupled_lm_info_s *decoupledlm;
unsigned int dcsize, lofs;
size_t dcsize;
unsigned int lofs;
unsigned short lmshift, lmscale;
char buf[64];
@ -4061,7 +4050,8 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
extern cvar_t gl_overbright;
float scale = (1<<(2-gl_overbright.ival));
loadmodel->lightmaps.fmt = LM_L8;
loadmodel->lightmaps.fmt = LM_RGB8;
loadmodel->lightmaps.prebaked = PTI_RGB8;
//round up the samples, in case the last one is partial.
maps = ((samples+mapsize-1)&~(mapsize-1)) / mapsize;
@ -4079,8 +4069,6 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
if (!samples)
return;
loadmodel->lightmaps.fmt = LM_RGB8;
if (loadmodel->lightmaps.deluxemapping)
maps /= 2;
@ -5359,6 +5347,7 @@ static int CM_LeafArea (model_t *model, int leafnum)
//=======================================================================
#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
#define PlaneDiffPush(point,plane,pushdist) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist - pushdist)
static mplane_t box_planes[6];
static model_t box_model;
@ -5660,10 +5649,14 @@ static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, c
mleaf_t *leaf;
q2cbrush_t *brush;
q2cbrushside_t *brushside;
vec3_t absmin, absmax, ofs;
int leaflist[64];
k = CM_BoxLeafnums (model, point, point, leaflist, 64, NULL);
VectorAdd(point, mins, absmin);
VectorAdd(point, maxs, absmax);
k = CM_BoxLeafnums (model, absmin, absmax, leaflist, 64, NULL);
contents = 0;
for (k--; k >= 0; k--)
@ -5680,10 +5673,18 @@ static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, c
continue;
}
brushside = brush->brushside;
for ( j = 0; j < brush->numsides; j++, brushside++ )
{
if (PlaneDiff (point, brushside->plane) > 0 )
for (j=0 ; j<3 ; j++)
{
if (brushside->plane->normal[j] < 0)
ofs[j] = maxs[j];
else
ofs[j] = mins[j];
}
if (PlaneDiffPush (point, brushside->plane, DotProduct (ofs, brushside->plane->normal)) > 0)
break;
}

View File

@ -1,5 +1,12 @@
#include "quakedef.h"
/*struct jsonparsectx_s
{
char const *const data;
const size_t size;
size_t pos;
};*/
//node destruction
static void JSON_Orphan(json_t *t)
{
@ -125,45 +132,45 @@ static json_t *JSON_CreateNode(json_t *parent, const char *namestart, const char
}
//node parsing
static void JSON_SkipWhite(const char *msg, int *pos, int max)
static void JSON_SkipWhite(struct jsonparsectx_s *ctx)
{
while (*pos < max)
while (ctx->pos < ctx->size)
{
//if its simple whitespace then keep skipping over it
if (msg[*pos] == ' ' ||
msg[*pos] == '\t' ||
msg[*pos] == '\r' ||
msg[*pos] == '\n' )
if (ctx->data[ctx->pos] == ' ' ||
ctx->data[ctx->pos] == '\t' ||
ctx->data[ctx->pos] == '\r' ||
ctx->data[ctx->pos] == '\n' )
{
*pos+=1;
ctx->pos+=1;
continue;
}
//BEGIN NON-STANDARD - Note that comments are NOT part of json, but people insist on using them anyway (c-style, like javascript).
else if (msg[*pos] == '/' && *pos+1 < max)
else if (ctx->data[ctx->pos] == '/' && ctx->pos+1 < ctx->size)
{
if (msg[*pos+1] == '/')
if (ctx->data[ctx->pos+1] == '/')
{ //C++ style single-line comments that continue till the next line break
*pos+=2;
while (*pos < max)
ctx->pos+=2;
while (ctx->pos < ctx->size)
{
if (msg[*pos] == '\r' || msg[*pos] == '\n')
if (ctx->data[ctx->pos] == '\r' || ctx->data[ctx->pos] == '\n')
break; //ends on first line break (the break is then whitespace will will be skipped naturally)
*pos+=1; //not yet
ctx->pos+=1; //not yet
}
continue;
}
else if (msg[*pos+1] == '*')
else if (ctx->data[ctx->pos+1] == '*')
{ /*C style multi-line comment*/
*pos+=2;
while (*pos+1 < max)
ctx->pos+=2;
while (ctx->pos+1 < ctx->size)
{
if (msg[*pos] == '*' && msg[*pos+1] == '/')
if (ctx->data[ctx->pos] == '*' && ctx->data[ctx->pos+1] == '/')
{
*pos+=2; //skip past the terminator ready for whitespace or trailing comments directly after
ctx->pos+=2; //skip past the terminator ready for whitespace or trailing comments directly after
break;
}
*pos+=1; //not yet
ctx->pos+=1; //not yet
}
continue;
}
@ -327,20 +334,20 @@ size_t JSON_ReadBody(json_t *t, char *out, size_t outsize)
return t->bodyend-t->bodystart;
}
static qboolean JSON_ParseString(char const*msg, int *pos, int max, char const**start, char const** end)
static qboolean JSON_ParseString(struct jsonparsectx_s *ctx, char const**start, char const** end)
{
if (*pos < max && msg[*pos] == '\"')
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{ //quoted string
//FIXME: no handling of backslash followed by one of "\/bfnrtu
*pos+=1;
*start = msg+*pos;
while (*pos < max)
ctx->pos+=1;
*start = ctx->data+ctx->pos;
while (ctx->pos < ctx->size)
{
if (msg[*pos] == '\"')
if (ctx->data[ctx->pos] == '\"')
break;
if (msg[*pos] == '\\')
if (ctx->data[ctx->pos] == '\\')
{ //escapes are expanded elsewhere, we're just skipping over them here.
switch(msg[*pos+1])
switch(ctx->data[ctx->pos+1])
{
case '\"':
case '\\':
@ -350,137 +357,137 @@ static qboolean JSON_ParseString(char const*msg, int *pos, int max, char const**
case 'n':
case 'r':
case 't':
*pos+=2;
ctx->pos+=2;
break;
case 'u':
*pos+=2;
ctx->pos+=2;
//*pos+=4; //4 hex digits, not escapes so just wait till later before parsing them properly.
break;
default:
//unknown escape. will warn when actually reading it.
*pos+=1;
ctx->pos+=1;
break;
}
}
else
*pos+=1;
ctx->pos+=1;
}
if (*pos < max && msg[*pos] == '\"')
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{
*end = msg+*pos;
*pos+=1;
*end = ctx->data+ctx->pos;
ctx->pos+=1;
return true;
}
}
else
{ //name
*start = msg+*pos;
while (*pos < max
&& msg[*pos] != ' '
&& msg[*pos] != '\t'
&& msg[*pos] != '\r'
&& msg[*pos] != '\n'
&& msg[*pos] != ':'
&& msg[*pos] != ','
&& msg[*pos] != '}'
&& msg[*pos] != '{'
&& msg[*pos] != '['
&& msg[*pos] != ']')
*start = ctx->data+ctx->pos;
while (ctx->pos < ctx->size
&& ctx->data[ctx->pos] != ' '
&& ctx->data[ctx->pos] != '\t'
&& ctx->data[ctx->pos] != '\r'
&& ctx->data[ctx->pos] != '\n'
&& ctx->data[ctx->pos] != ':'
&& ctx->data[ctx->pos] != ','
&& ctx->data[ctx->pos] != '}'
&& ctx->data[ctx->pos] != '{'
&& ctx->data[ctx->pos] != '['
&& ctx->data[ctx->pos] != ']')
{
*pos+=1;
ctx->pos+=1;
}
*end = msg+*pos;
*end = ctx->data+ctx->pos;
if (*start != *end)
return true;
}
*end = *start;
return false;
}
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, const char *json, int *jsonpos, int jsonlen)
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, struct jsonparsectx_s *ctx)
{
const char *childstart, *childend;
JSON_SkipWhite(json, jsonpos, jsonlen);
JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen)
if (ctx->pos < ctx->size)
{
if (json[*jsonpos] == '{')
if (ctx->data[ctx->pos] == '{')
{
*jsonpos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen);
ctx->pos+=1;
JSON_SkipWhite(ctx);
t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_object);
while (*jsonpos < jsonlen && json[*jsonpos] == '\"')
while (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{
if (!JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend))
if (!JSON_ParseString(ctx, &childstart, &childend))
break;
JSON_SkipWhite(json, jsonpos, jsonlen);
if (*jsonpos < jsonlen && json[*jsonpos] == ':')
JSON_SkipWhite(ctx);
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ':')
{
*jsonpos+=1;
if (!JSON_ParseNode(t, childstart, childend, json, jsonpos, jsonlen))
ctx->pos+=1;
if (!JSON_ParseNode(t, childstart, childend, ctx))
break;
}
JSON_SkipWhite(json, jsonpos, jsonlen);
JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen && json[*jsonpos] == ',')
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ',')
{
*jsonpos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen);
ctx->pos+=1;
JSON_SkipWhite(ctx);
continue;
}
break;
}
if (*jsonpos < jsonlen && json[*jsonpos] == '}')
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '}')
{
*jsonpos+=1;
ctx->pos+=1;
return t;
}
JSON_Destroy(t);
}
else if (json[*jsonpos] == '[')
else if (ctx->data[ctx->pos] == '[')
{
char idxname[MAX_QPATH];
unsigned int idx = 0;
*jsonpos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen);
ctx->pos+=1;
JSON_SkipWhite(ctx);
t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_array);
for(;;)
{
Q_snprintfz(idxname, sizeof(idxname), "%u", idx++);
if (!JSON_ParseNode(t, idxname, NULL, json, jsonpos, jsonlen))
if (!JSON_ParseNode(t, idxname, NULL, ctx))
break;
if (*jsonpos < jsonlen && json[*jsonpos] == ',')
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ',')
{
*jsonpos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen);
ctx->pos+=1;
JSON_SkipWhite(ctx);
continue;
}
break;
}
JSON_SkipWhite(json, jsonpos, jsonlen);
if (*jsonpos < jsonlen && json[*jsonpos] == ']')
JSON_SkipWhite(ctx);
if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ']')
{
*jsonpos+=1;
ctx->pos+=1;
return t;
}
JSON_Destroy(t);
}
else
{
if (json[*jsonpos] == '\"')
if (ctx->data[ctx->pos] == '\"')
{
if (JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend))
if (JSON_ParseString(ctx, &childstart, &childend))
return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_string);
}
else
{
if (JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend))
if (JSON_ParseString(ctx, &childstart, &childend))
{
if (childend-childstart == 4 && !strncasecmp(childstart, "true", 4))
return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_true);
@ -498,11 +505,15 @@ json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, co
}
json_t *JSON_Parse(const char *json)
{
size_t jsonlen = strlen(json);
int pos = (json[0] == '\xef' && json[1] == '\xbb' && json[2] == '\xbf')?3:0; //skip a utf-8 bom, if present, to be a bit more permissive.
json_t *n = JSON_ParseNode(NULL, NULL, NULL, json, &pos, jsonlen);
JSON_SkipWhite(json, &pos, jsonlen);
if (pos == jsonlen)
struct jsonparsectx_s ctx =
{
json,
strlen(json),
(json[0] == '\xef' && json[1] == '\xbb' && json[2] == '\xbf')?3:0, //skip a utf-8 bom, if present, to be a bit more permissive.
};
json_t *n = JSON_ParseNode(NULL, NULL, NULL, &ctx);
JSON_SkipWhite(&ctx);
if (ctx.pos == ctx.size)
return n;
JSON_Destroy(n); //trailing junk?... fail it.
return NULL;
@ -580,6 +591,14 @@ json_t *JSON_GetIndexed(json_t *t, unsigned int idx)
return NULL;
}
size_t JSON_GetCount(json_t *t)
{ //can't cope with deletions.
size_t count = 0;
while (JSON_GetIndexed(t, count))
count++;
return count;
}
//helpers...
json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx)

View File

@ -265,8 +265,8 @@ static struct {
{"logrcon", " frags"},
};
void Log_Logfile_f (void)
{
static void Log_Logfile_f (void)
{ //these legacy commands are just toggles. not args (other than the commandname to know which log type to toggle)
size_t logtype;
const char *cmd = Cmd_Argv(0);
for (logtype = 0; logtype < countof(legacylog); logtype++)
@ -293,7 +293,7 @@ void Log_Logfile_f (void)
else
f = va("%s.log", f);
if (FS_NativePath(f, log_root, syspath, sizeof(syspath)))
if (FS_DisplayPath(f, log_root, syspath, sizeof(syspath)))
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, syspath));
else
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, f));
@ -301,44 +301,6 @@ void Log_Logfile_f (void)
}
}
/*
void SV_Fraglogfile_f (void)
{
char name[MAX_QPATH];
int i;
if (sv_fraglogfile)
{
Con_TPrintf ("Frag file logging off.\n");
VFS_CLOSE (sv_fraglogfile);
sv_fraglogfile = NULL;
return;
}
// find an unused name
for (i=0 ; i<1000 ; i++)
{
sprintf (name, "frag_%i.log", i);
sv_fraglogfile = FS_OpenVFS(name, "rb", FS_GAME);
if (!sv_fraglogfile)
{ // can't read it, so create this one
sv_fraglogfile = FS_OpenVFS (name, "wb", FS_GAME);
if (!sv_fraglogfile)
i=1000; // give error
break;
}
VFS_CLOSE (sv_fraglogfile);
}
if (i==1000)
{
Con_TPrintf ("Can't open any logfiles.\n");
sv_fraglogfile = NULL;
return;
}
Con_TPrintf ("Logging frags to %s.\n", name);
}
*/
#endif
#ifdef IPLOG
@ -605,10 +567,10 @@ static int IPLog_Dump(const char *fname)
}
static void IPLog_Dump_f(void)
{
char native[MAX_OSPATH];
char displaypath[MAX_OSPATH];
const char *fname = Cmd_Argv(1);
if (FS_NativePath(fname, FS_GAMEONLY, native, sizeof(native)))
Q_strncpyz(native, fname, sizeof(native));
if (FS_DisplayPath(fname, FS_GAMEONLY, displaypath, sizeof(displaypath)))
Q_strncpyz(displaypath, fname, sizeof(displaypath));
IPLog_Merge_File(fname); //merge from the existing file, so that we're hopefully more robust if multiple processes are poking the same file.
switch (IPLog_Dump(fname))
{
@ -617,7 +579,7 @@ static void IPLog_Dump_f(void)
break;
default:
case 1:
Con_Printf("wrote %s\n", native);
Con_Printf("wrote %s\n", displaypath);
break;
case 2:
Con_Printf("nothing to write\n");
@ -814,7 +776,7 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize,
//(but do pin so we at least know when its MITMed after the fact)
Con_Printf(CON_WARNING"Auto-Pinning certificate for %s."CON_DEFAULT" ^[/seta %s 2^]+ for actual security.\n", hostname, net_enable_dtls.name);
if (certsize)
Base64_EncodeBlockURI(digest, CalcHash(&hash_sha1, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
Base64_EncodeBlockURI(digest, CalcHash(&hash_certfp, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
else
strcpy(fp, "<No Certificate>");
Con_Printf(S_COLOR_GRAY" fp: %s\n", fp);
@ -824,7 +786,7 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize,
else if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize) || (trusted && !l->trusted))
{ //new or different
if (certsize)
Base64_EncodeBlockURI(digest, CalcHash(&hash_sha1, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
Base64_EncodeBlockURI(digest, CalcHash(&hash_certfp, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
else
strcpy(fp, "<No Certificate>");
if (qrenderer)
@ -1062,9 +1024,8 @@ void Log_Init(void)
Cvar_Register (&log_enable[i], CONLOGGROUP);
Cvar_Register (&log_name[i], CONLOGGROUP);
log_newline[i] = true;
#ifdef IPLOG
Cmd_AddCommand(legacylog[i].commandname, IPLog_Merge_f);
#endif
Cmd_AddCommand(legacylog[i].commandname, Log_Logfile_f);
}
Cvar_Register (&log_dir_var, CONLOGGROUP);
Cvar_Register (&log_readable, CONLOGGROUP);

View File

@ -68,8 +68,6 @@ typedef enum {
NP_INVALID
} netproto_t;
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
typedef struct netadr_s
{
netadrtype_t type;
@ -91,7 +89,7 @@ typedef struct netadr_s
} irc;
#endif
#ifdef SUPPORT_ICE
char icename[16];
char icename[64];
#endif
#ifdef HAVE_WEBSOCKCL
char websocketurl[64];
@ -243,7 +241,7 @@ qboolean NET_RegisterCrypto(void *module, struct ftecrypto_s *driver);
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
#define MAX_LATENT 32
//#define MAX_LATENT 32
#define MAX_ADR_SIZE 64
typedef struct
@ -256,12 +254,26 @@ typedef struct
float nqreliable_resendtime;//force nqreliable_allowed, thereby forcing a resend of anything n
qbyte nqunreliableonly; //nq can't cope with certain reliables some times. if 2, we have a reliable that result in a block (that should be sent). if 1, we are blocking. if 0, we can send reliables freely. if 3, then we just want to ignore clc_moves
#endif
qboolean pext_fragmentation; //fte's packet fragmentation extension, to avoid issues with low mtus.
qboolean pext_stunaware; //prevent the two lead-bits of packets from being either 0(stun), so stray stun packets cannot mess things up for us.
unsigned int flags; //NCF_ bitmask
#define NCF_CLIENT (1u<<0) //clientside sends the qport.
#define NCF_SERVER (0u<<0) //serverside reads the qport.
#define NCF_FRAGABLE (1u<<1) //fte's packet fragmentation extension, to avoid issues with low mtus.
#define NCF_STUNAWARE (1u<<2) //prevent the two lead-bits of packets from being either 0(stun), so stray stun packets cannot mess things up for us.
struct netprim_s netprim;
int mtu; //the path mtu, if known
int dupe; //how many times to dupe packets
//Packetisation Layer Path MTU Discovery (PLPMTUD / RFC4821)
int mtu_cur; //the path mtu, if known
int mtu_min; //minimum mtu to drop to. lower values being abusive.
int mtu_max; //the size the user specified.
int mtu_resends; //number of times we had to resend a reliable.
int mtu_overhead; //extra slop vs a
int outgoing_mtu_probe; //sequence number that was a probe. if its acked we can send a new one straight away to grow fast. if its not acked, we back off.
int mtu_probes; //number of probes sent without success. give up if we get no growth.
double mtu_reprobetime; //send an extra mtu probe every 30ish secs to see if it grew
unsigned short sentsizes[64]; //to bump known mtu if an oversized packet got received.
int outgoing_sequence_last; //to detect gaps in outgoing sequences (servers get forced to match client's)
float last_received; // for timeouts
// the statistics are cleared at each client begin, because
@ -270,13 +282,11 @@ typedef struct
float frame_rate;
int drop_count; // dropped packets, cleared each level
int good_count; // cleared each level
int bytesin;
int bytesout;
netadr_t remote_address;
netsrc_t sock;
int qport;
int qportsize;
@ -307,8 +317,8 @@ typedef struct
qbyte reliable_buf[MAX_OVERALLMSGLEN]; // unacked reliable message
// time and size data to calculate bandwidth
int outgoing_size[MAX_LATENT];
double outgoing_time[MAX_LATENT];
// int outgoing_size[MAX_LATENT];
// double outgoing_time[MAX_LATENT];
struct huffman_s *compresstable;
//nq servers must recieve truncated packets.
@ -322,12 +332,13 @@ extern int net_drop; // packets dropped before this one
void Net_Master_Init(void);
void Netchan_Init (void);
size_t Netchan_GetMaxUnreliable(netchan_t *chan);
int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate);
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data);
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...) LIKEPRINTF(3);
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...);
void Netchan_OutOfBand (unsigned int ncflags, netadr_t *adr, int length, const qbyte *data);
void VARGS Netchan_OutOfBandPrint (unsigned int ncflags, netadr_t *adr, char *format, ...) LIKEPRINTF(3);
void VARGS Netchan_OutOfBandTPrintf (unsigned int ncflags, netadr_t *adr, int language, translation_t text, ...);
qboolean Netchan_Process (netchan_t *chan);
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport);
void Netchan_Setup (unsigned int ncflags, netchan_t *chan, netadr_t *adr, int qport, unsigned int mtu);
unsigned int Net_PextMask(unsigned int protover, qboolean fornq);
extern cvar_t net_mtu;

View File

@ -98,9 +98,10 @@ cvar_t pext_lerptime = CVARD("_pext_lerptime", "0", "RENAME ME WHEN STABLE. Send
cvar_t pext_infoblobs = CVARD("_pext_infoblobs", "0", "RENAME ME WHEN STABLE. Enables the use of very large infokeys containing potentially invalid chars. Note that the userinfo is still limited by sv_userinfo_bytelimit and sv_userinfo_keylimit.");
cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas");
cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols.");
extern cvar_t net_fakemtu;
#if defined(HAVE_CLIENT) && defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t)
#define NET_SendPacket(c,s,d,t) NET_SendPacket((c&NCF_CLIENT)?cls.sockets:svs.sockets,s,d,t)
#elif defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t)
#else
@ -303,7 +304,7 @@ Netchan_OutOfBand
Sends an out-of-band datagram
================
*/
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data)
void Netchan_OutOfBand (unsigned int ncflags, netadr_t *adr, int length, const qbyte *data)
{
sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER];
@ -322,7 +323,7 @@ void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *d
#ifndef SERVERONLY
if (!cls.demoplayback)
#endif
NET_SendPacket (sock, send.cursize, send.data, adr);
NET_SendPacket (ncflags, send.cursize, send.data, adr);
}
/*
@ -332,7 +333,7 @@ Netchan_OutOfBandPrint
Sends a text message in an out-of-band datagram
================
*/
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...)
void VARGS Netchan_OutOfBandPrint (unsigned int ncflags, netadr_t *adr, char *format, ...)
{
va_list argptr;
static char string[8192]; // ??? why static?
@ -342,10 +343,10 @@ void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, .
va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string);
Netchan_OutOfBand (ncflags, adr, strlen(string), (qbyte *)string);
}
#ifndef CLIENTONLY
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...)
void VARGS Netchan_OutOfBandTPrintf (unsigned int ncflags, netadr_t *adr, int language, translation_t text, ...)
{
va_list argptr;
static char string[8192]; // ??? why static?
@ -359,9 +360,44 @@ void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language,
va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string);
Netchan_OutOfBand (ncflags, adr, strlen(string), (qbyte *)string);
}
#endif
size_t Netchan_GetMaxUnreliable(netchan_t *chan)
{ //returns the maximum unreliable size we should be aiming for
#ifdef HAVE_SERVER
//debug prints
if (!(chan->flags&NCF_CLIENT) && chan == &svs.clients[0].netchan)
{
static int oldmtu;
if (oldmtu != chan->mtu_cur)
{
Con_DPrintf("Player0 MTU changed %i->%i\n", oldmtu, chan->mtu_cur);
oldmtu = chan->mtu_cur;
}
}
#endif
// if (chan->remote_address.type == NA_LOOPBACK)
// return ~0u; //our client supports big stuff. demos don't really care either so its fine.
if (chan->incoming_acknowledged > chan->last_reliable_sequence
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
{ //we want to send a reliable...
if (chan->reliable_length) //one will be resent
return chan->mtu_cur - chan->reliable_length;
if (chan->message.cursize) //a new one will go out
return chan->mtu_cur - chan->message.cursize;
}
return chan->mtu_cur;
}
/*
==============
Netchan_Setup
@ -369,28 +405,75 @@ Netchan_Setup
called to open a channel to a remote system
==============
*/
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport)
void Netchan_Setup (unsigned int flags, netchan_t *chan, netadr_t *adr, int qport, unsigned int mtu)
{
memset (chan, 0, sizeof(*chan));
chan->sock = sock;
chan->flags = flags;
chan->remote_address = *adr;
chan->last_received = realtime;
#ifdef NQPROT
chan->nqreliable_allowed = true;
#endif
chan->incoming_unreliable = -1;
chan->message.data = chan->message_buf;
chan->message.allowoverflow = true;
chan->message.maxsize = MAX_QWMSGLEN;
chan->qport = qport;
if (flags&NCF_CLIENT)
chan->outgoing_sequence = 1; //so the first one doesn't get dropped.
if (adr->prot == NP_KEXLAN)
chan->qportsize = 0;
else
chan->qportsize = 2;
chan->qport = qport;
//input mtu is the expected 'udp data size'
if (mtu<64 || mtu > 0xffff)
mtu = MAX_QWMSGLEN;
mtu = max(mtu, 508);
//compute the minimum mtu for the address type
if (adr->type == NA_IP)
chan->mtu_min = 508; //576 - 20..60(IP header) - 8(udp header)
else if (adr->type == NA_IPV6)
chan->mtu_min = 1200;
else if (adr->type == NA_IPX)
chan->mtu_min = 1450;
#ifdef SUPPORT_ICE
else if (adr->type == NA_ICE)
chan->mtu_min = 508; //match ipv4 here...
#endif
else if (adr->type == NA_LOOPBACK)
chan->mtu_min = 8192;
else
chan->mtu_min = 1450;
if (chan->mtu_min < 1024)
chan->mtu_min = 1200; //the internet is ethernet. if you can't deal with ipv6's limit then your connection is seriously dodgy. plus this lets us be a bit more agressive.
mtu -= PACKET_HEADER; //Note: This is not considered in vanilla - meaning net_mtu should be 1458 to match it (which will probably cause PTB issues).
if (flags&NCF_CLIENT)
mtu -= chan->qportsize;
if (flags&NCF_FRAGABLE)
mtu -= 2;
#ifdef SUPPORT_ICE
if (adr->type == NA_ICE)
mtu -= 48+12; //fixme: check if we're actually using the dtls and sctp layers or not.
else
#endif
{
if (adr->prot == NP_DTLS || adr->prot == NP_TLS)
mtu -= 48;
}
chan->mtu_min = min(mtu, chan->mtu_min);
chan->mtu_cur = mtu; //try to use the requested size to begin with. if it fails (probably on the realibles) then we'll allow it to drop
chan->mtu_max = mtu; //don't grow beyond what the user set. we're not aware of multiple paths nor are we tracking packetloss rates so if its partly wrong they'll get a load more loss, so don't be agressive here. let the user do that themselves!
chan->mtu_reprobetime = realtime; //try and grow the effective mtu after a bit (route may have changed)
chan->message.data = chan->message_buf;
chan->message.allowoverflow = true;
chan->message.maxsize = min(chan->mtu_cur, sizeof(chan->message_buf));
}
@ -481,9 +564,8 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
//note: its zlib rather than raw deflate (wasting a further 6 bytes...).
net_message.cursize = ZLib_DecompressBuffer(net_message.data+8, net_message.cursize-8, tmp, 0xffff);
if (net_message.cursize < PACKET_HEADER)
#endif
{
if (chan->sock == NS_CLIENT)
if (chan->flags&NCF_CLIENT)
{ //clients can just throw an error. the server will appear dead if we try to just ignore it.
Host_EndGame("QuakeEx netchan decompression error");
return NQNC_IGNORED;
@ -499,6 +581,15 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
MSG_BeginReading (&net_message, chan->netprim);
header = LongSwap(MSG_ReadLong()); //re-read the now-decompressed copy of the header for the real flags
#else
if (chan->flags&NCF_CLIENT)
Host_EndGame("NQNetChan_Process: zlib not enabled at compile time");
else
Con_Printf("QuakeEx netchan decompression error");
net_message.data[8] = (chan->flags&NCF_CLIENT)?svc_disconnect:clc_disconnect;
net_message.cursize = 9;
return NQNC_RELIABLE;
#endif
}
#endif
if (net_message.cursize != (header & NETFLAG_LENGTH_MASK))
@ -534,7 +625,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
if (showpackets.value)
Con_Printf ("in %s a=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence
, 0);
@ -568,11 +659,10 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
chan->last_received = realtime;
chan->incoming_acknowledged++;
chan->good_count++;
if (showpackets.value)
Con_Printf ("in %s u=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->incoming_unreliable
, net_message.cursize);
return NQNC_UNRELIABLE;
@ -583,10 +673,10 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
//always reply. a stale sequence probably means our ack got lost.
runt[0] = BigLong(NETFLAG_ACK | 8);
runt[1] = BigLong(sequence);
NET_SendPacket (chan->sock, 8, runt, &net_from);
NET_SendPacket (chan->flags, 8, runt, &net_from);
if (showpackets.value)
Con_Printf ("out %s a=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, sequence
, 0);
@ -613,7 +703,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
if (showpackets.value)
Con_Printf ("in %s r=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence
, net_message.cursize);
return NQNC_RELIABLE; //we can read it now
@ -648,12 +738,14 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
qbyte send_buf[MAX_OVERALLMSGLEN + PACKET_HEADER];
qboolean send_reliable;
char remote_adr[MAX_ADR_SIZE];
unsigned w1, w2;
unsigned w1, w2, mtuseq;
int i;
neterr_t e;
qboolean ismtuprobe;
int dupes = chan->dupe;
int availbytes = Netchan_CanBytes(chan, rate);
int hsz;
availbytes = max(0, availbytes); //make sure it can't go negative (clientside doesn't check rate limits much)
#ifdef NQPROT
@ -688,7 +780,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
MSG_WriteLong(&send, LongSwap(chan->reliable_sequence));
//limit the payload length to nq's datagram max size.
//relax the limitation if its reliable (ie: over tcp) where its assumed to have no real limit
//relax the limitation if its reliable (ie: over tcp) where its assumed to have no real limit (beware tunnels)
if (i > MAX_NQDATAGRAM && !NET_AddrIsReliable(&chan->remote_address))
i = MAX_NQDATAGRAM;
@ -711,13 +803,13 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
sentsize += send.cursize;
if (showpackets.value)
Con_Printf ("out %s r s=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->reliable_sequence
, send.cursize);
chan->nqreliable_allowed = false;
chan->nqreliable_resendtime = realtime + 0.3; //resend reliables after 0.3 seconds. nq transports suck.
chan->nqreliable_resendtime = realtime + 0.3; //resend reliables after 0.3 seconds. nq transports suck. FIXME: reduce to pingtime
if (NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address) == NETERR_SENT && (
if (NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address) == NETERR_SENT && (
NET_AddrIsReliable(&chan->remote_address) || chan->nqunreliableonly==3 ))
{ //if over tcp (or we're dropping the connection), everything is assumed to be reliable. pretend it got acked now.
//if we get an ack later, then who cares.
@ -746,17 +838,17 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
*(int*)send_buf = BigLong(NETFLAG_UNRELIABLE | send.cursize);
for (i = -1, e = NETERR_SENT; i < dupes && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
e = NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address);
sentsize += send.cursize*i;
if (e == NETERR_MTU && chan->mtu > 560)
{
Con_Printf("Reducing MSS to %i\n", chan->mtu);
chan->mtu -= 10;
if (e == NETERR_MTU && chan->mtu_cur > chan->mtu_min)
{ //yay, router works properly. unfortunately we don't know the exact size so keep retrying with a slightly smaller value until it goes through...
chan->mtu_cur = max(chan->mtu_min, chan->mtu_cur-10);
Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
}
if (showpackets.value)
Con_Printf ("out %s u=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->outgoing_unreliable-1
, send.cursize);
send.cursize = 0;
@ -781,7 +873,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->incoming_acknowledged > chan->last_reliable_sequence
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
send_reliable = true;
send_reliable = true; //they acked a later packet without acking the reliable...
// if the reliable transmit buffer is empty, copy the current message out
if (!chan->reliable_length && chan->message.cursize)
@ -791,9 +883,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
chan->message.cursize = 0;
chan->reliable_sequence ^= 1;
send_reliable = true;
chan->mtu_resends=0;
}
if (send_reliable && chan->remote_address.prot == NP_KEXLAN)
if (send_reliable && chan->remote_address.prot == NP_KEXLAN) //FIXME: use with webrtc too - sctp can avoid the round-trip delay.
#ifndef SERVERONLY
if (!cls.demoplayback)
#endif
@ -801,14 +895,14 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->reliable_length)
{
send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
send.maxsize = sizeof(send_buf);
send.cursize = 0;
MSG_WriteLong (&send, 1u<<31);
MSG_WriteLong (&send, 1u<<31);
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
if (NETERR_SENT == NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address))
if (NETERR_SENT == NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address))
chan->reliable_length = 0; //the lower layer will handle any retransmission for us.
}
send_reliable = 0;
@ -817,13 +911,18 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
// write the packet header
send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
send.maxsize = PACKET_HEADER + ((chan->flags&NCF_CLIENT)?chan->qportsize:0) + ((chan->flags&NCF_FRAGABLE)?2:0);
send.maxsize += chan->mtu_cur;
send.cursize = 0;
mtuseq = chan->outgoing_sequence&(countof(chan->sentsizes)-1);
for (; (chan->outgoing_sequence_last&(countof(chan->sentsizes)-1)) != mtuseq; chan->outgoing_sequence_last++)
chan->sentsizes[chan->outgoing_sequence_last&(countof(chan->sentsizes)-1)] = 0; //lost c2s or something, gaps now.
w1 = chan->outgoing_sequence | (send_reliable<<31);
w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence<<31);
if (chan->pext_stunaware)
if (chan->flags&NCF_STUNAWARE)
{
w1 = BigLong(w1+ANTISTUNBIAS);
w2 = BigLong(w2);
@ -833,23 +932,26 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
MSG_WriteLong (&send, w1);
MSG_WriteLong (&send, w2);
hsz = 8;
// send the qport if we are a client
#ifndef SERVERONLY
if (chan->sock == NS_CLIENT)
if (chan->flags&NCF_CLIENT)
{
if (chan->qportsize == 2)
MSG_WriteShort (&send, chan->qport);
else if (chan->qportsize == 1)
MSG_WriteByte (&send, chan->qport&0xff);
hsz += chan->qportsize;
}
#endif
if (chan->pext_fragmentation)
if (chan->flags&NCF_FRAGABLE)
{
//allow the max size to be bigger, sending everything available
send.maxsize = MAX_OVERALLMSGLEN + PACKET_HEADER;
send.maxsize = MAX_OVERALLMSGLEN-100;
MSG_WriteShort(&send, 0);
hsz += 2;
}
// copy the reliable message to the packet first
@ -868,22 +970,70 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
}
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence;
if (chan->mtu_resends > 5)
{ //getting blackholed?
if (chan->mtu_cur > chan->mtu_min)
{ //reset the mtu, and re-enable probes to get it back up to something usable.
chan->mtu_cur = chan->mtu_min;
// chan->mtu_cur = max(chan->mtu_min, min(send.cursize, chan->mtu_cur-16));
Con_DPrintf("Reliables Blackholed? Reducing MSS to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //and try and grow it again.
}
//chan->mtu_resends = 0;
}
chan->mtu_resends++;
}
if (chan->outgoing_sequence - chan->incoming_acknowledged > 128 && chan->mtu_cur > chan->mtu_min)
{
chan->mtu_cur = chan->mtu_min;
// chan->mtu_cur = max(chan->mtu_min, min(send.cursize, chan->mtu_cur-16));
Con_DPrintf("MTU blackhole? Reducing MSS to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //and try and grow it again.
}
// add the unreliable part if space is available
if (send.maxsize - send.cursize >= length)
SZ_Write (&send, data, length);
ismtuprobe = false;
if (chan->mtu_reprobetime < realtime)
{
chan->mtu_probes = min(chan->mtu_probes,4);
chan->mtu_reprobetime = realtime + 30;
}
if (!send_reliable/*reliables depend on round trip times, don't risk losing them*/ &&
chan->incoming_acknowledged >= chan->outgoing_mtu_probe+chan->mtu_probes/*not still waiting for one, slow down a bit if they're dropping.*/ &&
chan->mtu_cur < chan->mtu_max && chan->mtu_probes < 5/*give up if its just not growing*/)
{
int targsize = min(chan->mtu_max, chan->mtu_cur+16);
int padsize = (hsz+targsize)-send.cursize;
if (padsize > 0 && targsize <= send.maxsize)
{
if (chan->flags&NCF_CLIENT)
Q_memset (SZ_GetSpace(&send,padsize),clc_nop,padsize);
else
Q_memset (SZ_GetSpace(&send,padsize),svc_nop,padsize);
ismtuprobe = true; //don't do our fragmentation stuff.
chan->mtu_probes++;
chan->outgoing_mtu_probe = chan->outgoing_sequence;
chan->mtu_reprobetime = realtime + 30;
Con_DPrintf("Sending mtu probe\n");
}
}
// send the datagram
i = chan->outgoing_sequence & (MAX_LATENT-1);
chan->outgoing_size[i] = send.cursize;
chan->outgoing_time[i] = realtime;
// i = chan->outgoing_sequence & (MAX_LATENT-1);
// chan->outgoing_size[i] = send.cursize;
// chan->outgoing_time[i] = realtime;
#ifdef HUFFNETWORK
if (chan->compresstable)
{
//int oldsize = send.cursize;
Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->pext_fragmentation?2:0));
Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->flags&NCF_CLIENT)?2:0) + (chan->flags&NCF_FRAGABLE?2:0));
// Con_Printf("%i becomes %i\n", oldsize, send.cursize);
// Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8);
}
@ -895,23 +1045,25 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (!cls.demoplayback)
#endif
{
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
dupes = min(chan->dupe, availbytes / send.cursize);
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7))
if (ismtuprobe || !(chan->flags&NCF_FRAGABLE))// || send.cursize < ((chan->mtu - hsz)&~7))
{ //vanilla sends
for (i = -1; i < dupes && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * i;
e = NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address);
//ipv4 'guarentees' mtu sizes of at least 560ish.
//our reliable/backbuf messages are limited to 1024 bytes.
//this means that large reliables may be unsendable.
if (e == NETERR_MTU && chan->mtu > 560)
if (e == NETERR_MTU && send.cursize-hsz > chan->mtu_min)
{
Con_Printf("Reducing MSS to %i\n", chan->mtu);
chan->mtu -= 10;
chan->mtu_cur = max(chan->mtu_min, send.cursize-hsz-10);
chan->mtu_max = min(chan->mtu_max, chan->mtu_cur); //don't try growing past it
Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
}
chan->sentsizes[mtuseq] = send.cursize-hsz;
send.cursize += send.cursize * i;
}
else
{ //fte's fragmentaton protocol
@ -925,14 +1077,15 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
/*send the additional parts, adding new headers within the previous packet*/
do
{
no = offset + chan->mtu - hsz;
no = offset + chan->mtu_cur - hsz;
if (no < send.cursize-hsz)
{
no &= ~7;
more = true;
}
else
{
{ //this is the last...
no = send.cursize-hsz;
more = false;
}
@ -940,7 +1093,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
*(int*)&send.data[(offset) + 0] = LittleLong(w1);
*(int*)&send.data[(offset) + 4] = LittleLong(w2);
#ifndef SERVERONLY
if (chan->sock == NS_CLIENT)
if (chan->flags&NCF_CLIENT)
{
if (chan->qportsize == 2)
*(short*)&send.data[offset + hsz-4] = LittleShort(chan->qport);
@ -955,16 +1108,20 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
for (i = -1; i < dupes && e == NETERR_SENT; i++)
{
fragbytes = (no - offset) + hsz;
e = NET_SendPacket (chan->sock, fragbytes, send.data + offset, &chan->remote_address);
outbytes += fragbytes;
if (e == NETERR_MTU && !offset && chan->mtu > 560)
e = NET_SendPacket (chan->flags, fragbytes, send.data + offset, &chan->remote_address);
if (e == NETERR_MTU && !offset && chan->mtu_cur > chan->mtu_min)
{
chan->mtu -= 16;
Con_Printf("Reducing MSS to %i\n", chan->mtu);
chan->mtu_cur = max(chan->mtu_min, chan->mtu_cur-16);
chan->mtu_max = min(chan->mtu_max, chan->mtu_cur); //don't try growing past it
Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
no = offset;
more = true;
e = NETERR_SENT; //... keep trying...
break;
}
if (!offset)
chan->sentsizes[mtuseq] = fragbytes-hsz;
outbytes += fragbytes;
}
}
offset = no;
@ -1000,7 +1157,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
}
Con_Printf ("%f %s --> s=%i(%i) a=%i(%i) %i%s\n"
, Sys_DoubleTime()
, chan->sock == NS_SERVER?"s2c":"c2s"
, (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->outgoing_sequence
, send_reliable
, chan->incoming_sequence
@ -1026,6 +1183,7 @@ qboolean Netchan_Process (netchan_t *chan)
unsigned reliable_ack, reliable_message;
char adr[MAX_ADR_SIZE];
int offset;
int oob_reliable;
if (
#ifndef SERVERONLY
@ -1041,7 +1199,7 @@ qboolean Netchan_Process (netchan_t *chan)
sequence = MSG_ReadLong ();
sequence_ack = MSG_ReadLong ();
if (chan->pext_stunaware)
if (chan->flags&NCF_STUNAWARE)
{
sequence = BigLong(sequence);
if (!(sequence&ANTISTUNBIAS))
@ -1050,13 +1208,15 @@ qboolean Netchan_Process (netchan_t *chan)
sequence_ack = BigLong(sequence_ack);
}
oob_reliable = (sequence == (1u<<31) && sequence_ack == (1u<<31));
// skip over the qport if we are a server (its handled elsewhere)
#ifndef CLIENTONLY
if (chan->sock == NS_SERVER)
if (!(chan->flags&NCF_CLIENT))
MSG_ReadSkip (chan->qportsize);
#endif
if (chan->pext_fragmentation)
if (chan->flags&NCF_FRAGABLE)
offset = (unsigned short)MSG_ReadShort();
else
offset = 0;
@ -1070,7 +1230,7 @@ qboolean Netchan_Process (netchan_t *chan)
if (showpackets.value)
Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n"
, Sys_DoubleTime()
, chan->sock == NS_SERVER?"c2s":"s2c"
, (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence
, reliable_message
, sequence_ack
@ -1111,16 +1271,42 @@ qboolean Netchan_Process (netchan_t *chan)
//
// discard stale or duplicated packets
//
if (sequence <= (unsigned)chan->incoming_sequence &&
!(reliable_message && chan->remote_address.prot == NP_KEXLAN)) //*sigh* reliables don't work properly here.
{
if (showdrop.value)
Con_TPrintf ("%s:Out of order packet %i at %i\n"
if (oob_reliable)
{ //if its an oob reliable then its sequence numbers are screwy and bypass the dupe/etc check.
if (NET_AddrIsReliable(&chan->remote_address))
; //mostly for NP_KEXLAN.
else
{
Con_TPrintf ("%s:Unexpected out-of-band reliable at %i\n"
, NET_AdrToString (adr, sizeof(adr), &chan->remote_address)
, sequence
, chan->incoming_sequence);
return false;
return false;
}
}
else
{
int ssize = 0;
if (sequence <= (unsigned)chan->incoming_sequence &&
!(reliable_message && chan->remote_address.prot == NP_KEXLAN)) //*sigh* reliables don't work properly here.
{
if (showdrop.value)
Con_TPrintf ("%s:Out of order packet %i at %i\n"
, NET_AdrToString (adr, sizeof(adr), &chan->remote_address)
, sequence
, chan->incoming_sequence);
return false;
}
if (chan->outgoing_sequence-sequence_ack < countof(chan->sentsizes)-2)
ssize = chan->sentsizes[sequence_ack&(countof(chan->sentsizes)-1)];
if (ssize && ssize > chan->mtu_cur)
{
chan->mtu_cur = ssize;
Con_DPrintf("MTU confirmed to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //start growing again.
}
}
if (offset)
{
@ -1209,7 +1395,7 @@ qboolean Netchan_Process (netchan_t *chan)
//
// if this message contains a reliable message, bump incoming_reliable_sequence
//
if (reliable_message && chan->remote_address.prot == NP_KEXLAN) //*sigh* reliables don't work properly here.
if (oob_reliable) //*sigh* reliables don't work properly here.
; //don't corrupt sequences/acks/etc.
else
{
@ -1228,7 +1414,6 @@ qboolean Netchan_Process (netchan_t *chan)
+ (chan->outgoing_sequence-sequence_ack)*(1.0-OLD_AVG);
chan->frame_rate = chan->frame_rate*OLD_AVG
+ (realtime-chan->last_received)*(1.0-OLD_AVG);
chan->good_count += 1;
chan->last_received = realtime;

View File

@ -297,8 +297,10 @@ static const struct
static neterr_t ICE_Transmit(void *cbctx, const qbyte *data, size_t datasize);
static neterr_t TURN_Encapsulate(struct icestate_s *ice, netadr_t *to, const qbyte *data, size_t datasize);
static void TURN_AuthorisePeer(struct icestate_s *con, struct iceserver_s *srv, int peer);
#ifdef HAVE_DTLS
static neterr_t SCTP_Transmit(sctp_t *sctp, const void *data, size_t length);
#endif
static qboolean ICE_SetFailed(struct icestate_s *con, const char *reasonfmt, ...) LIKEPRINTF(2);
static struct icestate_s *icelist;
@ -2168,8 +2170,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
con->dtlsstate = con->dtlsfuncs->CreateContext(&con->cred, con, ICE_Transmit, con->dtlspassive);
else if (net_enable_dtls.ival >= 3)
{ //peer doesn't seem to support dtls.
con->state = ICE_FAILED;
Con_Printf(CON_WARNING"WARNING: [%s]: peer does not support dtls. Set net_enable_dtls to 1 to make optional.\n", con->friendlyname);
ICE_SetFailed(con, "peer does not support dtls. Set net_enable_dtls to 1 to make optional.\n");
}
else if (con->state == ICE_CONNECTING && net_enable_dtls.ival>=2)
Con_Printf(CON_WARNING"WARNING: [%s]: peer does not support dtls.\n", con->friendlyname);
@ -2189,10 +2190,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
else if (!con->dtlsstate && con->cred.peer.hash)
{
if (!con->peersctpoptional)
{
con->state = ICE_FAILED;
Con_Printf(CON_WARNING"WARNING: [%s]: peer is trying to use dtls.%s\n", con->friendlyname, net_enable_dtls.ival?"":" Set ^[/net_enable_dtls 1^].");
}
ICE_SetFailed(con, "peer is trying to use dtls.%s\n", net_enable_dtls.ival?"":" Set ^[/net_enable_dtls 1^].");
}
#endif
}
@ -2248,10 +2246,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
if (oldstate != con->state && con->state == ICE_CONNECTED)
{
if (con->chosenpeer.type == NA_INVALID)
{
con->state = ICE_FAILED;
Con_Printf(CON_WARNING"[%s]: ICE failed. peer not valid.\n", con->friendlyname);
}
ICE_SetFailed(con, "ICE failed. peer not valid.\n");
#ifndef CLIENTONLY
else if (con->proto == ICEP_QWSERVER && con->mode != ICEM_WEBRTC)
{
@ -2413,6 +2408,18 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
return false;
return true;
}
static qboolean ICE_SetFailed(struct icestate_s *con, const char *reasonfmt, ...)
{
va_list argptr;
char string[256];
va_start (argptr, reasonfmt);
Q_vsnprintf (string,sizeof(string)-1, reasonfmt,argptr);
va_end (argptr);
Con_Printf(CON_WARNING"[%s]: %s\n", con->friendlyname, string);
return ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); //does the disconnection stuff.
}
static char *ICE_CandidateToSDP(struct icecandidate_s *can, char *value, size_t valuelen)
{
Q_snprintfz(value, valuelen, "a=candidate:%i %i %s %i %s %i typ %s",
@ -2988,7 +2995,7 @@ void ICE_Tick(void)
continue;
}
else if ((signed int)(curtime-con->icetimeout) > 0)
ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); //with no broker context, if we're not trying to send anything then kill the link.
ICE_SetFailed(con, S_COLOR_GRAY"[%s]: ice timeout\n", con->friendlyname);
}
switch(con->mode)
@ -3195,6 +3202,7 @@ struct sctp_chunk_s
#define SCTP_TYPE_COOKIEECHO 10
#define SCTP_TYPE_COOKIEACK 11
#define SCTP_TYPE_SHUTDOWNDONE 14
#define SCTP_TYPE_PAD 132
#define SCTP_TYPE_FORWARDTSN 192
qbyte flags;
quint16_t length;
@ -3712,6 +3720,7 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
sctp->cookie = Z_Malloc(sctp->cookiesize);
memcpy(sctp->cookie, p+1, sctp->cookiesize);
break;
case 32773: //Padding
case 32776: //ASCONF
break;
case 49152:
@ -3720,6 +3729,12 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
default:
if (net_ice_debug.ival >= 2)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Found unknown init parameter %i||%#x\n", sctp->friendlyname, ptype, ptype);
if (ptype&0x4000)
; //FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")
if (!(ptype&0x8000))
return; //'do not process nay further chunks'
//otherwise parse the next as normal.
break;
}
p = (void*)((qbyte*)p + ((plen+3)&~3));
@ -3811,11 +3826,11 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
case SCTP_TYPE_ABORT:
SCTP_ErrorChunk(sctp, "Abort", (struct sctp_errorcause_s*)(c+1), clen-sizeof(*c));
if (sctp->icestate)
ICE_Set(sctp->icestate, "state", STRINGIFY(ICE_FAILED));
ICE_SetFailed(sctp->icestate, "SCTP Abort");
break;
case SCTP_TYPE_SHUTDOWN: //FIXME. we should send an ack...
if (sctp->icestate)
ICE_Set(sctp->icestate, "state", STRINGIFY(ICE_FAILED));
ICE_SetFailed(sctp->icestate, "SCTP Shutdown");
if (net_ice_debug.ival >= 1)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Shutdown\n", sctp->friendlyname);
break;
@ -3849,6 +3864,9 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
case SCTP_TYPE_COOKIEACK:
sctp->o.writable = true; //we know the other end is now open.
break;
case SCTP_TYPE_PAD:
//don't care.
break;
case SCTP_TYPE_FORWARDTSN:
if (clen >= sizeof(struct sctp_chunk_fwdtsn_s))
{
@ -3874,6 +3892,24 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
//no idea what this chunk is, just ignore it...
if (net_ice_debug.ival >= 1)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Unsupported chunk %i\n", sctp->friendlyname, c->type);
switch (c->type>>6)
{
case 0:
clen = (qbyte*)msgend - (qbyte*)c; //'do not process any further chunks'
break;
case 1:
clen = (qbyte*)msgend - (qbyte*)c; //'do not process any further chunks'
/*FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")*/
break;
case 2:
//silently ignore it
break;
case 3:
//ignore-with-error
/*FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")*/
break;
}
break;
}
c = (struct sctp_chunk_s*)((qbyte*)c + ((clen+3)&~3)); //next chunk is 4-byte aligned.
@ -5015,7 +5051,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
case NETERR_NOROUTE:
return false; //not a dtls packet at all. don't de-ICE it when we're meant to be using ICE.
case NETERR_DISCONNECTED: //dtls failure. ICE failed.
iceapi.Set(con, "state", STRINGIFY(ICE_FAILED));
ICE_SetFailed(con, "DTLS Failure");
return true;
default: //some kind of failure decoding the dtls packet. drop it.
return true;
@ -5528,7 +5564,7 @@ handleerror:
b->serverid = cl;
if (net_ice_debug.ival)
Con_Printf(S_COLOR_GRAY"[%s]: Relay to server now open\n", b->ice?b->ice->friendlyname:"?");
Con_Printf(S_COLOR_GRAY"[%s]: Meta channel to game server now open\n", b->ice?b->ice->friendlyname:"?");
}
break;
case ICEMSG_OFFER: //we received an offer from a client
@ -5604,6 +5640,10 @@ handleerror:
}
}
break;
default:
if (net_ice_debug.ival)
Con_Printf(S_COLOR_GRAY"[%s]: Broker send unknown packet: %i\n", b->ice?b->ice->friendlyname:"?", cmd);
break;
}
break;
}
@ -5765,9 +5805,9 @@ void SVC_ICE_Offer(void)
if (!sv.state)
return; //err..?
if (net_from.prot != NP_DTLS && net_from.prot != NP_WSS && net_from.prot != NP_TLS)
{ //a) dtls provides a challenge.
{ //a) dtls provides a challenge (ensuring we can at least ban them).
//b) this contains the caller's ips. We'll be pinging them anyway, but hey. also it'll be too late at this point but it keeps the other side honest.
Con_ThrottlePrintf(&throttletimer, 0, CON_WARNING"%s: ice handshake via %s was unencrypted\n", NET_AdrToString (buf, sizeof(buf), &net_from));
Con_ThrottlePrintf(&throttletimer, 0, CON_WARNING"%s: ice handshake from %s was unencrypted\n", NET_AdrToString (buf, sizeof(buf), &net_from), clientaddr);
return;
}

View File

@ -155,8 +155,8 @@
GNUTLS_FUNC(gnutls_certificate_set_verify_function,void,(gnutls_certificate_credentials_t cred, gnutls_certificate_verify_function *func)) \
GNUTLS_FUNC(gnutls_session_get_ptr,void*,(gnutls_session_t session)) \
GNUTLS_FUNC(gnutls_session_set_ptr,void,(gnutls_session_t session, void *ptr)) \
GNUTLS_FUNCPTR(gnutls_malloc,void*,(size_t)) \
GNUTLS_FUNCPTR(gnutls_free,void,(void * ptr)) \
GNUTLS_FUNCPTR(gnutls_malloc,void*,(size_t sz),(sz)) \
GNUTLS_FUNCPTR(gnutls_free,void,(void *ptr),(ptr)) \
GNUTLS_FUNC(gnutls_server_name_set,int,(gnutls_session_t session, gnutls_server_name_type_t type, const void * name, size_t name_length)) \
GNUTLS_TRUSTFUNCS \
GNUTLS_VERIFYFUNCS \
@ -166,10 +166,10 @@
#ifdef GNUTLS_DYNAMIC
#define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args;
#define GNUTLS_FUNCPTR(n,ret,args) static ret (VARGS **q##n)args;
#define GNUTLS_FUNCPTR(n,ret,arglist,callargs) static ret (VARGS **q##n)arglist;
#else
#define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args = n;
#define GNUTLS_FUNCPTR(n,ret,args) static ret (VARGS **q##n)args = &n;
#define GNUTLS_FUNCPTR(n,ret,arglist,callargs) static ret VARGS q##n arglist {return n(callargs);};
#endif
#ifdef HAVE_DTLS
@ -198,11 +198,10 @@ static struct
static qboolean Init_GNUTLS(void)
{
#ifdef GNUTLS_DYNAMIC
dllfunction_t functable[] =
{
#define GNUTLS_FUNC(nam,ret,args) {(void**)&q##nam, #nam},
#define GNUTLS_FUNCPTR(nam,ret,args) {(void**)&q##nam, #nam},
#define GNUTLS_FUNCPTR(nam,ret,arglist,calllist) {(void**)&q##nam, #nam},
GNUTLS_FUNCS
#undef GNUTLS_FUNC
#undef GNUTLS_FUNCPTR
@ -434,7 +433,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
#ifdef _DEBUG
for (j = 0, offset = 0; j < certcount; j++)
offset += certlist[j].size;
Con_Printf("%s cert %zu bytes (chain %u)\n", file->certname, offset, certcount);
Con_Printf("%s cert %"PRIuSIZE" bytes (chain %u)\n", file->certname, offset, certcount);
Con_Printf("/*%s*/\"", file->certname);
for (j = 0; file->certname[j]; j++)
Con_Printf("\\x%02x", file->certname[j]^0xff);
@ -551,8 +550,10 @@ static int QDECL SSL_CheckFingerprint(gnutls_session_t session)
if (!memcmp(digest, file->peerdigest, file->peerhashfunc->digestsize))
return 0;
Con_Printf(CON_ERROR "%s: certificate chain (%i) does not match fingerprint\n", *file->certname?file->certname:"<anon>", certcount);
}
Con_Printf(CON_ERROR "%s: rejecting certificate\n", file->certname);
else
Con_Printf(CON_ERROR "%s: peer did not provide any certificate\n", *file->certname?file->certname:"<anon>");
return GNUTLS_E_CERTIFICATE_ERROR;
}
#endif
@ -822,22 +823,23 @@ static qboolean servercertfail;
static gnutls_datum_t cookie_key;
#endif
static vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
static vfsfile_t *SSL_OpenPrivKey(char *displayname, size_t displaysize)
{
#define privname "privkey.pem"
vfsfile_t *privf;
const char *mode = nativename?"wb":"rb";
const char *mode = displayname?"wb":"rb";
int i = COM_CheckParm("-privkey");
if (i++)
{
if (nativename)
Q_strncpyz(nativename, com_argv[i], nativesize);
if (displayname)
if (!FS_DisplayPath(com_argv[i], FS_SYSTEM, displayname, displaysize))
Q_strncpyz(displayname, com_argv[i], displaysize);
privf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
}
else
{
if (nativename)
if (!FS_NativePath(privname, FS_ROOT, nativename, nativesize))
if (displayname)
if (!FS_DisplayPath(privname, FS_ROOT, displayname, displaysize))
return NULL;
privf = FS_OpenVFS(privname, mode, FS_ROOT);
@ -845,24 +847,24 @@ static vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
return privf;
#undef privname
}
static vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize)
static vfsfile_t *SSL_OpenPubKey(char *displayname, size_t displaysize)
{
#define fullchainname "fullchain.pem"
#define pubname "cert.pem"
vfsfile_t *pubf = NULL;
const char *mode = nativename?"wb":"rb";
const char *mode = displayname?"wb":"rb";
int i = COM_CheckParm("-pubkey");
if (i++)
{
if (nativename)
Q_strncpyz(nativename, com_argv[i], nativesize);
if (displayname)
Q_strncpyz(displayname, com_argv[i], displaysize);
pubf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
}
else
{
if (!pubf && (!nativename || FS_NativePath(fullchainname, FS_ROOT, nativename, nativesize)))
if (!pubf && (!displayname || FS_DisplayPath(fullchainname, FS_ROOT, displayname, displaysize)))
pubf = FS_OpenVFS(fullchainname, mode, FS_ROOT);
if (!pubf && (!nativename || FS_NativePath(pubname, FS_ROOT, nativename, nativesize)))
if (!pubf && (!displayname || FS_DisplayPath(pubname, FS_ROOT, displayname, displaysize)))
pubf = FS_OpenVFS(pubname, mode, FS_ROOT);
}
return pubf;
@ -957,24 +959,24 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred)
if (priv.size && pub.size)
{
char fullname[MAX_OSPATH];
privf = SSL_OpenPrivKey(fullname, sizeof(fullname));
char displayname[MAX_OSPATH];
privf = SSL_OpenPrivKey(displayname, sizeof(displayname));
if (privf)
{
VFS_WRITE(privf, priv.data, priv.size);
VFS_CLOSE(privf);
Con_Printf("Wrote %s\n", fullname);
Con_Printf("Wrote %s\n", displayname);
}
// memset(priv.data, 0, priv.size);
(*qgnutls_free)(priv.data);
memset(&priv, 0, sizeof(priv));
pubf = SSL_OpenPubKey(fullname, sizeof(fullname));
pubf = SSL_OpenPubKey(displayname, sizeof(displayname));
if (pubf)
{
VFS_WRITE(pubf, pub.data, pub.size);
VFS_CLOSE(pubf);
Con_Printf("Wrote %s\n", fullname);
Con_Printf("Wrote %s\n", displayname);
}
(*qgnutls_free)(pub.data);
memset(&pub, 0, sizeof(pub));
@ -1085,8 +1087,8 @@ qboolean SSL_InitGlobal(qboolean isserver)
char keyfile[MAX_OSPATH];
char certfile[MAX_OSPATH];
*keyfile = *certfile = 0;
if (FS_NativePath("key.pem", FS_ROOT, keyfile, sizeof(keyfile)))
if (FS_NativePath("cert.pem", FS_ROOT, certfile, sizeof(certfile)))
if (FS_SystemPath("key.pem", FS_ROOT, keyfile, sizeof(keyfile)))
if (FS_SystemPath("cert.pem", FS_ROOT, certfile, sizeof(certfile)))
ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], certfile, keyfile, GNUTLS_X509_FMT_PEM);
if (ret < 0)
{
@ -1127,6 +1129,13 @@ void GnuTLS_Shutdown(void)
qgnutls_global_deinit(); //refcounted.
}
#ifdef HAVE_DTLS
if (cookie_key.data)
{
(*qgnutls_free)(cookie_key.data);
memset(&cookie_key, 0, sizeof(cookie_key));
}
#endif
#ifdef GNUTLS_DYNAMIC
if (gnutls.hmod)
Sys_CloseLibrary(gnutls.hmod);

View File

@ -765,7 +765,7 @@ static PCCERT_CONTEXT SSPI_GetServerCertificate(void)
);
}
if (!ret)
Con_Printf(CON_ERROR"Certificate generation failed...\n");
Con_Printf(CON_ERROR"SChannel: Certificate generation failed...\n"); //happens in wine.
else
{
//this is stupid and redundant, yet apparently still needed.

File diff suppressed because it is too large Load Diff

View File

@ -394,7 +394,7 @@ typedef struct ftecrypto_s
const struct dtlsfuncs_s *(*DTLS_InitServer)(void); //returns NULL if there's no cert available.
//digital signature stuff. note: uses sha2_512
enum hashvalidation_e (*VerifyHash)(const qbyte *hashdata, size_t hashsize, const qbyte *certdata, size_t certsize, const qbyte *signdata, size_t signsize);
enum hashvalidation_e (*VerifyHash)(const qbyte *hashdata, size_t hashsize, const qbyte *certdata, size_t certsize, const qbyte *signdata, size_t signsize); //expect the cert in PEM format.
int (*GenerateSignature)(const qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax);
} ftecrypto_t;
#define cryptolib_count 6
@ -448,8 +448,8 @@ enum icemsgtype_s
ICEMSG_PEERLOST=0, //other side dropped connection
ICEMSG_GREETING=1, //master telling us our unique game name
ICEMSG_NEWPEER=2, //relay established, send an offer now.
ICEMSG_OFFER=3, //peer's initial details
ICEMSG_CANDIDATE=4, //candidate updates. may arrive late as new ones are discovered.
ICEMSG_OFFER=3, //peer->peer - peer's offer or answer details
ICEMSG_CANDIDATE=4, //peer->peer - candidate updates. may arrive late as new ones are discovered.
ICEMSG_ACCEPT=5, //go go go (response from offer)
ICEMSG_SERVERINFO=6,//server->broker (for advertising the server properly)
ICEMSG_SERVERUPDATE=7,//broker->browser (for querying available server lists)

View File

@ -16,7 +16,6 @@ struct q3gamecode_s *q3;
static struct plugin_s *q3plug;
#endif
#define Q_snprintf Q_snprintfz
#define Q_strlcpy Q_strncpyz
#define Q_strlcat Q_strncatz
#define Sys_Errorf Sys_Error
@ -28,12 +27,18 @@ static struct plugin_s *q3plug;
#include "../engine/common/com_phys_ode.c"
#endif
#ifdef STATIC_EZHUD //if its statically linked and loading by default then block it by default and let configs reenable it. The defaults must be maintained for deltaing configs to work, yet they're defective and should never be used in that default configuration
cvar_t plug_sbar = CVARD("plug_sbar", "0", "Controls whether plugins are allowed to draw the hud, rather than the engine (when allowed by csqc). This is typically used to permit the ezhud plugin without needing to bother unloading it.\n=0: never use hud plugins.\n&1: Use hud plugins in deathmatch.\n&2: Use hud plugins in singleplayer/coop.\n=3: Always use hud plugins (when loaded).");
#else
cvar_t plug_sbar = CVARD("plug_sbar", "3", "Controls whether plugins are allowed to draw the hud, rather than the engine (when allowed by csqc). This is typically used to permit the ezhud plugin without needing to bother unloading it.\n=0: never use hud plugins.\n&1: Use hud plugins in deathmatch.\n&2: Use hud plugins in singleplayer/coop.\n=3: Always use hud plugins (when loaded).");
#endif
cvar_t plug_loaddefault = CVARD("plug_loaddefault", "1", "0: Load plugins only via explicit plug_load commands\n1: Load built-in plugins and those selected via the package manager\n2: Scan for misc plugins, loading all that can be found, but not built-ins.\n3: Scan for plugins, and then load any built-ins");
extern qboolean Plug_Q3_Init(void);
extern qboolean Plug_Bullet_Init(void);
extern qboolean Plug_ODE_Init(void);
extern qboolean Plug_EZHud_Init(void);
extern qboolean Plug_OpenSSL_Init(void);
static struct
{
const char *name;
@ -50,6 +55,12 @@ static struct
{"GLTF", Plug_GLTF_Init},
#endif
#ifdef STATIC_OPENSSL
{"openssl_internal", Plug_OpenSSL_Init},
#endif
#ifdef STATIC_EZHUD
{"EZHud_internal", Plug_EZHud_Init},
#endif
#ifdef STATIC_Q3
{"quake3", Plug_Q3_Init},
#endif
@ -229,14 +240,14 @@ static plugin_t *Plug_Load(const char *file)
{ //already postfixed, don't mess with the name given
//mandate the fteplug_ prefix (don't let them load random dlls)
if (!Q_strncasecmp(file, PLUGINPREFIX, strlen(PLUGINPREFIX)))
if (FS_NativePath(file, prefixes[i], newplug->filename, sizeof(newplug->filename)))
if (FS_SystemPath(file, prefixes[i], newplug->filename, sizeof(newplug->filename)))
newplug->lib = Sys_LoadLibrary(newplug->filename, funcs);
}
else
{ //otherwise scan for it
for (j = 0; j < countof(postfixes) && !newplug->lib; j++)
{
if (FS_NativePath(va(PLUGINPREFIX"%s%s", file, postfixes[j]), prefixes[i], newplug->filename, sizeof(newplug->filename)))
if (FS_SystemPath(va(PLUGINPREFIX"%s%s", file, postfixes[j]), prefixes[i], newplug->filename, sizeof(newplug->filename)))
newplug->lib = Sys_LoadLibrary(newplug->filename, funcs);
}
}
@ -1068,7 +1079,9 @@ void Plug_Net_Close_Internal(qhandle_t handle)
static int QDECL Plug_Net_Recv(qhandle_t handle, void *dest, int destlen)
{
#ifdef HAVE_PACKET
int read;
#endif
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
return -2;
@ -1098,7 +1111,9 @@ static int QDECL Plug_Net_Recv(qhandle_t handle, void *dest, int destlen)
}
static int QDECL Plug_Net_Send(qhandle_t handle, void *src, int srclen)
{
#ifdef HAVE_PACKET
int written;
#endif
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
return -2;
switch(pluginstreamarray[handle].type)
@ -1125,6 +1140,7 @@ static int QDECL Plug_Net_Send(qhandle_t handle, void *src, int srclen)
return -2;
}
}
#ifdef HAVE_PACKET
static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr_t *address)
{
int written;
@ -1146,7 +1162,6 @@ static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr
return -2;
switch(pluginstreamarray[handle].type)
{
#ifdef HAVE_PACKET
case STREAM_SOCKET:
written = sendto(pluginstreamarray[handle].socket, src, srclen, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
if (written < 0)
@ -1159,11 +1174,11 @@ static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr
else if (written == 0)
return -2; //closed by remote connection.
return written;
#endif
default:
return -2;
}
}
#endif
static void QDECL Plug_Net_Close(qhandle_t handle)
{
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
@ -1187,7 +1202,7 @@ void QDECL Plug_FS_EnumerateFiles(enum fs_relative fsroot, const char *match, in
}
else
{
FS_NativePath("", fsroot, base, sizeof(base));
FS_SystemPath("", fsroot, base, sizeof(base));
Sys_EnumerateFiles(base, match, callback, ctx, NULL);
}
}
@ -1235,7 +1250,7 @@ static void Plug_Load_f(void)
void Plug_Initialise(qboolean fromgamedir)
{
char nat[MAX_OSPATH];
char sys[MAX_OSPATH], disp[MAX_OSPATH];
if (!plugfuncs)
{
@ -1260,15 +1275,15 @@ void Plug_Initialise(qboolean fromgamedir)
{
if (!fromgamedir)
{
if (FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)))
if (FS_DisplayPath("", FS_BINARYPATH, disp, sizeof(disp)) && FS_SystemPath("", FS_BINARYPATH, sys, sizeof(sys)))
{
Con_DPrintf("Loading plugins from \"%s\"\n", nat);
Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
Con_DPrintf("Loading plugins from \"%s\"\n", disp);
Sys_EnumerateFiles(sys, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
}
if (FS_NativePath("", FS_LIBRARYPATH, nat, sizeof(nat)))
if (FS_DisplayPath("", FS_LIBRARYPATH, disp, sizeof(disp)) && FS_SystemPath("", FS_BINARYPATH, sys, sizeof(sys)))
{
Con_DPrintf("Loading plugins from \"%s\"\n", nat);
Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
Con_DPrintf("Loading plugins from \"%s\"\n", disp);
Sys_EnumerateFiles(sys, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
}
}
}
@ -1664,7 +1679,7 @@ void Plug_Close_f(void)
for (plug = plugs; plug; plug = plug->next)
{
if (!strcmp(plug->name, name))
if (!Q_strcasecmp(plug->name, name))
{
Plug_Close(plug);
return;
@ -1674,7 +1689,7 @@ void Plug_Close_f(void)
name = va("plugins/%s", name);
for (plug = plugs; plug; plug = plug->next)
{
if (!strcmp(plug->name, name))
if (!Q_strcasecmp(plug->name, name))
{
Plug_Close(plug);
return;
@ -1760,6 +1775,7 @@ int QDECL Plug_List_Print(const char *fname, qofs_t fsize, time_t modtime, void
void Plug_List_f(void)
{
char displaypath[MAX_OSPATH];
char binarypath[MAX_OSPATH];
char librarypath[MAX_OSPATH];
char rootpath[MAX_OSPATH];
@ -1768,7 +1784,10 @@ void Plug_List_f(void)
Con_Printf("Loaded plugins:\n");
for (plug = plugs; plug; plug = plug->next)
Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", plug->filename, plug->name);
if (plug->lib && FS_DisplayPath(plug->filename, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", displaypath, plug->name);
else
Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", plug->filename, plug->name);
if (staticplugins[0].name)
{
@ -1777,17 +1796,18 @@ void Plug_List_f(void)
Plug_List_Print(staticplugins[u].name, 0, 0, NULL, NULL);
}
if (FS_NativePath("", FS_BINARYPATH, binarypath, sizeof(binarypath)))
if (FS_SystemPath("", FS_BINARYPATH, binarypath, sizeof(binarypath)))
{
#ifdef _WIN32
char *mssuck;
while ((mssuck=strchr(binarypath, '\\')))
*mssuck = '/';
#endif
Con_Printf("Scanning for plugins at %s:\n", binarypath);
Sys_EnumerateFiles(binarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, binarypath, NULL);
if (FS_DisplayPath(binarypath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(binarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
}
if (FS_NativePath("", FS_LIBRARYPATH, librarypath, sizeof(librarypath)))
if (FS_SystemPath("", FS_LIBRARYPATH, librarypath, sizeof(librarypath)))
{
#ifdef _WIN32
char *mssuck;
@ -1796,11 +1816,12 @@ void Plug_List_f(void)
#endif
if (strcmp(librarypath, rootpath))
{
Con_Printf("Scanning for plugins at %s:\n", librarypath);
Sys_EnumerateFiles(librarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, librarypath, NULL);
if (FS_DisplayPath(librarypath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(librarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
}
}
if (FS_NativePath("", FS_ROOT, rootpath, sizeof(rootpath)))
if (FS_SystemPath("", FS_ROOT, rootpath, sizeof(rootpath)))
{
#ifdef _WIN32
char *mssuck;
@ -1809,8 +1830,9 @@ void Plug_List_f(void)
#endif
if (strcmp(binarypath, rootpath))
{
Con_DPrintf("Scanning for plugins at %s:\n", rootpath);
Sys_EnumerateFiles(rootpath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, rootpath, NULL);
if (FS_DisplayPath(rootpath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(rootpath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
}
}
@ -1948,7 +1970,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
FS_FLocateFile,
FS_OpenVFS,
FS_NativePath,
FS_SystemPath,
FS_Rename,
FS_Remove,
@ -2009,6 +2031,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs))
return &funcs;
}
#ifdef HAVE_PACKET
if (!strcmp(interfacename, plugnetfuncs_name))
{
static plugnetfuncs_t funcs =
@ -2038,6 +2061,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs))
return &funcs;
}
#endif
if (!strcmp(interfacename, plugworldfuncs_name))
{
static plugworldfuncs_t funcs =
@ -2265,6 +2289,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
return &funcs;
}
#ifdef CL_MASTER
if (!strcmp(interfacename, plugmasterfuncs_name))
{
static plugmasterfuncs_t funcs =
@ -2285,6 +2310,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs))
return &funcs;
}
#endif
if (!strcmp(interfacename, plugimagefuncs_name))
{
static plugimagefuncs_t funcs =
@ -2374,6 +2400,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
VectorAngles,
AngleVectors,
GenMatrixPosQuat4Scale,
QuaternionSlerp,
Alias_ForceConvertBoneData,

View File

@ -1019,8 +1019,8 @@ void QCBUILTIN PF_getsurfacenormal(pubprogfuncs_t *prinst, struct globalvars_s *
model = w->Get_CModel(w, ent->v->modelindex);
if (!model || model->type != mod_brush || surfnum >= model->nummodelsurfaces)
{
if (!model || model->type != mod_brush || surfnum >= model->nummodelsurfaces || !model->surfaces[model->firstmodelsurface+surfnum].plane)
{ //non-planar surfs don't always have a single plane... return nothing instead of breaking.
G_FLOAT(OFS_RETURN+0) = 0;
G_FLOAT(OFS_RETURN+1) = 0;
G_FLOAT(OFS_RETURN+2) = 0;
@ -1053,11 +1053,23 @@ void QCBUILTIN PF_getsurfacetexture(pubprogfuncs_t *prinst, struct globalvars_s
if (!model || model->type != mod_brush)
return;
if (surfnum < 0 || surfnum >= model->nummodelsurfaces)
if (surfnum >= model->nummodelsurfaces)
return;
surfnum += model->firstmodelsurface;
surf = &model->surfaces[surfnum];
G_INT(OFS_RETURN) = PR_TempString(prinst, surf->texinfo->texture->name);
if (surfnum < 0)
{
surfnum = -1-surfnum;
if ((unsigned)surfnum >= (unsigned)model->numtextures)
return; //nope, outta range.
if (!model->textures[surfnum])
return; //some maps are just broken.
G_INT(OFS_RETURN) = PR_TempString(prinst, model->textures[surfnum]->name);
}
else
{
surfnum += model->firstmodelsurface;
surf = &model->surfaces[surfnum];
G_INT(OFS_RETURN) = PR_TempString(prinst, surf->texinfo->texture->name);
}
}
#define TriangleNormal(a,b,c,n) ( \
(n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), \
@ -2040,6 +2052,28 @@ void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
if (qcptr)
prinst->AddressableFree(prinst, cptr);
}
void QCBUILTIN PF_memcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int qcdst = G_INT(OFS_PARM0);
int qcsrc = G_INT(OFS_PARM1);
int size = G_INT(OFS_PARM2);
int srcoffset = (prinst->callargc>3)?G_INT(OFS_PARM3):0;
int dstoffset = (prinst->callargc>4)?G_INT(OFS_PARM4):0;
G_INT(OFS_RETURN) = 0;
if (size < 0)
PR_BIError(prinst, "PF_memcmp: invalid size\n");
else if (size)
{
void *dst = PR_PointerToNative_MoInvalidate(prinst, qcdst, dstoffset, size);
void *src = PR_PointerToNative_MoInvalidate(prinst, qcsrc, srcoffset, size);
if (!dst)
PR_BIError(prinst, "PF_memcmp: invalid dest\n");
else if (!src)
PR_BIError(prinst, "PF_memcmp: invalid source\n");
else
G_INT(OFS_RETURN) = memcmp(dst, src, size);
}
}
void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int qcdst = G_INT(OFS_PARM0);

View File

@ -579,6 +579,7 @@ void QCBUILTIN PF_base64decode(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_memalloc (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);
void QCBUILTIN PF_memfill8 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memgetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -930,6 +931,7 @@ enum packagemanagerinfo_e
GPMI_AVAILABLE, //whether it may be downloaded or not.
GPMI_FILESIZE, //whether it may be downloaded or not.
GPMI_GAMEDIR, //so you know which mod(s) its relevant for
GPMI_MAPS, //so you know which mod(s) its relevant for
};
#ifdef TERRAIN
@ -1060,6 +1062,7 @@ enum
globalfunction(CSQC_InputEvent, "float(float evtype, float scanx, float chary, float devid)") \
globalfunction(CSQC_Input_Frame, "void()")/*EXT_CSQC_1*/ \
globalfunction(CSQC_RendererRestarted, "void(string rendererdescription)") \
globalfunction(CSQC_GenerateMaterial, "string(string shadername)") \
globalfunction(CSQC_ConsoleCommand, "float(string cmd)") \
globalfunction(CSQC_ConsoleLink, "float(string text, string info)") \
globalfunction(GameCommand, "void(string cmdtext)") /*DP extension*/\

View File

@ -74,6 +74,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_Q3BSP PEXT_Q3BSP_
#endif
#define PEXT1_HIDEPROTOCOLS (PEXT_Q3BSP_|PEXT_Q2BSP_|PEXT_HLBSP) //These are hints for the server, and not useful to the client (they can figure stuff out themselves)
//#define PEXT1_DEPRECATED (PEXT_SCALE|PEXT_TRANS|PEXT_ACCURATETIMINGS|PEXT_SOUNDDBL|PEXT_FATNESS|PEXT_HULLSIZE|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_COLOURMOD|PEXT_SPAWNSTATIC2|PEXT_256PACKETENTITIES|PEXT_SETATTACHMENT|PEXT_DPFLAGS) //deprecated by replacementdeltas
#define PEXT1_MVDSUPPORT (PEXT1_CLIENTSUPPORT&~PEXT1_DEPRECATED&~PEXT1_HIDEPROTOCOLS) //pext2 extensions to use when recording mvds.
#define PEXT2_PRYDONCURSOR 0x00000001
#define PEXT2_VOICECHAT 0x00000002
@ -88,13 +90,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT2_LERPTIME 0x00000400 //fitz-bloat parity. redefines UF_16BIT as UF_LERPEND in favour of length coding.
#define PEXT2_SERVERADVERTISE ~0u
#define PEXT2_CLIENTSUPPORT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING|PEXT2_INFOBLOBS|PEXT2_STUNAWARE|PEXT2_VRINPUTS|PEXT2_LERPTIME) //warn if we see bits not listed here.
#define PEXT2_DEPRECATEDORNEW (PEXT2_INFOBLOBS|PEXT2_VRINPUTS|PEXT2_LERPTIME) //extensions that are outdated
#define PEXT2_MVDSUPPORT (PEXT2_CLIENTSUPPORT&~PEXT2_DEPRECATED&~PEXT2_STUNAWARE) //pext2 extensions to use when recording mvds.
//EzQuake/Mvdsv extensions. (use ezquake name, to avoid confusion about .mvd format and its protocol differences)
#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding...
#define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue.
#define EZPEXT1_SERVERADVERTISE EZPEXT1_FLOATENTCOORDS/* - implemented, but interactions with replacementdeltas is not defined*/ /*EZPEXT1_SETANGLEREASON - potentially causes compat issues with mods that stuffcmd it (common in nq)*/
//#define EZPEXT1_SERVERSIDEWEAPON 0x00000004 //looks half-baked. would be better to predict grabs clientside (oh noes! backpack knowledge!).
//#define EZPEXT1_DEBUG_WEAPON 0x00000008 //debug? not gonna bother.
//#define EZPEXT1_DEBUG_ANTILAG 0x00000010 //debug? not gonna bother.
#define EZPEXT1_HIDDEN_MESSAGES 0x00000020 //mvd bloat. shouldn't be seen on actual servers.
//#define MVD_PEXT1_SERVERSIDEWEAPON (1 << 2) // Server-side weapon selection
#define MVD_PEXT1_DEBUG_WEAPON (1 << 3) // Send weapon-choice explanation to server for logging
#define MVD_PEXT1_DEBUG_ANTILAG (1 << 4) // Send predicted positions to server (compare to antilagged positions)
#define MVD_PEXT1_HIDDEN_MESSAGES (1 << 5) // dem_multiple(0) packets are in format (<length> <type-id>+ <packet-data>)*
#define EZPEXT1_SERVERADVERTISE (EZPEXT1_FLOATENTCOORDS/* - implemented, but interactions with replacementdeltas is not defined*/ /*|EZPEXT1_SETANGLEREASON - potentially causes compat issues with mods that stuffcmd it (common in nq)*/)
#define EZPEXT1_CLIENTADVERTISE EZPEXT1_FLOATENTCOORDS //might as well ask for it, as a way around mvdsv's writecoord/PM_NudgePosition rounding difference bug.
#define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON) //ones we can support in demos. warning if other bits.
#define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON|EZPEXT1_HIDDEN_MESSAGES) //ones we can support in demos. warning if other bits.
//ZQuake transparent protocol extensions.
#define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held)
@ -555,12 +571,12 @@ enum {
//==============================================
#define DLERR_FILENOTFOUND -1 //server cannot serve the file
#define DLERR_PERMISSIONS -2 //server refuses to serve the file
#define DLERR_UNKNOWN -3 //server bugged out while trying to serve the request
#define DLERR_REDIRECTFILE -4 //client should download the specified file instead.
#define DLERR_REDIRECTPACK -5 //client should download the specified package instead.
#define DLERR_PACKAGE -6 //not networked. packages require special file access.
#define DLERR_FILENOTFOUND -1 //server cannot serve the file
#define DLERR_PERMISSIONS -2 //server refuses to serve the file
#define DLERR_UNKNOWN -3 //server bugged out while trying to serve the request
#define DLERR_REDIRECTFILE -4 //client should download the specified file instead.
#define DLERR_SV_REDIRECTPACK -5 //client should download the specified package instead. may also be an http(s):// location.
#define DLERR_SV_PACKAGE -6 //not networked. packages require special file access.
#define DLBLOCKSIZE 1024 //chunked downloads use fixed-size chunks (which I somewhat regret, but too late now I guess, really ought to use ranges.).
@ -1854,15 +1870,15 @@ typedef struct q1usercmd_s
#define MAX_MAP_AREA_BYTES 32
// edict->drawflags (hexen2 stuff)
#define MLS_MASK 7 // Model Light Style
#define MLS_MASK 7
#define MLS_NONE 0
#define MLS_FULLBRIGHT 1
#define MLS_POWERMODE 2
#define MLS_TORCH 3
#define MLS_TOTALDARK 4
#define MLS_UNUSED 4
#define MLS_ADDLIGHT 6
#define MLS_ABSLIGHT (MLS_MASK)
#define MLS_LIGHTSTYLE25 1 //indexes style 25 instead of using real lighting info
#define MLS_LIGHTSTYLE26 2 //indexes style 26
#define MLS_LIGHTSTYLE27 3 //27
#define MLS_LIGHTSTYLE28 4 //...
#define MLS_LIGHTSTYLE29 5 //duh
#define MLS_ADDLIGHT 6 //adds abslight to normal lighting
#define MLS_ABSLIGHT (MLS_MASK) //uses abslight specifically.
#define SCALE_TYPE_MASK (SCALE_TYPE_UNIFORM|SCALE_TYPE_XYONLY|SCALE_TYPE_ZONLY)
#define SCALE_TYPE_UNIFORM 0 // Scale X, Y, and Z
#define SCALE_TYPE_XYONLY 8 // Scale X and Y
@ -1873,7 +1889,7 @@ typedef struct q1usercmd_s
#define SCALE_ORIGIN_BOTTOM 32 // Scaling origin at object bottom
#define SCALE_ORIGIN_TOP 64 // Scaling origin at object top
#define SCALE_ORIGIN_ORIGIN (SCALE_ORIGIN_TOP|SCALE_ORIGIN_BOTTOM) // Scaling origin at object origin
#define DRF_TRANSLUCENT 128
#define DRF_TRANSLUCENT 128 //alpha is controlled by r_wateralpha
//TENEBRAE_GFX_DLIGHTS

View File

@ -1339,14 +1339,14 @@ static unsigned int Q1BSP_TranslateContents(enum q1contents_e contents)
case Q1CONTENTS_LAVA: return FTECONTENTS_LAVA;
case Q1CONTENTS_SKY: return FTECONTENTS_SKY|FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_LADDER: return FTECONTENTS_LADDER;
case Q1CONTENTS_CLIP: return FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_CURRENT_0: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_0; //q2 is better than nothing, right?
case Q1CONTENTS_CURRENT_90: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_90;
case Q1CONTENTS_CURRENT_180: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_180;
case Q1CONTENTS_CURRENT_270: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_270;
case Q1CONTENTS_CURRENT_UP: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_UP;
case Q1CONTENTS_CURRENT_DOWN: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_DOWN;
case Q1CONTENTS_TRANS: return FTECONTENTS_SOLID;
case HLCONTENTS_CLIP: return FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
case HLCONTENTS_CURRENT_0: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_0; //q2 is better than nothing, right?
case HLCONTENTS_CURRENT_90: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_90;
case HLCONTENTS_CURRENT_180: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_180;
case HLCONTENTS_CURRENT_270: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_270;
case HLCONTENTS_CURRENT_UP: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_UP;
case HLCONTENTS_CURRENT_DOWN: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_DOWN;
case HLCONTENTS_TRANS: return FTECONTENTS_EMPTY;
case Q1CONTENTS_MONSTERCLIP: return FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_PLAYERCLIP: return FTECONTENTS_PLAYERCLIP;
case Q1CONTENTS_CORPSE: return FTECONTENTS_CORPSE;
@ -1420,7 +1420,7 @@ void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base)
q2cbrush_t *brush;
q2cbrushside_t *sides; //grr!
mplane_t *planes; //bulky?
unsigned int lumpsizeremaining;
size_t lumpsizeremaining;
unsigned int numplanes;
unsigned int srcver, srcmodelidx, modbrushes, modplanes;
@ -2560,26 +2560,30 @@ BSPX Stuff
typedef struct {
char lumpname[24]; // up to 23 chars, zero-padded
int fileofs; // from file start
int filelen;
unsigned int fileofs; // from file start
unsigned int filelen;
} bspx_lump_t;
struct bspx_header_s {
char id[4]; // 'BSPX'
int numlumps;
unsigned int numlumps;
bspx_lump_t lumps[1];
};
//supported lumps:
//supported lumps (read specs/bspx.txt for more details):
//RGBLIGHTING (.lit)
//LIGHTING_E5BGR9 (hdr lit)
//LIGHTINGDIR (.lux)
//LMSHIFT (lightmap scaling)
//LMOFFSET (lightmap scaling)
//LMSTYLE (lightmap scaling)
//LMSHIFT (lightmap scaling, obsoleted bby DECOUPLED_LM)
//LMOFFSET (lightmap scaling, redundant without LMSHIFT)
//LMSTYLE (for when 4 styles per face are not enough)
//LMSTYLE16 (for when you need more than 256 different lightswitches)
//VERTEXNORMALS (smooth specular)
//BRUSHLIST (no hull size issues)
//ENVMAP (cubemaps)
//SURFENVMAP (cubemaps)
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize)
//FACENORMALS (because Quetoo's normals were rejected by ericw for some reason)
//DECOUPLED_LM (upgraded alternative to LM_SHIFT with float scaling and explicit lm sizes)
//LIGHTGRID_OCTREE (lightgrid alternative to floor-based model lighting, but still stuck with 4 8bit ldr styles)
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, size_t *lumpsize)
{
int i;
*lumpsize = 0;
@ -2751,12 +2755,12 @@ void BSPX_RenderEnvmaps(model_t *mod)
stride = -stride;
if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, cubesize, cubesize, fmt))
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
FS_SystemPath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname);
}
else
{
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
FS_SystemPath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Failed to write %s\n", sysname);
}
BZ_Free(buffer);
@ -2772,11 +2776,11 @@ void BSPX_RenderEnvmaps(model_t *mod)
void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base)
{
unsigned int *envidx, idx;
int i;
size_t i;
char base[MAX_QPATH];
char imagename[MAX_QPATH];
menvmap_t *out;
int count;
size_t count;
denvmap_t *in = BSPX_FindLump(bspx, mod_base, "ENVMAP", &count);
mod->envmaps = NULL;
mod->numenvmaps = 0;
@ -2830,6 +2834,9 @@ struct bspxrw
size_t corelumps;
size_t totallumps;
void *archivedata;
qofs_t archivesize;
struct
{
char lumpname[24]; // up to 23 chars, zero-padded
@ -2837,14 +2844,14 @@ struct bspxrw
qofs_t filelen;
} *lumps;
};
void Mod_BSPXRW_Free(struct bspxrw *ctx)
static void Mod_BSPXRW_Free(struct bspxrw *ctx)
{
FS_FreeFile(ctx->origfile);
Z_Free(ctx->lumps);
ctx->corelumps = ctx->totallumps = 0;
ctx->origfile = NULL;
}
void Mod_BSPXRW_Write(struct bspxrw *ctx)
static void Mod_BSPXRW_Write(struct bspxrw *ctx)
{
#if 1
vfsfile_t *f = FS_OpenVFS(ctx->fname, "wb", FS_GAMEONLY);
@ -2889,6 +2896,9 @@ void Mod_BSPXRW_Write(struct bspxrw *ctx)
VFS_WRITE(f, &paddata, pad);
}
//now reinsert any concatenated zip.
VFS_WRITE(f, ctx->archivedata, ctx->archivesize);
//now rewrite both sets of offsets.
VFS_SEEK(f, ctx->lumpofs);
VFS_WRITE(f, lumps, sizeof(lumps[0])*ctx->corelumps);
@ -2901,16 +2911,18 @@ void Mod_BSPXRW_Write(struct bspxrw *ctx)
Mod_BSPXRW_Free(ctx);
}
void Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, size_t datasize)
static qboolean Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, size_t datasize)
{
int i;
for (i = 0; i < ctx->totallumps; i++)
{
if (!strcmp(ctx->lumps[i].lumpname, lumpname))
{ //replace the existing lump
if (ctx->lumps[i].filelen == datasize && !memcmp(ctx->lumps[i].data, data, datasize))
return false; //nothing changed.
ctx->lumps[i].data = data;
ctx->lumps[i].filelen = datasize;
return;
return true;
}
}
@ -2918,9 +2930,10 @@ void Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, si
Q_strncpyz(ctx->lumps[i].lumpname, lumpname, sizeof(ctx->lumps[i].lumpname));
ctx->lumps[i].data = data;
ctx->lumps[i].filelen = datasize;
return true;
}
qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
static qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
{
int i;
lump_t *l;
@ -2937,6 +2950,8 @@ qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
static const char *q2corelumpnames[Q2HEADER_LUMPS] = {"entities","planes","vertexes","visibility","nodes","texinfo","faces","lighting","leafs","leaffaces","leafbrushes","edges","surfedges","models","brushes","brushsides","pop","areas","areaportals"};
#endif
static const char *q1corelumpnames[HEADER_LUMPS] = {"entities","planes","textures","vertexes","visibility","nodes","texinfo","faces","lighting","clipnodes","leafs","marksurfaces","edges","surfedges","models"};
ctx->archivedata = NULL;
ctx->archivesize = 0;
ctx->fname = fname;
ctx->origfile = FS_MallocFile(ctx->fname, FS_GAME, &ctx->origsize);
if (!ctx->origfile)
@ -3035,7 +3050,7 @@ qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
return true;
}
unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t nenvmap)
static unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t nenvmap)
{ //this is slow, yes.
size_t n, v;
unsigned int best = ~0;
@ -3070,7 +3085,7 @@ unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t
return best;
}
int QDECL envmapsort(const void *av, const void *bv)
static int QDECL envmapsort(const void *av, const void *bv)
{ //sorts cubemaps in order of size, to make texturearrays easier, if ever. The loader can then just make runs.
const denvmap_t *a=av, *b=bv;
if (a->cubesize == b->cubesize)
@ -3079,7 +3094,7 @@ int QDECL envmapsort(const void *av, const void *bv)
return 1;
return -1;
}
void Mod_FindCubemaps_f(void)
static void Mod_FindCubemaps_f(void)
{
struct bspxrw bspctx;
if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name))
@ -3180,13 +3195,27 @@ void Mod_FindCubemaps_f(void)
Z_Free(envmap);
}
}
void Mod_Realign_f(void)
static void Mod_Realign_f(void)
{
struct bspxrw bspctx;
if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name))
Mod_BSPXRW_Write(&bspctx);
}
void Mod_BSPX_List_f(void)
static searchpathfuncs_t *Mod_BSPX_List_ArchiveFile_handle;
static void QDECL Mod_BSPX_List_ArchiveFile(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)
{
searchpathfuncs_t *archive = Mod_BSPX_List_ArchiveFile_handle;
flocation_t loc;
time_t mtime;
char timestr[MAX_QPATH], sizestr[MAX_QPATH];
archive->FindFile(archive, &loc, fname, pathhandle);
archive->FileStat(archive, &loc, &mtime);
*timestr = 0;
strftime(timestr,sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
Con_Printf("\t\t%20s: %-12s %s\n", fname, FS_AbbreviateSize(sizestr,sizeof(sizestr), loc.len), timestr);
}
static void Mod_BSPX_List_f(void)
{
int i;
struct bspxrw ctx;
@ -3196,10 +3225,27 @@ void Mod_BSPX_List_f(void)
if (Mod_BSPXRW_Read(&ctx, fname))
{
Con_Printf("%s:\n", fname);
for (i = 0; i < ctx.corelumps; i++)
Con_Printf("\t%20s: %-12u csum:%08x\n", ctx.lumps[i].lumpname, (unsigned int)ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen)));
for ( ; i < ctx.totallumps; i++)
Con_Printf("\t%20s: %-12u csum:%08x\n", ctx.lumps[i].lumpname, (unsigned int)ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen)));
for (i = 0; i < ctx.totallumps; i++)
Con_Printf("\t%20s: %-12"PRIuQOFS" csum:%08x\n", ctx.lumps[i].lumpname, ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen)));
if (ctx.archivesize)
{
searchpathfuncs_t *f;
vfsfile_t *tmp = VFSPIPE_Open(1,true);
if (tmp)
{
VFS_WRITE(tmp, ctx.archivedata, ctx.archivesize);
f = FSZIP_LoadArchive(tmp, NULL, ctx.fname, ctx.fname, NULL);
if (!f)
VFS_CLOSE(tmp);
else
{
Con_Printf("\t%20s: %-12"PRIuQOFS"\n", "archive", ctx.archivesize);
Mod_BSPX_List_ArchiveFile_handle = f;
f->BuildHash(f, 0, Mod_BSPX_List_ArchiveFile);
f->ClosePath(f);
}
}
}
Mod_BSPXRW_Free(&ctx);
}
}
@ -3230,6 +3276,83 @@ void Mod_BSPX_Strip_f(void)
}
}
static qbyte *Mod_BSPX_Injest_Read(qofs_t *sz, char *name, char *fnamefmt, ...)
{
va_list argptr;
char fname[MAX_QPATH];
int i;
va_start (argptr, fnamefmt);
if (Q_vsnprintfz (fname,sizeof(fname), fnamefmt,argptr))
*fname = 0;
va_end (argptr);
if (!*fname)
return NULL;
for (i = 2; i < Cmd_Argc(); i++)
{
if (!Q_strcasecmp(Cmd_Argv(i), "all") || !Q_strcasecmp(Cmd_Argv(i), name))
return FS_MallocFile(fname, FS_GAME, sz);
}
Con_Printf("%s not requested\n", name);
return NULL;
}
static void Mod_BSPX_Injest_f(void)
{
qbyte *tmp;
struct bspxrw ctx;
qboolean found = false;
qofs_t sz;
if (Cmd_Argc() <= 2)
Con_Printf("%s FILENAME <all|LUMPNAMELIST>: inserts external supplementary resources into the bsp. "CON_WARNING"REMEMBER TO BACK-UP FIRST!\n", Cmd_Argv(0));
else if (Mod_BSPXRW_Read(&ctx, Cmd_Argv(1)))
{
char noext[MAX_QPATH];
COM_StripExtension(ctx.fname, noext,sizeof(noext));
if (ctx.fg == fg_quake)
{
tmp = Mod_BSPX_Injest_Read(&sz, "lit", "%s.lit", noext);
if (tmp)
{
if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*3 && !memcmp(tmp, "QLIT\0x01\x00\x00\x00", 8))
Con_Printf("Injesting sdr lit file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "RGBLIGHTING", tmp+8, sz-8); //ldr
else if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*4 && !memcmp(tmp, "QLIT\0x01\x00\x01\x00", 8))
Con_Printf("Injesting hdr lit file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "LIGHTING_E5BGR9", tmp+8, sz-8); //hdr
FS_FreeFile(tmp);
}
tmp = Mod_BSPX_Injest_Read(&sz, "lux", "%s.lux", noext);
if (tmp)
{
if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*3 && !memcmp(tmp, "QLIT\0x01\x00\x00\x00", 8))
Con_Printf("Injesting lux file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "LIGHTINGDIR", tmp+8, sz-8);
FS_FreeFile(tmp);
}
tmp = Mod_BSPX_Injest_Read(&sz, "ent", "%s.ent", noext);
if (tmp)
{
if (sz)
Con_Printf("Injesting ent file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "entities", tmp, sz);
FS_FreeFile(tmp);
}
// tmp = Mod_BSPX_Injest_Read(&sz, "vis", "%s.vis", noext);
// tmp = Mod_BSPX_Injest_Read(&sz, "rtlights", "%s.rtlights", noext);
// tmp = Mod_BSPX_Injest_Read(&sz, "way", "%s.way", noext);
//fixme: cubemaps
}
if (found)
Mod_BSPXRW_Write(&ctx);
else
{
Mod_BSPXRW_Free(&ctx);
Con_Printf("%s \"%s\": nothing changed.\n", Cmd_Argv(0), Cmd_Argv(1));
}
}
}
image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
{
int i;
@ -3252,4 +3375,13 @@ image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
return ret;
}
void Mod_BSPX_Init(void)
{
Cmd_AddCommandD("mod_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection env_cubemap sites and determines the nearest one to each surface.");
Cmd_AddCommandD("mod_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
Cmd_AddCommandD("mod_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
Cmd_AddCommandD("mod_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
Cmd_AddCommandD("mod_bspx_injest", Mod_BSPX_Injest_f, "Injests supplemental files (like .lits) into a new bspx file. "CON_WARNING"REMEMBER TO BACK-UP FIRST!");
}
#endif

View File

@ -80,6 +80,7 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
char fname[MAX_OSPATH*2];
char gpath[MAX_OSPATH];
char displaypath[MAX_OSPATH*2];
void *iterator;
dllfunction_t funcs[] =
@ -102,49 +103,53 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath)))
{
#ifndef ANDROID
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
#endif
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
#ifndef ANDROID
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
#endif
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
}
#ifdef ANDROID
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#else
if (!hVM && FS_NativePath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#endif
}
@ -160,13 +165,15 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
@ -174,13 +181,15 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s%s_"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s%s"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
#endif
@ -188,7 +197,8 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM)
{
snprintf (fname, sizeof(fname), "%s%s"ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname);
if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs);
}
}

View File

@ -21,7 +21,7 @@ static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue)
com_language = TL_FindLanguage(var->string);
}
cvar_t language = CVARAFC("lang", sys_language, "prvm_language", CVAR_USERINFO|CVAR_NORESET/*otherwise gamedir switches will be annoying*/, TL_LanguageChanged);
cvar_t language = CVARAFCD("lang", sys_language, "prvm_language", CVAR_USERINFO|CVAR_NORESET/*otherwise gamedir switches will be annoying*/, TL_LanguageChanged, "This cvar contains the language_dialect code of your language, used to find localisation strings.");
void TranslateInit(void)
{

View File

@ -829,6 +829,10 @@ void Memory_Init (void)
mainzone = Hunk_AllocName ( zonesize, "zone" );
Z_ClearZone (mainzone, zonesize);
#endif
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
}
void Memory_DeInit(void)

View File

@ -1234,6 +1234,13 @@ static void D3D9_SetupViewPortProjection(void)
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg);
d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view));
if (r_xflip.ival)
{
fov_x *= -1;
r_refdef.flipcull ^= SHADER_CULL_FLIP;
fovv_x *= -1;
}
if (r_refdef.maxdist)
{
/*d3d projection matricies scale depth to 0 to 1*/
@ -1258,6 +1265,7 @@ static void (D3D9_R_RenderView) (void)
{
if (!r_norefresh.value)
{
int cull = r_refdef.flipcull;
Surf_SetupFrame();
if (!r_refdef.globalfog.density)
@ -1293,13 +1301,14 @@ static void (D3D9_R_RenderView) (void)
R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view);
RQ_BeginFrame();
if (!(r_refdef.flags & RDF_NOWORLDMODEL))
{
if (cl.worldmodel)
P_DrawParticles ();
}
// if (!(r_refdef.flags & RDF_NOWORLDMODEL))
// {
// if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES))
// P_DrawParticles ();
// }
Surf_DrawWorld();
RQ_RenderBatchClear();
r_refdef.flipcull = cull;
}
D3D9_Set2D ();
}

View File

@ -840,7 +840,10 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
Con_Printf("D3D11 Adaptor: %S\n", adesc.Description);
}
else
{
adapt = NULL;
Con_Printf("D3D11 Adaptor: %s\n", "Unspecified");
}
if (FAILED(func(adapt, drivertype, NULL, flags,
flevels, sizeof(flevels)/sizeof(flevels[0]),
@ -1018,6 +1021,9 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
Con_Printf("CreateDXGIFactory1 failed: %s\n", D3D_NameForResult(hr));
if (fact)
{
ULONGLONG devid = strtoull(info->subrenderer, NULL, 16);
vrsetup.deviceid[0] = (devid )&0xffffffff;
vrsetup.deviceid[1] = (devid>>32)&0xffffffff;
if (info->vr)
{
if (!info->vr->Prepare(&vrsetup))
@ -1025,22 +1031,22 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
info->vr->Shutdown();
info->vr = NULL;
}
else
{
int id = 0;
while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt))
{
DXGI_ADAPTER_DESC desc;
IDXGIAdapter_GetDesc(adapt, &desc);
if (desc.AdapterLuid.LowPart == vrsetup.deviceid[0] && desc.AdapterLuid.HighPart == vrsetup.deviceid[1])
break;
IDXGIAdapter_Release(adapt);
adapt = NULL;
}
}
}
if (!adapt)
if (vrsetup.deviceid[0] || vrsetup.deviceid[1])
{
int id = 0;
while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt))
{
DXGI_ADAPTER_DESC desc;
IDXGIAdapter_GetDesc(adapt, &desc);
if (desc.AdapterLuid.LowPart == vrsetup.deviceid[0] && desc.AdapterLuid.HighPart == vrsetup.deviceid[1])
break;
IDXGIAdapter_Release(adapt);
adapt = NULL;
}
}
else
IDXGIFactory1_EnumAdapters(fact, 0, &adapt);
}
}
@ -1061,6 +1067,54 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
}
}
static qboolean D3D11_VID_EnumerateDevices(void *usercontext, void(*callback)(void *context, const char *devicename, const char *outputname, const char *desc))
{
static dllhandle_t *dxgi;
static HRESULT (WINAPI *pCreateDXGIFactory1)(IID *riid, void **ppFactory);
static IID factiid = {0x770aae78, 0xf26f, 0x4dba, {0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87}};
IDXGIFactory1 *fact = NULL;
dllfunction_t dxgifuncs[] =
{
{(void**)&pCreateDXGIFactory1, "CreateDXGIFactory1"},
{NULL}
};
if (!dxgi)
dxgi = Sys_LoadLibrary("dxgi", dxgifuncs);
if (!dxgi)
return true;
if (pCreateDXGIFactory1)
{
HRESULT hr;
hr = pCreateDXGIFactory1(&factiid, (void**)&fact);
if (FAILED(hr))
Con_Printf("CreateDXGIFactory1 failed: %s\n", D3D_NameForResult(hr));
if (fact)
{
IDXGIAdapter *adapt = NULL;
int id = 0;
char devname[128*4];
char dev[128*4];
DXGI_ADAPTER_DESC desc;
while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt))
{
IDXGIAdapter_GetDesc(adapt, &desc);
Q_snprintfz(devname,sizeof(devname), "Direct3D11 - %s", narrowen(dev,sizeof(dev), desc.Description));
Q_snprintfz(dev,sizeof(dev), "%"PRIx64, ((ULONGLONG)desc.AdapterLuid.HighPart<<32)|desc.AdapterLuid.LowPart);
callback(usercontext, dev, ""/*FIXME*/, devname);
IDXGIAdapter_Release(adapt);
adapt = NULL;
}
IDXGIFactory1_Release(fact);
}
}
return true;
}
static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette)
{
DWORD width = info->width;
@ -1556,18 +1610,19 @@ static void D3D11_SetupViewPort(void)
fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
}
if (r_xflip.ival)
{
fov_x *= -1;
r_refdef.flipcull ^= SHADER_CULL_FLIP;
fovv_x *= -1;
}
/*view matrix*/
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg);
if (r_refdef.maxdist)
{
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false);
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.maxdist, false);
}
else
{
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false);
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false);
}
/*projection matricies (main game, and viewmodel)*/
Matrix4x4_CM_Projection_Offset(r_refdef.m_projection_std, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, r_refdef.mindist, r_refdef.maxdist, true);
Matrix4x4_CM_Projection_Offset(r_refdef.m_projection_view, -fovv_x/2, fovv_x/2, -fovv_y/2, fovv_y/2, r_refdef.mindist, r_refdef.maxdist, true);
}
static void (D3D11_R_RenderView) (void)
@ -1575,6 +1630,7 @@ static void (D3D11_R_RenderView) (void)
float x, x2, y, y2;
double time1 = 0, time2 = 0;
qboolean dofbo = *r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname;
int cull = r_refdef.flipcull;
// texid_t colourrt[1];
if (!r_norefresh.value)
@ -1623,11 +1679,6 @@ static void (D3D11_R_RenderView) (void)
R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view);
RQ_BeginFrame();
// if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
// {
// if (cl.worldmodel)
// P_DrawParticles ();
// }
if (!(r_refdef.flags & RDF_NOWORLDMODEL))
if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel)
@ -1637,13 +1688,21 @@ static void (D3D11_R_RenderView) (void)
R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height);
R2D_ImageColours(1, 1, 1, 1);
r_refdef.flipcull = cull;
if (dofbo)
D3D11_ApplyRenderTargets(false);
return;
}
// if (!(r_refdef.flags & RDF_NOWORLDMODEL))
// {
// if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES))
// P_DrawParticles ();
// }
Surf_DrawWorld();
RQ_RenderBatchClear();
r_refdef.flipcull = cull;
if (r_speeds.ival)
{
time2 = Sys_DoubleTime();
@ -1739,6 +1798,9 @@ rendererinfo_t d3d11rendererinfo =
D3D11BE_RenderToTextureUpdate2d,
"no more"
"no more",
NULL, //VID_GetPriority
NULL, //VID_EnumerateVideoModes
D3D11_VID_EnumerateDevices
};
#endif

View File

@ -37,14 +37,14 @@ typedef struct
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models, ruleset_allow_fbmodels;
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models, ruleset_allow_fbmodels, gl_overbright_models;
extern cvar_t r_noaliasshadows;
extern cvar_t r_lodscale, r_lodbias;
extern cvar_t gl_ati_truform;
extern cvar_t r_vertexdlights;
extern cvar_t mod_md3flags;
extern cvar_t r_skin_overlays;
//extern cvar_t r_skin_overlays;
extern cvar_t r_globalskin_first, r_globalskin_count;
#ifndef SERVERONLY
@ -1373,25 +1373,27 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
return e->light_known-1;
e->light_dir[0] = 0; e->light_dir[1] = 1; e->light_dir[2] = 0;
if ((clmodel->engineflags & MDLF_FLAME) || r_fullbright.ival)
{
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;
e->light_known = 2;
return e->light_known-1;
}
if (
#ifdef HEXEN2
(e->drawflags & MLS_MASK) == MLS_FULLBRIGHT ||
#endif
(e->flags & RF_FULLBRIGHT))
{
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;
if ((e->drawflags & MLS_MASK) == MLS_ABSLIGHT)
{ //per-entity fixed lighting
e->light_range[0] = e->light_range[1] = e->light_range[2] =
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = e->abslight/255.f;
e->light_known = 2;
return e->light_known-1;
}
if (r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch)
if ((e->drawflags & MLS_MASK) && (e->drawflags & MLS_MASK) != MLS_ADDLIGHT)
{ //these use some qc-defined lightstyles.
i = 24 + (e->drawflags & MLS_MASK); //saves knowing the proper patterns at least.
VectorScale(cl_lightstyle[i].colours, d_lightstylevalue[i]/255.f, e->light_range);
VectorScale(cl_lightstyle[i].colours, d_lightstylevalue[i]/255.f, e->light_avg);
e->light_known = 2;
return e->light_known-1;
}
#endif
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
{
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;
@ -1432,21 +1434,24 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
}
#ifdef HEXEN2
if ((e->drawflags & MLS_MASK) == MLS_ABSLIGHT)
if ((e->drawflags & MLS_MASK) == MLS_ADDLIGHT)
{
shadelight[0] = shadelight[1] = shadelight[2] = e->abslight;
ambientlight[0] = ambientlight[1] = ambientlight[2] = e->abslight;
ambientlight[0] += e->abslight;
ambientlight[1] += e->abslight;
ambientlight[2] += e->abslight;
shadelight[0] += e->abslight;
shadelight[1] += e->abslight;
shadelight[2] += e->abslight;
}
else
#endif
if (r_softwarebanding)
if (r_softwarebanding)
{
//mimic software rendering as closely as possible
lightdir[2] = 0; //horizontal light only.
VectorMA(vec3_origin, 0.5, shadelight, ambientlight);
VectorCopy(ambientlight, shadelight);
// VectorMA(vec3_origin, 0.5, shadelight, ambientlight);
// VectorCopy(ambientlight, shadelight);
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
{
@ -1495,17 +1500,6 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
}
else
{
#ifdef HEXEN2
if ((e->drawflags & MLS_MASK) == MLS_ADDLIGHT)
{
ambientlight[0] += e->abslight;
ambientlight[1] += e->abslight;
ambientlight[2] += e->abslight;
shadelight[0] += e->abslight;
shadelight[1] += e->abslight;
shadelight[2] += e->abslight;
}
#endif
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
{
float *org = e->origin;
@ -1621,6 +1615,20 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
}
#if 1 //match quakespasm here.
if (gl_overbright_models.value > 0.f && ruleset_allow_fbmodels.ival)
{
m = (96*6) / (shadelight[0]+shadelight[1]+shadelight[2]+ambientlight[0]+ambientlight[1]+ambientlight[2]);
if (m > 1.0)
m = 1; //we only want to let it darken here.
m *= 1 + min(1,gl_overbright_models.value);
}
else
m = 1;
m /= 200.0/255; //a legacy quake fudge-factor.
VectorScale(shadelight, m, shadelight);
VectorScale(ambientlight, m, ambientlight);
#else
for (i = 0; i < 3; i++)
{
if (ambientlight[i] > 128)
@ -1629,6 +1637,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
shadelight[i] /= 200.0/255;
ambientlight[i] /= 200.0/255;
}
#endif
if ((e->model->flags & MF_ROTATE) && cl.hexen2pickups)
{
@ -1675,6 +1684,11 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
VectorScale(ambientlight, 2, e->light_avg);
VectorScale(shadelight, 2, e->light_range);
}
else if (1)
{ //calculate average and range, to allow for negative lighting dotproducts
VectorCopy(shadelight, e->light_avg);
VectorCopy(ambientlight, e->light_range);
}
else
{ //calculate average and range, to allow for negative lighting dotproducts
VectorMA(ambientlight, 0.5, shadelight, e->light_avg);

View File

@ -221,8 +221,6 @@ static void BE_PrintDrawCall(const char *msg)
{
char shadername[512];
char modelname[512];
int num;
Q_snprintfz(shadername, sizeof(shadername), "^[%-16s\\tipimg\\%s\\tipimgtype\\%i\\tip\\%s^]",
shaderstate.curshader->name,
shaderstate.curshader->name,shaderstate.curshader->usageflags,
@ -230,7 +228,9 @@ static void BE_PrintDrawCall(const char *msg)
if (shaderstate.curbatch && shaderstate.curbatch->ent)
{
num = shaderstate.curbatch->ent->keynum;
#ifdef HAVE_SERVER
int num = shaderstate.curbatch->ent->keynum;
#endif
if (shaderstate.curbatch->ent->model)
Q_snprintfz(modelname, sizeof(modelname), " - ^[%s\\modelviewer\\%s^]",
shaderstate.curbatch->ent->model->name, shaderstate.curbatch->ent->model->name);

View File

@ -2616,12 +2616,18 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal
if (!success && !TEXLOADED(f->singletexture) && *start)
{
f->singletexture = R_LoadHiResTexture(start, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE|IF_LOADNOW);
if (f->singletexture->status == TEX_LOADING)
COM_WorkerPartialSync(f->singletexture, &f->singletexture->status, TEX_LOADING);
const char *ext = COM_GetFileExtension(start, NULL);
if (!Q_strcasecmp(ext, ".ttf") || !Q_strcasecmp(ext, ".otf"))
; //no, don't try loading it as an image-based font. just let it fail.
else
{
f->singletexture = R_LoadHiResTexture(start, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE|IF_LOADNOW);
if (f->singletexture->status == TEX_LOADING)
COM_WorkerPartialSync(f->singletexture, &f->singletexture->status, TEX_LOADING);
if (!TEXLOADED(f->singletexture) && f->faces < MAX_FACES)
Font_LoadFontLump(f, start);
if (!TEXLOADED(f->singletexture) && f->faces < MAX_FACES)
Font_LoadFontLump(f, start);
}
}
if (end)

View File

@ -86,22 +86,18 @@ void validatelinks2(link_t *firstnode, link_t *panic)
}
#ifndef SERVERONLY
static void ted_dorelight(model_t *m, heightmap_t *hm);
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm);
#endif
static hmsection_t *QDECL Terr_GetSection(heightmap_t *hm, int x, int y, unsigned int flags);
static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b);
static void Terr_WorkerLoadedSection(void *ctx, void *data, size_t a, size_t b);
static void Terr_WorkerFailedSection(void *ctx, void *data, size_t a, size_t b);
static void Terr_Brush_DeleteIdx(heightmap_t *hm, size_t idx);
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static void ted_dorelight(model_t *m, heightmap_t *hm);
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm);
static void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e);
#endif
#ifndef SERVERONLY
static texid_t Terr_LoadTexture(char *name)
{
extern texid_t missing_texture;
@ -121,9 +117,9 @@ static texid_t Terr_LoadTexture(char *name)
}
#endif
static void QDECL Terr_LoadSectionTextures(hmsection_t *s)
static void Terr_LoadSectionTextures(hmsection_t *s)
{
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
extern texid_t missing_texture;
struct hmwater_s *w;
if (isDedicated)
@ -161,7 +157,7 @@ static void QDECL Terr_LoadSectionTextures(hmsection_t *s)
static qboolean QDECL Terr_InitLightmap(hmsection_t *s, qboolean initialise)
{
#ifdef SERVERONLY
#ifndef HAVE_CLIENT
return false;
#else
heightmap_t *hm = s->hmmod;
@ -283,7 +279,7 @@ static char *Terr_DiskSectionName(heightmap_t *hm, int sx, int sy, char *out, si
Q_snprintfz(out, outsize, "maps/%s/sect_%03x_%03x.hms", hm->path, sx, sy);
return out;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy)
{
sx -= CHUNKBIAS;
@ -295,6 +291,7 @@ static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy)
}
#endif
#ifdef HAVE_SERVER
static int dehex_e(int i, qboolean *error)
{
if (i >= '0' && i <= '9')
@ -357,6 +354,7 @@ static qboolean Terr_IsSectionFName(heightmap_t *hm, const char *fname, int *sx,
return false;
return true;
}
#endif
static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int count, hmsection_t **sects)
{
@ -381,7 +379,7 @@ static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int coun
{
s = Z_Malloc(sizeof(*s));
s->loadstate = TSLS_LOADING0;
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
s->lightmap = -1;
#endif
s->numents = 0;
@ -395,7 +393,7 @@ static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int coun
hm->loadingsections+=1;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
else if (s->loadstate == TSLS_LOADED && s->lightmap < 0)
; //it lost its lightmap. the main thread won't be drawing with it, nor do any loaders.
//FIXME: might be used by tracelines on a worker (eg lightmap generation)
@ -438,11 +436,8 @@ static hmsection_t *QDECL Terr_GenerateSection(heightmap_t *hm, int sx, int sy,
#endif
return NULL;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
s->lightmap = -1;
#endif
#ifndef SERVERONLY
s->numents = 0;
#endif
@ -508,7 +503,7 @@ static void *QDECL Terr_GenerateWater(hmsection_t *s, float maxheight)
//embeds a mesh
static void QDECL Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, const char *modelname, vec3_t epos, vec3_t axis[3], float scale)
{
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
struct hmentity_s *e, *f = NULL;
hmsection_t *s;
int min[2], max[2], coord[2];
@ -639,7 +634,7 @@ static void QDECL Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, con
static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
{
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
dsmesh_v1_t *dm;
float *colours;
qbyte *lmstart;
@ -670,7 +665,7 @@ static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
ptr = ds+1;
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
/*deal with textures*/
Q_strncpyz(s->texname[0], ds->texname[0], sizeof(s->texname[0]));
Q_strncpyz(s->texname[1], ds->texname[1], sizeof(s->texname[1]));
@ -760,7 +755,7 @@ static char *Terr_Read_String(struct terrstream_s *strm, char *val, int maxlen)
strm->pos += len+1;
return val;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static void Terr_Write_SInt(struct terrstream_s *strm, int val)
{
val = LittleLong(val);
@ -998,7 +993,7 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i
VFS_WRITE(f, strm.buffer, strm.pos);
strm.pos = 0;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b)
{
heightmap_t *hm = ctx;
@ -1027,7 +1022,7 @@ static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, si
#endif
static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
{
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
char modelname[MAX_QPATH];
qbyte last;
int y;
@ -1100,7 +1095,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
//dedicated server can stop reading here.
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (flags & TSF_HASCOLOURS)
{
for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++)
@ -1226,7 +1221,7 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s)
memset(s->holes, 0, sizeof(s->holes));
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
Q_strncpyz(s->texname[0], "", sizeof(s->texname[0]));
Q_strncpyz(s->texname[1], "", sizeof(s->texname[1]));
Q_strncpyz(s->texname[2], "", sizeof(s->texname[2]));
@ -1416,7 +1411,7 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int ver, v
return s;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
qboolean Terr_DownloadedSection(char *fname)
{
/*
@ -1450,7 +1445,7 @@ qboolean Terr_DownloadedSection(char *fname)
}
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, unsigned int flags)
{
//when using networked terrain, the client will never load a section from disk, but will only load it from the server
@ -1561,7 +1556,7 @@ static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b)
Terr_ReadSection(hm, s, 0, NULL, 0);
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static void Terr_SaveV1(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int sy)
{
int i;
@ -1681,7 +1676,7 @@ static void Terr_Save(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int
//doesn't clear edited/dirty flags or anything
static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, qboolean blocksave)
{
#ifdef SERVERONLY
#ifndef HAVE_CLIENT
return true;
#else
vfsfile_t *f;
@ -1804,7 +1799,7 @@ static hmsection_t *QDECL Terr_GetSection(heightmap_t *hm, int x, int y, unsigne
section = Terr_GenerateSection(hm, x, y, true);
}
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
//when using networked terrain, the client will never load a section from disk, but only loading it from the server
//this means we need to send a new request to download the section if it was flagged as modified.
if (!(flags & TGS_NODOWNLOAD))
@ -1893,7 +1888,7 @@ int Heightmap_Save(heightmap_t *hm)
return sectionssaved;
}
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
//on servers, we can get requests to download current map sections. if so, give them it.
qboolean Terrain_LocateSection(const char *name, flocation_t *loc)
{
@ -1958,7 +1953,7 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
Terr_ClearSection(s);
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (s->lightmap >= 0)
{
struct lmsect_s *lms;
@ -2014,14 +2009,14 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
validatelinks(&hm->recycle);
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
//dedicated servers do not support editing. no lightmap info causes problems.
//when a terrain section has the notify flag set on the server, the server needs to go through and set out notifications to replicate it to the various clients
//so the clients know to re-download the section.
static void Terr_DoEditNotify(heightmap_t *hm)
{
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
int i;
char *cmd;
hmsection_t *s;
@ -2141,7 +2136,7 @@ validatelinks(&hm->recycle);
else if (lightmapsonly)
{
numremaining++;
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
s->lightmap = -1;
#endif
}
@ -2160,7 +2155,7 @@ validatelinks(&hm->recycle);
}
}
validatelinks(&hm->recycle);
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (!lightmapreusable)
{
while (hm->unusedlmsects)
@ -2196,7 +2191,7 @@ void Terr_FreeModel(model_t *mod)
while(hm->brushtextures)
{
brushtex_t *bt = hm->brushtextures;
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
brushbatch_t *bb;
while((bb = bt->batches))
{
@ -2211,7 +2206,7 @@ void Terr_FreeModel(model_t *mod)
}
#ifdef RUNTIMELIGHTING
if (hm->relightcontext)
LightShutdown(hm->relightcontext);
LightShutdown(hm->relightcontext, mod);
if (hm->lightthreadmem && !hm->inheritedlightthreadmem)
BZ_Free(hm->lightthreadmem);
#endif
@ -2230,7 +2225,7 @@ void Terr_FreeModel(model_t *mod)
}
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmwater_s *w)
{
scenetris_t *t;
@ -3451,6 +3446,38 @@ typedef struct {
#endif
} hmtrace_t;
#ifdef HAVE_CLIENT
shader_t *Terr_GetShader(model_t *mod, trace_t *trace)
{
heightmap_t *hm = mod?mod->terrain:NULL;
unsigned int brushid = trace->brush_id;
unsigned int fa, i;
brushes_t *br;
if (!brushid)
return NULL;
if (!hm)
return NULL;
for (i = 0; i < hm->numbrushes; i++)
{
br = &hm->wbrushes[i];
if (br->id == trace->brush_id)
{
if (br->patch)
return br->patch->tex->shader;
fa = trace->brush_face-1;
if (fa >= br->numplanes)
return NULL;
return br->faces[fa].tex->shader;
}
}
return NULL;
}
#endif
static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes, brushes_t *brushinfo)
{
qboolean startout;
@ -4405,7 +4432,7 @@ unsigned int Heightmap_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *fte
return sizeof(*hmpvs);
}
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
qboolean Heightmap_EdictInFatPVS (model_t *mod, const struct pvscache_s *edict, const qbyte *pvsdata, const int *areas)
{
heightmap_t *hm = mod->terrain;
@ -4472,7 +4499,7 @@ int Heightmap_ClusterForPoint (model_t *model, const vec3_t point, int *area)
return -1;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
static unsigned char *QDECL Terr_GetLightmap(hmsection_t *s, int idx, qboolean edit)
{
int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE;
@ -5070,7 +5097,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
mod->entityinfo[idx].id = 0;
}
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv_state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -5086,7 +5113,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
else
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -5494,7 +5521,7 @@ void Terr_ParseEntityLump(model_t *mod, heightmap_t *heightmap)
void Terr_FinishTerrain(model_t *mod)
{
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
heightmap_t *hm = mod->terrain;
if (qrenderer != QR_NONE)
{
@ -5595,7 +5622,7 @@ void Terr_FinishTerrain(model_t *mod)
#endif
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
{
batch_t *b;
@ -6401,7 +6428,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
do
{
out->id = (++hm->brushidseq)&0x00ffffff;
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state) //avoid networking conflicts by having each node generating its own private ids
out->id |= (cl.playerview[0].playernum+1)<<24;
#endif
@ -6687,7 +6714,7 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br, void *mem)
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
heightmap_t *CL_BrushEdit_ForceContext(model_t *mod)
{
heightmap_t *hm = mod?mod->terrain:NULL;
@ -6719,10 +6746,10 @@ void CL_Parse_BrushEdit(void)
model_t *mod = (modelindex<countof(cl.model_precache))?cl.model_precache[modelindex]:NULL;
heightmap_t *hm = mod?mod->terrain:NULL;
#ifdef CLIENTONLY
const qboolean ignore = false;
#else
#ifdef HAVE_SERVER
const qboolean ignore = (sv_state>=ss_loading); //if we're the server then we already have this info. don't break anything (this info is present for demos).
#else
const qboolean ignore = false;
#endif
if (cmd == hmcmd_brush_delete)
@ -6828,7 +6855,7 @@ void CL_Parse_BrushEdit(void)
Host_EndGame("CL_Parse_BrushEdit: unknown command %i\n", cmd);
}
#endif
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned int *lastid)
{
//lastid starts at 0
@ -7268,7 +7295,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
//if we're creating one that already exists, then assume that its a move.
if (brushid && Terr_Brush_DeleteId(hm, brushid))
{
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7279,7 +7306,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
else
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7306,6 +7333,10 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
faces[i].stdir[0][3] = in_faces[i].sbias;
VectorCopy(in_faces[i].tdir, faces[i].stdir[1]);
faces[i].stdir[1][3] = in_faces[i].tbias;
//these are for compat with (q2/)q3 so as to not be lossy even if they're not really used.
faces[i].surfaceflags = 0;
faces[i].surfacevalue = 0;
}
//now emit it
@ -7321,7 +7352,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (nb)
{
G_INT(OFS_RETURN) = nb->id;
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7332,7 +7363,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return;
}
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7383,7 +7414,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
//if we're creating one that already exists, then assume that its a move.
if (brushid && Terr_Brush_DeleteId(hm, brushid))
{
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7394,7 +7425,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
else
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7435,7 +7466,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (nb)
{
G_INT(OFS_RETURN) = nb->id;
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7446,7 +7477,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return;
}
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7473,7 +7504,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
Terr_Brush_DeleteId(hm, brushid);
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
if (sv.state && modelindex > 0)
{
MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7484,7 +7515,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return;
}
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
if (cls.state && modelindex > 0)
{
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7919,7 +7950,8 @@ void Terr_WriteMapFile(vfsfile_t *file, model_t *mod)
else
entities = COM_ParseOut(entities, token, sizeof(token));
}
VFS_WRITE(file, start, entities - start);
if (entities)
VFS_WRITE(file, start, entities - start);
start = entities;
}
}
@ -7936,7 +7968,7 @@ void Mod_Terrain_Save_f(void)
}
if (*mapname)
mod = Mod_FindName(va("maps/%s", mapname));
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
else if (cls.state)
mod = cl.worldmodel;
#endif
@ -8030,7 +8062,16 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
{
start = entities;
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (token[0] == '}' && token[1] == 0)
if (!entities)
{
if (inbrush || nest)
{
Con_Printf(CON_ERROR "%s: File truncated?\n", mod->name);
return false;
}
break;
}
else if (token[0] == '}' && token[1] == 0)
{
nest--;
if (inbrush)
@ -8076,6 +8117,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
if (submodelnum)
{
Q_snprintfz(token, sizeof(token), "*%i", submodelnum);
*out++ = '\n';
*out++ = 'm';
*out++ = 'o';
*out++ = 'd';
@ -8108,7 +8150,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
submod->funcs.MarkLights = Heightmap_MarkLights;
submod->funcs.ClusterForPoint = Heightmap_ClusterForPoint;
submod->funcs.ClusterPVS = Heightmap_ClusterPVS;
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
submod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs;
submod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS;
submod->funcs.FatPVS = Heightmap_FatPVS;
@ -8117,7 +8159,8 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
submod->pvsbytes = sizeof(hmpvs_t);
#ifdef RUNTIMELIGHTING
subhm->relightcontext = LightStartup(hm->relightcontext, submod, false, false);
if (hm->relightcontext)
subhm->relightcontext = LightStartup(hm->relightcontext, submod, false, false);
subhm->lightthreadmem = hm->lightthreadmem;
subhm->inheritedlightthreadmem = true;
#endif
@ -8136,6 +8179,11 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
continue;
}
}
else if (!nest)
{
Con_Printf(CON_ERROR "%s: junk found\n", mod->name);
return false;
}
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") ||
!strcmp(token, "patchDef2WS") || !strcmp(token, "patchDef3WS")))
{
@ -8247,11 +8295,11 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
//Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale
//Hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale surfvalue
//Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//FTE : ( px py pz pd ) texname [x y z d] [x y z d] rotation sscale tscale
//FTE : ( px py pz pd ) texname [x y z d] [x y z d] rotation sscale tscale contents surfflags surfvalue
//Quake2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale contents surfflags surfvalue
//Quake3: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale contents surfflags surfvalue
//Q3 BP: brushDef { ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) ( ( x y o ) ( x y o ) ) texname contents surfflags surfvalue } //generate tangent+bitangent from the normal to generate base texcoords, then transform by the given 2*3 matrix. I prefer valve's way - it rotates more cleanly.
//Doom3: brushDef3 { ( px py pz pd ) ( ( x y o ) ( x y o ) ) texname contents surfflags surfvalue }
//Quake3: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale detailfl surfflags surfvalue
//Q3 BP: brushDef { ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) ( ( x y o ) ( x y o ) ) texname detailfl surfflags surfvalue } //generate tangent+bitangent from the normal to generate base texcoords, then transform by the given 2*3 matrix. I prefer valve's way - it rotates more cleanly.
//Doom3: brushDef3 { ( px py pz pd ) ( ( x y o ) ( x y o ) ) texname detailfl surfflags surfvalue }
//hexen2's extra surfvalue is completely unused, and should normally be -1
//q3 ignores all contents except detail, as well surfaceflags and surfacevalue
//220 ignores rotation, provided only for UI info, scale is still used
@ -8346,25 +8394,6 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
}
bt = Terr_Brush_FindTexture(subhm, token);
if (*token == '*')
{
if (!Q_strncasecmp(token, "*lava", 5))
brushcontents = FTECONTENTS_LAVA;
else if (!Q_strncasecmp(token, "*slime", 5))
brushcontents = FTECONTENTS_SLIME;
else
brushcontents = FTECONTENTS_WATER;
}
else if (!Q_strncasecmp(token, "*sky", 4))
brushcontents = FTECONTENTS_SKY;
else if (!Q_strcasecmp(token, "clip"))
brushcontents = FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
else if (!Q_strcasecmp(token, "hint"))
brushcontents = 0;
else if (!Q_strcasecmp(token, "skip"))
;//brushcontents = 0;
else
brushcontents = FTECONTENTS_SOLID;
if (textype != TEXTYPE_BP)
{
@ -8424,6 +8453,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
//The contents conveys only CONTENTS_DETAIL. which is awkward as it varies somewhat by game, but we assume q2/q3.
faces[numplanes].surfaceflags = 0;
faces[numplanes].surfacevalue = 0;
while (*entities == ' ' || *entities == '\t')
entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
@ -8448,10 +8478,8 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
ex3 = atoi(token);
//if we got this far, then its q3 format.
//q3 is weird. the first extra arg is contents. but only the detail contents is used.
if (ex1 & Q3CONTENTS_DETAIL)
{
brushcontents |= Q3CONTENTS_DETAIL;
}
//ex1 &= Q3CONTENTS_DETAIL;
brushcontents |= ex1;
//propagate these, in case someone tries editing a q2bsp.
faces[numplanes].surfaceflags = ex2;
@ -8475,6 +8503,39 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
}
faces[numplanes].tex = bt;
/*
shader_t *shader = R_RegisterCustom(NULL, bt->shadername, SUF_LIGHTMAP, NULL, NULL);
if (shader)
{
brushcontents &= Q3CONTENTS_DETAIL;
brushcontents |= shader->contentbits&~Q3CONTENTS_DETAIL;
faces[numplanes].surfaceflags = shader->surfacebits;
}
else
*/
if (bt && !numplanes)
{
if (*bt->shadername == '*')
{
if (!Q_strncasecmp(bt->shadername, "*lava", 5))
brushcontents |= FTECONTENTS_LAVA;
else if (!Q_strncasecmp(bt->shadername, "*slime", 5))
brushcontents |= FTECONTENTS_SLIME;
else
brushcontents |= FTECONTENTS_WATER;
}
else if (!Q_strncasecmp(bt->shadername, "*sky", 4))
brushcontents |= FTECONTENTS_SKY;
else if (!Q_strcasecmp(bt->shadername, "clip"))
brushcontents |= FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
else if (!Q_strcasecmp(bt->shadername, "hint"))
brushcontents |= 0;
else if (!Q_strcasecmp(bt->shadername, "skip")) //skip should not force content values if paired with lava etc.
;//brushcontents = 0;
else
brushcontents |= FTECONTENTS_SOLID;
}
if (textype == TEXTYPE_BP)
{
float *norm = planes[numplanes];
@ -8540,9 +8601,9 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
}
else
{
if (!strcmp(token, "classname"))
/*if (!strcmp(token, "classname"))
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
else
else*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
}
while(start < entities)
@ -8642,7 +8703,7 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize
mod->funcs.ClusterForPoint = Heightmap_ClusterForPoint;
mod->funcs.ClusterPVS = Heightmap_ClusterPVS;
#ifndef CLIENTONLY
#ifdef HAVE_SERVER
mod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs;
mod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS;
mod->funcs.FatPVS = Heightmap_FatPVS;
@ -8725,7 +8786,7 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
return hm;
}
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
#if 0 //not yet ready
struct ted_import_s
{
@ -9020,7 +9081,7 @@ void Mod_Terrain_Create_f(void)
//reads in the terrain a tile at a time, and writes it out again.
//the new version will match our current format version.
//this is mostly so I can strip out old format revisions...
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
void Mod_Terrain_Convert_f(void)
{
model_t *mod;
@ -9097,7 +9158,7 @@ void Mod_Terrain_Reload_f(void)
heightmap_t *hm;
if (Cmd_Argc() >= 2)
mod = Mod_FindName(va("maps/%s.hmp", Cmd_Argv(1)));
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
else if (cls.state)
mod = cl.worldmodel;
#endif
@ -9131,10 +9192,10 @@ plugterrainfuncs_t *Terr_GetTerrainFuncs(size_t structsize)
{
if (structsize != sizeof(plugterrainfuncs_t))
return NULL;
#ifdef SERVERONLY
return NULL; //dedicated server builds have all the visual stuff stripped, which makes APIs too inconsistent. Generate then save. Or fix up the API...
#else
#ifdef HAVE_CLIENT
return &terrainfuncs;
#else
return NULL; //dedicated server builds have all the visual stuff stripped, which makes APIs too inconsistent. Generate then save. Or fix up the API...
#endif
}
@ -9153,7 +9214,7 @@ void Terr_Init(void)
Cvar_Register(&mod_terrain_savever, "Terrain");
Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
// Cmd_AddCommandD("mod_terrain_export", Mod_Terrain_Export_f, "Export a raw heightmap");
// Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap");
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);

View File

@ -222,6 +222,8 @@ static void Mod_TextureList_f(void)
char *cr;
while ((cr = strchr(body, '\r')))
*cr = ' ';
if (strlen(body) > 3000)
body[3000] = 0; //arbitrary cut off, to avoid console glitches with big shaders.
}
if (preview)
@ -634,10 +636,7 @@ void Mod_SetModifier(const char *modifier)
}
#ifndef SERVERONLY
void Mod_FindCubemaps_f(void);
void Mod_Realign_f(void);
void Mod_BSPX_List_f(void);
void Mod_BSPX_Strip_f(void);
void Mod_BSPX_Init(void);
#endif
/*
@ -689,10 +688,7 @@ void Mod_Init (qboolean initial)
Cvar_Register (&r_sprite_backfacing, NULL);
#endif
#ifndef SERVERONLY
Cmd_AddCommandD("mod_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection env_cubemap sites and determines the nearest one to each surface.");
Cmd_AddCommandD("mod_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
Cmd_AddCommandD("mod_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
Cmd_AddCommandD("mod_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
Mod_BSPX_Init();
#endif
}
@ -1629,7 +1625,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
qbyte *litdata = NULL; //xyz8
qbyte *lumdata = NULL; //l8
qbyte *out;
unsigned int samples;
size_t samples;
#ifdef RUNTIMELIGHTING
qboolean relighting = false;
#endif
@ -1851,7 +1847,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
exptmp = littmp = false;
if (!litdata && !expdata)
{
int size;
size_t size;
/*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/
expdata = BSPX_FindLump(bspx, mod_base, "LIGHTING_E5BGR9", &size);
exptmp = true;
@ -1943,7 +1939,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
}
if (!luxdata)
{
int size;
size_t size;
luxdata = BSPX_FindLump(bspx, mod_base, "LIGHTINGDIR", &size);
if (size != samples*3)
luxdata = NULL;
@ -2038,28 +2034,28 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
if (overrides && !overrides->shifts)
{
int size;
size_t size;
//if we have shifts, then we probably also have legacy data in the surfaces that we want to override
if (!overrides->offsets)
{
int size;
size_t size;
overrides->offsets = BSPX_FindLump(bspx, mod_base, "LMOFFSET", &size);
if (size != loadmodel->numsurfaces * sizeof(int))
{
if (size)
Con_Printf(CON_ERROR"BSPX LMOFFSET lump is wrong size, expected %u entries, found %u\n", loadmodel->numsurfaces, size/(unsigned int)sizeof(int));
Con_Printf(CON_ERROR"BSPX LMOFFSET lump is wrong size, expected %u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, size/(unsigned int)sizeof(int));
overrides->offsets = NULL;
}
}
if (!overrides->styles8 && !overrides->styles16)
{ //16bit per-face lightmap styles index
int size;
size_t size;
overrides->styles16 = BSPX_FindLump(bspx, mod_base, "LMSTYLE16", &size);
overrides->stylesperface = size / (sizeof(*overrides->styles16)*loadmodel->numsurfaces); //rounding issues will be caught on the next line...
if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles16)*overrides->stylesperface)
{
if (size)
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %u\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles16));
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles16));
overrides->styles16 = NULL;
}
else if (overrides->stylesperface > MAXCPULIGHTMAPS)
@ -2067,13 +2063,13 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
}
if (!overrides->styles8 && !overrides->styles16)
{ //16bit per-face lightmap styles index
int size;
size_t size;
overrides->styles8 = BSPX_FindLump(bspx, mod_base, "LMSTYLE", &size);
overrides->stylesperface = size / (sizeof(*overrides->styles8)*loadmodel->numsurfaces); //rounding issues will be caught on the next line...
if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles8)*overrides->stylesperface)
{
if (size)
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %u\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles8));
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles8));
overrides->styles8 = NULL;
}
else if (overrides->stylesperface > MAXCPULIGHTMAPS)
@ -2085,7 +2081,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
{
if (size)
{ //ericw-tools is screwing up again. don't leave things screwed.
Con_Printf(CON_ERROR"BSPX LMSHIFT lump is wrong size, expected %u entries, found %u\n", loadmodel->numsurfaces, size);
Con_Printf(CON_ERROR"BSPX LMSHIFT lump is wrong size, expected %u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, size);
overrides->styles16 = NULL;
overrides->styles8 = NULL;
overrides->offsets = NULL;
@ -2290,7 +2286,7 @@ static void Mod_SaveEntFile_f(void)
if (COM_WriteFile(fname, FS_GAMEONLY, ents, strlen(ents)))
{
if (FS_NativePath(fname, FS_GAMEONLY, nname, sizeof(nname)))
if (FS_DisplayPath(fname, FS_GAMEONLY, nname, sizeof(nname)))
Con_Printf("Wrote %s\n", nname);
}
else
@ -2425,7 +2421,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, bspx_header_t *bspx, qbyte *
{
float *in;
float *out;
int i, count;
size_t i, count;
if (l)
{
@ -2442,7 +2438,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, bspx_header_t *bspx, qbyte *
}
else
{ //ericw's thing
unsigned int size;
size_t size;
quint32_t t;
int *normcount;
struct surfedgenormals_s *sen;
@ -3687,7 +3683,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, int
}
if (extsize != 16+sz)
{
Con_Printf("miptex %s has incomplete mipchain\n", Image_FormatName(newfmt));
Con_Printf(CON_WARNING"miptex %s (%s) has incomplete mipchain\n", tx->name, Image_FormatName(newfmt));
continue;
}
@ -3767,7 +3763,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, int
legacysize = 0;
for (m = 0; m < 4; m++)
{
if (mt->offsets[m])
if (mt->offsets[m] && (mt->offsets[m]+(mt->width>>m)*(mt->height>>m)<=miptexsize))
memcpy(tx->srcdata+legacysize, ptr + mt->offsets[m], (mt->width>>m)*(mt->height>>m));
else
memset(tx->srcdata+legacysize, 0, (mt->width>>m)*(mt->height>>m));
@ -3837,6 +3833,7 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
o = LittleLong(m->dataofs[i]);
if (o >= l->filelen) //e1m2, this happens
{
badmip:
tx = ZG_Malloc(&loadmodel->memgroup, sizeof(texture_t));
memcpy(tx, r_notexture_mip, sizeof(texture_t));
sprintf(tx->name, "unnamed%i", i);
@ -3870,6 +3867,12 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
TRACE(("dbg: Mod_LoadTextures: texture %s\n", mt->name));
if (mt->offsets[0] && (mt->width > 0xffff|| mt->height > 0xffff))
{
Con_Printf(CON_WARNING "%s: miptex %i is excessively large. probably corrupt\n", loadmodel->name, i);
goto badmip;
}
if (!*mt->name) //I HATE MAPPERS!
{
Q_snprintfz(mt->name, sizeof(mt->name), "unnamed%i", i);
@ -4269,7 +4272,7 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m
qboolean lightmapusable = false;
struct decoupled_lm_info_s *decoupledlm;
unsigned int dcsize;
size_t dcsize;
memset(&overrides, 0, sizeof(overrides));
@ -4406,8 +4409,20 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m
lofs = LittleLong(decoupledlm->lmoffset);
out->texturemins[0] = out->texturemins[1] = 0; // should be handled by the now-per-surface vecs[][3] value.
out->lmshift = 0; //redundant.
out->extents[0] = (unsigned short)LittleShort(decoupledlm->lmsize[0]) - 1;
out->extents[1] = (unsigned short)LittleShort(decoupledlm->lmsize[1]) - 1;
if (!decoupledlm->lmsize[0] || !decoupledlm->lmsize[1])
{
decoupledlm->lmsize[0] = decoupledlm->lmsize[1] = 0;
if (lofs != (unsigned int)-1)
{ //we'll silently allow these buggy surfaces for now... but only if they've got no lightmap data at all. unsafe if they're the last otherwise.
lofs = -1;
Con_Printf(CON_WARNING"%s: Face %i has invalid extents\n", loadmodel->name, surfnum);
}
}
else
{
out->extents[0] = (unsigned short)LittleShort(decoupledlm->lmsize[0]) - 1; //surfaces should NEVER have an extent of 0. even if the surface is omitted it should still have some padding...
out->extents[1] = (unsigned short)LittleShort(decoupledlm->lmsize[1]) - 1;
}
loadmodel->facelmvecs[surfnum].lmvecs[0][0] = LittleFloat(decoupledlm->lmvecs[0][0]);
loadmodel->facelmvecs[surfnum].lmvecs[0][1] = LittleFloat(decoupledlm->lmvecs[0][1]);
loadmodel->facelmvecs[surfnum].lmvecs[0][2] = LittleFloat(decoupledlm->lmvecs[0][2]);

View File

@ -209,9 +209,11 @@ m*_t structures are in-memory
#define QWEF_FLAG1 (1<<4) //only applies to qw player entities
#define NQEF_NODRAW (1<<4) //so packet entities are free to get this instead
#define REEF_QUADLIGHT (1<<4)
#define TENEBRAEEF_FULLDYNAMIC (1<<4)
#define QWEF_FLAG2 (1<<5) //only applies to qw player entities
#define NQEF_ADDITIVE (1<<5) //so packet entities are free to get this instead
#define REEF_PENTLIGHT (1<<5)
#define TENEBRAEEF_GREEN (1<<5)
#define EF_BLUE (1<<6)
#define REEF_CANDLELIGHT (1<<6)
#define EF_RED (1<<7)
@ -602,7 +604,7 @@ void Q1BSP_GenerateShadowMesh(struct model_s *model, struct dlight_s *dl, const
void BSPX_LightGridLoad(struct model_s *model, bspx_header_t *bspx, qbyte *mod_base); //for q1 or q2 models.
void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base);
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize);
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, size_t *lumpsize);
bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, size_t filelen, lump_t *lumps, size_t numlumps);
typedef struct fragmentdecal_s fragmentdecal_t;
@ -1107,8 +1109,9 @@ typedef struct model_s
//internally, we still use integers for lighting, with .7 bits of extra precision.
LM_L8,
LM_RGB8,
LM_E5BGR9
LM_E5BGR9,
} fmt;
enum uploadfmt prebaked;
qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values)
qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl.
} lightmaps;
@ -1180,6 +1183,7 @@ unsigned int Heightmap_PointContents(model_t *model, const vec3_t axis[3], const
struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);
qboolean Terr_DownloadedSection(char *fname);
shader_t *Terr_GetShader(struct model_s *mod, struct trace_s *trace);
void CL_Parse_BrushEdit(void);
qboolean SV_Parse_BrushEdit(void);

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