diff --git a/CMakeLists.txt b/CMakeLists.txt index 722962278..94798cf8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0) cmake_policy(SET CMP0063 NEW) -PROJECT(fteqw) +PROJECT(FTEQuake) INCLUDE_DIRECTORIES( engine/common @@ -35,51 +35,40 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_C_VISIBILITY_PRESET hidden) IF(${CMAKE_VERSION} VERSION_LESS "3.9.0") + MESSAGE(STATUS "no LTO - old cmake.") ELSE() - IF(NOT ${CMAKE_BUILD_TYPE} MATCHES "Debug") + cmake_policy(SET CMP0069 NEW) + IF(NOT CMAKE_BUILD_TYPE MATCHES "Debug") #use LTO where possible. reportedly requires cmake 3.9 to actually work INCLUDE(CheckIPOSupported) check_ipo_supported(RESULT result) IF(result) SET(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + MESSAGE(STATUS "Using LTO.") + ELSE() + MESSAGE(STATUS "no LTO - not supported.") ENDIF() + ELSE() + MESSAGE(STATUS "no LTO - debug.") ENDIF() ENDIF() +SET(FTE_BUILD_CONFIG ${CMAKE_HOME_DIRECTORY}/engine/common/config_fteqw.h CACHE FILEPATH "Which build config file to use to control supported features.") +SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};CONFIG_FILE_NAME=${FTE_BUILD_CONFIG}) + FIND_PACKAGE(ZLIB) IF(NOT ZLIB_FOUND) MESSAGE(WARNING "libz library NOT available. compressed pk3 will not be available.") SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_ZLIB) - SET(ZLIB_LIBRARY m) - SET(ZLIB_LIBRARIES m) -ENDIF() - -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) -ENDIF() - -FIND_PACKAGE(ALSA) -IF(NOT ALSA_FOUND) - MESSAGE(WARNING "asound (alsa) library NOT available.") - SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_ALSA) -ENDIF() - -FIND_PACKAGE(X11) -IF(X11_FOUND) - IF (NOT X11_Xcursor_FOUND) - SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_CURSOR) - MESSAGE(WARNING "Xcursor library NOT available.") - ENDIF() -ELSE() - MESSAGE(WARNING "x11 library NOT available.") - SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11) + SET(ZLIB_LIBRARY ) + SET(ZLIB_LIBRARIES ) ENDIF() SET(OpenGL_GL_PREFERENCE LEGACY) FIND_PACKAGE(OpenGL) -IF(NOT OpenGL_FOUND) +IF(OpenGL_FOUND) + SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};GLQUAKE) +ELSE() MESSAGE(WARNING "opengl library NOT available. Will depend upon vulkan.") SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_OPENGL) ENDIF() @@ -104,6 +93,15 @@ ELSE() SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_FREETYPE) ENDIF() +#FIND_PACKAGE(Vulkan) +#IF(Vulkan_FOUND) +# INCLUDE_DIRECTORIES( ${Vulkan_INCLUDE_DIRS} ) + SET(FTE_DEFINES ${FTE_DEFINES};VKQUAKE) +#ELSE() +# SET(FTE_DEFINES ${FTE_DEFINES};VKQUAKE) +# MESSAGE(WARNING "System vulkan headers NOT available.") +#ENDIF() + FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile) IF(NOT VORBISFILE_LIBRARY) MESSAGE(WARNING "libvorbisfile library NOT available. Who listens to the bgm anyway?") @@ -133,7 +131,7 @@ IF(${ANDROID}) # INCLUDE_DIRECTORIES( ${FREETYPE_INCLUDE_DIRS} ) - SET(FTE_DEFINES ${FTE_DEFINES};ANDROID;GLQUAKE;VKQUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;MULTITHREAD;stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTE_DEFINES ${FTE_DEFINES};ANDROID;VKQUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;MULTITHREAD;stricmp=strcasecmp;strnicmp=strncasecmp) SET(FTE_LIBS android log EGL ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS}) SET(FTE_ARCH_FILES engine/client/sys_droid.c @@ -148,8 +146,8 @@ ELSEIF(${WIN32}) # engine/server/sv_sys_win.c - SET(FTE_LIBS ${ZLIB_LIBRARIES} ole32 gdi32 wsock32 winmm) - SET(FTE_DEFINES ${FTE_DEFINES};GLQUAKE;VKQUAKE;D3D9QUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG) #D3D11QUAKE not included. + SET(FTE_LIBS ${ZLIB_LIBRARIES} ole32 gdi32 wsock32 winmm dxguid) + SET(FTE_DEFINES ${FTE_DEFINES};D3D9QUAKE;D3D11QUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG) SET(FTE_ARCH_FILES engine/client/winquake.rc engine/common/sys_win_threads.c @@ -189,7 +187,32 @@ ELSEIF(${WIN32}) ) ELSEIF(${UNIX}) #linux(ish) #openbsd will have issues with snd_linux.c - SET(FTE_DEFINES ${FTE_DEFINES};GLQUAKE;VKQUAKE;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;DYNAMIC_SDL;MULTITHREAD;stricmp=strcasecmp;strnicmp=strncasecmp) + + #linux-only packages + 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) + ENDIF() + + FIND_PACKAGE(ALSA) + IF(NOT ALSA_FOUND) + MESSAGE(WARNING "asound (alsa) library NOT available.") + SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_ALSA) + ENDIF() + + FIND_PACKAGE(X11) + IF(X11_FOUND) + IF (NOT X11_Xcursor_FOUND) + SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_CURSOR) + MESSAGE(WARNING "Xcursor library NOT available.") + ENDIF() + ELSE() + MESSAGE(WARNING "x11 library NOT available.") + SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11) + ENDIF() + + SET(FTE_DEFINES ${FTE_DEFINES};DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;DYNAMIC_SDL;MULTITHREAD;stricmp=strcasecmp;strnicmp=strncasecmp) SET(FTE_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread ${SDL2_LIBRARIES}) SET(FTE_ARCH_FILES engine/client/sys_linux.c @@ -262,7 +285,7 @@ ELSEIF(1) #SDL INCLUDE_DIRECTORIES(${FREETYPE_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}) #SDL2.0.7 supports vulkan, so lets use it. - SET(FTE_DEFINES ${FTE_DEFINES};GLQUAKE;VKQUAKE;FTE_SDL;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;stricmp=strcasecmp;strnicmp=strncasecmp) + SET(FTE_DEFINES ${FTE_DEFINES};FTE_SDL;DYNAMIC_LIBPNG;DYNAMIC_LIBJPEG;stricmp=strcasecmp;strnicmp=strncasecmp) SET(FTE_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES}) SET(FTE_ARCH_FILES engine/client/sys_sdl.c @@ -519,7 +542,7 @@ SET(FTE_CLIENT_FILES engine/vk/vk_init.c ) -IF(${ANDROID}) +IF(ANDROID) #android sucks. everything is a library. so we build the engine as a shared library and completely ignore dedicated servers+tools ADD_LIBRARY(ftedroid MODULE ${FTE_ARCH_FILES} @@ -545,6 +568,19 @@ ELSE() SET_TARGET_PROPERTIES(fteqw-sv PROPERTIES COMPILE_DEFINITIONS "SERVERONLY;${FTE_LIB_DEFINES};${FTESV_DEFINES};${FTE_REVISON}") TARGET_LINK_LIBRARIES(fteqw-sv ${FTESV_LIBS}) + ADD_EXECUTABLE(iqmtool + iqm/iqm.cpp + iqm/iqm.h + ) + SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "${FTE_REVISON}") + + ADD_EXECUTABLE(httpserver + engine/common/fs_stdio.c + engine/http/httpserver.c + engine/http/iwebiface.c + engine/http/ftpserver.c + ) + SET_TARGET_PROPERTIES(httpserver PROPERTIES COMPILE_DEFINITIONS "WEBSERVER;WEBSVONLY;${FTE_REVISON};stricmp=strcasecmp;strnicmp=strncasecmp") ADD_EXECUTABLE(fteqcc engine/qclib/qcctui.c @@ -593,7 +629,7 @@ SET_TARGET_PROPERTIES(qi PROPERTIES PREFIX "fteplug_") #Bullet Physics library plugin #FIND_PACKAGE(Bullet) -IF (${BULLET_FOUND}) +IF (BULLET_FOUND) ADD_LIBRARY(bullet MODULE plugins/qvm_api.c plugins/plugin.c @@ -606,7 +642,7 @@ ENDIF() #ODE Physics library plugin #FIND_PACKAGE(ode) -IF (${ODE_FOUND}) +IF (ODE_FOUND) ADD_LIBRARY(ode MODULE plugins/qvm_api.c plugins/plugin.c @@ -638,7 +674,34 @@ ADD_LIBRARY(irc MODULE SET_TARGET_PROPERTIES(irc PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(irc PROPERTIES PREFIX "fteplug_") -IF(NOT ${ANDROID}) +#ffmpeg client plugin. no proper way to detect dependancies right now, so I've gotta try the manual way. +FIND_PATH(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h) +FIND_PATH(AVFORMAT_INCLUDE_DIR libavformat/avformat.h) +FIND_PATH(AVUTIL_INCLUDE_DIR libavutil/avutil.h) +FIND_PATH(AVSWSCALE_INCLUDE_DIR libswscale/swscale.h) +IF(AVFORMAT_INCLUDE_DIR) + FIND_LIBRARY(AVCODEC_LIBRARY avcodec) + FIND_LIBRARY(AVFORMAT_LIBRARY avformat) + FIND_LIBRARY(AVUTIL_LIBRARY avutil) + FIND_LIBRARY(AVSWSCALE_LIBRARY swscale) + + ADD_LIBRARY(ffmpeg MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/avplug/avaudio.c + plugins/avplug/avdecode.c + plugins/avplug/avencode.c + ) + TARGET_INCLUDE_DIRECTORIES(ffmpeg PUBLIC ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${AVSWSCALE_INCLUDE_DIR}) + SET_TARGET_PROPERTIES(ffmpeg PROPERTIES LINK_FLAGS "-Wl,--no-undefined") + TARGET_LINK_LIBRARIES(ffmpeg m ${AVFORMAT_LIBRARY} ${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY} ${AVSWSCALE_LIBRARY}) + SET_TARGET_PROPERTIES(ffmpeg PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") + SET_TARGET_PROPERTIES(ffmpeg PROPERTIES PREFIX "fteplug_") +ELSE() + MESSAGE(WARNING "ffmpeg library NOT available. Quake shouldn't be playing fmv anyway.") +ENDIF() + +IF(NOT ANDROID) #XMPP/jabber client plugin ADD_LIBRARY(xmpp MODULE plugins/qvm_api.c @@ -654,5 +717,4 @@ IF(NOT ${ANDROID}) SET_TARGET_PROPERTIES(xmpp PROPERTIES PREFIX "fteplug_") ENDIF() -#ffmpeg plugin #cef plugin diff --git a/engine/Makefile b/engine/Makefile index 1cfd9d83a..ffe075228 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -40,16 +40,22 @@ BULLETVER=2.87 #only limited forms of cross-making is supported #only the following 3 are supported #linux->win32 (FTE_TARGET=win32) RPM Package: "mingw32-gcc", DEB Package: "mingw32" -#linux->linux32 (FTE_TARGET=linux32) -#linux->linux64 (FTE_TARGET=linux64) +#linux->win64 (FTE_TARGET=win64) RPM Package: "mingw32-gcc", DEB Package: "mingw32" +#linux->linux 32 (FTE_TARGET=linux32) +#linux->linux 64 (FTE_TARGET=linux64) +#linux->linux x32 (FTE_TARGET=linuxx32) +#linux->linux armhf (FTE_TARGET=linuxarmhf) +#linux->linux arm64/aarch64 (FTE_TARGET=linuxarm64) +#linux->linux *others* (FTE_TARGET=linux CC=other-gcc) #linux->morphos (FTE_TARGET=morphos) #linux->macosx (FTE_TARGET=macosx) or (FTE_TARGET=macosx_x86) #linux->javascript (FTE_TARGET=web) -#linux->nacl (FTE_TARGET=nacl NARCH=x86_64) +#linux->nacl (FTE_TARGET=nacl NARCH=x86_64) deprecated. #win32->nacl #linux->droid (make droid) #win32->droid (make droid) #if you are cross compiling, you'll need to use FTE_TARGET=mytarget +#note: cross compiling will typically require 'make makelibs FTE_TARGET=mytarget', which avoids installing lots of extra system packages. #cygwin's make's paths confuses non-cygwin things RELEASE_DIR=$(BASE_DIR)/release @@ -86,7 +92,7 @@ endif BRANDFLAGS+=-DCONFIG_FILE_NAME=config_$(FTE_CONFIG).h $(FTE_CONFIG_EXTRA) EXE_NAME=$(FTE_CONFIG) ifeq (,$(findstring DNO_SPEEX,$(FTE_CONFIG_EXTRA))) - USE_SPEEX=1 + USE_SPEEX?=1 endif ifeq (,$(findstring DNO_OPUS,$(FTE_CONFIG_EXTRA))) USE_OPUS=1 @@ -395,12 +401,25 @@ ifeq ($(FTE_TARGET),linuxarmhf) CXX=arm-linux-gnueabihf-g++ -marm -march=armv6 -mfpu=vfp -mfloat-abi=hard BITS=armhf endif +ifeq ($(FTE_TARGET),linuxarm64) + FTE_TARGET=linux + CC=aarch64-linux-gnu-gcc + CXX=aarch64-linux-gnu-g++ + BITS=arm64 + USE_SPEEX=0 #fails to compile due to neon asm, I'm just going to disable it (will still soft-link). +endif ifeq ($(FTE_TARGET),linuxx32) #note: the x32 abi is still not finished or something. #at the current time, you will need to edit your kernel's commandline to allow this stuff to run + #try and use a proper cross-compiler if we can, otherwise fall back on multi-arch. FTE_TARGET=linux +ifneq ($(shell which x86_64-linux-gnux32-gcc 2> /dev/null),) + CC=x86_64-linux-gnux32-gcc + CXX=x86_64-linux-gnux32-g++ +else CC=gcc -mx32 CXX=g++ -mx32 +endif BITS=x32 endif ifeq ($(FTE_TARGET),linux64) @@ -1351,12 +1370,12 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) SV_LDFLAGS= SV_CFLAGS=$(SERVER_ONLY_CFLAGS) -DMULTITHREAD - ifneq ("$(wildcard $(/usr/include/wayland-client.h))","") + ifneq ("$(wildcard /usr/include/wayland-client.h)","") HAVE_WAYLAND=-DWAYLANDQUAKE else HAVE_WAYLAND= endif - ifneq ("$(wildcard $(/usr/include/EGL/egl.h))","") + ifneq ("$(wildcard /usr/include/EGL/egl.h)","") HAVE_EGL=-DUSE_EGL else HAVE_EGL= diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index e23e0f4eb..54a196672 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -27,7 +27,7 @@ float recdemostart; //keyed to Sys_DoubleTime int demoframe; int cls_lastto; -int cls_lasttype; +static int cls_lasttype; void CL_PlayDemo(char *demoname, qboolean usesystempath); void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath); @@ -1680,7 +1680,7 @@ static int CL_RecordInitialPlayers(sizebuf_t *buf, int seq, qboolean isnq) } static int CL_RecordInitialStats(sizebuf_t *buf, int seq, qboolean isnq) { - int seat, i; + size_t seat, i; for (seat = 0; seat < cl.splitclients; seat++) { //higher stats should be 0 and thus not be sent, if not valid. @@ -1741,7 +1741,7 @@ void CL_Record_f (void) int c; char name[MAX_OSPATH]; sizebuf_t buf; - char buf_data[MAX_OVERALLMSGLEN]; + qbyte buf_data[MAX_OVERALLMSGLEN]; int n, i; char *s, *p, *fname; extern char gamedirfile[]; @@ -2601,12 +2601,12 @@ void CL_Demo_ClientCommand(char *commandtext) } } -char qtvhostname[1024]; -char qtvrequestbuffer[4096]; -int qtvrequestsize; -char qtvrequestcmdbuffer[4096]; -int qtvrequestcmdsize; -vfsfile_t *qtvrequest; +static char qtvhostname[1024]; +static char qtvrequestbuffer[4096]; +static size_t qtvrequestsize; +static char qtvrequestcmdbuffer[4096]; +static int qtvrequestcmdsize; +static vfsfile_t *qtvrequest; void CL_QTVPoll (void) { diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index a6d8ecadb..e1d832abb 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -125,6 +125,8 @@ void CL_FreeDlights(void) if (cl_dlights) for (i = 0; i < rtlights_max; i++) { + if (cl_dlights[i].customstyle) + Z_Free(cl_dlights[i].customstyle); if (cl_dlights[i].worldshadowmesh) SH_FreeShadowMesh(cl_dlights[i].worldshadowmesh); @@ -147,11 +149,26 @@ void CL_InitDlights(void) memset(cl_dlights, 0, sizeof(*cl_dlights)*cl_maxdlights); } +void CL_CloneDlight(dlight_t *dl, dlight_t *src) +{ + char *customstyle = dl->customstyle; + void *sm = dl->worldshadowmesh; + unsigned int oq = dl->coronaocclusionquery; + unsigned int oqr = (dl->key == src->key)?dl->coronaocclusionresult:false; + memcpy (dl, src, sizeof(*dl)); + dl->coronaocclusionquery = oq; + dl->coronaocclusionresult = oqr; + dl->rebuildcache = true; + dl->worldshadowmesh = sm; + dl->customstyle = src->customstyle?Z_StrDup(src->customstyle):NULL; + Z_Free(customstyle); +} static void CL_ClearDlight(dlight_t *dl, int key) { void *sm = dl->worldshadowmesh; unsigned int oq = dl->coronaocclusionquery; unsigned int oqr = (dl->key == key)?dl->coronaocclusionresult:false; + Z_Free(dl->customstyle); memset (dl, 0, sizeof(*dl)); dl->coronaocclusionquery = oq; dl->coronaocclusionresult = oqr; @@ -179,13 +196,23 @@ static void CL_ClearDlight(dlight_t *dl, int key) dlight_t *CL_AllocSlight(void) { dlight_t *dl; - if (rtlights_max == cl_maxdlights) + int i; + for (i = RTL_FIRST; i < rtlights_max; i++) { - cl_maxdlights = rtlights_max+8; - cl_dlights = BZ_Realloc(cl_dlights, sizeof(*cl_dlights)*cl_maxdlights); - memset(&cl_dlights[rtlights_max], 0, sizeof(*cl_dlights)*(cl_maxdlights-rtlights_max)); + if (cl_dlights[i].radius <= 0) + break; } - dl = &cl_dlights[rtlights_max++]; + if (i == rtlights_max) + { + if (rtlights_max == cl_maxdlights) + { + cl_maxdlights = rtlights_max+8; + cl_dlights = BZ_Realloc(cl_dlights, sizeof(*cl_dlights)*cl_maxdlights); + memset(&cl_dlights[rtlights_max], 0, sizeof(*cl_dlights)*(cl_maxdlights-rtlights_max)); + } + i = rtlights_max++; + } + dl = &cl_dlights[i]; CL_ClearDlight(dl, 0); dl->flags = LFLAG_REALTIMEMODE; @@ -2459,10 +2486,86 @@ void CLQ1_DrawLine(shader_t *shader, vec3_t v1, vec3_t v2, float r, float g, flo t->numidx = cl_numstrisidx - t->firstidx; cl_numstrisvert += 2; } +void CLQ1_AddSpriteQuad(shader_t *shader, vec3_t mid, float radius) +{ + float r=1, g=1, b=1; + scenetris_t *t; + int flags = BEF_NODLIGHT|BEF_NOSHADOWS; + + if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == flags && cl_stris[cl_numstris-1].numvert + 4 <= MAX_INDICIES) + t = &cl_stris[cl_numstris-1]; + else + { + if (cl_numstris == cl_maxstris) + { + cl_maxstris+=8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + t = &cl_stris[cl_numstris++]; + t->shader = shader; + t->firstidx = cl_numstrisidx; + t->firstvert = cl_numstrisvert; + t->numvert = 0; + t->numidx = 0; + t->flags = flags; + } + + if (cl_numstrisidx+6 > cl_maxstrisidx) + { + cl_maxstrisidx=cl_numstrisidx+6 + 64; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); + } + if (cl_numstrisvert+4 > cl_maxstrisvert) + { + cl_maxstrisvert+=64; + cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert); + cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert); + cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert); + } + + { + VectorMA(mid, radius, vright, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, vup, cl_strisvertv[cl_numstrisvert]); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); + Vector2Set(cl_strisvertt[cl_numstrisvert], 1, 1); + cl_numstrisvert++; + + VectorMA(mid, radius, vright, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, vup, cl_strisvertv[cl_numstrisvert]); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); + Vector2Set(cl_strisvertt[cl_numstrisvert], 1, 0); + cl_numstrisvert++; + + VectorMA(mid, -radius, vright, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, vup, cl_strisvertv[cl_numstrisvert]); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); + Vector2Set(cl_strisvertt[cl_numstrisvert], 0, 0); + cl_numstrisvert++; + + VectorMA(mid, -radius, vright, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, vup, cl_strisvertv[cl_numstrisvert]); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); + Vector2Set(cl_strisvertt[cl_numstrisvert], 0, 1); + cl_numstrisvert++; + } + + /*build the triangles*/ + cl_strisidx[cl_numstrisidx++] = t->numvert + 0; + cl_strisidx[cl_numstrisidx++] = t->numvert + 1; + cl_strisidx[cl_numstrisidx++] = t->numvert + 2; + + cl_strisidx[cl_numstrisidx++] = t->numvert + 0; + cl_strisidx[cl_numstrisidx++] = t->numvert + 2; + cl_strisidx[cl_numstrisidx++] = t->numvert + 3; + + + t->numidx = cl_numstrisidx - t->firstidx; + t->numvert += 4; +} #include "shader.h" -//well, 8192 void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qboolean enqueue) { + const float radius = 8192; //infinite is quite small nowadays. scenetris_t *t; if (!enqueue) cl_numstris = 0; @@ -2501,26 +2604,26 @@ void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qbo VectorNormalize(forward); VectorScale( normal, dist, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], 8192, right, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], 8192, forward, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, right, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, forward, cl_strisvertv[cl_numstrisvert]); Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); cl_numstrisvert++; VectorScale( normal, dist, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], 8192, right, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], -8192, forward, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, right, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, forward, cl_strisvertv[cl_numstrisvert]); Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); cl_numstrisvert++; VectorScale( normal, dist, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], -8192, right, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], -8192, forward, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, right, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, forward, cl_strisvertv[cl_numstrisvert]); Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); cl_numstrisvert++; VectorScale( normal, dist, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], -8192, right, cl_strisvertv[cl_numstrisvert]); - VectorMA(cl_strisvertv[cl_numstrisvert], 8192, forward, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], -radius, right, cl_strisvertv[cl_numstrisvert]); + VectorMA(cl_strisvertv[cl_numstrisvert], radius, forward, cl_strisvertv[cl_numstrisvert]); Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, 0.2); cl_numstrisvert++; } @@ -2874,7 +2977,7 @@ static void CL_AddDecal_Callback(void *vctx, vec3_t *fte_restrict points, size_t cl_strisvertc[cl_numstrisvert+v][0] = ctx->rgbavalue[0]; cl_strisvertc[cl_numstrisvert+v][1] = ctx->rgbavalue[1]; cl_strisvertc[cl_numstrisvert+v][2] = ctx->rgbavalue[2]; - cl_strisvertc[cl_numstrisvert+v][3] = ctx->rgbavalue[3] * (1-(DotProduct(points[v], ctx->axis[0]) - ctx->offset[0]) * ctx->scale[0]); + cl_strisvertc[cl_numstrisvert+v][3] = ctx->rgbavalue[3] * (1-fabs(DotProduct(points[v], ctx->axis[0]) - ctx->offset[0]) * ctx->scale[0]); } for (v = 0; v < numpoints; v++) { @@ -2889,7 +2992,7 @@ static void CL_AddDecal_Callback(void *vctx, vec3_t *fte_restrict points, size_t void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t rgbvalue, float alphavalue) { scenetris_t *t; - float l, s, radius; + float l, s, radius, vradius; cl_adddecal_ctx_t ctx; VectorNegate(up, ctx.axis[0]); @@ -2897,20 +3000,24 @@ void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t s = DotProduct(ctx.axis[2], ctx.axis[2]); l = DotProduct(ctx.axis[0], ctx.axis[0]); + vradius = 1/sqrt(l); radius = 1/sqrt(s); - VectorScale(ctx.axis[0], 1/sqrt(l), ctx.axis[0]); + VectorScale(ctx.axis[0], vradius, ctx.axis[0]); VectorScale(ctx.axis[2], radius, ctx.axis[2]); CrossProduct(ctx.axis[0], ctx.axis[2], ctx.axis[1]); - ctx.offset[1] = DotProduct(origin, ctx.axis[1]) + 0.5*radius; ctx.offset[2] = DotProduct(origin, ctx.axis[2]) + 0.5*radius; + ctx.offset[1] = DotProduct(origin, ctx.axis[1]) + 0.5*radius; ctx.offset[0] = DotProduct(origin, ctx.axis[0]); - ctx.scale[1] = 1/radius; ctx.scale[2] = 1/radius; - ctx.scale[0] = 1; + ctx.scale[1] = 1/radius; + ctx.scale[0] = 2/vradius; + + if (R2D_Flush) + R2D_Flush(); /*reuse the previous trigroup if its the same shader*/ if (cl_numstris && cl_stris[cl_numstris-1].shader == shader && cl_stris[cl_numstris-1].flags == (BEF_NODLIGHT|BEF_NOSHADOWS)) @@ -2934,7 +3041,7 @@ void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t ctx.t = t; VectorCopy(rgbvalue, ctx.rgbavalue); ctx.rgbavalue[3] = alphavalue; - Mod_ClipDecal(cl.worldmodel, origin, ctx.axis[0], ctx.axis[1], ctx.axis[2], radius, 0,0, CL_AddDecal_Callback, &ctx); + Mod_ClipDecal(cl.worldmodel, origin, ctx.axis[0], ctx.axis[1], ctx.axis[2], max(radius, vradius), 0,0, CL_AddDecal_Callback, &ctx); if (!t->numidx) cl_numstris--; @@ -4302,6 +4409,10 @@ void CL_LinkPacketEntities (void) #endif CLQ1_AddVisibleBBoxes(); + +#ifdef RTLIGHTS + R_EditLights_DrawLights(); +#endif } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index d84887184..7abe171a9 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -232,10 +232,10 @@ static_entity_t *cl_static_entities; unsigned int cl_max_static_entities; lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; dlight_t *cl_dlights; -unsigned int cl_maxdlights; /*size of cl_dlights array*/ +size_t cl_maxdlights; /*size of cl_dlights array*/ int cl_baselines_count; -int rtlights_first, rtlights_max; +size_t rtlights_first, rtlights_max; // refresh list // this is double buffered so the last frame @@ -2448,7 +2448,7 @@ void CL_SetInfo_f (void) if (Cmd_Argc() == 1) { InfoBuf_Print (&cls.userinfo[pnum], ""); - Con_Printf("[%u]", (unsigned int)cls.userinfo[pnum].totalsize); + Con_Printf("[%u]\n", (unsigned int)cls.userinfo[pnum].totalsize); return; } if (Cmd_Argc() != 3) @@ -4876,10 +4876,10 @@ void Host_RunFileNotify(struct dl_download *dl) #define HRF_DEMO (HRF_DEMO_MVD|HRF_DEMO_QWD|HRF_DEMO_DM2|HRF_DEMO_DEM) #define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE|HRF_ARCHIVE|HRF_MODEL|HRF_CONFIG) typedef struct { - unsigned int flags; struct dl_download *dl; vfsfile_t *srcfile; vfsfile_t *dstfile; + unsigned int flags; char fname[1]; //system path or url. } hrf_t; @@ -6294,8 +6294,10 @@ void Host_FinishLoading(void) 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(true)) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 00362885d..02047c4f7 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -6029,7 +6029,8 @@ void CL_PrintChat(player_info_t *plr, char *msg, int plrflags) if (con_separatechat.ival == 1) { - Con_PrintCon(&con_main, fullchatmessage, con_main.parseflags|PFS_NONOTIFY); + console_t *c = Con_GetMain(); + Con_PrintCon(c, fullchatmessage, c->parseflags|PFS_NONOTIFY); return; } } @@ -6585,7 +6586,7 @@ static void CL_ParsePrecache(void) } } -static void Con_HexDump(qbyte *packet, size_t len) +static void Con_HexDump(qbyte *packet, size_t len, size_t badoffset) { int i; int pos; @@ -6598,6 +6599,8 @@ static void Con_HexDump(qbyte *packet, size_t len) { if (pos >= len) Con_Printf(" - "); + else if (pos == badoffset) + Con_Printf("^b^1%2x ", packet[pos]); else Con_Printf("%2x ", packet[pos]); pos++; @@ -6608,9 +6611,19 @@ static void Con_HexDump(qbyte *packet, size_t len) if (pos >= len) Con_Printf("X"); else if (packet[pos] == 0 || packet[pos] == '\t' || packet[pos] == '\r' || packet[pos] == '\n') - Con_Printf("."); + { + if (pos == badoffset) + Con_Printf("^b^1."); + else + Con_Printf("."); + } else - Con_Printf("%c", packet[pos]); + { + if (pos == badoffset) + Con_Printf("^b^1%c", packet[pos]); + else + Con_Printf("%c", packet[pos]); + } pos++; } Con_Printf("\n"); @@ -6619,7 +6632,7 @@ static void Con_HexDump(qbyte *packet, size_t len) } void CL_DumpPacket(void) { - Con_HexDump(net_message.data, net_message.cursize); + Con_HexDump(net_message.data, net_message.cursize, msg_readcount-1); } static void CL_ParsePortalState(void) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index ab087f8fc..87b014869 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -183,8 +183,8 @@ float mousemove_x, mousemove_y; float multicursor_x[8], multicursor_y[8]; qboolean multicursor_active[8]; -float scr_con_current; -float scr_conlines; // lines of console to display +float scr_con_current; //current console lines shown +float scr_con_target; //the target number of lines (not a local, because it helps to know if we're at the target yet, etc) qboolean scr_con_forcedraw; @@ -200,7 +200,6 @@ extern cvar_t scr_printspeed; extern cvar_t scr_allowsnap; extern cvar_t scr_sshot_type; extern cvar_t scr_sshot_prefix; -extern cvar_t scr_sshot_compression; extern cvar_t crosshair; extern cvar_t scr_consize; cvar_t scr_neticontimeout = CVAR("scr_neticontimeout", "0.3"); @@ -222,7 +221,7 @@ qboolean scr_disabled_for_loading; qboolean scr_drawloading; float scr_disabled_time; -cvar_t con_stayhidden = CVARFD("con_stayhidden", "0", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); +cvar_t con_stayhidden = CVARFD("con_stayhidden", "1", CVAR_NOTFROMSERVER, "0: allow console to pounce on the user\n1: console stays hidden unless explicitly invoked\n2:toggleconsole command no longer works\n3: shift+escape key no longer works"); cvar_t show_fps = CVARFD("show_fps", "0", CVAR_ARCHIVE, "Displays the current framerate on-screen.\n1: framerate average over a second.\n2: Slowest frame over the last second (the game will play like shit if this is significantly lower than the average).\n3: Shows the rate of the fastest frame (not very useful).\n4: Shows the current frame's timings (this depends upon timer precision).\n5: Display a graph of how long it took to render each frame, large spikes are BAD BAD BAD.\n6: Displays the standard deviation of the frame times, if its greater than 3 then something is probably badly made, or you've a virus scanner running...\n7: Framegraph, for use with slower frames."); cvar_t show_fps_x = CVAR("show_fps_x", "-1"); cvar_t show_fps_y = CVAR("show_fps_y", "-1"); @@ -727,7 +726,7 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font) Font_BeginString(font, rect->x, y, &left, &top); Font_BeginString(font, rect->x+rect->width, rect->y+rect->height, &right, &bottom); - linecount = Font_LineBreaks(p->string, p->string + p->charcount, right - left, MAX_CPRINT_LINES, line_start, line_end); + linecount = Font_LineBreaks(p->string, p->string + p->charcount, (p->flags & CPRINT_NOWRAP)?0x7fffffff:(right - left), MAX_CPRINT_LINES, line_start, line_end); ch = Font_CharHeight(); @@ -1943,8 +1942,6 @@ void SCR_SetLoadingStage(int stage) SCR_SetLoadingFile("waiting for connection..."); break; case LS_SERVER: - if (scr_con_current > vid.height*scr_consize.value) - scr_con_current = vid.height*scr_consize.value; SCR_SetLoadingFile("starting server..."); break; case LS_CLIENT: @@ -2287,85 +2284,85 @@ SCR_SetUpToDrawConsole void SCR_SetUpToDrawConsole (void) { extern int startuppending; //true if we're downloading media or something and have not yet triggered the startup action (read: main menu or cinematic) -// if (scr_drawloading) -// return; // never a console with loading plaque - -// decide on the height of the console -// if (!scr_disabled_for_loading) - { - float fullscreenpercent = 1; + float fullscreenpercent = 1; #ifdef ANDROID - //android has an onscreen imm that we don't want to obscure - fullscreenpercent = scr_consize.value; + //android has an onscreen imm that we don't want to obscure + fullscreenpercent = scr_consize.value; #endif - if (!con_stayhidden.ival && (!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->loadstate != MLS_LOADED)) + if (!con_stayhidden.ival && (!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->loadstate != MLS_LOADED)) + { + //force console to fullscreen if we're loading stuff (but don't necessarily force focus) +// Key_Dest_Add(kdm_console); + scr_con_target = scr_con_current = vid.height * fullscreenpercent; + } + else if (!startuppending && !Key_Dest_Has(kdm_emenu|kdm_gmenu) && (!Key_Dest_Has(~((!con_stayhidden.ival?kdm_console:0)|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false)) + { + //go fullscreen if we're not doing anything + if (con_curwindow && !cls.state && !scr_drawloading && !Key_Dest_Has(kdm_console)) { - //force console to fullscreen if we're loading stuff -// Key_Dest_Add(kdm_console); - scr_conlines = scr_con_current = vid.height * fullscreenpercent; + Key_Dest_Add(kdm_cwindows); + scr_con_target = 0; // not looking at an normal console } - else if (!startuppending && !Key_Dest_Has(kdm_emenu|kdm_gmenu) && (!Key_Dest_Has(~((!con_stayhidden.ival?kdm_console:0)|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false)) - { - //go fullscreen if we're not doing anything - if (con_curwindow && !cls.state && !scr_drawloading) - { - Key_Dest_Add(kdm_cwindows); - scr_conlines = 0; - } #ifdef VM_UI - else if (UI_MenuState() || UI_OpenMenu()) - scr_con_current = scr_conlines = 0; + else if (UI_MenuState() || UI_OpenMenu()) + scr_con_current = scr_con_target = 0; //force instantly hidden. #endif - else + else + { + qboolean legacyfullscreen = false; + if (cls.state < ca_demostart) { - if (cls.state < ca_demostart) - { - if (con_stayhidden.ival) + if (con_stayhidden.ival) + { //go to the menu instead of the console. + extern int startuppending; + if (!scr_drawloading && SCR_GetLoadingStage() == LS_NONE) { - extern int startuppending; - scr_conlines = 0; - if (SCR_GetLoadingStage() == LS_NONE) - { - if (CL_TryingToConnect()) //if we're trying to connect, make sure there's a loading/connecting screen showing instead of forcing the menu visible - SCR_SetLoadingStage(LS_CONNECTION); - else if (!Key_Dest_Has(kdm_emenu) && !startuppending) //don't force anything until the startup stuff has been done - M_ToggleMenu_f(); - } + if (CL_TryingToConnect()) //if we're trying to connect, make sure there's a loading/connecting screen showing instead of forcing the menu visible + SCR_SetLoadingStage(LS_CONNECTION); + else if (!Key_Dest_Has(kdm_emenu) && !startuppending) //don't force anything until the startup stuff has been done + M_ToggleMenu_f(); } - else + } + else + { //nothing happening, make sure the console is visible or something. + if (!scr_drawloading) Key_Dest_Add(kdm_console); + legacyfullscreen = true; } } - if (Key_Dest_Has(kdm_console) || (!con_stayhidden.ival && !startuppending && !scr_drawloading && !scr_disabled_for_loading && cls.state < ca_connected)) - scr_con_current = scr_conlines = vid.height * fullscreenpercent; - else - scr_conlines = 0; - } - else if (Key_Dest_Has(kdm_console)) - { - //go half-screen if we're meant to have the console visible - scr_conlines = vid.height*scr_consize.value; // half screen - if (scr_conlines < 32) - scr_conlines = 32; //prevent total loss of console. - else if (scr_conlines>vid.height) - scr_conlines = vid.height; - } - else - scr_conlines = 0; // none visible + if (startuppending) + scr_con_target = 0; //not made any decisions yet + else if (Key_Dest_Has(kdm_console) || legacyfullscreen) + scr_con_current = scr_con_target = vid.height * fullscreenpercent; // force instantly to fullscreen + else + scr_con_target = 0; + } } - if (scr_conlines < scr_con_current) + else if (Key_Dest_Has(kdm_console)) + { + //go half-screen if we're meant to have the console visible + scr_con_target = vid.height*scr_consize.value; // half screen + if (scr_con_target < 32) + scr_con_target = 32; //prevent total loss of console. + else if (scr_con_target>vid.height) + scr_con_target = vid.height; + } + else + scr_con_target = 0; // scroll to nothing + + if (scr_con_target < scr_con_current) { scr_con_current -= scr_conspeed.value*host_frametime * (vid.height/320.0f); - if (scr_conlines > scr_con_current) - scr_con_current = scr_conlines; + if (scr_con_target > scr_con_current) + scr_con_current = scr_con_target; } - else if (scr_conlines > scr_con_current) + else if (scr_con_target > scr_con_current) { scr_con_current += scr_conspeed.value*host_frametime * (vid.height/320.0f); - if (scr_conlines < scr_con_current) - scr_con_current = scr_conlines; + if (scr_con_target < scr_con_current) + scr_con_current = scr_con_target; } if (scr_con_current>vid.height) @@ -2406,266 +2403,6 @@ void SCR_DrawConsole (qboolean noback) ============================================================================== */ -typedef struct _TargaHeader { - unsigned char id_length, colormap_type, image_type; - unsigned short colormap_index, colormap_length; - unsigned char colormap_size; - unsigned short x_origin, y_origin, width, height; - unsigned char pixel_size, attributes; -} TargaHeader; - - -#if defined(AVAIL_JPEGLIB) && !defined(NO_JPEG) -qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int bytestride, int screenwidth, int screenheight, enum uploadfmt fmt); -#endif -#ifdef AVAIL_PNGLIB -int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt); -#endif -qboolean WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int instride, int width, int height, uploadfmt_t fmt); - -qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_restrict rgb_buffer, int bytestride, int width, int height, enum uploadfmt fmt) -{ - size_t c, i; - vfsfile_t *vfs; - if (fmt != TF_BGRA32 && fmt != TF_RGB24 && fmt != TF_RGBA32 && fmt != TF_BGR24 && fmt != TF_RGBX32 && fmt != TF_BGRX32) - return false; - FS_CreatePath(filename, fsroot); - vfs = FS_OpenVFS(filename, "wb", fsroot); - if (vfs) - { - int ipx,opx; - qboolean rgb; - unsigned char header[18]; - memset (header, 0, 18); - - if (fmt == TF_BGRA32 || fmt == TF_RGBA32) - { - rgb = fmt==TF_RGBA32; - ipx = 4; - opx = 4; - } - else if (fmt == TF_RGBX32 || fmt == TF_BGRX32) - { - rgb = fmt==TF_RGBX32; - ipx = 4; - opx = 3; - } - else - { - rgb = fmt==TF_RGB24; - ipx = 3; - opx = 3; - } - - header[2] = 2; // uncompressed type - header[12] = width&255; - header[13] = width>>8; - header[14] = height&255; - header[15] = height>>8; - header[16] = opx*8; // pixel size - header[17] = 0x00; // flags - - if (bytestride < 0) - { //if we're upside down, lets just use an upside down tga. - rgb_buffer += bytestride*(height-1); - bytestride = -bytestride; - //now we can just do everything without worrying about rows - } - else //our data is top-down, set up the header to also be top-down. - header[17] = 0x20; - - if (ipx == opx && !rgb) - { //can just directly write it - //bgr24, bgra24 - c = width*height*opx; - - VFS_WRITE(vfs, header, sizeof(header)); - VFS_WRITE(vfs, rgb_buffer, c); - } - else - { - qbyte *fte_restrict rgb_out = malloc(width*opx*height); - - //no need to swap alpha, and if we're just swapping alpha will be fine in-place. - if (rgb) - { //rgb24, rgbx32, rgba32 - // compact, and swap - c = width*height; - for (i=0 ; iloadstate != MLS_LOADED) { @@ -3106,74 +2909,146 @@ void SCR_ScreenShot_Cubemap_f(void) fbheight = 512; fbwidth = fbheight; - for (i = firstside; i < firstside+6; i++) + ext = COM_GetFileExtension(fname, NULL); + if (!*fname || ext == fname) + { //generate a default filename if none exists yet. + char base[MAX_QPATH]; + COM_FileBase(cl.worldmodel->name, base, sizeof(base)); + fname = va("%s/%i_%i_%i", base, (int)r_refdef.vieworg[0], (int)r_refdef.vieworg[1], (int)r_refdef.vieworg[2]); + } + if (!strcmp(ext, ".ktx") || !strcmp(ext, ".dds")) { - if (!*fname) + qboolean fail = false; + mips.type = PTI_CUBEMAP; + mips.encoding = 0; + mips.extrafree = NULL; + mips.mipcount = 6; + + for (i = 0; i < 6; i++) { - char base[MAX_QPATH]; - COM_FileBase(cl.worldmodel->name, base, sizeof(base)); - fname = va("%s/%i_%i_%i", base, (int)r_refdef.vieworg[0], (int)r_refdef.vieworg[1], (int)r_refdef.vieworg[2]); + VectorCopy(sides[i].angle, cl.playerview->simangles); + VectorCopy(cl.playerview->simangles, cl.playerview->viewangles); + + mips.mip[i].data = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true); + if (!mips.mip[i].data) + fail = true; + if (!i) + mips.encoding = fmt; + else if (fmt != mips.encoding || fbwidth != mips.mip[0].width || fbheight != mips.mip[0].height) + fail = true; //zomgwtfbbq + + mips.mip[i].data = SCR_ScreenShot_FixStride(mips.mip[i].data, fbwidth, fbheight, &stride, fmt, sides[i].horizontalflip, sides[i].verticalflip); + Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh); + + mips.mip[i].datasize = bb*((fbwidth+bw-1)/bw)*((fbheight+bh-1)/bh); + mips.mip[i].width = fbwidth; + mips.mip[i].height = fbheight; + mips.mip[i].depth = 0; + mips.mip[i].needfree = true; } - Q_snprintfz(filename, sizeof(filename), "textures/%s%s", fname, sides[i].postfix); - COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename)); - VectorCopy(sides[i].angle, cl.playerview->simangles); - VectorCopy(cl.playerview->simangles, cl.playerview->viewangles); + /*FIXME: + while (!fail && (w > 1 || h > 1)) + { //warning: d3d is different + w = max(1,w>>1); + h = max(1,h>>1); + if (mips.mipcount+6 > countof(mips.mip)) + break; //erk! how big was the original image?!? - buffer = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt); - if (buffer) - { - char sysname[1024]; - if (sides[i].horizontalflip) + for (i = 0; i < 6; i++) { - int y, x, p; - int pxsize; - char *bad = buffer; - char *in = buffer, *out; - switch(fmt) - { - case TF_RGBA32: - case TF_BGRA32: - case TF_RGBX32: - case TF_BGRX32: - pxsize = 4; - break; - case TF_RGB24: - case TF_BGR24: - pxsize = 3; - break; - default: //erk! - pxsize = 1; - break; - } - buffer = out = BZ_Malloc(fbwidth*fbheight*pxsize); - for (y = 0; y < fbheight; y++, in += abs(stride), out += fbwidth*pxsize) - { - for (x = 0; x < fbwidth*pxsize; x+=pxsize) - { - for (p = 0; p < pxsize; p++) - out[x+p] = in[(fbwidth-1)*pxsize-x+p]; - } - } - BZ_Free(bad); - if (stride < 0) - stride = -fbwidth*pxsize; - else - stride = fbwidth*pxsize; + mips.mip[mips.mipcount] = GenerateMip(mips.mip[mips.mipcount-6]); + mips.mipcount++; } - if (sides[i].verticalflip) - stride = -stride; - if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, fbwidth, fbheight, fmt)) + } + */ + + Q_snprintfz(filename, sizeof(filename), "textures/%s", fname); + COM_DefaultExtension (filename, ext, sizeof(filename)); +#ifdef IMAGEFMT_KTX + COM_DefaultExtension (filename, ".ktx", sizeof(filename)); +#endif +#ifdef IMAGEFMT_DDS + COM_DefaultExtension (filename, ".dds", sizeof(filename)); +#endif + ext = COM_GetFileExtension(filename, NULL); + if (fail) + Con_Printf("Unable to generate cubemap data\n"); +#ifdef IMAGEFMT_DDS + else if (!strcmp(ext, ".dds")) + { + if (Image_WriteDDSFile(filename, FS_GAMEONLY, &mips)) { FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); Con_Printf ("Wrote %s\n", sysname); } - else + } +#endif +#ifdef IMAGEFMT_KTX + else if (!strcmp(ext, ".ktx")) + { + if (Image_WriteKTXFile(filename, FS_GAMEONLY, &mips)) { FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); - Con_Printf ("Failed to write %s\n", sysname); + Con_Printf ("Wrote %s\n", sysname); + } + } +#endif + else + Con_Printf ("%s: Unknown format %s\n", Cmd_Argv(0), filename); + while (i-- > 0) + if (mips.mip[i].needfree) + BZ_Free(mips.mip[i].data); + } + else + { + for (i = firstside; i < firstside+6; i++) + { + VectorCopy(sides[i].angle, cl.playerview->simangles); + VectorCopy(cl.playerview->simangles, cl.playerview->viewangles); + + buffer = SCR_ScreenShot_Capture(fbwidth, fbheight, &stride, &fmt, true); + if (buffer) + { + Image_BlockSizeForEncoding(fmt, &bb, &bw, &bh); + if (sides[i].horizontalflip) + { + int y, x, p; + char *bad = buffer; + char *in = buffer, *out; + buffer = out = BZ_Malloc(fbwidth*fbheight*bb); + for (y = 0; y < fbheight; y++, in += abs(stride), out += fbwidth*bb) + { + for (x = 0; x < fbwidth*bb; x+=bb) + { + for (p = 0; p < bb; p++) + out[x+p] = in[(fbwidth-1)*bb-x+p]; + } + } + BZ_Free(bad); + if (stride < 0) + stride = -fbwidth*bb; + else + stride = fbwidth*bb; + } + if (sides[i].verticalflip) + stride = -stride; + + Q_snprintfz(filename, sizeof(filename), "textures/%s%s", fname, sides[i].postfix); + COM_DefaultExtension (filename, scr_sshot_type.string, sizeof(filename)); + + 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); + } + else + { + FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); + Con_Printf ("Failed to write %s\n", sysname); + } + BZ_Free(buffer); } - BZ_Free(buffer); } } @@ -3527,6 +3402,7 @@ void SCR_Init (void) // Cmd_AddCommandD ("screenshot_mega",SCR_ScreenShot_Mega_f, "screenshot_mega [width] [height]\nTakes a screenshot with explicit sizes that are not tied to the size of your monitor, allowing for true monstrosities."); Cmd_AddCommandD ("screenshot_stereo",SCR_ScreenShot_Mega_f, "screenshot_stereo [width] [height]\nTakes a simple stereo screenshot."); + Cmd_AddCommandD ("screenshot_360",SCR_ScreenShot_Mega_f, "screenshot_360 [width] [height]\nTakes an equirectangular screenshot."); Cmd_AddCommandD ("screenshot_vr",SCR_ScreenShot_VR_f, "screenshot_vr [width]\nTakes a spherical stereoscopic panorama image, for viewing with VR displays."); Cmd_AddCommandD ("screenshot_cubemap",SCR_ScreenShot_Cubemap_f, "screenshot_cubemap [size]\nTakes 6 screenshots forming a single cubemap."); Cmd_AddCommandD ("envmap",SCR_ScreenShot_Cubemap_f, "Legacy name for the screenshot_cubemap command."); //legacy diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 3dde29d69..29ca74231 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -1561,8 +1561,6 @@ qboolean UI_KeyPress(int key, int unicode, qboolean down) } UI_OpenMenu(); - - scr_conlines = 0; return true; } return false; diff --git a/engine/client/client.h b/engine/client/client.h index 8d010d8e1..55a2053f6 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -315,6 +315,7 @@ typedef struct dlight_s int key; // so entities can reuse same entry vec3_t origin; vec3_t axis[3]; + vec3_t angles; //used only for reflection, to avoid things getting rounded/cycled. vec3_t rotation; //cubemap/spotlight rotation float radius; float die; // stop lighting after this time @@ -330,6 +331,7 @@ typedef struct dlight_s unsigned int flags; char cubemapname[64]; + char *customstyle; int coronaocclusionquery; unsigned int coronaocclusionresult; @@ -780,7 +782,7 @@ typedef struct double last_servermessage; //list of ent frames that still need to be acked. - int numackframes; + unsigned int numackframes; int ackframes[64]; #ifdef Q2CLIENT @@ -1049,9 +1051,9 @@ extern static_entity_t *cl_static_entities; extern unsigned int cl_max_static_entities; extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; extern dlight_t *cl_dlights; -extern unsigned int cl_maxdlights; +extern size_t cl_maxdlights; -extern int rtlights_first, rtlights_max; +extern size_t rtlights_first, rtlights_max; extern int cl_baselines_count; extern qboolean nomaster; @@ -1068,6 +1070,7 @@ dlight_t *CL_AllocDlight (int key); dlight_t *CL_AllocSlight (void); //allocates a static light dlight_t *CL_NewDlight (int key, const vec3_t origin, float radius, float time, float r, float g, float b); dlight_t *CL_NewDlightCube (int key, const vec3_t origin, vec3_t angles, float radius, float time, vec3_t colours); +void CL_CloneDlight(dlight_t *dl, dlight_t *src); //copies one light to another safely void CL_DecayLights (void); void CLQW_ParseDelta (struct entity_state_s *from, struct entity_state_s *to, int bits); @@ -1305,7 +1308,7 @@ qboolean CL_CheckBaselines (int size); void V_StartPitchDrift (playerview_t *pv); void V_StopPitchDrift (playerview_t *pv); -void V_RenderView (void); +void V_RenderView (qboolean no2d); void V_Register (void); void V_ParseDamage (playerview_t *pv); void V_SetContentsColor (int contents); diff --git a/engine/client/console.c b/engine/client/console.c index 04bedbf96..46bb36088 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -22,10 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" #include "shader.h" -console_t con_main; -console_t *con_curwindow; -console_t *con_current; // points to whatever is the visible console +console_t *con_head; // first console in the list +console_t *con_curwindow; // the (window) console that's currently got focus. +console_t *con_current; // points to whatever is the active console (the one that has focus ONLY when kdm_console) console_t *con_mouseover; // points to whichever console's title is currently mouseovered, or null + +console_t *con_main; // the default console that text will be thrown at. recreated as needed. console_t *con_chat; // points to a chat console #define Font_ScreenWidth() (vid.pixelwidth) @@ -55,27 +57,55 @@ qterm_t *activeqterm; //int con_linewidth; // characters across screen //int con_totallines; // total lines in console scrollback -float con_cursorspeed = 4; +static float con_cursorspeed = 4; -cvar_t con_numnotifylines = CVAR("con_notifylines","4"); //max lines to show -cvar_t con_notifytime = CVAR("con_notifytime","3"); //seconds -cvar_t con_notify_x = CVAR("con_notify_x","0"); -cvar_t con_notify_y = CVAR("con_notify_y","0"); -cvar_t con_notify_w = CVAR("con_notify_w","1"); -cvar_t con_centernotify = CVAR("con_centernotify", "0"); -cvar_t con_displaypossibilities = CVAR("con_displaypossibilities", "1"); -cvar_t con_showcompletion = CVAR("con_showcompletion", "1"); -cvar_t con_maxlines = CVAR("con_maxlines", "1024"); -cvar_t cl_chatmode = CVARD("cl_chatmode", "2", "0(nq) - everything is assumed to be a console command. prefix with 'say', or just use a messagemode bind\n1(q3) - everything is assumed to be chat, unless its prefixed with a /\n2(qw) - anything explicitly recognised as a command will be used as a command, anything unrecognised will be a chat message.\n/ prefix is supported in all cases.\nctrl held when pressing enter always makes any implicit chat into team chat instead."); -cvar_t con_numnotifylines_chat = CVAR("con_numnotifylines_chat", "8"); -cvar_t con_notifytime_chat = CVAR("con_notifytime_chat", "8"); -cvar_t con_separatechat = CVAR("con_separatechat", "0"); -cvar_t con_timestamps = CVAR("con_timestamps", "0"); -cvar_t con_timeformat = CVAR("con_timeformat", "(%H:%M:%S) "); -cvar_t con_textsize = CVARD("con_textsize", "8", "Resize the console text to be a different height, scaled separately from the hud. The value is the height in (virtual) pixels."); +static cvar_t con_numnotifylines = CVAR("con_notifylines","4"); //max lines to show +static cvar_t con_notifytime = CVAR("con_notifytime","3"); //seconds +static cvar_t con_notify_x = CVAR("con_notify_x","0"); +static cvar_t con_notify_y = CVAR("con_notify_y","0"); +static cvar_t con_notify_w = CVAR("con_notify_w","1"); +static cvar_t con_centernotify = CVAR("con_centernotify", "0"); +static cvar_t con_displaypossibilities = CVAR("con_displaypossibilities", "1"); +static cvar_t con_showcompletion = CVAR("con_showcompletion", "1"); +static cvar_t con_maxlines = CVAR("con_maxlines", "1024"); +cvar_t cl_chatmode = CVARD("cl_chatmode", "2", "0(nq) - everything is assumed to be a console command. prefix with 'say', or just use a messagemode bind\n1(q3) - everything is assumed to be chat, unless its prefixed with a /\n2(qw) - anything explicitly recognised as a command will be used as a command, anything unrecognised will be a chat message.\n/ prefix is supported in all cases.\nctrl held when pressing enter always makes any implicit chat into team chat instead."); +static cvar_t con_numnotifylines_chat = CVAR("con_numnotifylines_chat", "8"); +static cvar_t con_notifytime_chat = CVAR("con_notifytime_chat", "8"); +cvar_t con_separatechat = CVAR("con_separatechat", "0"); +static cvar_t con_timestamps = CVAR("con_timestamps", "0"); +static cvar_t con_timeformat = CVAR("con_timeformat", "(%H:%M:%S) "); +cvar_t con_textsize = CVARD("con_textsize", "8", "Resize the console text to be a different height, scaled separately from the hud. The value is the height in (virtual) pixels."); extern cvar_t log_developer; +void con_window_cb(cvar_t *var, char *oldval) +{ + if (!con_main) + return; //doesn't matter right now. + + if (var->ival) + { + con_main->flags &= ~CONF_NOTIFY; + if (!(con_main->flags & CONF_ISWINDOW)) + { + con_main->flags |= CONF_ISWINDOW; + if (con_current == con_main) + Con_SetActive(con_main); + } + } + else + { + con_main->flags |= CONF_NOTIFY; + if (con_main->flags & CONF_ISWINDOW) + { + con_main->flags &= ~CONF_ISWINDOW; + if (con_curwindow == con_main) + Con_SetActive(con_main); + } + } +} +static cvar_t con_window = CVARCD("con_window", "0", con_window_cb, "States whether the console should be a floating window as in source engine games, or a top-of-the-screen-only thing."); + #define NUM_CON_TIMES 24 qboolean con_initialized; @@ -110,7 +140,7 @@ int Con_IsActive (console_t *con) void Con_Destroy (console_t *con) { shader_t *shader; - console_t *prev; + console_t **link; conline_t *t; if (con->close) @@ -135,19 +165,11 @@ void Con_Destroy (console_t *con) Z_Free(con->completionline); con->completionline = NULL; - if (con == &con_main) + for (link = &con_head; *link; link = &(*link)->next) { - /*main console is never destroyed, only cleared (unless shutting down)*/ - if (con_initialized) - Con_Finit(con); - return; - } - - for (prev = &con_main; prev->next; prev = prev->next) - { - if (prev->next == con) + if (*link == con) { - prev->next = con->next; + (*link) = con->next; break; } } @@ -156,12 +178,15 @@ void Con_Destroy (console_t *con) BZ_Free(con); + //make sure any special references are fixed up now that its gone + if (con_mouseover == con) + con_mouseover = NULL; if (con_current == con) - con_current = &con_main; + con_current = con_head; if (con_curwindow == con) { - for (con_curwindow = &con_main; con_curwindow; con_curwindow = con_curwindow->next) + for (con_curwindow = con_head; con_curwindow; con_curwindow = con_curwindow->next) { if (con_curwindow->flags & CONF_ISWINDOW) break; @@ -180,7 +205,7 @@ void Con_FlushBackgrounds(void) { console_t *con; //fixme: we really need to handle videomaps differently here, for vid_restarts. - for (con = &con_main; con; con = con->next) + for (con = con_head; con; con = con->next) { if (con->backshader) R_UnloadShader(con->backshader); @@ -194,7 +219,9 @@ console_t *Con_FindConsole(const char *name) console_t *con; if (!strcmp(name, "current") && con_current) return con_current; - for (con = &con_main; con; con = con->next) + if (!strcmp(name, "head") && con_current) + return con_head; + for (con = con_head; con; con = con->next) { if (!strcmp(con->name, name)) return con; @@ -204,9 +231,11 @@ console_t *Con_FindConsole(const char *name) /*creates a potentially duplicate console_t - please use Con_FindConsole first, as its confusing otherwise*/ console_t *Con_Create(const char *name, unsigned int flags) { - console_t *con; + console_t *con, *p; if (!strcmp(name, "current")) return NULL; + if (!strcmp(name, "head")) + return NULL; con = Z_Malloc(sizeof(console_t)); Q_strncpyz(con->name, name, sizeof(con->name)); Q_strncpyz(con->title, name, sizeof(con->title)); @@ -214,11 +243,51 @@ console_t *Con_Create(const char *name, unsigned int flags) con->flags = flags; Con_Finit(con); - con->next = con_main.next; - con_main.next = con; + + //insert at end. make it active if you must. + if (!con_head) + con_head = con; + else + { + for (p = con_head; p->next; p = p->next) + ; + p->next = con; + } return con; } + +static qboolean Con_Main_BlockClose(console_t *con, qboolean force) +{ + if (!force) + { //trying to close it just hides it (this is to avoid it getting cleared). + if (con_curwindow == con) + Key_Dest_Remove(kdm_cwindows); + return false; + } + con_main = NULL; //its forced to die. and don't forget it. + return true; +} +console_t *Con_GetMain(void) +{ + if (!con_main) + { + con_main = Con_Create("", 0); + + con_main->linebuffered = Con_ExecuteLine; + con_main->commandcompletion = true; + con_main->wnd_w = 640; + con_main->wnd_h = 480; + con_main->wnd_x = 0; + con_main->wnd_y = 0; + con_main->close = Con_Main_BlockClose; + Q_strncpyz(con_main->title, "MAIN", sizeof(con_main->title)); + Q_strncpyz(con_main->prompt, "]", sizeof(con_main->prompt)); + + Cvar_ForceCallback(&con_window); + } + return con_main; +} /*sets a console as the active one*/ void Con_SetActive (console_t *con) { @@ -231,7 +300,7 @@ void Con_SetActive (console_t *con) if (con_curwindow == con) return; - for (prev = &con_main; prev; prev = prev->next) + for (prev = con_head; prev; prev = prev->next) { if (prev->next == con) { @@ -248,7 +317,13 @@ void Con_SetActive (console_t *con) con_curwindow = con; } else + { + if (con_curwindow == con) + con_curwindow = NULL; + Key_Dest_Add(kdm_console); + Key_Dest_Remove(kdm_cwindows); con_current = con; + } if (con->footerline) { @@ -263,7 +338,7 @@ void Con_SetActive (console_t *con) qboolean Con_NameForNum(int num, char *buffer, int buffersize) { console_t *con; - for (con = &con_main; con; con = con->next, num--) + for (con = con_head; con; con = con->next, num--) { if (num <= 0) { @@ -544,9 +619,11 @@ void Con_ToggleConsole_f (void) { extern cvar_t con_stayhidden; + Con_GetMain(); + if (!con_curwindow) { - for (con_curwindow = &con_main; con_curwindow; con_curwindow = con_curwindow->next) + for (con_curwindow = con_head; con_curwindow; con_curwindow = con_curwindow->next) if (con_curwindow->flags & CONF_ISWINDOW) break; } @@ -598,9 +675,10 @@ Con_Clear_f */ void Con_Clear_f (void) { - if (Cmd_IsInsecure()) + console_t *con = Con_FindConsole(Cmd_Argv(1)); + if (!con || Cmd_IsInsecure()) return; - Con_ClearCon(&con_main); + Con_ClearCon(con); } @@ -680,7 +758,7 @@ void Con_MessageMode2_f (void) void Con_ForceActiveNow(void) { Key_Dest_Add(kdm_console); - scr_conlines = scr_con_current = vid.height; + scr_con_target = scr_con_current = vid.height; } /* @@ -692,18 +770,10 @@ void Log_Init (void); void Con_Init (void) { - con_current = &con_main; - Con_Finit(&con_main); + con_current = NULL; + con_head = NULL; - con_main.linebuffered = Con_ExecuteLine; - con_main.commandcompletion = true; -// con_main.flags |= CONF_ISWINDOW; - con_main.wnd_w = 640; - con_main.wnd_h = 480; - con_main.wnd_x = 0; - con_main.wnd_y = 0; - Q_strncpyz(con_main.title, "MAIN", sizeof(con_main.title)); - Q_strncpyz(con_main.prompt, "]", sizeof(con_main.prompt)); + con_main = Con_GetMain(); con_initialized = true; // Con_TPrintf ("Console initialized.\n"); @@ -727,6 +797,8 @@ void Con_Init (void) Cvar_Register (&con_timestamps, "Console controls"); Cvar_Register (&con_timeformat, "Console controls"); Cvar_Register (&con_textsize, "Console controls"); + Cvar_Register (&con_window, "Console controls"); + Cvar_ForceCallback(&con_window); Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); @@ -736,11 +808,11 @@ void Con_Init (void) Cmd_AddCommand ("qterm", Con_QTerm_f); #endif - Cmd_AddCommand ("conecho_center", Cmd_ConEchoCenter_f); - Cmd_AddCommand ("conecho", Cmd_ConEcho_f); - Cmd_AddCommand ("conclear", Cmd_ConClear_f); - Cmd_AddCommand ("conclose", Cmd_ConClose_f); - Cmd_AddCommand ("conactivate", Cmd_ConActivate_f); + Cmd_AddCommandD ("conecho_center", Cmd_ConEchoCenter_f, "conecho_center consolename The Text To Echo\nUse \"\" for the main console.\nAny added lines will be aligned to the middle of the console."); + Cmd_AddCommandD ("conecho", Cmd_ConEcho_f, "conecho consolename The Text To Echo\nEchos text to a named console instead of just the main one."); + Cmd_AddCommandD ("conclear", Cmd_ConClear_f, "Clears a named console (instead of just the main one)"); + Cmd_AddCommandD ("conclose", Cmd_ConClose_f, "Destroys a named console"); + Cmd_AddCommandD ("conactivate", Cmd_ConActivate_f, "Brings focus to the named console. Will not do anything if the named console is not created yet (so be sure to do any echos before using this command)"); Log_Init(); } @@ -754,12 +826,9 @@ void Con_Shutdown(void) BZ_Free(key_lines[i]); } - while(con_main.next) - { - Con_Destroy(con_main.next); - } + while(con_head) + Con_Destroy(con_head); con_initialized = false; - Con_Destroy(&con_main); } void TTS_SayConString(conchar_t *stringtosay); @@ -935,19 +1004,22 @@ void Con_PrintCon (console_t *con, const char *txt, unsigned int parseflags) void Con_CenterPrint(const char *txt) { - int flags = con_main.parseflags|PFS_NONOTIFY|PFS_CENTERED; - Con_PrintCon(&con_main, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n", flags); - Con_PrintCon(&con_main, txt, flags); //client console - Con_PrintCon(&con_main, "\n^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n", flags); + console_t *c = Con_GetMain(); + int flags = c->parseflags|PFS_NONOTIFY|PFS_CENTERED; + Con_PrintCon(c, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n", flags); + Con_PrintCon(c, txt, flags); //client console + Con_PrintCon(c, "\n^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f\n", flags); } void Con_Print (const char *txt) { - Con_PrintCon(&con_main, txt, con_main.parseflags); //client console + console_t *c = Con_GetMain(); + Con_PrintCon(c, txt, c->parseflags); //client console } void Con_PrintFlags(const char *txt, unsigned int setflags, unsigned int clearflags) { - setflags |= con_main.parseflags; + console_t *c = Con_GetMain(); + setflags |= c->parseflags; setflags &= ~clearflags; // also echo to debugging console @@ -957,19 +1029,26 @@ void Con_PrintFlags(const char *txt, unsigned int setflags, unsigned int clearfl Con_Log (txt); if (con_initialized) - Con_PrintCon(&con_main, txt, setflags); + Con_PrintCon(c, txt, setflags); } void Con_CycleConsole(void) { + console_t *first = con_current?con_current:con_head; while(1) { con_current = con_current->next; if (!con_current) - con_current = &con_main; + con_current = con_head; + if (con_current == first) + { + if (con_current->flags & (CONF_HIDDEN|CONF_ISWINDOW)) + con_current = NULL; //no valid consoles + break; //we wrapped? oh noes + } if (con_current->flags & (CONF_HIDDEN|CONF_ISWINDOW)) - continue; + continue; //this is a valid choice break; } } @@ -1098,8 +1177,9 @@ static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b) Con_Log(data); if (developer.ival >= (int)a) { + console_t *c = Con_GetMain(); Sys_Printf ("%s", (const char*)data); // also echo to debugging console - Con_PrintCon(&con_main, data, con_main.parseflags); + Con_PrintCon(c, data, c->parseflags); } BZ_Free(data); } @@ -1140,9 +1220,9 @@ void VARGS Con_DPrintf (const char *fmt, ...) Con_Log(msg); if (developer.ival) { + console_t *c = Con_GetMain(); Sys_Printf ("%s", msg); // also echo to debugging console - if (con_initialized) - Con_PrintCon(&con_main, msg, con_main.parseflags); + Con_PrintCon(c, msg, c->parseflags); } } void VARGS Con_DLPrintf (int level, const char *fmt, ...) @@ -1177,7 +1257,10 @@ void VARGS Con_DLPrintf (int level, const char *fmt, ...) { Sys_Printf ("%s", msg); // also echo to debugging console if (con_initialized) - Con_PrintCon(&con_main, msg, con_main.parseflags); + { + console_t *c = Con_GetMain(); + Con_PrintCon(c, msg, c->parseflags); + } } } @@ -1607,7 +1690,7 @@ void Con_ClearNotify(void) { console_t *con; conline_t *l; - for (con = &con_main; con; con = con->next) + for (con = con_head; con; con = con->next) { for (l = con->current; l; l = l->older) l->flags |= CONL_NONOTIFY; @@ -1618,13 +1701,15 @@ void Con_DrawNotify (void) extern int startuppending; console_t *con; - con_main.flags |= CONF_NOTIFY; - /*keep the main console up to date*/ - con_main.notif_l = con_numnotifylines.ival; - con_main.notif_w = con_notify_w.value; - con_main.notif_x = con_notify_x.value; - con_main.notif_y = con_notify_y.value; - con_main.notif_t = con_notifytime.value; + if (con_main) + { + /*keep the main console up to date*/ + con_main->notif_l = con_numnotifylines.ival; + con_main->notif_w = con_notify_w.value; + con_main->notif_x = con_notify_x.value; + con_main->notif_y = con_notify_y.value; + con_main->notif_t = con_notifytime.value; + } if (con_chat) { @@ -1643,7 +1728,7 @@ void Con_DrawNotify (void) } else { - for (con = &con_main; con; con = con->next) + for (con = con_head; con; con = con->next) { if (con->flags & CONF_NOTIFY) Con_DrawNotifyOne(con); @@ -1660,7 +1745,7 @@ void Con_DrawNotify (void) char *foo = va(chat_team?"say_team: %s":"say: %s", chat_buffer?(char*)chat_buffer:""); int lines, i, pos; Font_BeginString(font_console, 0, 0, &x, &y); - y = con_main.notif_l * Font_CharHeight(); + y = con_numnotifylines.ival * Font_CharHeight(); i = chat_team?10:5; pos = strlen(foo)+i; @@ -1697,12 +1782,15 @@ void Con_DrawNotify (void) //This is so that system consoles in windows can scroll up and have all the text. void Con_PrintToSys(void) { - console_t *curcon = &con_main; + console_t *curcon = con_main; conline_t *l; int i; conchar_t *t; char buf[16]; + if (!curcon) + return; + for (l = curcon->oldest; l; l = l->newer) { t = (conchar_t*)(l+1); @@ -1896,23 +1984,23 @@ int Con_DrawAlternateConsoles(int lines) char *txt; int x, y = 0, lx; int consshown = 0; - console_t *con = &con_main, *om = con_mouseover; + console_t *con, *om = con_mouseover; conchar_t buffer[512], *end, *start; unsigned int codeflags, codepoint; - for (con = &con_main; con; con = con->next) + for (con = con_head; con; con = con->next) { if (!(con->flags & (CONF_HIDDEN|CONF_ISWINDOW))) consshown++; } - if (lines == (int)scr_conlines && consshown > 1) + if (lines == (int)scr_con_target && consshown > 1) { int mx, my, h; Font_BeginString(font_console, mousecursor_x, mousecursor_y, &mx, &my); Font_BeginString(font_console, 0, y, &x, &y); h = Font_CharHeight(); - for (x = 0, con = &con_main; con; con = con->next) + for (x = 0, con = con_head; con; con = con->next) { if (con->flags & (CONF_HIDDEN|CONF_ISWINDOW)) continue; @@ -2386,10 +2474,13 @@ void Con_DrawConsole (int lines, qboolean noback) console_t *w, *mouseconsole; float fadetime; + if (!con_current) + con_current = Con_GetMain(); + con_mouseover = NULL; //draw any windowed consoles (under main console) - for (w = &con_main; w; w = w->next) + for (w = con_head; w; w = w->next) { srect_t srect; if ((w->flags & (CONF_HIDDEN|CONF_ISWINDOW)) != CONF_ISWINDOW) @@ -2576,7 +2667,7 @@ void Con_DrawConsole (int lines, qboolean noback) } //draw main console... - if (lines > 0 && !(con_current->flags & CONF_ISWINDOW)) + if (lines > 0 && con_current && !(con_current->flags & CONF_ISWINDOW)) { int top; #ifdef QTERM diff --git a/engine/client/image.c b/engine/client/image.c index 40e90530c..1bc8576b5 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -29,14 +29,18 @@ char *r_defaultimageextensions = #if defined(AVAIL_PNGLIB) || defined(FTE_TARGET_WEB) " png" //pngs, fairly common, but slow #endif +#ifdef IMAGEFMT_BMP //" bmp" //wtf? at least not lossy + //" ico" //noone wants this... +#endif #if defined(AVAIL_JPEGLIB) || defined(FTE_TARGET_WEB) " jpg" //q3 uses some jpegs, for some reason + //" jpeg" //thankfuly the quake community stuck to .jpg instead #endif -#if 0//def IMAGEFMT_PKM - " pkm" //compressed format, but lacks mipmaps which makes it terrible to use. +#ifdef IMAGEFMT_PKM + //" pkm" //compressed format, but lacks mipmaps which makes it terrible to use. #endif -#ifndef NOLEGACY +#ifdef IMAGEFMT_PCX " pcx" //pcxes are the original gamedata of q2. So we don't want them to override pngs. #endif ; @@ -44,6 +48,7 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla static void QDECL R_ImageExtensions_Callback(struct cvar_s *var, char *oldvalue); cvar_t r_imageexensions = CVARCD("r_imageexensions", NULL, R_ImageExtensions_Callback, "The list of image file extensions which fte should attempt to load."); cvar_t r_image_downloadsizelimit = CVARFD("r_image_downloadsizelimit", "131072", CVAR_NOTFROMSERVER, "The maximum allowed file size of images loaded from a web-based url. 0 disables completely, while empty imposes no limit."); +extern cvar_t scr_sshot_compression; extern cvar_t gl_lerpimages; extern cvar_t gl_picmip2d; extern cvar_t gl_picmip; @@ -59,6 +64,45 @@ extern cvar_t r_shadow_heightscale_bumpmap; static bucket_t *imagetablebuckets[256]; static hashtable_t imagetable; static image_t *imagelist; + + + + + +static void GenerateXMPData(char *blob, size_t blobsize, int width, int height, unsigned int metainfo) +{ //XMP is a general thing that applies to multiple formats - or at least png+jpeg. + //we need this if we want to correctly flag the data as a 360 image. + Q_snprintfz(blob, blobsize, + "" + "" + ); + + if (metainfo) + Q_snprintfz(blob, blobsize, + "" + "equirectangular" + "%f" + "%f" + "%f" + "%f" + "%f" + "%f" + "0" + "0" + "%i" + "%i" + "%i" + "%i" + "", + r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], + r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], + width, height, width, height); + + Q_snprintfz(blob+strlen(blob), blobsize-strlen(blob), + "" + "" + ); +} #endif #ifndef _WIN32 @@ -69,9 +113,11 @@ typedef struct { //cm = colourmap char id_len; //0 char cm_type; //1 char version; //2 + char pad1; short cm_idx; //3 short cm_len; //5 char cm_size; //7 + char pad2; short originx; //8 (ignored) short originy; //10 (ignored) short width; //12-13 @@ -723,6 +769,104 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_ return NULL; } +qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_restrict rgb_buffer, int bytestride, int width, int height, enum uploadfmt fmt) +{ + size_t c, i; + vfsfile_t *vfs; + if (fmt != TF_BGRA32 && fmt != TF_RGB24 && fmt != TF_RGBA32 && fmt != TF_BGR24 && fmt != TF_RGBX32 && fmt != TF_BGRX32) + return false; + FS_CreatePath(filename, fsroot); + vfs = FS_OpenVFS(filename, "wb", fsroot); + if (vfs) + { + int ipx,opx; + qboolean rgb; + unsigned char header[18]; + memset (header, 0, 18); + + if (fmt == TF_BGRA32 || fmt == TF_RGBA32) + { + rgb = fmt==TF_RGBA32; + ipx = 4; + opx = 4; + } + else if (fmt == TF_RGBX32 || fmt == TF_BGRX32) + { + rgb = fmt==TF_RGBX32; + ipx = 4; + opx = 3; + } + else + { + rgb = fmt==TF_RGB24; + ipx = 3; + opx = 3; + } + + header[2] = 2; // uncompressed type + header[12] = width&255; + header[13] = width>>8; + header[14] = height&255; + header[15] = height>>8; + header[16] = opx*8; // pixel size + header[17] = 0x00; // flags + + if (bytestride < 0) + { //if we're upside down, lets just use an upside down tga. + rgb_buffer += bytestride*(height-1); + bytestride = -bytestride; + //now we can just do everything without worrying about rows + } + else //our data is top-down, set up the header to also be top-down. + header[17] = 0x20; + + if (ipx == opx && !rgb) + { //can just directly write it + //bgr24, bgra24 + c = width*height*opx; + + VFS_WRITE(vfs, header, sizeof(header)); + VFS_WRITE(vfs, rgb_buffer, c); + } + else + { + qbyte *fte_restrict rgb_out = malloc(width*opx*height); + + //no need to swap alpha, and if we're just swapping alpha will be fine in-place. + if (rgb) + { //rgb24, rgbx32, rgba32 + // compact, and swap + c = width*height; + for (i=0 ; i= 10400 -void (PNGAPI *qpng_set_expand_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PSTATIC(png_set_expand_gray_1_2_4_to_8); +static void (PNGAPI *qpng_set_expand_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PSTATIC(png_set_expand_gray_1_2_4_to_8); #else -void (PNGAPI *qpng_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PSTATIC(png_set_gray_1_2_4_to_8); +static void (PNGAPI *qpng_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PSTATIC(png_set_gray_1_2_4_to_8); #endif -void (PNGAPI *qpng_set_bgr) PNGARG((png_structp png_ptr)) PSTATIC(png_set_bgr); -void (PNGAPI *qpng_set_filler) PNGARG((png_structp png_ptr, png_uint_32 filler, int flags)) PSTATIC(png_set_filler); -void (PNGAPI *qpng_set_palette_to_rgb) PNGARG((png_structp png_ptr)) PSTATIC(png_set_palette_to_rgb); -png_uint_32 (PNGAPI *qpng_get_IHDR) PNGARG((png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, +static void (PNGAPI *qpng_set_bgr) PNGARG((png_structp png_ptr)) PSTATIC(png_set_bgr); +static void (PNGAPI *qpng_set_filler) PNGARG((png_structp png_ptr, png_uint_32 filler, int flags)) PSTATIC(png_set_filler); +static void (PNGAPI *qpng_set_palette_to_rgb) PNGARG((png_structp png_ptr)) PSTATIC(png_set_palette_to_rgb); +static png_uint_32 (PNGAPI *qpng_get_IHDR) PNGARG((png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_method, int *compression_method, int *filter_method)) PSTATIC(png_get_IHDR); -void (PNGAPI *qpng_read_info) PNGARG((png_structp png_ptr, png_infop info_ptr)) PSTATIC(png_read_info); -void (PNGAPI *qpng_set_sig_bytes) PNGARG((png_structp png_ptr, int num_bytes)) PSTATIC(png_set_sig_bytes); -void (PNGAPI *qpng_set_read_fn) PNGARG((png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn)) PSTATIC(png_set_read_fn); -void (PNGAPI *qpng_destroy_read_struct) PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)) PSTATIC(png_destroy_read_struct); -png_infop (PNGAPI *qpng_create_info_struct) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_create_info_struct); -png_structp (PNGAPI *qpng_create_read_struct) PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)) PSTATIC(png_create_read_struct); -int (PNGAPI *qpng_sig_cmp) PNGARG((png_const_bytep sig, png_size_t start, png_size_t num_to_check)) PSTATIC(png_sig_cmp); +static void (PNGAPI *qpng_read_info) PNGARG((png_structp png_ptr, png_infop info_ptr)) PSTATIC(png_read_info); +static void (PNGAPI *qpng_set_sig_bytes) PNGARG((png_structp png_ptr, int num_bytes)) PSTATIC(png_set_sig_bytes); +static void (PNGAPI *qpng_set_read_fn) PNGARG((png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn)) PSTATIC(png_set_read_fn); +static void (PNGAPI *qpng_destroy_read_struct) PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)) PSTATIC(png_destroy_read_struct); +static png_infop (PNGAPI *qpng_create_info_struct) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_create_info_struct); +static png_structp (PNGAPI *qpng_create_read_struct) PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)) PSTATIC(png_create_read_struct); +static int (PNGAPI *qpng_sig_cmp) PNGARG((png_const_bytep sig, png_size_t start, png_size_t num_to_check)) PSTATIC(png_sig_cmp); -void (PNGAPI *qpng_write_end) PNGARG((png_structrp png_ptr, png_inforp info_ptr)) PSTATIC(png_write_end); -void (PNGAPI *qpng_write_image) PNGARG((png_structrp png_ptr, png_bytepp image)) PSTATIC(png_write_image); -void (PNGAPI *qpng_write_info) PNGARG((png_structrp png_ptr, png_const_inforp info_ptr)) PSTATIC(png_write_info); -void (PNGAPI *qpng_set_IHDR) PNGARG((png_const_structrp png_ptr, png_infop info_ptr, png_uint_32 width, png_uint_32 height, +static void (PNGAPI *qpng_write_end) PNGARG((png_structrp png_ptr, png_inforp info_ptr)) PSTATIC(png_write_end); +static void (PNGAPI *qpng_write_image) PNGARG((png_structrp png_ptr, png_bytepp image)) PSTATIC(png_write_image); +static void (PNGAPI *qpng_write_info) PNGARG((png_structrp png_ptr, png_const_inforp info_ptr)) PSTATIC(png_write_info); +#ifdef PNG_TEXT_SUPPORTED +static void (PNGAPI *qpng_set_text) PNGARG((png_const_structrp png_ptr, png_infop info_ptr, png_const_textp text_ptr, int num_text)) PSTATIC(png_set_text); +#endif +static void (PNGAPI *qpng_set_IHDR) PNGARG((png_const_structrp png_ptr, png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_method, int compression_method, int filter_method)) PSTATIC(png_set_IHDR); -void (PNGAPI *qpng_set_compression_level) PNGARG((png_structrp png_ptr, int level)) PSTATIC(png_set_compression_level); -void (PNGAPI *qpng_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)) PSTATIC(png_init_io); -png_voidp (PNGAPI *qpng_get_io_ptr) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_get_io_ptr); -void (PNGAPI *qpng_destroy_write_struct) PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)) PSTATIC(png_destroy_write_struct); -png_structp (PNGAPI *qpng_create_write_struct) PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)) PSTATIC(png_create_write_struct); -void (PNGAPI *qpng_set_unknown_chunks) PNGARG((png_const_structrp png_ptr, png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)) PSTATIC(png_set_unknown_chunks); +static void (PNGAPI *qpng_set_compression_level) PNGARG((png_structrp png_ptr, int level)) PSTATIC(png_set_compression_level); +static void (PNGAPI *qpng_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)) PSTATIC(png_init_io); +static png_voidp (PNGAPI *qpng_get_io_ptr) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_get_io_ptr); +static void (PNGAPI *qpng_destroy_write_struct) PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)) PSTATIC(png_destroy_write_struct); +static png_structp (PNGAPI *qpng_create_write_struct) PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn)) PSTATIC(png_create_write_struct); +static void (PNGAPI *qpng_set_unknown_chunks) PNGARG((png_const_structrp png_ptr, png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)) PSTATIC(png_set_unknown_chunks); -png_voidp (PNGAPI *qpng_get_error_ptr) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_get_error_ptr); +static png_voidp (PNGAPI *qpng_get_error_ptr) PNGARG((png_const_structrp png_ptr)) PSTATIC(png_get_error_ptr); qboolean LibPNG_Init(void) { @@ -858,6 +1005,9 @@ qboolean LibPNG_Init(void) {(void **) &qpng_create_read_struct, "png_create_read_struct"}, {(void **) &qpng_sig_cmp, "png_sig_cmp"}, +#ifdef PNG_TEXT_SUPPORTED + {(void **) &qpng_set_text, "png_set_text"}, +#endif {(void **) &qpng_write_end, "png_write_end"}, {(void **) &qpng_write_image, "png_write_image"}, {(void **) &qpng_write_info, "png_write_info"}, @@ -1073,7 +1223,7 @@ error: #ifndef NPFTE -int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int bufferstride, int width, int height, enum uploadfmt fmt) +static int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata) { char name[MAX_OSPATH]; int i; @@ -1147,12 +1297,12 @@ err: if (fmt == TF_BGR24 || fmt == TF_BGRA32 || fmt == TF_BGRX32) qpng_set_bgr(png_ptr); - if (fmt == TF_RGBA32 || fmt == TF_BGRA32) + if (fmt == TF_RGBA32 || fmt == TF_BGRA32 || fmt == PTI_LLLA8) { pxsize = 4; qpng_set_IHDR(png_ptr, info_ptr, outwidth, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } - else if (fmt == TF_RGBX32 || fmt == TF_BGRX32) + else if (fmt == TF_RGBX32 || fmt == TF_BGRX32 || fmt == PTI_LLLX8) { pxsize = 4; qpng_set_IHDR(png_ptr, info_ptr, outwidth, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); @@ -1163,6 +1313,18 @@ err: qpng_set_IHDR(png_ptr, info_ptr, outwidth, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } +#ifdef PNG_TEXT_SUPPORTED + if (writemetadata) + { + char blob[8192]; + png_text pngtext = {PNG_ITXT_COMPRESSION_NONE, "XML:com.adobe.xmp"}; + pngtext.text = blob; + GenerateXMPData(blob, sizeof(blob), width, height, writemetadata); + pngtext.itxt_length = strlen(pngtext.text); + qpng_set_text(png_ptr, info_ptr, &pngtext, 1); + } +#endif + if (numbuffers == 2) //flag it as a standard stereographic image qpng_set_unknown_chunks(png_ptr, info_ptr, &unknowns, 1); @@ -1179,6 +1341,7 @@ err: goto err; pixels = (qbyte*)row_pointers + height; //png requires right then left, which is a bit weird. + //they're meant to be viewable by going cross-eyed (if needed) right = pixels; left = right + (outwidth-width)*pxsize; @@ -1275,23 +1438,24 @@ err: (size_t) sizeof(struct jpeg_decompress_struct)) #ifdef DYNAMIC_LIBJPEG -boolean (VARGS *qjpeg_resync_to_restart) JPP((j_decompress_ptr cinfo, int desired)) JSTATIC(jpeg_resync_to_restart); -boolean (VARGS *qjpeg_finish_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_finish_decompress); -JDIMENSION (VARGS *qjpeg_read_scanlines) JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)) JSTATIC(jpeg_read_scanlines); -boolean (VARGS *qjpeg_start_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_start_decompress); -int (VARGS *qjpeg_read_header) JPP((j_decompress_ptr cinfo, boolean require_image)) JSTATIC(jpeg_read_header); -void (VARGS *qjpeg_CreateDecompress) JPP((j_decompress_ptr cinfo, int version, size_t structsize)) JSTATIC(jpeg_CreateDecompress); -void (VARGS *qjpeg_destroy_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_destroy_decompress); +static boolean (VARGS *qjpeg_resync_to_restart) JPP((j_decompress_ptr cinfo, int desired)) JSTATIC(jpeg_resync_to_restart); +static boolean (VARGS *qjpeg_finish_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_finish_decompress); +static JDIMENSION (VARGS *qjpeg_read_scanlines) JPP((j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines)) JSTATIC(jpeg_read_scanlines); +static boolean (VARGS *qjpeg_start_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_start_decompress); +static int (VARGS *qjpeg_read_header) JPP((j_decompress_ptr cinfo, boolean require_image)) JSTATIC(jpeg_read_header); +static void (VARGS *qjpeg_CreateDecompress) JPP((j_decompress_ptr cinfo, int version, size_t structsize)) JSTATIC(jpeg_CreateDecompress); +static void (VARGS *qjpeg_destroy_decompress) JPP((j_decompress_ptr cinfo)) JSTATIC(jpeg_destroy_decompress); -struct jpeg_error_mgr * (VARGS *qjpeg_std_error) JPP((struct jpeg_error_mgr * err)) JSTATIC(jpeg_std_error); +static struct jpeg_error_mgr * (VARGS *qjpeg_std_error) JPP((struct jpeg_error_mgr * err)) JSTATIC(jpeg_std_error); -void (VARGS *qjpeg_finish_compress) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_finish_compress); -JDIMENSION (VARGS *qjpeg_write_scanlines) JPP((j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)) JSTATIC(jpeg_write_scanlines); -void (VARGS *qjpeg_start_compress) JPP((j_compress_ptr cinfo, boolean write_all_tables)) JSTATIC(jpeg_start_compress); -void (VARGS *qjpeg_set_quality) JPP((j_compress_ptr cinfo, int quality, boolean force_baseline)) JSTATIC(jpeg_set_quality); -void (VARGS *qjpeg_set_defaults) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_set_defaults); -void (VARGS *qjpeg_CreateCompress) JPP((j_compress_ptr cinfo, int version, size_t structsize)) JSTATIC(jpeg_CreateCompress); -void (VARGS *qjpeg_destroy_compress) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_destroy_compress); +static void (VARGS *qjpeg_finish_compress) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_finish_compress); +static JDIMENSION (VARGS *qjpeg_write_scanlines) JPP((j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines)) JSTATIC(jpeg_write_scanlines); +static void (VARGS *qjpeg_write_marker) JPP((j_compress_ptr cinfo, int marker, const JOCTET *dataptr, unsigned int datalen))JSTATIC(jpeg_write_marker); +static void (VARGS *qjpeg_start_compress) JPP((j_compress_ptr cinfo, boolean write_all_tables)) JSTATIC(jpeg_start_compress); +static void (VARGS *qjpeg_set_quality) JPP((j_compress_ptr cinfo, int quality, boolean force_baseline)) JSTATIC(jpeg_set_quality); +static void (VARGS *qjpeg_set_defaults) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_set_defaults); +static void (VARGS *qjpeg_CreateCompress) JPP((j_compress_ptr cinfo, int version, size_t structsize)) JSTATIC(jpeg_CreateCompress); +static void (VARGS *qjpeg_destroy_compress) JPP((j_compress_ptr cinfo)) JSTATIC(jpeg_destroy_compress); #endif qboolean LibJPEG_Init(void) @@ -1311,6 +1475,7 @@ qboolean LibJPEG_Init(void) {(void **) &qjpeg_finish_compress, "jpeg_finish_compress"}, {(void **) &qjpeg_write_scanlines, "jpeg_write_scanlines"}, + {(void **) &qjpeg_write_marker, "jpeg_write_marker"}, {(void **) &qjpeg_start_compress, "jpeg_start_compress"}, {(void **) &qjpeg_set_quality, "jpeg_set_quality"}, {(void **) &qjpeg_set_defaults, "jpeg_set_defaults"}, @@ -1647,6 +1812,7 @@ badjpeg: #define qjpeg_CreateCompress jpeg_CreateCompress #define qjpeg_set_defaults jpeg_set_defaults #define qjpeg_set_quality jpeg_set_quality +#define qjpeg_write_marker jpeg_write_marker #define qjpeg_start_compress jpeg_start_compress #define qjpeg_write_scanlines jpeg_write_scanlines #define qjpeg_finish_compress jpeg_finish_compress @@ -1694,7 +1860,7 @@ METHODDEF(void) term_destination (j_compress_ptr cinfo) dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } -void ftejpeg_mem_dest (j_compress_ptr cinfo, vfsfile_t *vfs) +static void ftejpeg_mem_dest (j_compress_ptr cinfo, vfsfile_t *vfs) { my_destination_mgr *dest; @@ -1724,7 +1890,7 @@ METHODDEF(void) jpeg_error_exit (j_common_ptr cinfo) { longjmp(((jpeg_error_mgr_wrapper *) cinfo->err)->setjmp_buffer, 1); } -qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int stride, int screenwidth, int screenheight, enum uploadfmt fmt) +static qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int stride, int screenwidth, int screenheight, enum uploadfmt fmt, unsigned int writemeta) { qbyte *buffer; vfsfile_t *outfile; @@ -1828,6 +1994,15 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression qjpeg_set_quality (&cinfo, bound(0, compression, 100), true); qjpeg_start_compress(&cinfo, true); + if (writemeta) + { + static const char header[] = "http://ns.adobe.com/xap/1.0/"; + char blob[8192]; + memcpy(blob, header, sizeof(header)); //MUST include the null terminator. + GenerateXMPData(blob+sizeof(header), sizeof(blob)-sizeof(header), screenwidth, screenheight, writemeta); + qjpeg_write_marker(&cinfo, JPEG_APP0+1, blob, sizeof(header)+strlen(blob+sizeof(header))); + } + while (cinfo.next_scanline < cinfo.image_height) { *row_pointer = &buffer[cinfo.next_scanline * stride]; @@ -1841,7 +2016,7 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression #endif #endif -#ifndef NPFTE +#ifdef IMAGEFMT_PCX /* ============== WritePCXfile @@ -1908,8 +2083,6 @@ void WritePCXfile (const char *filename, enum fs_relative fsroot, qbyte *data, i else COM_WriteFile (filename, fsroot, pcx, length); } -#endif - /* ============ @@ -2114,8 +2287,9 @@ qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out) return out; } +#endif - +#ifdef IMAGEFMT_BMP typedef struct bmpheader_s { unsigned int SizeofBITMAPINFOHEADER; @@ -2186,7 +2360,7 @@ static qbyte *ReadRawBMPFile(qbyte *buf, int length, int *width, int *height, si for (i = 0; i < h.NumofColorIndices; i++) { - pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255/*data[i*4+3]*/<<24); + pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255u/*data[i*4+3]*/<<24); } if (OffsetofBMPBits) @@ -2237,7 +2411,7 @@ static qbyte *ReadRawBMPFile(qbyte *buf, int length, int *width, int *height, si for (i = 0; i < h.NumofColorIndices; i++) { - pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255/*data[i*4+3]*/<<24); + pal[i] = data[i*4+2] + (data[i*4+1]<<8) + (data[i*4+0]<<16) + (255u/*data[i*4+3]*/<<24); } if (OffsetofBMPBits) @@ -2328,7 +2502,7 @@ static qbyte *ReadRawBMPFile(qbyte *buf, int length, int *width, int *height, si return NULL; } -qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height) +static qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height) { unsigned short Type = buf[0] | (buf[1]<<8); unsigned short Size = buf[2] | (buf[3]<<8) | (buf[4]<<16) | (buf[5]<<24); @@ -2532,6 +2706,7 @@ static qbyte *ReadICOFile(qbyte *buf, int length, int *width, int *height, const return NULL; } +#endif #ifndef NPFTE @@ -2745,7 +2920,7 @@ typedef struct unsigned int numberofmipmaplevels; unsigned int bytesofkeyvaluedata; } ktxheader_t; -void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips) +qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips) { vfsfile_t *file; ktxheader_t header = {{0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A}, 0x04030201, @@ -2753,8 +2928,8 @@ void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips) 0/*base*/, mips->mip[0].width, mips->mip[0].height, 0/*depth*/, 0/*array elements*/, (mips->type==PTI_CUBEMAP)?6:1, mips->mipcount, 0/*kvdatasize*/}; size_t mipnum; - if (mips->type != PTI_2D)// && mips->type != PTI_CUBEMAP) - return; + if (mips->type != PTI_2D && mips->type != PTI_CUBEMAP) + return false; header.numberofmipmaplevels /= header.numberoffaces; switch(mips->encoding) @@ -2852,18 +3027,18 @@ void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips) #endif case PTI_EMULATED: case PTI_MAX: - return; + return false; // default: // return; } if (strchr(filename, '*') || strchr(filename, ':')) - return; + return false; - file = FS_OpenVFS(filename, "wb", FS_GAMEONLY); + file = FS_OpenVFS(filename, "wb", fsroot); if (!file) - return; + return false; VFS_WRITE(file, &header, sizeof(header)); for (mipnum = 0; mipnum < mips->mipcount; mipnum++) @@ -2879,6 +3054,7 @@ void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips) } VFS_CLOSE(file); + return true; } static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize) { @@ -2979,7 +3155,8 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch case 0x93DC/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR*/: encoding = PTI_ASTC_12X10_SRGB; break; case 0x93DD/*GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR*/: encoding = PTI_ASTC_12X12_SRGB; break; case 0x80E1/*GL_BGRA_EXT*/: encoding = PTI_BGRA8; break; //not even an internal format - case 0x1908/*GL_RGBA*/: encoding = (header->glformat==0x80E1/*GL_BGRA*/)?PTI_BGRA8:PTI_RGBA8; break; //unsized types shouldn't really be here + case 0x1908/*GL_RGBA*/: + case 0x8058/*GL_RGBA8*/: encoding = (header->glformat==0x80E1/*GL_BGRA*/)?PTI_BGRA8:PTI_RGBA8; break; //unsized types shouldn't really be here case 0x8C43/*GL_SRGB8_ALPHA8*/: encoding = (header->glformat==0x80E1/*GL_BGRA*/)?PTI_BGRA8_SRGB:PTI_RGBA8_SRGB; break; case 0x8040/*GL_LUMINANCE8*/: encoding = PTI_L8; break; case 0x8045/*GL_LUMINANCE8_ALPHA8*/: encoding = PTI_L8A8; break; @@ -3090,6 +3267,10 @@ static struct pendingtextureinfo *Image_ReadKTXFile(unsigned int flags, const ch w = header->pixelwidth; h = header->pixelheight; d = header->pixeldepth; + + //fixme: if (w+blockwidth-1)/blockwidth)*blockbytes MUST be a multiple of 4. + //we need to de-pad it otherwise. + for (mipnum = 0; mipnum < nummips; mipnum++) { datasize = *(int*)filedata; @@ -3334,12 +3515,18 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch // pad = 8; switch(fmt10header.dxgiformat) { + case 2/*DXGI_FORMAT_R32G32B32A32_FLOAT*/: + encoding = PTI_RGBA32F; + break; case 10/*DXGI_FORMAT_R16G16B16A16_FLOAT*/: encoding = PTI_RGBA16F; break; case 24/*DXGI_FORMAT_R10G10B10A2_UNORM*/: encoding = PTI_A2BGR10; break; + case 28/*DXGI_FORMAT_R8G8B8A8_UNORM*/: + encoding = PTI_RGBA8; + break; case 67/*DXGI_FORMAT_R9G9B9E5_SHAREDEXP*/: encoding = PTI_E5BGR9; break; @@ -3379,6 +3566,9 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch case 86/*DXGI_FORMAT_B5G5R5A1_UNORM*/: encoding = PTI_ARGB1555; break; + case 87/*DXGI_FORMAT_B8G8R8A8_UNORM*/: + encoding = PTI_BGRA8; + break; case 95/*DXGI_FORMAT_BC6H_UF16*/: encoding = PTI_BC6_RGB_UFLOAT; break; @@ -3460,6 +3650,213 @@ static struct pendingtextureinfo *Image_ReadDDSFile(unsigned int flags, const ch return mips; } + +qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips) +{ + vfsfile_t *file; + size_t mipnum; + size_t a; + dds10header_t h10={0}; + ddsheader h9={0}; + + unsigned int blockbytes, blockwidth, blockheight; + unsigned int arraysize = (mips->type==PTI_CUBEMAP||mips->type==PTI_CUBEMAP_ARRAY)?6:1; + + Image_BlockSizeForEncoding(mips->encoding, &blockbytes, &blockwidth, &blockheight); + + h9.dwSize = sizeof(h9); + h9.dwFlags = 0; + h9.dwFlags |= 1; //CAPS + h9.dwFlags |= 2; //HEIGHT + h9.dwFlags |= 4; //WIDTH + h9.dwFlags |= 0x1000; //PIXELFORMAT + if (blockwidth != 1 || blockheight != 1) + { + h9.dwFlags |= 0x80000; //LINEARSIZE + h9.dwPitchOrLinearSize = ((mips->mip[0].width+blockwidth-1)/blockwidth)*((mips->mip[0].height+blockheight-1)/blockheight)*blockbytes; + } + else + { + h9.dwFlags |= 8; //PITCH + h9.dwPitchOrLinearSize = mips->mip[0].width*blockbytes; + } + if (mips->mipcount > 1) + h9.dwFlags |= 0x20000; //MIPMAPCOUNT + h9.dwHeight = mips->mip[0].height; + h9.dwWidth = mips->mip[0].width; + h9.dwDepth = 0; + h9.dwMipMapCount = mips->mipcount/arraysize; + h9.ddpfPixelFormat.dwSize = 32; + h9.ddpfPixelFormat.dwFlags = 4/*DDPF_FOURCC*/; + h9.ddpfPixelFormat.dwFourCC = ('D'<<0)|('X'<<8)|('1'<<16)|('0'<<24); + h9.ddsCaps[0] = 0x1000; //TEXTURE + if (mips->mipcount > 1) + h9.ddsCaps[0] |= 0x8; //COMPLEX + if (mips->mipcount > arraysize) + h9.ddsCaps[0] |= 0x400000; //MIPMAP + h9.ddsCaps[1] = 0; + h10.miscflag = 0; + h10.arraysize = arraysize; + h10.miscflags2 = 0; + + switch(mips->type) + { + case PTI_3D: + h9.ddsCaps[1] |= 0x200000; //VOLUME + h10.resourcetype = 4; //3d + break; + case PTI_CUBEMAP: + case PTI_CUBEMAP_ARRAY: + h9.ddsCaps[1] |= 0x200|0xfc00; //CUBEMAP+faces + h10.resourcetype = 3; //2d + h10.miscflag = 4;//DDS_RESOURCE_MISC_TEXTURECUBE - otherwise they're basicaly just 2d_arrays + break; + case PTI_2D: + case PTI_2D_ARRAY: + h10.resourcetype = 3; //2d + break; + } + + h10.dxgiformat = 0; + + switch(mips->encoding) + { + case PTI_ETC1_RGB8: + case PTI_ETC2_RGB8: + case PTI_ETC2_RGB8_SRGB: + case PTI_ETC2_RGB8A1: + case PTI_ETC2_RGB8A1_SRGB: + case PTI_ETC2_RGB8A8: + case PTI_ETC2_RGB8A8_SRGB: + case PTI_EAC_R11: + case PTI_EAC_R11_SNORM: + case PTI_EAC_RG11: + case PTI_EAC_RG11_SNORM: + case PTI_ASTC_4X4: + case PTI_ASTC_5X4: + case PTI_ASTC_5X5: + case PTI_ASTC_6X5: + case PTI_ASTC_6X6: + case PTI_ASTC_8X5: + case PTI_ASTC_8X6: + case PTI_ASTC_10X5: + case PTI_ASTC_10X6: + case PTI_ASTC_8X8: + case PTI_ASTC_10X8: + case PTI_ASTC_10X10: + case PTI_ASTC_12X10: + case PTI_ASTC_12X12: + case PTI_ASTC_4X4_SRGB: + case PTI_ASTC_5X4_SRGB: + case PTI_ASTC_5X5_SRGB: + case PTI_ASTC_6X5_SRGB: + case PTI_ASTC_6X6_SRGB: + case PTI_ASTC_8X5_SRGB: + case PTI_ASTC_8X6_SRGB: + case PTI_ASTC_10X5_SRGB: + case PTI_ASTC_10X6_SRGB: + case PTI_ASTC_8X8_SRGB: + case PTI_ASTC_10X8_SRGB: + case PTI_ASTC_10X10_SRGB: + case PTI_ASTC_12X10_SRGB: + case PTI_ASTC_12X12_SRGB: return false; //unsupported + case PTI_BC1_RGB: + case PTI_BC1_RGBA: h10.dxgiformat = 71/*DXGI_FORMAT_BC1_UNORM*/; break; + case PTI_BC1_RGB_SRGB: + case PTI_BC1_RGBA_SRGB: h10.dxgiformat = 72/*DXGI_FORMAT_BC1_UNORM_SRGB*/; break; + case PTI_BC2_RGBA: h10.dxgiformat = 74/*DXGI_FORMAT_BC2_UNORM*/; break; + case PTI_BC2_RGBA_SRGB: h10.dxgiformat = 75/*DXGI_FORMAT_BC2_UNORM_SRGB*/; break; + case PTI_BC3_RGBA: h10.dxgiformat = 77/*DXGI_FORMAT_BC3_UNORM*/; break; + case PTI_BC3_RGBA_SRGB: h10.dxgiformat = 78/*DXGI_FORMAT_BC3_UNORM_SRGB*/; break; + case PTI_BC4_R8_SNORM: h10.dxgiformat = 81/*DXGI_FORMAT_BC4_SNORM*/; break; + case PTI_BC4_R8: h10.dxgiformat = 80/*DXGI_FORMAT_BC4_UNORM*/; break; + case PTI_BC5_RG8_SNORM: h10.dxgiformat = 84/*DXGI_FORMAT_BC5_SNORM*/; break; + case PTI_BC5_RG8: h10.dxgiformat = 83/*DXGI_FORMAT_BC5_UNORM*/; break; + case PTI_BC6_RGB_UFLOAT: h10.dxgiformat = 95/*DXGI_FORMAT_BC6H_UF16*/; break; + case PTI_BC6_RGB_SFLOAT: h10.dxgiformat = 96/*DXGI_FORMAT_BC6H_SF16*/; break; + case PTI_BC7_RGBA: h10.dxgiformat = 98/*DXGI_FORMAT_BC7_UNORM*/; break; + case PTI_BC7_RGBA_SRGB: h10.dxgiformat = 99/*DXGI_FORMAT_BC7_UNORM_SRGB*/; break; + + case PTI_BGRA8: h10.dxgiformat = 87/*DXGI_FORMAT_B8G8R8A8_UNORM*/; break; + case PTI_RGBA8: h10.dxgiformat = 28/*DXGI_FORMAT_R8G8B8A8_UNORM*/; break; + case PTI_BGRA8_SRGB: h10.dxgiformat = 91/*DXGI_FORMAT_B8G8R8A8_UNORM_SRGB*/; break; + case PTI_RGBA8_SRGB: h10.dxgiformat = 29/*DXGI_FORMAT_R8G8B8A8_UNORM_SRGB*/; break; + case PTI_L8: return false; //unsupported + case PTI_L8A8: return false; //unsupported + case PTI_L8_SRGB: return false; //unsupported + case PTI_L8A8_SRGB: return false; //unsupported + case PTI_RGB8: return false; //unsupported + case PTI_BGR8: return false; //unsupported + case PTI_RGBA16F: h10.dxgiformat = 10/*DXGI_FORMAT_R16G16B16A16_FLOAT*/; break; + case PTI_RGBA32F: h10.dxgiformat = 2/*DXGI_FORMAT_R32G32B32A32_FLOAT*/; break; + case PTI_A2BGR10: h10.dxgiformat = 24/*DXGI_FORMAT_R10G10B10A2_UNORM*/; break; + case PTI_E5BGR9: h10.dxgiformat = 67/*DXGI_FORMAT_R9G9B9E5_SHAREDEXP*/; break; + case PTI_R8: h10.dxgiformat = 61/*DXGI_FORMAT_R8_UNORM*/; break; + case PTI_RG8: h10.dxgiformat = 49/*DXGI_FORMAT_R8G8_UNORM*/; break; + case PTI_R8_SNORM: h10.dxgiformat = 63/*DXGI_FORMAT_R8_SNORM*/; break; + case PTI_RG8_SNORM: h10.dxgiformat = 51/*DXGI_FORMAT_R8G8_SNORM*/; break; + case PTI_BGRX8: h10.dxgiformat = 88/*DXGI_FORMAT_B8G8R8X8_UNORM*/; break; + case PTI_RGBX8: return false; //unsupported + case PTI_BGRX8_SRGB: h10.dxgiformat = 93/*DXGI_FORMAT_B8G8R8X8_UNORM_SRGB*/; break; + case PTI_RGBX8_SRGB: return false; //unsupported + case PTI_RGB565: h10.dxgiformat = 85/*DXGI_FORMAT_B5G6R5_UNORM*/; break; + case PTI_RGBA4444: return false; //unsupported + case PTI_ARGB4444: h10.dxgiformat = 115/*DXGI_FORMAT_B4G4R4A4_UNORM*/; break; + case PTI_RGBA5551: return false; //unsupported + case PTI_ARGB1555: h10.dxgiformat = 86/*DXGI_FORMAT_B5G5R5A1_UNORM*/; break; + case PTI_DEPTH16: h10.dxgiformat = 55/*DXGI_FORMAT_D16_UNORM*/; break; + case PTI_DEPTH24: return false; //unsupported + case PTI_DEPTH32: h10.dxgiformat = 40/*DXGI_FORMAT_D32_FLOAT*/; break; + case PTI_DEPTH24_8: h10.dxgiformat = 45/*DXGI_FORMAT_D24_UNORM_S8_UINT*/; break; + +#ifdef FTE_TARGET_WEB + case PTI_WHOLEFILE: +#endif + case PTI_EMULATED: + case PTI_MAX: + return false; + +// default: +// return; + } + + //truncate the mip chain if they're dodgy sizes. + for (mipnum = 1; mipnum < h9.dwMipMapCount; mipnum++) + { + size_t m = mipnum*arraysize; + size_t p = (mipnum-1)*arraysize; + if (mips->mip[m].width != max(1,(mips->mip[p].width)>>1) || + mips->mip[m].height != max(1,(mips->mip[p].height)>>1)) + { + h9.dwMipMapCount = mipnum; + break; + } + } + + if (strchr(filename, '*') || strchr(filename, ':')) + return false; + + file = FS_OpenVFS(filename, "wb", FS_GAMEONLY); + if (!file) + return false; + VFS_WRITE(file, "DDS ", 4); + VFS_WRITE(file, &h9, sizeof(h9)); + VFS_WRITE(file, &h10, sizeof(h10)); + + //our internal state uses a0m0, a1m0, a0m1, a1m1 + //DDS requires a0m0, a0m1, a1m0, a1m1, so reorder with two nested loops + for (a = 0; a < arraysize; a++) + { + for (mipnum = 0; mipnum < h9.dwMipMapCount; mipnum++) + { + size_t m = a + mipnum*arraysize; + VFS_WRITE(file, mips->mip[m].data, mips->mip[m].datasize); + } + } + + VFS_CLOSE(file); + return true; +} #endif #ifdef IMAGEFMT_BLP @@ -3659,13 +4056,16 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_ return data; } #endif +#ifdef IMAGEFMT_PCX if ((data = ReadPCXFile(buf, len, width, height))) { *format = PTI_RGBA8; TRACE(("dbg: Read32BitImageFile: pcx\n")); return data; } +#endif +#ifdef IMAGEFMT_BMP if (len > 2 && (buf[0] == 'B' && buf[1] == 'M') && (data = ReadBMPFile(buf, len, width, height))) { *format = PTI_RGBA8; @@ -3679,14 +4079,16 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_ TRACE(("dbg: Read32BitImageFile: ico\n")); return data; } +#endif +#if 1//def IMAGEFMT_LMP if (len >= 8) //.lmp has no magic id. guess at it. { int w = LittleLong(((int*)buf)[0]); int h = LittleLong(((int*)buf)[1]); int i; - if (w >= 3 && h >= 4 && w*h+sizeof(int)*2 == len) - { + if (w >= 3 && h >= 4 && w*h+sizeof(int)*2 == len) + { //quake lmp qboolean foundalpha = false; qbyte *in = (qbyte*)((int*)buf+2); data = BZ_Malloc(w * h * sizeof(int)); @@ -3702,7 +4104,7 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_ return data; } else if (w >= 3 && h >= 4 && w*h+sizeof(int)*2+768+2 == len) - { + { //halflife. should probably verify that those 2 extra bytes read as 256. qboolean foundalpha = false; qbyte *in = (qbyte*)((int*)buf+2); qbyte *palette = in + w*h+2, *p; @@ -3723,6 +4125,7 @@ qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_ return data; } } +#endif TRACE(("dbg: Read32BitImageFile: life sucks\n")); @@ -3786,7 +4189,7 @@ static void *R_FlipImage32(void *in, int *inoutwidth, int *inoutheight, qboolean return out; } -int tex_extensions_count; +static int tex_extensions_count; #define tex_extensions_max 15 static struct { @@ -3815,20 +4218,20 @@ static void QDECL R_ImageExtensions_Callback(struct cvar_s *var, char *oldvalue) static struct { - int args; char *path; + int args; int enabled; } tex_path[] = { /*if three args, first is the subpath*/ /*the last two args are texturename then extension*/ - {2, "%s%s", 1}, /*directly named texture*/ - {3, "textures/%s/%s%s", 1}, /*fuhquake compatibility*/ - {3, "%s/%s%s", 1}, /*fuhquake compatibility*/ - {2, "textures/%s%s", 1}, /*directly named texture with textures/ prefix*/ + {"%s%s", 2, 1}, /*directly named texture*/ + {"textures/%s/%s%s",3, 1}, /*fuhquake compatibility*/ + {"%s/%s%s", 3, 1}, /*fuhquake compatibility*/ + {"textures/%s%s", 2, 1}, /*directly named texture with textures/ prefix*/ #ifndef NOLEGACY - {2, "override/%s%s", 1} /*tenebrae compatibility*/ + {"override/%s%s", 2, 1} /*tenebrae compatibility*/ #endif }; @@ -4061,7 +4464,7 @@ static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, lerp = f & 0xFFFF; if (yi != oldy) { - inrow = (qbyte *)indata + inwidth4*yi; + inrow = (const qbyte *)indata + inwidth4*yi; if (yi == oldy+1) memcpy(row1, row2, outwidth4); else @@ -4125,7 +4528,7 @@ static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight, yi = endy; //don't read off the end if (yi != oldy) { - inrow = (qbyte *)indata + inwidth4*yi; + inrow = (const qbyte *)indata + inwidth4*yi; if (yi == oldy+1) memcpy(row1, row2, outwidth4); else @@ -4683,6 +5086,8 @@ static void Image_Decode_ETC2_Block_TH_Internal(qbyte *fte_restrict in, pixel32_ } static void Image_Decode_ETC2_Block_Internal(qbyte *fte_restrict in, pixel32_t *fte_restrict out0, int w, int alphamode) { + //the overflow modes are only valid with ETC2. + //alphamode=1 is used for punchthrough-alpha (which also forces the diff mode) static const char tab[8][2] = { {2,8}, @@ -5412,7 +5817,7 @@ static void Image_DecompressFormat(struct pendingtextureinfo *mips) //iiuc any basic s3tc patents have now expired, so it is legally safe to decode (though fancy compression logic may still have restrictions, but we don't compress). static float throttle; - void *decodefunc = NULL; + void (*decodefunc)(qbyte *fte_restrict, pixel32_t *fte_restrict, int) = NULL; int rcoding = mips->encoding; int mip; switch(mips->encoding) @@ -6818,8 +7223,9 @@ static struct pendingtextureinfo *Image_LoadCubemapTextureData(const char *nicen { static struct { - char *suffix; + const char *suffix; qboolean flipx, flipy, flipd; + int pad; } cmscheme[][6] = { { @@ -6995,6 +7401,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be if (!tex->fallbackdata || (gl_load24bit.ival && !(tex->flags & IF_NOREPLACE))) { +#ifdef IMAGEFMT_DDS Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename); depth = FS_FLocateFile(fname, locflags, &loc); if (depth < bestdepth) @@ -7004,6 +7411,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be *bestloc = loc; bestflags = 0; } +#endif if (strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic i = 0; @@ -7635,6 +8043,7 @@ typedef struct char *name; char *legacyname; int maximize, minmip, minimize; + int pad; } texmode_t; static texmode_t texmodes[] = { {"n", "GL_NEAREST", 0, -1, 0}, @@ -8074,3 +8483,166 @@ void AddOcranaLEDsIndexed (qbyte *image, int h, int w) } } #endif + +/* +Find closest color in the palette for named color +*/ +int MipColor(int r, int g, int b) +{ + int i; + float dist; + int best=15; + float bestdist; + int r1, g1, b1; + static int lr = -1, lg = -1, lb = -1; + static int lastbest; + + if (r == lr && g == lg && b == lb) + return lastbest; + + bestdist = 256*256*3; + + for (i = 0; i < 256; i++) + { + r1 = host_basepal[i*3] - r; + g1 = host_basepal[i*3+1] - g; + b1 = host_basepal[i*3+2] - b; + dist = r1*r1 + g1*g1 + b1*b1; + if (dist < bestdist) { + bestdist = dist; + best = i; + } + } + lr = r; lg = g; lb = b; + lastbest = best; + return best; +} + +qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta) +{ + char ext[8]; + void *nbuffers[2]; + + switch(fmt) + { //nuke any alpha channel... + case TF_RGBA32: fmt = TF_RGBX32; break; + case TF_BGRA32: fmt = TF_BGRX32; break; + default: break; + } + + if (!bytestride) + bytestride = width*4; + if (bytestride < 0) + { //fix up the buffers so callers don't have to. + int nb = numbuffers; + for (numbuffers = 0; numbuffers < nb && numbuffers < countof(nbuffers); numbuffers++) + nbuffers[numbuffers] = (char*)buffer[numbuffers] - bytestride*(height-1); + buffer = nbuffers; + } + + COM_FileExtension(filename, ext, sizeof(ext)); + + #ifdef AVAIL_PNGLIB + if (!Q_strcasecmp(ext, "png") || !Q_strcasecmp(ext, "pns")) + { + //png can do bgr+rgb + //rgba bgra will result in an extra alpha chan + //actual stereo is also supported. huzzah. + return Image_WritePNG(filename, fsroot, scr_sshot_compression.value, buffer, numbuffers, bytestride, width, height, fmt, writemeta); + } + else +#endif +#ifdef AVAIL_JPEGLIB + if (!Q_strcasecmp(ext, "jpeg") || !Q_strcasecmp(ext, "jpg") || !Q_strcasecmp(ext, "jps")) + { + return screenshotJPEG(filename, fsroot, scr_sshot_compression.value, buffer[0], bytestride, width, height, fmt, writemeta); + } + else +#endif +#ifdef IMAGEFMT_BMP + if (!Q_strcasecmp(ext, "bmp")) + { + return WriteBMPFile(filename, fsroot, buffer[0], bytestride, width, height, fmt); + } + else +#endif +#ifdef IMAGEFMT_PCX + if (!Q_strcasecmp(ext, "pcx")) + { + int y, x, s; + qbyte *src, *dest; + qbyte *srcbuf = buffer[0], *dstbuf; + if (fmt == TF_RGB24 || fmt == TF_RGBA32 || fmt == TF_RGBX32) + { + dstbuf = malloc(width*height); + s = (fmt == TF_RGB24)?3:4; + // convert in-place to eight bit + for (y = 0; y < height; y++) + { + src = srcbuf + (bytestride * y); + dest = dstbuf + (width * y); + + for (x = 0; x < width; x++) { + *dest++ = MipColor(src[0], src[1], src[2]); + src += s; + } + } + } + else if (fmt == TF_BGR24 || fmt == TF_BGRA32 || fmt == TF_BGRX32) + { + dstbuf = malloc(width*height); + s = (fmt == TF_BGR24)?3:4; + // convert in-place to eight bit + for (y = 0; y < height; y++) + { + src = srcbuf + (bytestride * y); + dest = dstbuf + (width * y); + + for (x = 0; x < width; x++) { + *dest++ = MipColor(src[2], src[1], src[0]); + src += s; + } + } + } + else + return false; + + WritePCXfile (filename, fsroot, dstbuf, width, height, width, host_basepal, false); + free(dstbuf); + } + else +#endif + if (!Q_strcasecmp(ext, "tga")) //tga + return WriteTGA(filename, fsroot, buffer[0], bytestride, width, height, fmt); +#ifdef IMAGEFMT_KTX + else if (!Q_strcasecmp(ext, "ktx") && bytestride > 0) //ktx + { + struct pendingtextureinfo out = {PTI_2D}; + out.encoding = fmt; + out.mipcount = 1; + out.mip[0].data = buffer[0]; + out.mip[0].datasize = bytestride*height; + out.mip[0].width = width; + out.mip[0].height = height; + out.mip[0].depth = 1; + return Image_WriteKTXFile(filename, fsroot, &out); + } +#endif +#ifdef IMAGEFMT_DDS + else if (!Q_strcasecmp(ext, "dds") && bytestride > 0) //dds + { + struct pendingtextureinfo out = {PTI_2D}; + out.encoding = fmt; + out.mipcount = 1; + out.mip[0].data = buffer[0]; + out.mip[0].datasize = bytestride*height; + out.mip[0].width = width; + out.mip[0].height = height; + out.mip[0].depth = 1; + return Image_WriteDDSFile(filename, fsroot, &out); + } +#endif + else //extension / type not recognised. + return false; + return true; +} \ No newline at end of file diff --git a/engine/client/keys.c b/engine/client/keys.c index e4c6cb024..23056f133 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -1579,16 +1579,16 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) if ((unicode >= '0' && unicode <= '9') || unicode == '.' || key < 0) key = 0; + if (key == K_TAB && !(con->flags & CONF_ISWINDOW) && ctrl&&shift) + { // cycle consoles with ctrl+shift+tab. + // (ctrl+tab forces tab completion, + // shift+tab controls completion cycle, + // so it has to be both.) + Con_CycleConsole(); + return true; + } if (con->redirect) { - if (key == K_TAB) - { // command completion - if (ctrl || shift) - { - Con_CycleConsole(); - return true; - } - } if (key == K_MOUSE1 || key == K_MOUSE2) ; else if (con->redirect(con, unicode, key)) @@ -1614,7 +1614,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) { if (key == K_MOUSE2 && !(con->flags & CONF_ISWINDOW)) { - if (con->close && !con->close(con, true)) + if (con->close && !con->close(con, false)) return true; Con_Destroy (con); } @@ -1843,12 +1843,6 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) if (key == K_TAB) { // command completion - if (ctrl&&shift) - { - Con_CycleConsole(); - return true; - } - if (con->commandcompletion) CompleteCommand (ctrl, shift?-1:1); return true; @@ -2841,7 +2835,13 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down { if (Key_Dest_Has(kdm_console|kdm_cwindows)) { - console_t *con = Key_Dest_Has(kdm_console)?con_current:con_curwindow; + console_t *con; + if (Key_Dest_Has(kdm_console)) + con = con_current; + else if (Key_Dest_Has(kdm_cwindows)) + con = con_curwindow; + else + con = NULL; if (con_mouseover && key >= K_MOUSE1 && key <= K_MWHEELDOWN) con = con_mouseover; if (con_curwindow && con_curwindow != con) diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 49ee3d85e..f78765ad8 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -2321,7 +2321,17 @@ static void PM_StartADownload(void) } if (tmpfile) + { p->download = HTTP_CL_Get(mirror, NULL, PM_Download_Got); + if (!p->download) + Con_Printf("Unable to download %s\n", p->name); + } + else + { + char syspath[MAX_OSPATH]; + FS_NativePath(temp, p->fsroot, syspath, sizeof(syspath)); + Con_Printf("Unable to write %s. Fix permissions before trying to download %s\n", syspath, p->name); + } if (p->download) { Con_Printf("Downloading %s\n", p->name); @@ -2333,7 +2343,6 @@ static void PM_StartADownload(void) } else { - Con_Printf("Unable to download %s\n", p->name); p->flags &= ~DPF_MARKED; //can't do it. if (tmpfile) VFS_CLOSE(tmpfile); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 2b4e61629..84cba2d7f 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -213,7 +213,7 @@ void Draw_BigFontString(int x, int y, const char *text) p = QBigFontWorks(); if (!p) { - Draw_AltFunString(x, y, text); + Draw_AltFunString(x, y + (20-8)/2, text); return; } @@ -438,7 +438,10 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu case mt_menudot: i = (int)(realtime * 10)%maxdots; p = R2D_SafeCachePic(va(menudotstyle, i+mindot )); - R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, option->common.width, option->common.height, p); + if (R_GetShaderSizes(p, NULL, NULL, false)>0) + R2D_ScalePic(xpos+option->common.posx, ypos+option->common.posy+dotofs, option->common.width, option->common.height, p); + else if ((int)(realtime*4)&1) + Draw_FunString(xpos+option->common.posx, ypos+option->common.posy + (option->common.height-8)/2, "^a^Ue00d"); break; case mt_picturesel: p = NULL; @@ -2206,6 +2209,8 @@ void M_Menu_Main_f (void) MC_AddConsoleCommandQBigFont (mainm, 72, y, "Options", "menu_options\n"); y += 20; y = M_Main_AddExtraOptions(mainm, y); MC_AddConsoleCommandQBigFont (mainm, 72, y, "Quit", "menu_quit\n"); y += 20; + + mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 36); } if (!m_preset_chosen.ival) diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 4997ba0c4..d3a371532 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -2986,7 +2986,7 @@ static void QDECL capture_raw_video (void *vctx, int frame, void *data, int stri char filename[MAX_OSPATH]; ctx->frames = frame+1; Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension); - SCR_ScreenShot(filename, ctx->fsroot, &data, 1, stride, width, height, fmt); + SCR_ScreenShot(filename, ctx->fsroot, &data, 1, stride, width, height, fmt, true); if (capturethrottlesize.ival) { @@ -5159,10 +5159,10 @@ void Media_Init(void) #endif Media_RegisterEncoder(NULL, &capture_raw); - Cmd_AddCommand("capture", Media_RecordFilm_f); - Cmd_AddCommand("capturedemo", Media_RecordDemo_f); - Cmd_AddCommand("capturestop", Media_StopRecordFilm_f); - Cmd_AddCommand("capturepause", Media_CapturePause_f); + Cmd_AddCommandD("capture", Media_RecordFilm_f, "Captures realtime action to a named video file. Check the capture* cvars to control driver/codecs/rates."); + Cmd_AddCommandD("capturedemo", Media_RecordDemo_f, "Capture a nemed demo to a named video file. Demo capturing can be performed offscreen, allowing arbitrary video sizes, or smooth captures on underpowered hardware."); + Cmd_AddCommandD("capturestop", Media_StopRecordFilm_f, "Aborts the current video capture."); + Cmd_AddCommandD("capturepause", Media_CapturePause_f, "Pauses the video capture, allowing you to avoid capturing uninteresting parts. This is a toggle, so reuse the same command to resume capturing again."); Cvar_Register(&capturemessage, "Video Capture Controls"); Cvar_Register(&capturesound, "Video Capture Controls"); diff --git a/engine/client/merged.h b/engine/client/merged.h index 42c738569..63def1964 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -145,6 +145,7 @@ void R_DrawTextField(int x, int y, int w, int h, const char *text, unsigned int #define CPRINT_RALIGN (1<<2) //R #define CPRINT_BALIGN (1<<3) //B #define CPRINT_BACKGROUND (1<<4) //P +#define CPRINT_NOWRAP (1<<5) #define CPRINT_OBITUARTY (1<<16) //O (show at 2/3rds from top) #define CPRINT_PERSIST (1<<17) //P (doesn't time out) @@ -309,6 +310,8 @@ struct pendingtextureinfo int depth; qboolean needfree; } mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture... + //mips are ordered as in arrayindex THEN mip order, allowing easy truncation of mip levels. + //cubemaps are just arrayindex*6 }; //small context for easy vbo creation. diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 5e275ec06..917cf9e67 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1117,7 +1117,7 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa { const char *s; dlight_t *l; - unsigned int lno = G_FLOAT(OFS_PARM0); + size_t lno = G_FLOAT(OFS_PARM0); int field = G_FLOAT(OFS_PARM1); while (lno >= cl_maxdlights) { @@ -1149,7 +1149,8 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa l->style = G_FLOAT(OFS_PARM2)+1; break; case lfield_angles: - AngleVectors(G_VECTOR(OFS_PARM2), l->axis[0], l->axis[1], l->axis[2]); + VectorCopy(G_VECTOR(OFS_PARM2), l->angles); + AngleVectors(l->angles, l->axis[0], l->axis[1], l->axis[2]); VectorInverse(l->axis[1]); break; case lfield_fov: @@ -1170,6 +1171,11 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa l->cubetexture = r_nulltex; break; #ifdef RTLIGHTS + case lfield_stylestring: + s = PR_GetStringOfs(prinst, OFS_PARM2); + Z_Free(l->customstyle); + l->customstyle = (s&&*s)?Z_StrDup(s):NULL; + break; case lfield_ambientscale: l->lightcolourscales[0] = G_FLOAT(OFS_PARM2); break; @@ -1202,7 +1208,6 @@ static void QCBUILTIN PF_R_DynamicLight_Set(pubprogfuncs_t *prinst, struct globa } static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - vec3_t v; dlight_t *l; unsigned int lno = G_FLOAT(OFS_PARM0); enum lightfield_e field = G_FLOAT(OFS_PARM1); @@ -1233,10 +1238,7 @@ static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globa G_FLOAT(OFS_RETURN) = l->style-1; break; case lfield_angles: - VectorAngles(l->axis[0], l->axis[2], v, false); - G_FLOAT(OFS_RETURN+0) = anglemod(v[0]); - G_FLOAT(OFS_RETURN+1) = v[1]; - G_FLOAT(OFS_RETURN+2) = v[2]; + VectorCopy(l->angles, G_VECTOR(OFS_RETURN)); break; case lfield_fov: G_FLOAT(OFS_RETURN) = l->fov; @@ -1251,6 +1253,12 @@ static void QCBUILTIN PF_R_DynamicLight_Get(pubprogfuncs_t *prinst, struct globa RETURN_TSTRING(l->cubemapname); break; #ifdef RTLIGHTS + case lfield_stylestring: + if (l->customstyle) + RETURN_TSTRING(l->customstyle); + else + RETURN_TSTRING(""); + break; case lfield_ambientscale: G_FLOAT(OFS_RETURN) = l->lightcolourscales[0]; break; @@ -1497,7 +1505,6 @@ static void CSQC_PolyFlush(void) if (!csqc_poly_2d) { scenetris_t *t; - /*regular 3d polys are inserted into a 'scene trisoup' that the backend can then source from (multiple times, depending on how its drawn)*/ if (cl_numstris == cl_maxstris) { cl_maxstris+=8; @@ -1510,7 +1517,7 @@ static void CSQC_PolyFlush(void) t->firstvert = csqc_poly_origvert; t->numidx = cl_numstrisidx - t->firstidx; - t->numvert = cl_numstrisvert-csqc_poly_origvert; + t->numvert = cl_numstrisvert-t->firstvert; } else { @@ -2135,7 +2142,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_ case VF_ACTIVESEAT: if (prinst == csqc_world.progs) { - if (csqc_playerseat != *p) + if (csqc_playerseat != (int)*p) { CSQC_ChangeLocalPlayer(*p); if (prinst->callargc < 3 || G_FLOAT(OFS_PARM2)) @@ -2419,6 +2426,9 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars scissored = false; R_DrawNameTags(); +#ifdef RTLIGHTS + R_EditLights_DrawInfo(); +#endif if (r_refdef.drawsbar) { @@ -7010,6 +7020,9 @@ void CSQC_Shutdown(void) int i; if (csqcprogs) { + if (csqcg.shutdown_function) + PR_ExecuteProgram(csqcprogs, csqcg.shutdown_function); + key_dest_absolutemouse &= ~kdm_game; CSQC_ForgetThreads(); PR_ReleaseFonts(kdm_game); diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 211260256..94e9d7f15 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -996,7 +996,7 @@ void QCBUILTIN PF_SubConGetSet (pubprogfuncs_t *prinst, struct globalvars_s *pr_ else if (!strcmp(field, "next")) { con = con->next; - if (con && con != &con_main) + if (con) RETURN_TSTRING(con->name); } else if (!strcmp(field, "unseen")) diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index aff35f892..fa4a4e0d6 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -164,6 +164,7 @@ extern "C" { #include "mathlib.h" #include "cvar.h" #include "net.h" +#ifndef WEBSVONLY #include "protocol.h" #include "cmd.h" #include "console.h" @@ -197,6 +198,7 @@ extern "C" { #else #include "server.h" #endif +#endif #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 4812094d4..86b2b2e9f 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -967,6 +967,7 @@ void QDECL R2D_Conback_Callback(struct cvar_s *var, char *oldvalue) } } +#ifdef AVAIL_FREETYPE #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX) #include qboolean R2D_Font_WasAdded(char *buffer, char *fontfilename) @@ -1026,6 +1027,7 @@ int R2D_Font_ListSystemFonts(const char *fname, qofs_t fsize, time_t modtime, vo return true; } #endif +#endif void R2D_Font_Changed(void) { float tsize; @@ -1062,7 +1064,9 @@ void R2D_Font_Changed(void) if (!strcmp(gl_font.string, "?")) { -#if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX) +#ifndef AVAIL_FREETYPE + Cvar_Set(&gl_font, ""); +#elif defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX) BOOL (APIENTRY *pChooseFontW)(LPCHOOSEFONTW) = NULL; dllfunction_t funcs[] = { @@ -1112,6 +1116,7 @@ void R2D_Font_Changed(void) return; #else Sys_EnumerateFiles("/usr/share/fonts/truetype/", "*/*.ttf", R2D_Font_ListSystemFonts, NULL, NULL); + COM_EnumerateFiles("*.ttf", R2D_Font_ListSystemFonts, NULL); Cvar_Set(&gl_font, ""); #endif } diff --git a/engine/client/render.h b/engine/client/render.h index 6b91a0bf3..3b2bd6580 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -452,6 +452,8 @@ void Image_Upload (texid_t tex, uploadfmt_t fmt, void *data, void *palette, in void Image_Purge(void); //purge any textures which are not needed any more (releases memory, but doesn't give null pointers). void Image_Init(void); void Image_Shutdown(void); +qboolean Image_WriteKTXFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips); +qboolean Image_WriteDDSFile(const char *filename, enum fs_relative fsroot, struct pendingtextureinfo *mips); void Image_BlockSizeForEncoding(uploadfmt_t encoding, unsigned int *blockbytes, unsigned int *blockwidth, unsigned int *blockheight); const char *Image_FormatName(uploadfmt_t encoding); @@ -612,10 +614,6 @@ extern cvar_t r_shadow_realtime_dlight_diffuse; extern cvar_t r_shadow_realtime_dlight_specular; extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_shadows, r_shadow_realtime_world_lightmaps; extern cvar_t r_shadow_shadowmapping; -extern cvar_t r_editlights_import_radius; -extern cvar_t r_editlights_import_ambient; -extern cvar_t r_editlights_import_diffuse; -extern cvar_t r_editlights_import_specular; extern cvar_t r_mirroralpha; extern cvar_t r_wateralpha; extern cvar_t r_lavaalpha; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 7fc6db50c..6c04c0e97 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -240,7 +240,7 @@ cvar_t scr_showpause = CVAR ("showpause", "1"); cvar_t scr_showturtle = CVAR ("showturtle", "0"); cvar_t scr_turtlefps = CVAR ("scr_turtlefps", "10"); cvar_t scr_sshot_compression = CVAR ("scr_sshot_compression", "75"); -cvar_t scr_sshot_type = CVAR ("scr_sshot_type", "png"); +cvar_t scr_sshot_type = CVARD ("scr_sshot_type", "png", "This specifies the default extension(and thus file format) for screenshots.\nKnown extensions are: png, jpg/jpeg, bmp, pcx, tga, ktx, dds."); cvar_t scr_sshot_prefix = CVAR ("scr_sshot_prefix", "screenshots/fte-"); cvar_t scr_viewsize = CVARFC("viewsize", "100", CVAR_ARCHIVE, SCR_Viewsize_Callback); @@ -458,6 +458,7 @@ cvar_t vid_hardwaregamma = CVARFD ("vid_hardwaregamma", "1", cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Apply gamma ramps upon the desktop rather than the window."); +cvar_t r_fog_cullentities = CVARD ("r_fog_cullentities", "1", "Automatically cull entities according to fog."); cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces's default) is typically more realistic, while 1 (matching FitzQuake and others) is more common."); cvar_t r_fog_permutation = CVARFD ("r_fog_permutation", "1", CVAR_SHADERSYSTEM, "Renders fog using a material permutation. 0 plays nicer with q3 shaders, but 1 is otherwise a better choice."); @@ -557,6 +558,7 @@ void GLRenderer_Init(void) Cvar_Register (&gl_overbright, GRAPHICALNICETIES); Cvar_Register (&gl_overbright_all, GRAPHICALNICETIES); Cvar_Register (&gl_dither, GRAPHICALNICETIES); + Cvar_Register (&r_fog_cullentities, GRAPHICALNICETIES); Cvar_Register (&r_fog_exp2, GLRENDEREROPTIONS); Cvar_Register (&r_fog_permutation, GLRENDEREROPTIONS); @@ -732,14 +734,9 @@ void Renderer_Init(void) Cmd_AddCommand("vid_toggle", R_ToggleFullscreen_f); #ifdef RTLIGHTS - Cmd_AddCommand ("r_editlights_reload", R_ReloadRTLights_f); - Cmd_AddCommand ("r_editlights_save", R_SaveRTLights_f); - Cvar_Register (&r_editlights_import_radius, "Realtime Light editing/importing"); - Cvar_Register (&r_editlights_import_ambient, "Realtime Light editing/importing"); - Cvar_Register (&r_editlights_import_diffuse, "Realtime Light editing/importing"); - Cvar_Register (&r_editlights_import_specular, "Realtime Light editing/importing"); - + R_EditLights_RegisterCommands(); #endif + Cmd_AddCommand("r_dumpshaders", Shader_WriteOutGenerics_f); Cmd_AddCommand("r_remapshader", Shader_RemapShader_f); Cmd_AddCommand("r_showshader", Shader_ShowShader_f); @@ -1243,12 +1240,12 @@ rendererinfo_t *rendererinfo[16] = void R_RegisterRenderer(rendererinfo_t *ri) { size_t i; - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0; i < countof(rendererinfo); i++) { //already registered if (rendererinfo[i] == ri) return; } - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0; i < countof(rendererinfo); i++) { //register it in the first empty slot if (!rendererinfo[i]) { @@ -1603,7 +1600,6 @@ TRACE(("dbg: R_ApplyRenderer: initing mods\n")); Cvar_ForceSetValue(&vid_dpi_x, vid.dpi_x); Cvar_ForceSetValue(&vid_dpi_y, vid.dpi_y); - TRACE(("dbg: R_ApplyRenderer: R_PreNewMap (how handy)\n")); Surf_PreNewMap(); @@ -1690,6 +1686,10 @@ TRACE(("dbg: R_ApplyRenderer: clearing world\n")); Plug_ResChanged(); #endif Cvar_ForceCallback(&r_particlesystem); +#ifdef MENU_NATIVECODE + if (mn_entry) + mn_entry->Init(MI_RENDERER, vid.width, vid.height, vid.rotpixelwidth, vid.rotpixelheight); +#endif CL_InitDlights(); @@ -1861,6 +1861,22 @@ void R_ReloadRenderer_f (void) #endif } +static int R_PriorityForRenderer(rendererinfo_t *r) +{ + if (r && r->name[0]) + { + if (r->VID_GetPriority) + return r->VID_GetPriority(); + else if (r->rtype == QR_HEADLESS) + return -1; //headless renderers are a really poor choice, and will make the user think it buggy. + else if (r->rtype == QR_NONE) + return 0; //dedicated servers are possible, but we really don't want to use them unless we have no other choice. + else + return 1; //assume 1 for most renderers. + } + return -2; //invalid renderer +} + //use Cvar_ApplyLatches(CVAR_RENDERERLATCH) beforehand. qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) { @@ -1932,20 +1948,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) //I'd like to just qsort the renderers, but that isn't stable and might reorder gl+d3d etc. for (i = 0; i < countof(rendererinfo); i++) { - if (rendererinfo[i] && rendererinfo[i]->name[0]) - { - if (rendererinfo[i]->VID_GetPriority) - pri = rendererinfo[i]->VID_GetPriority(); - else if (rendererinfo[i]->rtype == QR_HEADLESS) - pri = -1; //headless renderers are a really poor choice, and will make the user think it buggy. - else if (rendererinfo[i]->rtype == QR_NONE) - pri = 0; //dedicated servers are possible, but we really don't want to use them unless we have no other choice. - else - pri = 1; //assume 1 for most renderers. - } - else - pri = -2; - + pri = R_PriorityForRenderer(rendererinfo[i]); if (pri > bestpri) { bestpri = pri; @@ -1956,7 +1959,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) else if (!strcmp(com_token, "random")) { int count; - for (i = 0, count = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0, count = 0; i < countof(rendererinfo); i++) { if (!rendererinfo[i] || !rendererinfo[i]->description) continue; //not valid in this build. :( @@ -1967,7 +1970,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) count++; } count = rand()%count; - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0; i < countof(rendererinfo); i++) { if (!rendererinfo[i] || !rendererinfo[i]->description) continue; //not valid in this build. :( @@ -1986,7 +1989,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) else { int bestpri = -2, pri; - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0; i < countof(rendererinfo); i++) { if (!rendererinfo[i] || !rendererinfo[i]->description) continue; //not valid in this build. :( @@ -1996,14 +1999,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) continue; if (!stricmp(rendererinfo[i]->name[j], com_token)) { - if (rendererinfo[i]->VID_GetPriority) - pri = rendererinfo[i]->VID_GetPriority(); - else if (rendererinfo[i]->rtype == QR_HEADLESS) - pri = -1; //headless renderers are a really poor choice, and will make the user think it buggy. - else if (rendererinfo[i]->rtype == QR_NONE) - pri = 0; //dedicated servers are possible, but we really don't want to use them unless we have no other choice. - else - pri = 1; + pri = R_PriorityForRenderer(rendererinfo[i]); if (pri > bestpri) { @@ -2073,6 +2069,21 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) return newr->renderer != NULL; } +struct sortedrenderers_s +{ + int index; //original index, to try to retain stable sort orders. + int pri; + rendererinfo_t *r; +}; +static int QDECL R_SortRenderers(const void *av, const void *bv) +{ + const struct sortedrenderers_s *a = av; + const struct sortedrenderers_s *b = bv; + if (a->pri == b->pri) + return (a->index > b->index)?1:-1; + return (a->pri < b->pri)?1:-1; +} + void R_RestartRenderer (rendererstate_t *newr) { #ifndef CLIENTONLY @@ -2112,6 +2123,7 @@ void R_RestartRenderer (rendererstate_t *newr) int i; qboolean failed = true; rendererinfo_t *skip = newr->renderer; + struct sortedrenderers_s sorted[countof(rendererinfo)]; if (failed && newr->fullscreen == 1) { @@ -2141,10 +2153,16 @@ void R_RestartRenderer (rendererstate_t *newr) failed = !R_ApplyRenderer(newr); } - //FIXME: query renderers for their priority and then use that. then we can favour X11 when DISPLAY is set and wayland when WAYLAND_DISPLAY is set, etc. - for (i = 0; failed && i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + for (i = 0; i < countof(sorted); i++) { - newr->renderer = rendererinfo[i]; + sorted[i].index = i; + sorted[i].r = rendererinfo[i]; + sorted[i].pri = R_PriorityForRenderer(sorted[i].r); + } + qsort(sorted, countof(sorted), sizeof(sorted[0]), R_SortRenderers); + for (i = 0; failed && i < countof(sorted); i++) + { + newr->renderer = sorted[i].r; if (newr->renderer && newr->renderer != skip && newr->renderer->rtype != QR_HEADLESS) { Con_Printf(CON_NOTICE "Trying %s"CON_DEFAULT"\n", newr->renderer->description); @@ -2216,11 +2234,21 @@ void R_SetRenderer_f (void) if (Cmd_Argc() == 1 || !stricmp(param, "help")) { - Con_Printf ("\nValid setrenderer parameters are:\n"); - for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++) + struct sortedrenderers_s sorted[countof(rendererinfo)]; + for (i = 0; i < countof(sorted); i++) { - if (rendererinfo[i] && rendererinfo[i]->description) - Con_Printf("^[%s\\type\\/setrenderer %s^]^7: %s%s\n", rendererinfo[i]->name[0], rendererinfo[i]->name[0], rendererinfo[i]->description, (currentrendererstate.renderer == rendererinfo[i])?" ^2(current)":""); + sorted[i].index = i; + sorted[i].r = rendererinfo[i]; + sorted[i].pri = R_PriorityForRenderer(sorted[i].r); + } + qsort(sorted, countof(sorted), sizeof(sorted[0]), R_SortRenderers); + + Con_Printf ("\nValid setrenderer parameters are:\n"); + for (i = 0; i < countof(rendererinfo); i++) + { + rendererinfo_t *r = sorted[i].r; + if (r && r->description) + Con_Printf("^[%s\\type\\/setrenderer %s^]^7: %s%s\n", r->name[0], r->name[0], r->description, (currentrendererstate.renderer == r)?" ^2(current)":""); } return; } @@ -2966,7 +2994,7 @@ void R_SetFrustum (float projmat[16], float viewmat[16]) //do far plane //fog will logically not actually reach 0, though precision issues will force it. we cut off at an exponant of -500 - if (r_refdef.globalfog.density) + if (r_refdef.globalfog.density && r_fog_cullentities.ival) { float culldist; float fog; diff --git a/engine/client/screen.h b/engine/client/screen.h index 3f9b7d6cc..f123f1861 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef struct playerview_s playerview_t; extern float scr_con_current; -extern float scr_conlines; // lines of console to display +extern float scr_con_target; // lines of console to display extern int sb_lines; @@ -231,7 +231,7 @@ typedef enum uploadfmt #define PTI_EMULATED TF_INVALID:case TF_BGR24_FLIP:case TF_MIP4_R8:case TF_MIP4_SOLID8:case TF_MIP4_8PAL24:case TF_MIP4_8PAL24_T255:case TF_SOLID8:case TF_TRANS8:case TF_TRANS8_FULLBRIGHT:case TF_HEIGHT8:case TF_HEIGHT8PAL:case TF_H2_T7G1:case TF_H2_TRANS8_0:case TF_H2_T4A4:case TF_8PAL24:case TF_8PAL32:case PTI_LLLX8:case PTI_LLLA8 } uploadfmt_t; -qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt); +qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta); void SCR_DrawTwoDimensional(int uimenu, qboolean nohud); diff --git a/engine/client/snd_alsa.c b/engine/client/snd_alsa.c index ed046a185..8640e41b1 100755 --- a/engine/client/snd_alsa.c +++ b/engine/client/snd_alsa.c @@ -33,6 +33,7 @@ #include #include "quakedef.h" +#ifdef HAVE_MIXER #include static void *alsasharedobject; @@ -589,4 +590,4 @@ sounddriver_t ALSA_Output = ALSA_Enumerate }; #endif - +#endif diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index 3b110032a..d32048d0e 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -316,13 +316,13 @@ typedef struct { GUID SubFormat; } QWAVEFORMATEX; -const static GUID QKSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; -const static GUID QKSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static const GUID QKSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static const GUID QKSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; #ifdef _IKsPropertySet_ //const static GUID CLSID_EAXDIRECTSOUND = {0x4ff53b81, 0x1ce0, 0x11d3, //{0xaa, 0xb8, 0x0, 0xa0, 0xc9, 0x59, 0x49, 0xd5}}; -const static GUID DSPROPSETID_EAX20_LISTENERPROPERTIES = {0x306a6a8, 0xb224, 0x11d2, +static const GUID DSPROPSETID_EAX20_LISTENERPROPERTIES = {0x306a6a8, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}}; typedef struct _EAXLISTENERPROPERTIES @@ -399,7 +399,7 @@ typedef enum 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};*/ -const static GUID CLSID_EAXDirectSound ={ +static const GUID CLSID_EAXDirectSound ={ 0x4ff53b81, 0x1ce0, 0x11d3, diff --git a/engine/client/snd_linux.c b/engine/client/snd_linux.c index 6aeb601a6..012700bb1 100644 --- a/engine/client/snd_linux.c +++ b/engine/client/snd_linux.c @@ -14,6 +14,8 @@ #include #include "quakedef.h" +#ifdef HAVE_MIXER + #ifdef __linux__ #include #endif @@ -458,23 +460,30 @@ static qboolean QDECL OSS_Enumerate(void (QDECL *cb) (const char *drivername, co int i; int fd; oss_sysinfo si; + const char *devmixer; if (COM_CheckParm("-nooss")) return true; - fd = open("/dev/mixer", O_RDWR, 0); + + devmixer = getenv("OSS_MIXERDEV"); + if (!devmixer) + devmixer = "/dev/mixer"; + fd = open(devmixer, O_RDWR|O_NONBLOCK, 0); if (fd == -1) return true; //oss not supported. don't list any devices. - if (ioctl(fd, SNDCTL_SYSINFO, &si) != -1) + memset(&si, 0, sizeof(si)); //just in case the driver is really dodgy... + if (ioctl(fd, SNDCTL_SYSINFO, &si) >= 0) { - if ((si.versionnum>>16) >= 4) - { //only trust all the fields if its recent enough + if ((si.versionnum>>16) >= 4 || si.numaudios > 128) + { //only trust all the fields if its recent enough and doesn't look dodgy. for(i = 0; i < si.numaudios; i++) { oss_audioinfo ai; + memset(&ai, 0, sizeof(ai)); //just in case the driver is really dodgy... ai.dev = i; - if (ioctl(fd, SNDCTL_AUDIOINFO, &ai) != -1) + if (ioctl(fd, SNDCTL_AUDIOINFO, &ai) >= 0) cb(SDRVNAME, ai.devnode, ai.name); } close(fd); @@ -497,9 +506,7 @@ sounddriver_t OSS_Output = OSS_Enumerate }; - - - +#endif #ifdef VOICECHAT //this does apparently work after all. #include @@ -597,4 +604,3 @@ snd_capture_driver_t OSS_Capture = OSS_Capture_Shutdown }; #endif - diff --git a/engine/client/snd_mix.c b/engine/client/snd_mix.c index b192c752c..921d18657 100644 --- a/engine/client/snd_mix.c +++ b/engine/client/snd_mix.c @@ -146,16 +146,16 @@ CHANNEL MIXING =============================================================================== */ -static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count); -static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count); -static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count); -static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count); -static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count); +static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate); +static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate); +static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count, int rate); +static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate); +static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate); //NOTE: MAY NOT CALL SYS_ERROR void S_PaintChannels(soundcardinfo_t *sc, int endtime) @@ -169,6 +169,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) int ltime, count; int avail; unsigned int maxlen = ruleset_allow_overlongsounds.ival?0xffffffffu>>PITCHSHIFT:snd_speed*20; + int rate; while (sc->paintedtime < endtime) { @@ -272,6 +273,11 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) break; } + if (sc->sn.speed != scache->speed) + rate = (ch->rate * scache->speed) / sc->sn.speed; //sound was loaded at the wrong speed. just play it back at a different speed and hope that all is well. this is nearest sampling, so expect it to be a little poo. + else + rate = ch->rate; + if (spos < scache->soundoffset || spos > scache->soundoffset+scache->length) avail = 0; //urm, we would be trying to read outside of the buffer. let mixing slip when there's no data available yet. else @@ -280,7 +286,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) avail = scache->length; if (avail > maxlen) avail = snd_speed*10; - avail = (((int)(scache->soundoffset + avail)<pos + (ch->rate-1)) / ch->rate; + avail = (((int)(scache->soundoffset + avail)<pos + (rate-1)) / rate; } // mix the smaller of how much is available or the time left count = min(avail, end - ltime); @@ -293,38 +299,38 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) if (count > (-ch->pos+255)>>PITCHSHIFT) count = ((-ch->pos+255)>>PITCHSHIFT); ltime += count; - ch->pos += count*ch->rate; + ch->pos += count*rate; continue; } if (scache->width == 1) { if (scache->numchannels==2) - SND_PaintChannel8_O2I2(ch, scache, ltime-sc->paintedtime, count); + SND_PaintChannel8_O2I2(ch, scache, ltime-sc->paintedtime, count, rate); else if (sc->sn.numchannels <= 2) - SND_PaintChannel8_O2I1(ch, scache, ltime-sc->paintedtime, count); + SND_PaintChannel8_O2I1(ch, scache, ltime-sc->paintedtime, count, rate); else if (sc->sn.numchannels <= 4) - SND_PaintChannel8_O4I1(ch, scache, count); + SND_PaintChannel8_O4I1(ch, scache, count, rate); else if (sc->sn.numchannels <= 6) - SND_PaintChannel8_O6I1(ch, scache, count); + SND_PaintChannel8_O6I1(ch, scache, count, rate); else - SND_PaintChannel8_O8I1(ch, scache, count); + SND_PaintChannel8_O8I1(ch, scache, count, rate); } else if (scache->width == 2) { if (scache->numchannels==2) - SND_PaintChannel16_O2I2(ch, scache, ltime-sc->paintedtime, count); + SND_PaintChannel16_O2I2(ch, scache, ltime-sc->paintedtime, count, rate); else if (sc->sn.numchannels <= 2) - SND_PaintChannel16_O2I1(ch, scache, ltime-sc->paintedtime, count); + SND_PaintChannel16_O2I1(ch, scache, ltime-sc->paintedtime, count, rate); else if (sc->sn.numchannels <= 4) - SND_PaintChannel16_O4I1(ch, scache, count); + SND_PaintChannel16_O4I1(ch, scache, count, rate); else if (sc->sn.numchannels <= 6) - SND_PaintChannel16_O6I1(ch, scache, count); + SND_PaintChannel16_O6I1(ch, scache, count, rate); else - SND_PaintChannel16_O8I1(ch, scache, count); + SND_PaintChannel16_O8I1(ch, scache, count, rate); } ltime += count; - ch->pos += ch->rate * count; + ch->pos += rate * count; } else break; @@ -337,20 +343,20 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) } } -static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count) +static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate) { int data; signed char *sfx; int i; unsigned int pos = ch->pos-(sc->soundoffset<rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[starttime+i].s[0] += ch->vol[0] * data; paintbuffer[starttime+i].s[1] += ch->vol[1] * data; } @@ -367,21 +373,21 @@ static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime } } -static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count) +static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate) { // int data; signed char *sfx; int i; unsigned int pos = ch->pos-(sc->soundoffset<rate != (1<data; for (i=0 ; ivol[0] * sfx[(pos>>(PITCHSHIFT-1))&~1]; paintbuffer[starttime+i].s[1] += ch->vol[1] * sfx[(pos>>(PITCHSHIFT-1))|1]; - pos += ch->rate; + pos += rate; } } else @@ -395,20 +401,20 @@ static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime } } -static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { signed char *sfx; int i; unsigned int pos = ch->pos-(sc->soundoffset<rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += ch->vol[0] * data; paintbuffer[i].s[1] += ch->vol[1] * data; paintbuffer[i].s[2] += ch->vol[2] * data; @@ -428,20 +434,20 @@ static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count) } } -static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { signed char *sfx; int i; unsigned int pos = ch->pos-(sc->soundoffset<rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += ch->vol[0] * data; paintbuffer[i].s[1] += ch->vol[1] * data; paintbuffer[i].s[2] += ch->vol[2] * data; @@ -465,20 +471,20 @@ static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count) } } -static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { signed char *sfx; int i; unsigned int pos = ch->pos-(sc->soundoffset<rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += ch->vol[0] * data; paintbuffer[i].s[1] += ch->vol[1] * data; paintbuffer[i].s[2] += ch->vol[2] * data; @@ -507,7 +513,7 @@ static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count) } -static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count) +static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate) { int data; int left, right; @@ -519,7 +525,7 @@ static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttim leftvol = ch->vol[0]; rightvol = ch->vol[1]; - if (ch->rate != (1<data; @@ -527,7 +533,7 @@ static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttim { float frac = pos&((1<>PITCHSHIFT] * (1-frac) + sfx[(pos>>PITCHSHIFT)+1] * frac; - pos += ch->rate; + pos += rate; paintbuffer[starttime+i].s[0] += (leftvol * data)>>8; paintbuffer[starttime+i].s[1] += (rightvol * data)>>8; } @@ -546,7 +552,7 @@ static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttim } } -static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count) +static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count, int rate) { int leftvol, rightvol; signed short *sfx; @@ -556,7 +562,7 @@ static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttim leftvol = ch->vol[0]; rightvol = ch->vol[1]; - if (ch->rate != (1<data; @@ -564,7 +570,7 @@ static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttim { l = sfx[(pos>>(PITCHSHIFT-1))&~1]; r = sfx[(pos>>(PITCHSHIFT-1))|1]; - pos += ch->rate; + pos += rate; paintbuffer[starttime+i].s[0] += (ch->vol[0] * l)>>8; paintbuffer[starttime+i].s[1] += (ch->vol[1] * r)>>8; } @@ -580,7 +586,7 @@ static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttim } } -static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { int vol[4]; signed short *sfx; @@ -592,14 +598,14 @@ static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count) vol[2] = ch->vol[2]; vol[3] = ch->vol[3]; - if (ch->rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += (vol[0] * data)>>8; paintbuffer[i].s[1] += (vol[1] * data)>>8; paintbuffer[i].s[2] += (vol[2] * data)>>8; @@ -619,7 +625,7 @@ static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count) } } -static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { int vol[6]; signed short *sfx; @@ -633,14 +639,14 @@ static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count) vol[4] = ch->vol[4]; vol[5] = ch->vol[5]; - if (ch->rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += (vol[0] * data)>>8; paintbuffer[i].s[1] += (vol[1] * data)>>8; paintbuffer[i].s[2] += (vol[2] * data)>>8; @@ -664,7 +670,7 @@ static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count) } } -static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count, int rate) { int vol[8]; signed short *sfx; @@ -680,14 +686,14 @@ static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count) vol[6] = ch->vol[6]; vol[7] = ch->vol[7]; - if (ch->rate != (1<data; for (i=0 ; i>PITCHSHIFT]; - pos += ch->rate; + pos += rate; paintbuffer[i].s[0] += (vol[0] * data)>>8; paintbuffer[i].s[1] += (vol[1] * data)>>8; paintbuffer[i].s[2] += (vol[2] * data)>>8; diff --git a/engine/client/snd_sdl.c b/engine/client/snd_sdl.c index d3fe08928..b9f1f8c6e 100644 --- a/engine/client/snd_sdl.c +++ b/engine/client/snd_sdl.c @@ -65,6 +65,25 @@ static const char *(SDLCALL *SDL_GetError) (void); static uint32_t (SDLCALL *SDL_GetQueuedAudioSize) (SDL_AudioDeviceID dev); static uint32_t (SDLCALL *SDL_DequeueAudio) (SDL_AudioDeviceID dev, void *data, uint32_t len); #endif +static dllfunction_t sdl_funcs[] = +{ + {(void*)&SDL_Init, "SDL_Init"}, + {(void*)&SDL_InitSubSystem, "SDL_InitSubSystem"}, + {(void*)&SDL_OpenAudioDevice, "SDL_OpenAudioDevice"}, + {(void*)&SDL_PauseAudioDevice, "SDL_PauseAudioDevice"}, + {(void*)&SDL_LockAudioDevice, "SDL_LockAudioDevice"}, + {(void*)&SDL_UnlockAudioDevice, "SDL_UnlockAudioDevice"}, + {(void*)&SDL_CloseAudioDevice, "SDL_CloseAudioDevice"}, + {(void*)&SDL_GetNumAudioDevices, "SDL_GetNumAudioDevices"}, + {(void*)&SDL_GetAudioDeviceName, "SDL_GetAudioDeviceName"}, + {(void*)&SDL_GetError, "SDL_GetError"}, +#if SDL_VERSION_ATLEAST(2,0,5) + {(void*)&SDL_GetQueuedAudioSize, "SDL_GetQueuedAudioSize"}, + {(void*)&SDL_DequeueAudio, "SDL_DequeueAudio"}, +#endif + {NULL, NULL} +}; +static dllhandle_t *libsdl; #else #include #endif @@ -81,34 +100,17 @@ static uint32_t (SDLCALL *SDL_DequeueAudio) (SDL_AudioDeviceID dev, void *da static qboolean SSDL_InitAudio(void) { static qboolean inited = false; + if (COM_CheckParm("-nosdlsnd") || COM_CheckParm("-nosdl")) + return false; #ifdef DYNAMIC_SDL - static dllfunction_t funcs[] = - { - {(void*)&SDL_Init, "SDL_Init"}, - {(void*)&SDL_InitSubSystem, "SDL_InitSubSystem"}, - {(void*)&SDL_OpenAudioDevice, "SDL_OpenAudioDevice"}, - {(void*)&SDL_PauseAudioDevice, "SDL_PauseAudioDevice"}, - {(void*)&SDL_LockAudioDevice, "SDL_LockAudioDevice"}, - {(void*)&SDL_UnlockAudioDevice, "SDL_UnlockAudioDevice"}, - {(void*)&SDL_CloseAudioDevice, "SDL_CloseAudioDevice"}, - {(void*)&SDL_GetNumAudioDevices, "SDL_GetNumAudioDevices"}, - {(void*)&SDL_GetAudioDeviceName, "SDL_GetAudioDeviceName"}, - {(void*)&SDL_GetError, "SDL_GetError"}, -#if SDL_VERSION_ATLEAST(2,0,5) - {(void*)&SDL_GetQueuedAudioSize, "SDL_GetQueuedAudioSize"}, - {(void*)&SDL_DequeueAudio, "SDL_DequeueAudio"}, -#endif - {NULL, NULL} - }; - static dllhandle_t *libsdl; if (!libsdl) { - libsdl = Sys_LoadLibrary("libSDL2-2.0.so.0", funcs); + libsdl = Sys_LoadLibrary("libSDL2-2.0.so.0", sdl_funcs); if (!libsdl) - libsdl = Sys_LoadLibrary("libSDL2.so", funcs); //maybe they have a dev package installed that fixes this mess. + libsdl = Sys_LoadLibrary("libSDL2.so", sdl_funcs); //maybe they have a dev package installed that fixes this mess. #ifdef _WIN32 if (!libsdl) - libsdl = Sys_LoadLibrary("SDL2", funcs); + libsdl = Sys_LoadLibrary("SDL2", sdl_funcs); #endif if (libsdl) SDL_Init(SDL_INIT_NOPARACHUTE); @@ -120,9 +122,6 @@ static qboolean SSDL_InitAudio(void) } #endif - if (COM_CheckParm("-nosndsnd")) - return false; - if (!inited) if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE)) { diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 5fe5aa4fd..abfce6c4d 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -791,7 +791,11 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext) #endif // print out all the frames to stderr +#ifdef SVNREVISION + fprintf(stderr, "Error: signal %s (revision "STRINGIFY(SVNREVISION)")\n", signame); +#else fprintf(stderr, "Error: signal %s:\n", signame); +#endif backtrace_symbols_fd(array+firstframe, size-firstframe, 2); if (sig == SIGINT) diff --git a/engine/client/view.c b/engine/client/view.c index 22f6d4931..b2d6da278 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "winquake.h" #include "glquake.h" +#include "shader.h" #include // for isdigit(); @@ -103,8 +104,8 @@ cvar_t v_gunkick = CVARD("v_gunkick", "0", "Controls the strength of view ang cvar_t v_gunkick_q2 = CVARD("v_gunkick_q2", "1", "Controls the strength of view angle changes when firing weapons (in Quake2)."); cvar_t v_viewmodel_quake = CVARD("r_viewmodel_quake", "0", "Controls whether to use weird viewmodel movements from vanilla quake."); //name comes from MarkV. -cvar_t v_viewheight = CVAR("v_viewheight", "0"); -cvar_t v_projectionmode = CVAR("v_projectionmode", "0"); +cvar_t v_viewheight = CVARF("v_viewheight", "0", CVAR_ARCHIVE); +cvar_t v_projectionmode = CVARF("v_projectionmode", "0", CVAR_ARCHIVE); cvar_t v_depthsortentities = CVARAD("v_depthsortentities", "0", "v_reorderentitiesrandomly", "Reorder entities for transparency such that the furthest entities are drawn first, allowing nearer transparent entities to draw over the top of them."); @@ -2160,6 +2161,9 @@ void V_RenderPlayerViews(playerview_t *pv) R_RenderView (); R2D_PolyBlend (); R_DrawNameTags(); +#ifdef RTLIGHTS + R_EditLights_DrawInfo(); +#endif if(cl.intermissionmode == IM_NONE) R2D_DrawCrosshair(); @@ -2271,8 +2275,7 @@ void V_RenderPlayerViews(playerview_t *pv) r_refdef.externalview = false; } -#include "shader.h" -void V_RenderView (void) +void V_RenderView (qboolean no2d) { int seatnum; int maxseats = cl.splitclients; @@ -2291,6 +2294,8 @@ void V_RenderView (void) for (seatnum = 0; seatnum < cl.splitclients && seatnum < maxseats; seatnum++) { V_ClearRefdef(&cl.playerview[seatnum]); + if (no2d) + r_refdef.drawcrosshair = r_refdef.drawsbar = 0; if (seatnum) { //should be enough to just hack a few things. @@ -2348,7 +2353,7 @@ void V_RenderView (void) #ifdef QUAKEHUD case 0: //show a mini-console. { - console_t *con = &con_main; + console_t *con = Con_GetMain(); extern cvar_t gl_conback; shader_t *conback; if (*gl_conback.string && (conback = R_RegisterPic(gl_conback.string, NULL)) && R_GetShaderSizes(conback, NULL, NULL, true) > 0) @@ -2357,7 +2362,7 @@ void V_RenderView (void) R2D_Image(r_refdef.grect.x, r_refdef.grect.y, r_refdef.grect.width, r_refdef.grect.height, 0, 0, 1, 1, conback); else R2D_TileClear (r_refdef.grect.x, r_refdef.grect.y, r_refdef.grect.width, r_refdef.grect.height); - if (!scr_conlines) + if (!scr_con_target && con) { int gah; Font_BeginString(font_console, 0, 0, &gah, &gah); diff --git a/engine/client/view.h b/engine/client/view.h index 1cbcb5708..9b71221d2 100644 --- a/engine/client/view.h +++ b/engine/client/view.h @@ -28,7 +28,7 @@ extern float hw_blend[4]; extern qboolean r_secondaryview; void V_Init (void); -void V_RenderView (void); +void V_RenderView (qboolean no2d); float V_CalcRoll (vec3_t angles, vec3_t velocity); void V_UpdatePalette (qboolean force); void V_ClearCShifts (void); diff --git a/engine/client/wad.c b/engine/client/wad.c index 91473855a..4fda99e27 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -835,7 +835,7 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel) //actually, this should be in Q_strncatz(wads, token, sizeof(wads)); //cache it for later (so that we don't play with any temp memory yet) #endif } - else if (!strcmp("fog", key)) //q1 extension. FIXME: should be made temporary. + else if (!strcmp("fog", key) || !strcmp("airfog", key)) //q1 extension. FIXME: should be made temporary. { key[0] = 'f'; key[1] = 'o'; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 56998b6d6..9fe4ca8c1 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -96,259 +96,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif -#ifdef CONFIG_FILE_NAME - #undef MULTITHREAD - #define HEADLESSQUAKE //usable renderers are normally specified via the makefile, but HEADLESS is considered a feature rather than an actual renderer, so usually gets forgotten about... +#undef MULTITHREAD +#define HEADLESSQUAKE //usable renderers are normally specified via the makefile, but HEADLESS is considered a feature rather than an actual renderer, so usually gets forgotten about... - //yup, C89 allows this (doesn't like C's token concat though). - #include STRINGIFY(CONFIG_FILE_NAME) -#else - #define QWSKINS //disables qw .pcx skins, as well as enemy/team colour forcing. - - #ifndef NO_LIBRARIES - #define AVAIL_OPENAL - #define AVAIL_FREETYPE - #endif - - #define AVAIL_OGGVORBIS - #if defined(__CYGWIN__) - #define AVAIL_ZLIB - #else - #define AVAIL_PNGLIB - #define AVAIL_JPEGLIB - #define AVAIL_ZLIB - #define AVAIL_OGGVORBIS - #endif - - #ifdef WINRT - #define AVAIL_XAUDIO2 - #define AVAIL_WASAPI - #elif !defined(NO_DIRECTX) && !defined(NODIRECTX) && defined(_WIN32) - #define AVAIL_DINPUT - #define AVAIL_DSOUND - #define AVAIL_WASAPI - //#define AVAIL_XAUDIO2 //gcc doesn't provide any headers - #endif - #define AVAIL_XZDEC - - #if !defined(MINIMAL) && !defined(NPFTE) && !defined(NPQTV) - #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) && !defined(_XBOX) - #if !defined(_MSC_VER) || _MSC_VER > 1200 - #define HAVE_WINSSPI //built in component, checks against windows' root ca database and revocations etc. - #endif - #elif (defined(__linux__) || defined(__CYGWIN__)) && !defined(ANDROID) - #define HAVE_GNUTLS //currently disabled as it does not validate the server's certificate, beware the mitm attack. - #endif - #endif - - //#define DYNAMIC_ZLIB - //#define DYNAMIC_LIBPNG - //#define DYNAMIC_LIBJPEG - //#define LIBVORBISFILE_STATIC - //#define SPEEX_STATIC - - #if defined(_WIN32) && defined(GLQUAKE) - //#define USE_EGL - #endif - - #if defined(_MSC_VER) && !defined(BOTLIB_STATIC) //too lazy to fix up the makefile - #define BOTLIB_STATIC - #endif - - #if (defined(_MSC_VER) && (_MSC_VER < 1500)) || defined(FTE_SDL) - #undef AVAIL_WASAPI //wasapi is available in the vista sdk, while that's compatible with earlier versions, its not really expected until 2008 - #endif - - #define HAVE_TCP //says we can use tcp too (either ipv4 or ipv6) - #define HAVE_PACKET //if we have the socket api at all... - #define HAVE_MIXER //can be disabled if you have eg openal instead. - -//set any additional defines or libs in win32 - #define LOADERTHREAD - - #define PACKAGE_Q1PAK - #define PACKAGE_PK3 - #define AVAIL_GZDEC - #define PACKAGE_TEXWAD //quake's image wad support - - #ifdef GLQUAKE - #define HEADLESSQUAKE - #endif - #define AVAIL_MP3_ACM //microsoft's Audio Compression Manager api - - #ifdef NOLEGACY - //these are only the features that really make sense in a more modern engine - #define QUAKETC //skip some legacy stuff - #define SPRMODELS //quake1 sprite models - #define INTERQUAKEMODELS - #define RTLIGHTS //realtime lighting - #define Q1BSPS //quake 1 bsp support, because we're still a quake engine - #define Q2BSPS //quake 2 bsp support (a dependancy of q3bsp) - #define Q3BSPS //quake 3 bsp support -// #define TERRAIN //heightmap support - #define WEBCLIENT //http/ftp clients. - #define IMAGEFMT_DDS //a sort of image file format. - #define PSET_SCRIPT -// #define PLUGINS //qvm/dll plugins. -// #define SUPPORT_ICE //Interactive Connectivity Establishment protocol, for peer-to-peer connections - #define CSQC_DAT //support for csqc -// #define VOICECHAT - - #undef AVAIL_JPEGLIB - #undef AVAIL_XZDEC - - #elif defined(MINIMAL) - #define QUAKESTATS - #define QUAKEHUD - #define CL_MASTER //this is useful - - #undef AVAIL_JPEGLIB //no jpeg support - #undef AVAIL_PNGLIB //no png support - #undef AVAIL_OPENAL //just bloat... - #undef AVAIL_GZDEC - - #define Q1BSPS - #define SPRMODELS //quake1 sprite models - #define MD1MODELS //quake ain't much use without this - #define MD3MODELS //we DO want to use quake3 alias models. This might be a minimal build, but we still want this. - #define PLUGINS - #define NOQCDESCRIPTIONS 2 //trim space from no fteextensions.qc info - - #define PSET_CLASSIC - - //#define CSQC_DAT //support for csqc - - #ifndef SERVERONLY //don't be stupid, stupid. - #ifndef CLIENTONLY - #define CLIENTONLY - #endif - #endif - #else - #define NETPREPARSE - #define QUAKESTATS - #define QUAKEHUD - #define SVRANKING - #define USE_SQLITE - #ifdef SERVERONLY -// #define USE_MYSQL //allow mysql in dedicated servers. - #endif - #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) - #define SUBSERVERS //use subserver code. - #elif defined(__linux__) && !defined(ANDROID) && !defined(FTE_SDL) - #define SUBSERVERS //use subserver code. - #endif - - #define SIDEVIEWS 4 //enable secondary/reverse views. - -// #define DSPMODELS //doom sprites (only needs PACKAGE_DOOMWAD to generate the right wad file names) - #define SPRMODELS //quake1 sprite models - #define SP2MODELS //quake2 sprite models - #define MD1MODELS //quake1 alias models - #define MD2MODELS //quake2 alias models - #define MD3MODELS //quake3 alias models - #define MD5MODELS //doom3 models - #define ZYMOTICMODELS //zymotic skeletal models. - #define DPMMODELS //darkplaces model format (which I've never seen anyone use) -// #define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses) - #define HALFLIFEMODELS //halflife model support (experimental) - #define INTERQUAKEMODELS - #define RAGDOLL - - #define USEAREAGRID //world collision optimisation. REQUIRED for performance with xonotic. hopefully it helps a few other mods too. - #define HUFFNETWORK //huffman network compression -// #define PACKAGE_DOOMWAD //doom wad support (maps+sprites are separate) -// #define MAP_DOOM //doom map support -// #define MAP_PROC //doom3/quake4 map support - //#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet) - #define Q1BSPS //quake 1 bsp support, because we're still a quake engine - #define Q2BSPS //quake 2 bsp support - #define Q3BSPS //quake 3 bsp support - #define RFBSPS //rogue(sof+jk2o)+qfusion bsp support - #define TERRAIN //heightmap support -// #define SV_MASTER //starts up a master server - #define SVCHAT //serverside npc chatting. see sv_chat.c - #define Q2SERVER //server can run a q2 game dll and switches to q2 network and everything else. - #define Q2CLIENT //client can connect to q2 servers - #define Q3CLIENT - #define Q3SERVER - #define HEXEN2 //mostly server only, but also includes some hud+menu stuff, and effects -// #define HLCLIENT 7 //we can run HL gamecode (not protocol compatible, set to 6 or 7) -// #define HLSERVER 140 //we can run HL gamecode (not protocol compatible, set to 138 or 140) - #define NQPROT //server and client are capable of using quake1/netquake protocols. (qw is still prefered. uses the command 'nqconnect') - #define PACKAGE_DZIP //support for the dzip format, common with the speed-demos-archive site -// #define WEBSERVER //http server - #define FTPSERVER //ftp server - #define WEBCLIENT //http clients. - #define RUNTIMELIGHTING //calculate lit/lux files the first time the map is loaded and doesn't have a loadable lit. -// #define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm. - #define CL_MASTER //query master servers and stuff for a dynamic server listing. - #define R_XFLIP //allow view to be flipped horizontally - #define TEXTEDITOR - #define IMAGEFMT_KTX //Khronos TeXture. common on gles3 devices for etc2 compression - #define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool - #define IMAGEFMT_DDS //a sort of image file format. - #define IMAGEFMT_BLP //a sort of image file format. - #define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). -// #define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... - #define DECOMPRESS_RGTC //bc4+bc5 - //would be nice to have BPTC decompression too, for gl<4.2, d3d9, or d3d11_level10, but frankly its overcomplicated. I'm not going to bother with ASTC either. - #ifndef RTLIGHTS - #define RTLIGHTS //realtime lighting - #endif - //#define SHADOWDBG_COLOURNOTDEPTH //for debugging. renders shadowmaps to a colour buffer instead of a depth buffer. resulting in projected textures instead of actual shadows (the glsl only picks up the red component, but whatever) - -// #define QWOVERQ3 //allows qw servers with q3 clients. requires specific cgame. - - #define VM_Q1 //q1 qvm gamecode interface - //#define VM_LUA //q1 lua gamecode interface - - #define TCPCONNECT //a tcpconnect command, that allows the player to connect to tcp-encapsulated qw protocols. -// #define IRCCONNECT //an ircconnect command, that allows the player to connect to irc-encapsulated qw protocols... yeah, really. - - #define PLUGINS //qvm/dll plugins. - #define SUPPORT_ICE //Interactive Connectivity Establishment protocol, for peer-to-peer connections - - #define CSQC_DAT //support for csqc - #define MENU_DAT //support for menu.dat - - #define PSET_SCRIPT - #define PSET_CLASSIC - - - #define HAVE_CDPLAYER //includes cd playback. actual cds. faketracks are supported regardless. - #define HAVE_JUKEBOX //includes built-in jukebox crap - #define HAVE_MEDIA_DECODER //can play cin/roq, more with plugins - #define HAVE_MEDIA_ENCODER //capture/capturedemo work. - #define HAVE_SPEECHTOTEXT //windows speech-to-text thing - - #define VOICECHAT - -#if defined(_WIN32) && !defined(FTE_SDL) && !defined(MULTITHREAD) //always thread on win32 non-minimal builds - #define MULTITHREAD -#endif - #endif +//yup, C89 allows this (doesn't like C's token concat though). +#include STRINGIFY(CONFIG_FILE_NAME) - #ifdef QUAKETC - #define NOBUILTINMENUS //kill engine menus (should be replaced with ewither csqc or menuqc) - #undef Q2CLIENT //not useful - #undef Q2SERVER //not useful - #undef Q3CLIENT //not useful - #undef Q3SERVER //not useful - #undef HLCLIENT //not useful - #undef HLSERVER //not useful - #undef VM_Q1 //not useful - #undef VM_LUA //not useful - #undef HALFLIFEMODELS //yuck - #undef RUNTIMELIGHTING //presumably not useful - #undef HEXEN2 - #endif - -#endif - - - #ifndef MSVCLIBSPATH +#ifndef MSVCLIBSPATH #ifdef MSVCLIBPATH #define MSVCLIBSPATH STRINGIFY(MSVCLIBPATH) #elif _MSC_VER == 1200 @@ -356,16 +112,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #else #define MSVCLIBSPATH "../libs/" #endif - #endif +#endif #if defined(SERVERONLY) && defined(CLIENTONLY) #undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server #endif -#ifndef CLIENTONLY - #define HAVE_SERVER -#endif -#ifndef SERVERONLY - #define HAVE_CLIENT +#ifndef WEBSVONLY + #ifndef CLIENTONLY + #define HAVE_SERVER + #endif + #ifndef SERVERONLY + #define HAVE_CLIENT + #endif #endif #ifndef HAVE_SERVER @@ -796,8 +554,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define IFMINIMAL(x,y) y #endif -//#define PRE_SAYONE 2.487 //FIXME: remove. - // defs common to client and server #ifndef PLATFORM @@ -863,30 +619,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ARCH_DL_POSTFIX ".so" #endif -#if defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) - #ifdef __ILP32__ - #define ARCH_CPU_POSTFIX "x32" //32bit pointers, with 16 registers. - #else - #ifdef _WIN32 - #define ARCH_CPU_POSTFIX "x64" +#ifndef ARCH_CPU_POSTFIX + #if defined(_M_AMD64) || defined(__amd64__) || defined(__x86_64__) + #ifdef __ILP32__ + #define ARCH_CPU_POSTFIX "x32" //32bit pointers, with 16 registers. #else - #define ARCH_CPU_POSTFIX "amd64" + #ifdef _WIN32 + #define ARCH_CPU_POSTFIX "x64" + #else + #define ARCH_CPU_POSTFIX "amd64" + #endif + #endif + #elif defined(_M_IX86) || defined(__i386__) + #define ARCH_CPU_POSTFIX "x86" + #elif defined(__powerpc__) || defined(__ppc__) + #define ARCH_CPU_POSTFIX "ppc" + #elif defined(__aarch64__) + #define ARCH_CPU_POSTFIX "arm64" + #elif defined(__arm__) + #ifdef __SOFTFP__ + #define ARCH_CPU_POSTFIX "arm" + #else + #define ARCH_CPU_POSTFIX "armhf" #endif - #endif -#elif defined(_M_IX86) || defined(__i386__) - #define ARCH_CPU_POSTFIX "x86" -#elif defined(__powerpc__) || defined(__ppc__) - #define ARCH_CPU_POSTFIX "ppc" -#elif defined(__aarch64__) - #define ARCH_CPU_POSTFIX "arm64" -#elif defined(__arm__) - #ifdef __SOFTFP__ - #define ARCH_CPU_POSTFIX "arm" #else - #define ARCH_CPU_POSTFIX "armhf" + #define ARCH_CPU_POSTFIX "unk" #endif -#else - #define ARCH_CPU_POSTFIX "unk" #endif #ifdef _MSC_VER diff --git a/engine/common/cmd.c b/engine/common/cmd.c index c7fe1d146..3d7ea285c 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -45,9 +45,9 @@ typedef struct cmdalias_s { struct cmdalias_s *next; char *value; + int flags; qbyte execlevel; qbyte restriction; - int flags; char name[1]; } cmdalias_t; @@ -4044,11 +4044,12 @@ static void Cmd_Reset_f(void) // dumps current console contents to a text file static void Cmd_Condump_f(void) { + console_t *c = Con_GetMain(); vfsfile_t *f; char *filename; char line[8192]; - if (!con_current) + if (!c) { Con_Printf ("No console to dump.\n"); return; @@ -4074,13 +4075,12 @@ static void Cmd_Condump_f(void) // print out current contents of console // stripping out starting blank lines and blank spaces { - console_t *curcon = &con_main; conline_t *l; conchar_t *t; - for (l = curcon->oldest; l; l = l->newer) + for (l = c->oldest; l; l = l->newer) { t = (conchar_t*)(l+1); - COM_DeFunString(t, t + l->length, line, sizeof(line), true, !!(curcon->parseflags & PFS_FORCEUTF8)); + COM_DeFunString(t, t + l->length, line, sizeof(line), true, !!(c->parseflags & PFS_FORCEUTF8)); VFS_WRITE(f, line, strlen(line)); VFS_WRITE(f, "\n", 1); } diff --git a/engine/common/cmd.h b/engine/common/cmd.h index 4d086b1bb..6f347fdba 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -148,6 +148,7 @@ char *Cmd_AliasExist(const char *name, int restrictionlevel); void Alias_WipeStuffedAliases(void); void Cmd_AddMacro(char *s, char *(*f)(void), int disputableintentions); +#define Cmd_AddMacroD(s,f,unsafe,desc) Cmd_AddMacro(s,f,unsafe) void Cmd_TokenizePunctation (char *text, char *punctuation); const char *Cmd_TokenizeString (const char *text, qboolean expandmacros, qboolean qctokenize); diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 835939ee5..c2842864a 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -33,7 +33,7 @@ cvar_t r_meshpitch = CVARCD ("r_meshpitch", "1", r_meshpitch_callback, "Sp cvar_t r_meshpitch = CVARCD ("r_meshpitch", "-1", r_meshpitch_callback, "Specifies the direction of the pitch angle on mesh models formats, Quake compatibility requires -1."); #endif -#ifndef SERVERONLY +#ifdef HAVE_CLIENT static void Mod_UpdateCRC(void *ctx, void *data, size_t a, size_t b) { char st[40]; @@ -50,7 +50,7 @@ static void Mod_UpdateCRC(void *ctx, void *data, size_t a, size_t b) //Common loader function. void Mod_DoCRC(model_t *mod, char *buffer, int buffersize) { -#ifndef SERVERONLY +#ifdef HAVE_CLIENT //we've got to have this bit if (mod->engineflags & MDLF_DOCRC) { @@ -78,7 +78,7 @@ extern cvar_t r_skin_overlays; extern cvar_t mod_md3flags; - +#ifdef HAVE_CLIENT typedef struct { char *name; @@ -88,7 +88,7 @@ typedef struct //these should be rounded up slightly. //really this is only to catch spiked models. This doesn't prevent more visible models, just bigger ones. -clampedmodel_t clampedmodel[] = { +static clampedmodel_t clampedmodel[] = { {"maps/b_bh100.bsp", 3440}, {"progs/player.mdl", 22497}, {"progs/eyes.mdl", 755}, @@ -129,7 +129,7 @@ clampedmodel_t clampedmodel[] = { {"progs/turrbase.mdl", 3000}, {"progs/turrgun.mdl", 3000} }; - +#endif @@ -240,7 +240,7 @@ void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, qboolea #ifdef SKELETALMODELS /*like above, but guess the quat.w*/ -static void GenMatrixPosQuat3Scale(vec3_t pos, vec3_t quat3, vec3_t scale, float result[12]) +static void GenMatrixPosQuat3Scale(vec3_t const pos, vec3_t const quat3, vec3_t const scale, float result[12]) { vec4_t quat4; float term = 1 - DotProduct(quat3, quat3); @@ -581,7 +581,7 @@ static const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *so for (i = 0; i < bonecount; i++) { if (bones[i].parent >= 0) - R_ConcatTransforms((void*)(dest + bones[i].parent*12), (void*)(sourcedata+i*12), (void*)(dest+i*12)); + R_ConcatTransforms((void*)(dest + bones[i].parent*12), (const void*)(sourcedata+i*12), (void*)(dest+i*12)); else { Vector4Copy(sourcedata+i*12+0, dest+i*12+0); @@ -605,7 +605,7 @@ static const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *so for (i = 0; i < bonecount; i++) { Matrix3x4_Invert_Simple(bones[i].inverse, iim); - R_ConcatTransforms((void*)(sourcedata + i*12), (void*)iim, (void*)(dest + i*12)); + R_ConcatTransforms((const void*)(sourcedata + i*12), (const void*)iim, (void*)(dest + i*12)); } sourcedata = dest; sourcetype = SKEL_ABSOLUTE; @@ -623,7 +623,7 @@ static const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *so if (bones[i].parent >= 0) { Matrix3x4_Invert_Simple(sourcedata+bones[i].parent*12, ip); - R_ConcatTransforms((void*)ip, (void*)(sourcedata+i*12), (void*)(dest+i*12)); + R_ConcatTransforms((void*)ip, (const void*)(sourcedata+i*12), (void*)(dest+i*12)); } else { @@ -644,7 +644,7 @@ static const float *Alias_ConvertBoneData(skeltype_t sourcetype, const float *so { float *dest = (sourcedata == destbuffer)?destbufferalt:destbuffer; for (i = 0; i < bonecount; i++) - R_ConcatTransforms((void*)(sourcedata + i*12), (void*)(bones[i].inverse), (void*)(dest + i*12)); + R_ConcatTransforms((const void*)(sourcedata + i*12), (void*)(bones[i].inverse), (void*)(dest + i*12)); sourcedata = dest; sourcetype = SKEL_INVERSE_ABSOLUTE; } @@ -1002,9 +1002,9 @@ typedef struct skeltype_t skeltype; //the skeletal type of this bone block. all blocks should have the same result or the whole thing is unusable or whatever. int firstbone; //first bone of interest int endbone; //the first bone of the next group (ie: if first is 0, this is the count) + int lerpcount; //number of pose+frac entries. float frac[FRAME_BLENDS*2]; //weight of this animation (1 if lerpcount is 1) float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0. - int lerpcount; //number of pose+frac entries. } skellerps_t; static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, struct framestateregion_s *fs, int numbones, galiasinfo_t *inf) { @@ -1470,7 +1470,7 @@ static void Alias_BuildGPUWeights(model_t *mod, galiasinfo_t *inf, size_t num_tr #endif #ifndef SERVERONLY -static void Alias_DrawSkeletalBones(galiasbone_t *bones, float *bonepose, int bonecount, int basebone) +static void Alias_DrawSkeletalBones(galiasbone_t *bones, float const*bonepose, int bonecount, int basebone) { scenetris_t *t; int flags = BEF_NODLIGHT|BEF_NOSHADOWS|BEF_LINES; @@ -1788,7 +1788,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); #ifndef SERVERONLY if (inf->shares_bones != surfnum && qrenderer) - Alias_DrawSkeletalBones(inf->ofsbones, (float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone); + Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone); #endif } } @@ -3104,7 +3104,7 @@ static void Q1MDL_LoadPose(galiasinfo_t *galias, dmdl_t *pq1inmodel, vecV_t *ver } } } -static void Q1MDL_LoadPose16(galiasinfo_t *galias, dmdl_t *pq1inmodel, vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype) +static void Q1MDL_LoadPoseQF16(galiasinfo_t *galias, dmdl_t *pq1inmodel, vecV_t *verts, vec3_t *normals, vec3_t *svec, vec3_t *tvec, dtrivertx_t *pinframe, int *seamremaps, int mdltype) { //quakeforge's MD16 format has regular 8bit stuff, trailed by an extra low-order set of the verts providing the extra 8bits of precision. //its worth noting that the model could be rendered using the high-order parts only, if your software renderer only supports that or whatever. @@ -3186,24 +3186,24 @@ static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, mod if (mdltype & 16) { - Q1MDL_LoadPose16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype); + Q1MDL_LoadPoseQF16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype); pframetype = (daliasframetype_t *)&pinframe[pq1inmodel->numverts*2]; } else { Q1MDL_LoadPose(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype, bbox); pframetype = (daliasframetype_t *)&pinframe[pq1inmodel->numverts]; - } #ifdef _DEBUG - if ((bbox[3] > frameinfo->bboxmax.v[0] || bbox[4] > frameinfo->bboxmax.v[1] || bbox[5] > frameinfo->bboxmax.v[2] || - bbox[0] < frameinfo->bboxmin.v[0] || bbox[1] < frameinfo->bboxmin.v[1] || bbox[2] < frameinfo->bboxmin.v[2]) && !galias->warned) + if ((bbox[3] > frameinfo->bboxmax.v[0] || bbox[4] > frameinfo->bboxmax.v[1] || bbox[5] > frameinfo->bboxmax.v[2] || + bbox[0] < frameinfo->bboxmin.v[0] || bbox[1] < frameinfo->bboxmin.v[1] || bbox[2] < frameinfo->bboxmin.v[2]) && !galias->warned) #else - if (galias->numverts && pinframe[0].v[2] > frameinfo->bboxmax.v[2] && !galias->warned) + if (galias->numverts && pinframe[0].v[2] > frameinfo->bboxmax.v[2] && !galias->warned) #endif - { - Con_DPrintf(CON_WARNING"%s has incorrect frame bounds\n", loadmodel->name); - galias->warned = true; + { + Con_DPrintf(CON_WARNING"%s has incorrect frame bounds\n", loadmodel->name); + galias->warned = true; + } } @@ -3260,26 +3260,26 @@ static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, mod if (mdltype & 16) { - Q1MDL_LoadPose16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype); + Q1MDL_LoadPoseQF16(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype); pinframe += pq1inmodel->numverts*2; } else { Q1MDL_LoadPose(galias, pq1inmodel, verts, normals, svec, tvec, pinframe, seamremaps, mdltype, bbox); pinframe += pq1inmodel->numverts; - } #ifdef _DEBUG - if ((bbox[3] > frameinfo->bboxmax.v[0] || bbox[4] > frameinfo->bboxmax.v[1] || bbox[5] > frameinfo->bboxmax.v[2] || - bbox[0] < frameinfo->bboxmin.v[0] || bbox[1] < frameinfo->bboxmin.v[1] || bbox[2] < frameinfo->bboxmin.v[2] || + if ((bbox[3] > frameinfo->bboxmax.v[0] || bbox[4] > frameinfo->bboxmax.v[1] || bbox[5] > frameinfo->bboxmax.v[2] || + bbox[0] < frameinfo->bboxmin.v[0] || bbox[1] < frameinfo->bboxmin.v[1] || bbox[2] < frameinfo->bboxmin.v[2] || #else - if (galias->numverts && (pinframe[0].v[2] > frameinfo->bboxmax.v[2] || + if (galias->numverts && (pinframe[0].v[2] > frameinfo->bboxmax.v[2] || #endif - frameinfo->bboxmin.v[0] < ingroup->bboxmin.v[0] || frameinfo->bboxmin.v[1] < ingroup->bboxmin.v[1] || frameinfo->bboxmin.v[2] < ingroup->bboxmin.v[2] || - frameinfo->bboxmax.v[0] > ingroup->bboxmax.v[0] || frameinfo->bboxmax.v[1] > ingroup->bboxmax.v[1] || frameinfo->bboxmax.v[2] > ingroup->bboxmax.v[2]) && !galias->warned) - { - Con_DPrintf(CON_WARNING"%s has incorrect frame bounds\n", loadmodel->name); - galias->warned = true; + frameinfo->bboxmin.v[0] < ingroup->bboxmin.v[0] || frameinfo->bboxmin.v[1] < ingroup->bboxmin.v[1] || frameinfo->bboxmin.v[2] < ingroup->bboxmin.v[2] || + frameinfo->bboxmax.v[0] > ingroup->bboxmax.v[0] || frameinfo->bboxmax.v[1] > ingroup->bboxmax.v[1] || frameinfo->bboxmax.v[2] > ingroup->bboxmax.v[2]) && !galias->warned) + { + Con_DPrintf(CON_WARNING"%s has incorrect frame bounds\n", loadmodel->name); + galias->warned = true; + } } #ifndef SERVERONLY @@ -6899,7 +6899,7 @@ galisskeletaltransforms_t *IQM_ImportTransforms(int *resultcount, int inverts, f } */ -static qboolean IQM_ImportArray4B(const qbyte *base, const struct iqmvertexarray *src, byte_vec4_t *out, size_t count, unsigned int maxval) +static qboolean IQM_ImportArray4B(const qbyte *fte_restrict base, const struct iqmvertexarray *fte_restrict src, byte_vec4_t *fte_restrict out, size_t count, unsigned int maxval) { size_t i; unsigned int j; @@ -6922,7 +6922,7 @@ static qboolean IQM_ImportArray4B(const qbyte *base, const struct iqmvertexarray case IQM_BYTE: //FIXME: should be signed, but this makes no sense for our uses case IQM_UBYTE: { - qbyte *in = (qbyte*)(base+offset); + const qbyte *in = (const qbyte*)(base+offset); /*if (sz == 4) memcpy(out, in, count * sizeof(*out)); //the fast path. else*/ for (i = 0; i < count; i++) @@ -6943,7 +6943,7 @@ static qboolean IQM_ImportArray4B(const qbyte *base, const struct iqmvertexarray case IQM_SHORT://FIXME: should be signed, but this makes no sense for our uses case IQM_USHORT: { - unsigned short *in = (unsigned short*)(base+offset); + const unsigned short *in = (const unsigned short*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < 4 && j < sz; j++) @@ -6962,7 +6962,7 @@ static qboolean IQM_ImportArray4B(const qbyte *base, const struct iqmvertexarray case IQM_INT://FIXME: should be signed, but this makes no sense for our uses case IQM_UINT: { - unsigned int *in = (unsigned int*)(base+offset); + const unsigned int *in = (const unsigned int*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < 4 && j < sz; j++) @@ -6993,7 +6993,7 @@ static qboolean IQM_ImportArray4B(const qbyte *base, const struct iqmvertexarray return !invalid; } -static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src, float *out, size_t e, size_t count, float *def) +static void IQM_ImportArrayF(const qbyte *fte_restrict base, const struct iqmvertexarray *fte_restrict src, float *fte_restrict out, size_t e, size_t count, float *def) { size_t i; unsigned int j; @@ -7012,7 +7012,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_BYTE: //negatives not handled properly { - signed char *in = (signed char*)(base+offset); + const signed char *in = (const signed char*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7022,7 +7022,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_UBYTE: { - qbyte *in = (qbyte*)(base+offset); + const qbyte *in = (const qbyte*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7032,7 +7032,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_SHORT: //negatives not handled properly { - signed short *in = (signed short*)(base+offset); + const signed short *in = (const signed short*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7042,7 +7042,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_USHORT: { - unsigned short *in = (unsigned short*)(base+offset); + const unsigned short *in = (const unsigned short*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7052,7 +7052,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_INT: //negatives not handled properly { - signed int *in = (signed int*)(base+offset); + const signed int *in = (const signed int*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7062,7 +7062,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_UINT: { - unsigned int *in = (unsigned int*)(base+offset); + const unsigned int *in = (const unsigned int*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7074,7 +7074,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src case IQM_HALF: #ifdef __F16C__ { //x86 intrinsics - unsigned short *in = (qbyte*)(base+offset); + const unsigned short *in = (const qbyte*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7083,7 +7083,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src } #elif 0 { - _Float16 *in = (qbyte*)(base+offset); + const _Float16 *in = (const _Float16*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7096,7 +7096,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_FLOAT: { - float *in = (float*)(base+offset); + const float *in = (const float*)(base+offset); if (e == sz) memcpy(out, in, e * sizeof(float) * count); else for (i = 0; i < count; i++) @@ -7108,7 +7108,7 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src break; case IQM_DOUBLE: { - double *in = (double*)(base+offset); + const double *in = (const double*)(base+offset); for (i = 0; i < count; i++) { for (j = 0; j < e && j < sz; j++) @@ -7131,13 +7131,13 @@ static void IQM_ImportArrayF(const qbyte *base, const struct iqmvertexarray *src static const void *IQM_FindExtension(const char *buffer, size_t buffersize, const char *extname, int index, size_t *extsize) { - struct iqmheader *h = (struct iqmheader *)buffer; + const struct iqmheader *h = (const struct iqmheader *)buffer; const char *strings = buffer + h->ofs_text; - struct iqmextension *ext; + const struct iqmextension *ext; int i; - for (i = 0, ext = (struct iqmextension*)(buffer + h->ofs_extensions); i < h->num_extensions; i++, ext = (struct iqmextension*)(buffer + ext->ofs_extensions)) + for (i = 0, ext = (const struct iqmextension*)(buffer + h->ofs_extensions); i < h->num_extensions; i++, ext = (const struct iqmextension*)(buffer + ext->ofs_extensions)) { - if ((char*)ext > buffer+buffersize || ext->name > h->num_text || ext->ofs_data+ext->num_data>buffersize) + if ((const char*)ext > buffer+buffersize || ext->name > h->num_text || ext->ofs_data+ext->num_data>buffersize) break; if (!Q_strcasecmp(strings + ext->name, extname) && index-->=0) { @@ -7185,7 +7185,7 @@ static void Mod_CleanWeights(const char *modelname, size_t numverts, vec4_t *owe static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, size_t fsize) { - const struct iqmheader *h = (struct iqmheader *)buffer; + const struct iqmheader *h = (const struct iqmheader *)buffer; const struct iqmmesh *mesh; const struct iqmvertexarray *varray; const struct iqmtriangle *tris; @@ -7197,15 +7197,15 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz unsigned int i, j, t, numtris, numverts, firstvert, firsttri; size_t extsize; - float *vtang = NULL; + const float *vtang = NULL; struct iqmvertexarray vpos = {0}, vnorm = {0}, vtcoord = {0}, vbone = {0}, vweight = {0}, vrgba = {0}; unsigned int type, fmt, size, offset; - unsigned short *framedata; + const unsigned short *framedata; vec4_t defaultcolour = {1,1,1,1}; vec4_t defaultweight = {0,0,0,0}; vec4_t defaultvert = {0,0,0,1}; - struct iqmbounds *inbounds; + const struct iqmbounds *inbounds; int memsize; qbyte *obase=NULL; @@ -7249,7 +7249,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz return NULL; } - varray = (struct iqmvertexarray*)(buffer + h->ofs_vertexarrays); + varray = (const struct iqmvertexarray*)(buffer + h->ofs_vertexarrays); for (i = 0; i < h->num_vertexarrays; i++) { type = LittleLong(varray[i].type); @@ -7263,7 +7263,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz else if (type == IQM_NORMAL) vnorm = varray[i]; else if (type == IQM_TANGENT && fmt == IQM_FLOAT && size == 4) /*yup, 4, extra is side, for the bitangent*/ - vtang = (float*)(buffer + offset); + vtang = (const float*)(buffer + offset); else if (type == IQM_BLENDINDEXES) vbone = varray[i]; else if (type == IQM_BLENDWEIGHTS) @@ -7340,7 +7340,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz numgroups = h->num_anims; framegroups = malloc(sizeof(*framegroups)*numgroups); - anim = (struct iqmanim*)(buffer + h->ofs_anims); + anim = (const struct iqmanim*)(buffer + h->ofs_anims); for (i = 0; i < numgroups; i++) { framegroups[i].firstpose = LittleLong(anim[i].first_frame); @@ -7363,7 +7363,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz strcpy(framegroups->name, "base"); } - mesh = (struct iqmmesh*)(buffer + h->ofs_meshes); + mesh = (const struct iqmmesh*)(buffer + h->ofs_meshes); #ifndef SERVERONLY skinfiles = Mod_CountSkinFiles(mod); @@ -7414,13 +7414,13 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz #undef dalloc //no code to load animations or bones - framedata = (unsigned short*)(buffer + h->ofs_frames); + framedata = (const unsigned short*)(buffer + h->ofs_frames); /*Version 1 supports only normalized quaternions, version 2 uses complete quaternions. Some struct sizes change for this, otherwise functionally identical.*/ if (h->version == IQM_VERSION1) { - struct iqmpose1 *p, *ipose = (struct iqmpose1*)(buffer + h->ofs_poses); - struct iqmjoint1 *ijoint = (struct iqmjoint1*)(buffer + h->ofs_joints); + const struct iqmpose1 *p, *ipose = (const struct iqmpose1*)(buffer + h->ofs_poses); + const struct iqmjoint1 *ijoint = (const struct iqmjoint1*)(buffer + h->ofs_joints); vec3_t pos; vec4_t quat; vec3_t scale; @@ -7464,8 +7464,8 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz } else { - struct iqmpose2 *p, *ipose = (struct iqmpose2*)(buffer + h->ofs_poses); - struct iqmjoint2 *ijoint = (struct iqmjoint2*)(buffer + h->ofs_joints); + const struct iqmpose2 *p, *ipose = (const struct iqmpose2*)(buffer + h->ofs_poses); + const struct iqmjoint2 *ijoint = (const struct iqmjoint2*)(buffer + h->ofs_joints); vec3_t pos; vec4_t quat; vec3_t scale; @@ -7564,7 +7564,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz } //determine the bounds - inbounds = (struct iqmbounds*)(buffer + h->ofs_bounds); + inbounds = (const struct iqmbounds*)(buffer + h->ofs_bounds); if (h->ofs_bounds) { for (i = 0; i < h->num_frames; i++) @@ -7642,7 +7642,7 @@ static galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, const char *buffer, siz } #endif - tris = (struct iqmtriangle*)(buffer + LittleLong(h->ofs_triangles)); + tris = (const struct iqmtriangle*)(buffer + LittleLong(h->ofs_triangles)); tris += firsttri; gai[i].numindexes = numtris*3; idx = ZG_Malloc(&mod->memgroup, sizeof(*idx)*gai[i].numindexes); diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 027fc05c3..51220cccf 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -218,7 +218,7 @@ typedef struct modplugfuncs_s void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, int size); //ctx=&mod->memgroup and the data will be freed when the model is freed. - void (QDECL *ConcatTransforms) (float in1[3][4], float in2[3][4], float out[3][4]); + void (QDECL *ConcatTransforms) (const float in1[3][4], const float in2[3][4], float out[3][4]); void (QDECL *M3x4_Invert) (const float *in1, float *out); void (QDECL *VectorAngles)(float *forward, float *up, float *result, qboolean meshpitch); void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); diff --git a/engine/common/common.c b/engine/common/common.c index e1f2dd80c..c59c6bedc 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -84,7 +84,7 @@ glibc SUCKS. 64bit glibc is depending upon glibc 2.14 because of some implementa or something. anyway, the actual interface is the same. the old version might be slower, but when updating glibc generally results in also installing systemd, requiring the new version is NOT an option. */ -#if defined(__GNUC__) && defined(__LP64__) && defined(__linux__) && !defined(FTE_SDL) +#if defined(__GNUC__) && defined(__amd64__) && defined(__linux__) && !defined(FTE_SDL) #include /* for glibc version */ #if defined(__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 14) __asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); @@ -4790,7 +4790,7 @@ static void COM_Version_f (void) { Con_Printf("\n"); Con_Printf("^&F0%s\n", FULLENGINENAME); - Con_Printf("%s\n", ENGINEWEBSITE); + Con_Printf("^[%s\\url\\%s^]\n", ENGINEWEBSITE, ENGINEWEBSITE); Con_Printf("%s\n", version_string()); Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__); @@ -4799,7 +4799,7 @@ static void COM_Version_f (void) Con_Printf("SVN Revision: %s\n",STRINGIFY(SVNREVISION)); #endif #ifdef CONFIG_FILE_NAME - Con_Printf("Build config: %s\n\n", STRINGIFY(CONFIG_FILE_NAME)); + Con_Printf("Build config: %s\n\n", COM_SkipPath(STRINGIFY(CONFIG_FILE_NAME))); #endif #ifdef _DEBUG @@ -5150,8 +5150,8 @@ static void COM_ErrorMe_f(void) #ifdef LOADERTHREAD static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue); cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread."); -cvar_t worker_count = CVARFCD("worker_count", "", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise."); -cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSERVER, "Causes workers to sleep for a period of time after each job."); +static cvar_t worker_count = CVARFCD("worker_count", "", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise."); +static cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSERVER, "Causes workers to sleep for a period of time after each job."); #define WORKERTHREADS 16 //max /*multithreading worker thread stuff*/ @@ -6429,7 +6429,7 @@ static qboolean InfoBuf_EncodeString_Internal(const char *n, size_t s, char *out for (c = n; c < n+s; c++) { - base64_cur |= *(unsigned char*)c<<(16- base64_bits);//first byte fills highest bits + base64_cur |= *(const unsigned char*)c<<(16- base64_bits);//first byte fills highest bits base64_bits += 8; if (base64_bits == 24) diff --git a/engine/common/common.h b/engine/common/common.h index e070f4c70..86a2d8966 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -164,13 +164,13 @@ typedef struct sizebuf_s { qboolean allowoverflow; // if false, do a Sys_Error qboolean overflowed; // set to true if the buffer size failed - qbyte *data; - int maxsize; - int cursize; - int packing; - int currentbit; + qbyte *data; + int maxsize; //storage size of data + int cursize; //assigned size of data + sbpacking_t packing; //required for q3 + int currentbit; //ignored for rawbytes - struct netprim_s prim; + struct netprim_s prim; //for unsized write/read coord/angles } sizebuf_t; void SZ_Clear (sizebuf_t *buf); @@ -851,8 +851,10 @@ void Con_Log (const char *s); void Log_Logfile_f (void); void Log_Init(void); void Log_ShutDown(void); +#ifdef IPLOG void IPLog_Add(const char *ip, const char *name); //for associating player ip addresses with names. qboolean IPLog_Merge_File(const char *fname); +#endif qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize); diff --git a/engine/common/config_freecs.h b/engine/common/config_freecs.h index 608deb1be..6033bd55c 100644 --- a/engine/common/config_freecs.h +++ b/engine/common/config_freecs.h @@ -104,6 +104,8 @@ #undef IMAGEFMT_PKM #undef IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load. #undef IMAGEFMT_BLP //legacy crap +#undef IMAGEFMT_BMP //legacy crap +#undef IMAGEFMT_PCX //legacy crap #undef DECOMPRESS_ETC2 #undef DECOMPRESS_RGTC #undef DECOMPRESS_S3TC diff --git a/engine/common/config_fteqw.h b/engine/common/config_fteqw.h index 7631d0c56..0ebdb2a8a 100644 --- a/engine/common/config_fteqw.h +++ b/engine/common/config_fteqw.h @@ -48,6 +48,7 @@ #define TEXTEDITOR //my funky text editor! its awesome! #define PLUGINS //support for external plugins (like huds or fancy menus or whatever) #define USE_SQLITE //sql-database-as-file support +#define IPLOG //track player's ip addresses (any decent server will hide ip addresses, so this probably isn't that useful, but nq players expect its) //Filesystem formats #define PACKAGE_PK3 @@ -87,9 +88,11 @@ #define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool. doesn't support mips. #define IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load. #define IMAGEFMT_BLP //legacy crap -#define PACKAGE_TEXWAD //quake's image wad support +#define IMAGEFMT_BMP //windows bmp. yuck. +#define IMAGEFMT_PCX //paletted junk. required for qw player skins, q2 and a few old skyboxes. #define AVAIL_PNGLIB //.png image format support (read+screenshots) #define AVAIL_JPEGLIB //.jpeg image format support (read+screenshots) +#define PACKAGE_TEXWAD //quake's image wad support #define AVAIL_FREETYPE //for truetype font rendering #define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). #define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... diff --git a/engine/common/config_minimal.h b/engine/common/config_minimal.h index b3618679a..e6981e467 100644 --- a/engine/common/config_minimal.h +++ b/engine/common/config_minimal.h @@ -89,13 +89,15 @@ //#define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool. doesn't support mips. //#define IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load. //#define IMAGEFMT_BLP //legacy crap -#define PACKAGE_TEXWAD //quake's image wad support +//#define IMAGEFMT_BMP //windows bmp. yuck. +//#define IMAGEFMT_PCX //paletted junk. required for qw player skins, q2 and a few old skyboxes. #define AVAIL_PNGLIB //.png image format support (read+screenshots) //#define AVAIL_JPEGLIB //.jpeg image format support (read+screenshots) -//#define AVAIL_FREETYPE //for truetype font rendering -//#define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). -////#define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... -//#define DECOMPRESS_RGTC //bc4+bc5 +#define PACKAGE_TEXWAD //quake's image wad support +//#define AVAIL_FREETYPE //for truetype font rendering +//#define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). +////#define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... +//#define DECOMPRESS_RGTC //bc4+bc5 // Game/Gamecode Support //#define CSQC_DAT diff --git a/engine/common/config_nocompat.h b/engine/common/config_nocompat.h index bc31d97d5..afbc27794 100644 --- a/engine/common/config_nocompat.h +++ b/engine/common/config_nocompat.h @@ -1,5 +1,5 @@ -// Build-Config file for FTE's standard builds, the default settings. -// to use: make FTE_CONFIG=fteqw +// Build-Config file for Quake-derived total-conversion mods that have chosen to break compatibility. +// to use: make FTE_CONFIG=nocompat // Features should either be commented or not. If you change undefs to defines or vice versa then expect problems. // Later code will disable any features if they're not supported on the current platform, so don't worry about win/lin/mac/android/web/etc here - any such issues should be fixed elsewhere. @@ -86,12 +86,14 @@ //#define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool. doesn't support mips. #define IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load. //#define IMAGEFMT_BLP //legacy crap -//#define PACKAGE_TEXWAD //quake's image wad support +//#define IMAGEFMT_BMP //windows bmp. yuck. +//#define IMAGEFMT_PCX //paletted junk. required for qw player skins, q2 and a few old skyboxes. #define AVAIL_PNGLIB //.png image format support (read+screenshots) //#define AVAIL_JPEGLIB //.jpeg image format support (read+screenshots) +//#define PACKAGE_TEXWAD //quake's image wad support #define AVAIL_FREETYPE //for truetype font rendering #define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan). -//#define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... +//#define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet... #define DECOMPRESS_RGTC //bc4+bc5 // Game/Gamecode Support diff --git a/engine/common/config_wastes.h b/engine/common/config_wastes.h index 47b6e50b6..7425456ac 100644 --- a/engine/common/config_wastes.h +++ b/engine/common/config_wastes.h @@ -112,6 +112,8 @@ #undef IMAGEFMT_KTX #undef IMAGEFMT_PKM #undef IMAGEFMT_BLP //legacy crap +#undef IMAGEFMT_BMP //legacy crap +#undef IMAGEFMT_PCX //legacy crap #undef NETPREPARSE //allows for running both nq+qw on the same server (if not, protocol used must match gamecode). #undef USE_SQLITE //sql-database-as-file support #undef QUAKESTATS //defines STAT_HEALTH etc. if omitted, you'll need to provide that functionality yourself. diff --git a/engine/common/console.h b/engine/common/console.h index 5b9431196..19e7c40d9 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -200,10 +200,11 @@ typedef struct console_s struct console_s *next; } console_t; -extern console_t con_main; +extern console_t *con_head; extern console_t *con_curwindow; // refers to a windowed console extern console_t *con_current; // point to either con_main or con_chat extern console_t *con_mouseover; + extern console_t *con_chat; //shared between console and keys. @@ -260,6 +261,7 @@ void Con_SetActive (console_t *con); qboolean Con_NameForNum(int num, char *buffer, int buffersize); console_t *Con_FindConsole(const char *name); console_t *Con_Create(const char *name, unsigned int flags); +console_t *Con_GetMain(void); //retrieves the main console (creating it if needed) void Con_PrintCon (console_t *con, const char *txt, unsigned int parseflags); qboolean Con_InsertConChars (console_t *con, conline_t *line, int offset, conchar_t *c, int len); conline_t *Con_ResizeLineBuffer(console_t *con, conline_t *old, unsigned int length); diff --git a/engine/common/fs.c b/engine/common/fs.c index cbb855521..09f44095f 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -3066,7 +3066,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) /*quake requires a few settings for compatibility*/ #define EZQUAKECOMPETITIVE "set ruleset_allow_fbmodels 1\nset sv_demoExtensions \"\"\n" #define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8" -#define QCFG "set com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT +#define QCFG "set con_stayhidden 0\nset com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT /*NetQuake reconfiguration, to make certain people feel more at home...*/ #define NQCFG "//-nohome\ncfg_save_auto 1\n" QCFG "sv_nqplayerphysics 1\ncl_loopbackprotocol auto\ncl_sbar 1\nplug_sbar 0\nsv_port "STRINGIFY(PORT_NQSERVER)"\ncl_defaultport "STRINGIFY(PORT_NQSERVER)"\n" //nehahra has to be weird with its extra cvars, and buggy fullbrights. diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index dceffe28b..a9be3e132 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -5,13 +5,13 @@ #if !defined(NACL) && !defined(FTE_TARGET_WEB) #ifdef WEBSVONLY -#define Z_Free free -#define Z_Malloc malloc + #define Z_Free free + #define Z_Malloc malloc #else -#if !defined(_WIN32) || defined(FTE_SDL) || defined(WINRT) || defined(_XBOX) -#define FSSTDIO_OpenPath VFSOS_OpenPath -#endif -#define FSSTDIO_OpenTemp FS_OpenTemp + #if !defined(_WIN32) || defined(FTE_SDL) || defined(WINRT) || defined(_XBOX) + #define FSSTDIO_OpenPath VFSOS_OpenPath + #endif + #define FSSTDIO_OpenTemp FS_OpenTemp #endif typedef struct { @@ -148,7 +148,7 @@ vfsfile_t *FSSTDIO_OpenTemp(void) vfsfile_t *Sys_OpenAsset(const char *fname); #endif -static vfsfile_t *VFSSTDIO_Open(const char *osname, const char *mode, qboolean *needsflush) +vfsfile_t *VFSSTDIO_Open(const char *osname, const char *mode, qboolean *needsflush) { FILE *f; vfsstdiofile_t *file; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index e02a9b22d..e9e77a3f3 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -254,18 +254,24 @@ typedef struct q2cbrushside_t *brushside; } q2cbrush_t; +#ifdef Q2BSPS typedef struct { int numareaportals; int firstareaportal; - int floodnum; // if two areas have equal floodnums, they are connected - int floodvalid; } q2carea_t; - +#endif +#ifdef Q3BSPS typedef struct { int numareaportals[MAX_CM_AREAS]; } q3carea_t; +#endif +typedef struct +{ + int floodnum; // if two areas have equal floodnums, they are connected + int floodvalid; // flags the area as having been visited (sequence numbers matching prv->floodvalid) +} careaflood_t; typedef struct { @@ -353,10 +359,22 @@ typedef struct cminfo_s q3dvis_t *q3phs; int numareas; - q2carea_t q2areas[MAX_Q2MAP_AREAS]; + int floodvalid; + careaflood_t areaflood[MAX_CM_AREAS]; +#ifdef Q3BSPS + //q3's areas are simple bidirectional area1/area2 pairs. refcounted (so two areas can have two doors/openings) q3carea_t q3areas[MAX_CM_AREAS]; - int numareaportals; - q2dareaportal_t areaportals[MAX_Q2MAP_AREAPORTALS]; +#endif +#ifdef Q2BSPS + //q2's areas have a list of portals that open into other areas. + q2carea_t *q2areas; //indexes into q2areaportals for flooding + size_t numq2areaportals; + q2dareaportal_t *q2areaportals; + + //and this is the state that is actually changed. booleans. + qbyte q2portalopen[MAX_Q2MAP_AREAPORTALS]; //memset will work if it's a qbyte, really it should be a qboolean +#endif + //list of mesh surfaces within the leaf q3cmesh_t cmeshes[MAX_CM_PATCHES]; @@ -374,10 +392,7 @@ typedef struct cminfo_s int maxleafpatches; //FIXME: remove the above - int floodvalid; - qbyte portalopen[MAX_Q2MAP_AREAPORTALS]; //memset will work if it's a qbyte, really it should be a qboolean - - int mapisq3; + qboolean mapisq3; @@ -1964,7 +1979,7 @@ static qboolean CModQ2_LoadAreas (model_t *mod, qbyte *mod_base, lump_t *l) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; int i; - q2carea_t *out; + q2carea_t *out; q2darea_t *in; int count; @@ -1982,15 +1997,13 @@ static qboolean CModQ2_LoadAreas (model_t *mod, qbyte *mod_base, lump_t *l) return false; } - out = prv->q2areas; + out = prv->q2areas = ZG_Malloc(&mod->memgroup, sizeof(*out) * count);; prv->numareas = count; for ( i=0 ; inumareaportals = LittleLong (in->numareaportals); out->firstareaportal = LittleLong (in->firstareaportal); - out->floodvalid = 0; - out->floodnum = 0; } return true; @@ -2023,8 +2036,8 @@ static qboolean CModQ2_LoadAreaPortals (model_t *mod, qbyte *mod_base, lump_t *l return false; } - out = prv->areaportals; - prv->numareaportals = count; + out = prv->q2areaportals = ZG_Malloc(&mod->memgroup, sizeof(*out) * count); + prv->numq2areaportals = count; for ( i=0 ; ilightmaps.merge = 0; - if (!samples) - return; loadmodel->engineflags |= MDLF_NEEDOVERBRIGHT; + if (!samples) + return; + loadmodel->lightmaps.fmt = LM_RGB8; if (loadmodel->lightmaps.deluxemapping) @@ -4450,10 +4464,20 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole BSPX_LoadEnvmaps(mod, bspx, mod_base); +#ifdef Q3BSPS + { + int x, y; + for (x = 0; x < prv->numareas; x++) + for (y = 0; y < prv->numareas; y++) + prv->q3areas[x].numareaportals[y] = map_autoopenportals.ival; + } +#endif +#ifdef Q2BSPS if (map_autoopenportals.value) - memset (prv->portalopen, 1, sizeof(prv->portalopen)); //open them all. Used for progs that havn't got a clue. + memset (prv->q2portalopen, 1, sizeof(prv->q2portalopen)); //open them all. Used for progs that havn't got a clue. else - memset (prv->portalopen, 0, sizeof(prv->portalopen)); //make them start closed. + memset (prv->q2portalopen, 0, sizeof(prv->q2portalopen)); //make them start closed. +#endif FloodAreaConnections (prv); mod->checksum = mod->checksum2 = *checksum; @@ -6485,36 +6509,45 @@ AREAPORTALS =============================================================================== */ -static void FloodArea_r (cminfo_t *prv, q2carea_t *area, int floodnum) +static void FloodArea_r (cminfo_t *prv, size_t areaidx, int floodnum) { - int i; + size_t i; - if (area->floodvalid == prv->floodvalid) + careaflood_t *flood = &prv->areaflood[areaidx]; + if (flood->floodvalid == prv->floodvalid) { - if (area->floodnum == floodnum) + if (flood->floodnum == floodnum) return; Con_Printf ("FloodArea_r: reflooded\n"); return; } - area->floodnum = floodnum; - area->floodvalid = prv->floodvalid; - if (prv->mapisq3) + flood->floodnum = floodnum; + flood->floodvalid = prv->floodvalid; + switch(prv->mapisq3) { + case true: +#ifdef Q3BSPS for (i=0 ; inumareas ; i++) { - if (prv->q3areas[area - prv->q2areas].numareaportals[i]>0) - FloodArea_r (prv, &prv->q2areas[i], floodnum); + if (prv->q3areas[areaidx].numareaportals[i]>0) + FloodArea_r (prv, i, floodnum); } - } - else - { - q2dareaportal_t *p = &prv->areaportals[area->firstareaportal]; - for (i=0 ; inumareaportals ; i++, p++) +#endif + break; + case false: +#ifdef Q2BSPS { - if (prv->portalopen[p->portalnum]) - FloodArea_r (prv, &prv->q2areas[p->otherarea], floodnum); + q2carea_t *area = &prv->q2areas[areaidx]; + q2dareaportal_t *p = &prv->q2areaportals[area->firstareaportal]; + for (i=0 ; inumareaportals ; i++, p++) + { + if (prv->q2portalopen[p->portalnum]) + FloodArea_r (prv, p->otherarea, floodnum); + } } +#endif + break; } } @@ -6527,8 +6560,7 @@ FloodAreaConnections */ static void FloodAreaConnections (cminfo_t *prv) { - int i; - q2carea_t *area; + size_t i; int floodnum; // all current floods are now invalid @@ -6538,15 +6570,14 @@ static void FloodAreaConnections (cminfo_t *prv) // area 0 is not used for (i=0 ; inumareas ; i++) { - area = &prv->q2areas[i]; - if (area->floodvalid == prv->floodvalid) + if (prv->areaflood[i].floodvalid == prv->floodvalid) continue; // already flooded into floodnum++; - FloodArea_r (prv, area, floodnum); + FloodArea_r (prv, i, floodnum); } - } +#ifdef Q2BSPS void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean open) { cminfo_t *prv; @@ -6555,17 +6586,19 @@ void CMQ2_SetAreaPortalState (model_t *mod, unsigned int portalnum, qboolean ope prv = (cminfo_t*)mod->meshinfo; if (prv->mapisq3) return; - if (portalnum > prv->numareaportals) + if (portalnum > prv->numq2areaportals) Host_Error ("areaportal > numareaportals"); - if (prv->portalopen[portalnum] == open) + if (prv->q2portalopen[portalnum] == open) return; - prv->portalopen[portalnum] = open; + prv->q2portalopen[portalnum] = open; FloodAreaConnections (prv); return; } +#endif +#ifdef Q3BSPS void CMQ3_SetAreaPortalState (model_t *mod, unsigned int area1, unsigned int area2, qboolean open) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; @@ -6589,6 +6622,7 @@ void CMQ3_SetAreaPortalState (model_t *mod, unsigned int area1, unsigned int are FloodAreaConnections(prv); } +#endif qboolean VARGS CM_AreasConnected (model_t *mod, unsigned int area1, unsigned int area2) { @@ -6602,7 +6636,7 @@ qboolean VARGS CM_AreasConnected (model_t *mod, unsigned int area1, unsigned int if (area1 > prv->numareas || area2 > prv->numareas) Host_Error ("area > numareas"); - if (prv->q2areas[area1].floodnum == prv->q2areas[area2].floodnum) + if (prv->areaflood[area1].floodnum == prv->areaflood[area2].floodnum) return true; return false; } @@ -6637,10 +6671,10 @@ int CM_WriteAreaBits (model_t *mod, qbyte *buffer, int area, qboolean merge) if (!merge) memset (buffer, 0, bytes); - floodnum = prv->q2areas[area].floodnum; + floodnum = prv->areaflood[area].floodnum; for (i=0 ; inumareas ; i++) { - if (prv->q2areas[i].floodnum == floodnum || !area) + if (prv->areaflood[i].floodnum == floodnum || !area) buffer[i>>3] |= 1<<(i&7); } } @@ -6661,17 +6695,19 @@ size_t CM_WritePortalState (model_t *mod, void **data) if (mod->type == mod_brush && (mod->fromgame == fg_quake2 || mod->fromgame == fg_quake3)) { + switch(prv->mapisq3) + { #ifdef Q3BSPS - if (prv->mapisq3) - { //endian issues. oh well. + case true: + //endian issues. oh well. *data = prv->q3areas; return sizeof(prv->q3areas); - } - else #endif - { - *data = prv->portalopen; - return sizeof(prv->portalopen); +#ifdef Q2BSPS + case false: + *data = prv->q2portalopen; + return sizeof(prv->q2portalopen); +#endif } } *data = NULL; @@ -6692,9 +6728,10 @@ qofs_t CM_ReadPortalState (model_t *mod, qbyte *ptr, qofs_t ptrsize) if (mod->type == mod_brush && (mod->fromgame == fg_quake2 || mod->fromgame == fg_quake3)) { -#ifdef Q3BSPS - if (prv->mapisq3) + switch(prv->mapisq3) { +#ifdef Q3BSPS + case 1: if (ptrsize < sizeof(prv->q3areas)) Con_Printf("CM_ReadPortalState() expected %u, but only %u available\n",(unsigned int)sizeof(prv->q3areas),(unsigned int)ptrsize); else @@ -6702,21 +6739,23 @@ qofs_t CM_ReadPortalState (model_t *mod, qbyte *ptr, qofs_t ptrsize) memcpy(prv->q3areas, ptr, sizeof(prv->q3areas)); FloodAreaConnections (prv); - return sizeof(prv->portalopen); + return sizeof(prv->q3areas); } - } - else + break; #endif - { - if (ptrsize < sizeof(prv->portalopen)) - Con_Printf("CM_ReadPortalState() expected %u, but only %u available\n",(unsigned int)sizeof(prv->portalopen),(unsigned int)ptrsize); +#ifdef Q2BSPS + case 0: + if (ptrsize < sizeof(prv->q2portalopen)) + Con_Printf("CM_ReadPortalState() expected %u, but only %u available\n",(unsigned int)sizeof(prv->q2portalopen),(unsigned int)ptrsize); else { - memcpy(prv->portalopen, ptr, sizeof(prv->portalopen)); + memcpy(prv->q2portalopen, ptr, sizeof(prv->q2portalopen)); FloodAreaConnections (prv); - return sizeof(prv->portalopen); + return sizeof(prv->q2portalopen); } + break; +#endif } } return 0; diff --git a/engine/common/log.c b/engine/common/log.c index 998ace7ae..b59044199 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -28,6 +28,10 @@ cvar_t log_dosformat = CVARF("log_dosformat", "0", CVAR_NOTFROMSERVER); #endif qboolean log_newline[LOG_TYPES]; +#ifdef IPLOG +cvar_t iplog_autodump = CVARFD("ipautodump", "1", CVAR_NOTFROMSERVER, "Enables dumping the 'iplog.txt' file, which contains a log of usernames seen for a given IP, which is useful for detecting fake-nicks."); +#endif + static char log_dir[MAX_OSPATH]; static enum fs_relative log_root = FS_GAMEONLY; @@ -335,6 +339,7 @@ void SV_Fraglogfile_f (void) } */ +#ifdef IPLOG /*for fuck sake, why can people still not write simple files. proquake is writing binary files as text ones. this function is to try to deal with that fuckup*/ static size_t IPLog_Read_Fucked(qbyte *file, size_t *offset, size_t totalsize, qbyte *out, size_t outsize) { @@ -356,7 +361,7 @@ static size_t IPLog_Read_Fucked(qbyte *file, size_t *offset, size_t totalsize, q } return read; } -/*need to make sure any 13 bytes followed by 10s don't bug out when read back in *sigh* */ +/*need to make sure any 13 bytes are followed by 10s so that we don't bug out when read back in *sigh* */ static size_t IPLog_Write_Fucked(vfsfile_t *file, qbyte *out, size_t outsize) { qbyte tmp[64]; @@ -623,6 +628,7 @@ static void IPLog_Merge_f(void) if (!IPLog_Merge_File(fname)) Con_Printf("unable to read %s\n", fname); } +#endif #ifndef SERVERONLY struct certlog_s @@ -791,7 +797,9 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize) void Log_ShutDown(void) { - IPLog_Dump("iplog.txt"); +#ifdef IPLOG + if (iplog_autodump.ival) + IPLog_Dump("iplog.txt"); // IPLog_Dump("iplog.dat"); while(iplog_num > 0) @@ -802,6 +810,7 @@ void Log_ShutDown(void) BZ_Free(iplog_entries); iplog_entries = NULL; iplog_max = iplog_num = 0; +#endif } void Log_Init(void) @@ -824,9 +833,12 @@ void Log_Init(void) Cmd_AddCommand("logfile", Log_Logfile_f); - Cmd_AddCommand("identify", IPLog_Identify_f); +#ifdef IPLOG + Cmd_AddCommandD("identify", IPLog_Identify_f, "Looks up a player's ip to see if they're using a different name"); Cmd_AddCommand("ipmerge", IPLog_Merge_f); Cmd_AddCommand("ipdump", IPLog_Dump_f); + Cvar_Register (&iplog_autodump, CONLOGGROUP); +#endif // cmd line options, debug options #ifdef CRAZYDEBUGGING diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index c55e2cf65..7411246c2 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -554,7 +554,7 @@ void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]) R_ConcatTransforms ================ */ -void QDECL R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +void QDECL R_ConcatTransforms (const float in1[3][4], const float in2[3][4], float out[3][4]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 3288497a3..307532dad 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -203,7 +203,7 @@ fixed16_t Mul16_30 (fixed16_t multiplier, fixed16_t multiplicand); int Q_log2 (int val); void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); void R_ConcatRotationsPad (float in1[3][4], float in2[3][4], float out[3][4]); -void QDECL R_ConcatTransforms (matrix3x4 in1, matrix3x4 in2, matrix3x4 out); +void QDECL R_ConcatTransforms (const matrix3x4 in1, const matrix3x4 in2, matrix3x4 out); void R_ConcatTransformsAxis (float in1[3][3], float in2[3][4], float out[3][4]); void RotatePointAroundVector (vec3_t dst, const vec3_t dir, const vec3_t point, float degrees); void RotateLightVector(const vec3_t *axis, const vec3_t origin, const vec3_t lightpoint, vec3_t result); diff --git a/engine/common/net.h b/engine/common/net.h index c020a9b81..26bf3a99f 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -177,6 +177,12 @@ qboolean NET_CompareAdrMasked(netadr_t *a, netadr_t *b, netadr_t *mask); qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot); +enum certprops_e +{ + QCERT_PEERFINGERPRINT +}; +size_t NET_GetConnectionCertificate(struct ftenet_connections_s *col, netadr_t *a, enum certprops_e prop, char *out, size_t outsize); + #ifdef HAVE_DTLS qboolean NET_DTLS_Create(struct ftenet_connections_s *col, netadr_t *to); qboolean NET_DTLS_Decode(struct ftenet_connections_s *col); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index aa491f7b6..06ecd6bde 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -2715,6 +2715,37 @@ qboolean NET_DTLS_Decode(ftenet_connections_t *col) #endif +size_t NET_GetConnectionCertificate(struct ftenet_connections_s *col, netadr_t *a, enum certprops_e prop, char *out, size_t outsize) +{ + if (!col) + return 0; + + switch(prop) + { + default: + break; + case QCERT_PEERFINGERPRINT: +#if 0//def HAVE_DTLS + if (a->prot == NP_DTLS) + { + struct dtlspeer_s *peer; + { + a->prot = NP_DGRAM; + for (peer = col->dtls; peer; peer = peer->next) + { + if (NET_CompareAdr(&peer->addr, a)) + break; + } + a->prot = NP_DTLS; + } + if (peer) + return peer->funcs->GetPeerCertificate(peer->dtlsstate, data, length); + } +#endif + return 0; + } + return 0; +} diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 342fd5b62..ddbb6a498 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -308,6 +308,7 @@ typedef struct dtlsfuncs_s neterr_t (*Transmit)(void *ctx, const qbyte *data, size_t datasize); neterr_t (*Received)(void *ctx, qbyte *data, size_t datasize); neterr_t (*Timeouts)(void *ctx); + void (*GetPeerCertificate)(void *ctx); } dtlsfuncs_t; const dtlsfuncs_t *DTLS_InitServer(void); const dtlsfuncs_t *DTLS_InitClient(void); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 79444020c..47df20dc9 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1640,10 +1640,10 @@ typedef struct char *stringdata; }; } pf_hashentry_t; -pf_hashtab_t *pf_hashtab; -size_t pf_hash_maxtables; -pf_hashtab_t pf_peristanthashtab; //persists over map changes. -pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts. +static pf_hashtab_t *pf_hashtab; +static size_t pf_hash_maxtables; +static pf_hashtab_t pf_peristanthashtab; //persists over map changes. +//static pf_hashtab_t pf_reverthashtab; //pf_peristanthashtab as it was at map start, for map restarts. static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx) { idx -= 1; @@ -1664,7 +1664,7 @@ static pf_hashtab_t *PF_hash_findtab(pubprogfuncs_t *prinst, int idx) else PR_BIError(prinst, "PF_hash_findtab: invalid hash table\n"); return NULL; -}; +} void QCBUILTIN PF_hash_getkey (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -1734,10 +1734,10 @@ void QCBUILTIN PF_hash_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob } else memcpy(G_VECTOR(OFS_RETURN), ent->data, sizeof(vec3_t)); + return; } - else - memcpy(G_VECTOR(OFS_RETURN), dflt, sizeof(vec3_t)); } + memcpy(G_VECTOR(OFS_RETURN), dflt, sizeof(vec3_t)); } void QCBUILTIN PF_hash_getcb (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -1904,10 +1904,10 @@ typedef struct { size_t bufferlen; size_t len; size_t ofs; - int accessmode; pubprogfuncs_t *prinst; + long accessmode; } pf_fopen_files_t; -pf_fopen_files_t pf_fopen_files[MAX_QC_FILES]; +static pf_fopen_files_t pf_fopen_files[MAX_QC_FILES]; //returns false if the file is denied. //fallbackread can be NULL, if the qc is not allowed to read that (original) file at all. diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 90c656450..60fd4cc8f 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -775,7 +775,9 @@ enum lightfield_e lfield_rotation=13, lfield_dietime=14, lfield_rgbdecay=15, - lfield_radiusdecay=16 + lfield_radiusdecay=16, + + lfield_stylestring=17 }; enum csqc_input_event { diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 58bbb591a..c8737aa4a 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -2199,7 +2199,15 @@ struct bspx_header_s { }; //supported lumps: //RGBLIGHTING (.lit) +//LIGHTING_E5BGR9 (hdr lit) //LIGHTINGDIR (.lux) +//LMSHIFT (lightmap scaling) +//LMOFFSET (lightmap scaling) +//LMSTYLE (lightmap scaling) +//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) { int i; @@ -2424,11 +2432,11 @@ void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base) struct bspxrw { - fromgame_t fg; const char *fname; char *origfile; qofs_t origsize; int lumpofs; + fromgame_t fg; size_t corelumps; size_t totallumps; diff --git a/engine/common/sha1.c b/engine/common/sha1.c index 2b118d4e2..9d0e08e6b 100644 --- a/engine/common/sha1.c +++ b/engine/common/sha1.c @@ -240,7 +240,7 @@ static void memxor(char *dest, const char *src, size_t length) } } -typedef size_t hashfunc_t(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens); +//typedef size_t hashfunc_t(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens); size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen) diff --git a/engine/common/world.h b/engine/common/world.h index e1e806b7f..3a48dfddf 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -122,7 +122,9 @@ typedef struct q2trace_s #define MOVE_NORMAL 0 #define MOVE_NOMONSTERS (1<<0) #define MOVE_MISSILE (1<<1) -#define MOVE_WORLDONLY (MOVE_NOMONSTERS|MOVE_MISSILE) +#ifndef NOLEGACY +#define MOVE_WORLDONLY (MOVE_NOMONSTERS|MOVE_MISSILE) //use MOVE_OTHERONLY instead +#endif #define MOVE_HITMODEL (1<<2) #define MOVE_RESERVED (1<<3) //so we are less likly to get into tricky situations when we want to steal annother future DP extension. #define MOVE_TRIGGERS (1<<4) //triggers must be marked with FINDABLE_NONSOLID (an alternative to solid-corpse) diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 9156cef8f..2037d3f55 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -3,11 +3,11 @@ #include "gl_draw.h" #ifdef D3D9QUAKE #include "shader.h" +#include #if !defined(HMONITOR_DECLARED) && (WINVER < 0x0500) #define HMONITOR_DECLARED DECLARE_HANDLE(HMONITOR); #endif -#include /* Things to improve: diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index ccbb9fef6..44b47aa38 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1127,7 +1127,7 @@ static qboolean (D3D9_SCR_UpdateScreen) (void) if (uimenu != 1) { if (r_worldentity.model && cls.state == ca_active) - V_RenderView (); + V_RenderView (nohud); else { noworld = true; diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 4a630d13c..d11d7e28a 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -1426,7 +1426,7 @@ static qboolean (D3D11_SCR_UpdateScreen) (void) if (uimenu != 1) { if (r_worldentity.model && cls.state == ca_active) - V_RenderView (); + V_RenderView (nohud); else { noworld = true; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 734dd8187..dc34c1a7c 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1079,16 +1079,19 @@ qboolean GLBE_BeginShadowMap(int id, int w, int h, int *restorefbo) if (!TEXVALID(shadowmap[id])) { - shadowmap[id] = Image_CreateTexture(va("***shadowmap2d%i***", id), NULL, 0); - qglGenTextures(1, &shadowmap[id]->num); - GL_MTBind(0, GL_TEXTURE_2D, shadowmap[id]); + uploadfmt_t encoding = PTI_DEPTH32; + texid_t tex = shadowmap[id] = Image_CreateTexture(va("***shadowmap2d%i***", id), NULL, 0); + qglGenTextures(1, &tex->num); + GL_MTBind(0, GL_TEXTURE_2D, tex); #ifdef SHADOWDBG_COLOURNOTDEPTH qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); #else - if (gl_config.gles) - qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + if (qglTexStorage2D) + qglTexStorage2D(GL_TEXTURE_2D, 1, gl_config.formatinfo[encoding].sizedformat, w, h); + else if (gl_config.formatinfo[encoding].type) + qglTexImage2D (GL_TEXTURE_2D, 0, gl_config.formatinfo[encoding].sizedformat, w, h, 0, gl_config.formatinfo[encoding].format, gl_config.formatinfo[encoding].type, NULL); else - qglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16_ARB, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + qglCompressedTexImage2D (GL_TEXTURE_2D, 0, gl_config.formatinfo[encoding].sizedformat, w, h, 0, 0, NULL); #endif qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1614,7 +1617,16 @@ void GLBE_Init(void) gl_overbright.modified = true; /*in case the d3d renderer does the same*/ /*lock the cvar down if the backend can't actually do it*/ - if (!gl_config.tex_env_combine && !gl_config_nofixedfunc && gl_overbright.ival) + if ( +#if 1//defined(QUAKETC) + //TCs are expected to be using glsl and weird overbright things etc, don't take the risk. + (!sh_config.progs_supported) +#else + //Q3 can get away with tex_env_combine for everything, if only because the content allows everything to be flattened to a single pass if needed... + //some shaders might screw up from our approach though... + (!gl_config.tex_env_combine && !gl_config_nofixedfunc) +#endif + && gl_overbright.ival) Cvar_ApplyLatchFlag(&gl_overbright, "0", CVAR_RENDERERLATCH); shaderstate.shaderbits = ~SBITS_ATEST_BITS; BE_SendPassBlendDepthMask(0); diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index e6e126808..1a53d7957 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -43,8 +43,6 @@ static int gl_filter_mip[3]; //everything else int gl_mipcap_min = 0; int gl_mipcap_max = 1000; -void Image_WriteKTXFile(const char *filename, struct pendingtextureinfo *mips); - void GL_DestroyTexture(texid_t tex) { if (!tex) @@ -964,7 +962,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips) if (i) { out.mipcount = i; - Image_WriteKTXFile(va("textures/%s.ktx", tex->ident), &out); + Image_WriteKTXFile(va("textures/%s.ktx", tex->ident), FS_GAMEONLY, &out); } while (i-- > 0) if (out.mip[i].needfree) diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 47395d688..f6fe0eb24 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1750,15 +1750,26 @@ static texid_t Font_LoadFallbackConchars(void) Font_CopyGlyph('[', 128, lump); Font_CopyGlyph('-', 129, lump); Font_CopyGlyph(']', 130, lump); - Font_CopyGlyph('o', 131, lump); + Font_CopyGlyph('|', 131, lump); + Font_CopyGlyph('>', 13, lump); } tex = R_LoadTexture32("charset", width, height, (void*)lump, IF_PREMULTIPLYALPHA|IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA); BZ_Free(lump); return tex; } +enum fontfmt_e +{ + FMT_AUTO, //freetype, or quake + FMT_QUAKE, //first is default + FMT_ISO88591, //latin-1 (first 256 chars of unicode too, c1 glyphs are usually invisible) + FMT_WINDOWS1252,//variation of latin-1 with extra glyphs + FMT_KOI8U, //image is 16*16 koi8-u codepage. + FMT_HORIZONTAL, //unicode, charcount=width/(height-2). single strip of chars, like halflife. +}; + /*loads a fallback image. not allowed to fail (use syserror if needed)*/ -static texid_t Font_LoadDefaultConchars(void) +static texid_t Font_LoadDefaultConchars(enum fontfmt_e *fmt) { texid_t tex; tex = Font_LoadReplacementConchars(); @@ -1774,13 +1785,19 @@ static texid_t Font_LoadDefaultConchars(void) if (tex && tex->status == TEX_LOADING) COM_WorkerPartialSync(tex, &tex->status, TEX_LOADING); if (TEXLOADED(tex)) + { + *fmt = FMT_ISO88591; return tex; + } #endif tex = Font_LoadFallbackConchars(); if (tex && tex->status == TEX_LOADING) COM_WorkerPartialSync(tex, &tex->status, TEX_LOADING); if (TEXLOADED(tex)) + { + *fmt = FMT_QUAKE; return tex; + } Sys_Error("Unable to load any conchars\n"); } @@ -1838,15 +1855,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight) char facename[MAX_QPATH*12]; struct charcache_s *c; float aspect = 1; - enum - { - FMT_AUTO, //freetype, or quake - FMT_QUAKE, //first is default - FMT_ISO88591, //latin-1 (first 256 chars of unicode too, c1 glyphs are usually invisible) - FMT_WINDOWS1252,//variation of latin-1 with extra glyphs - FMT_KOI8U, //image is 16*16 koi8-u codepage. - FMT_HORIZONTAL, //unicode, charcount=width/(height-2). single strip of chars, like halflife. - } fmt = FMT_AUTO; + enum fontfmt_e fmt = FMT_AUTO; Q_strncpyz(facename, fontfilename, sizeof(facename)); @@ -2155,7 +2164,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight) { if (!TEXLOADED(fontplanes.defaultfont)) { - fontplanes.defaultfont = Font_LoadDefaultConchars(); + fontplanes.defaultfont = Font_LoadDefaultConchars(&fmt); } #ifdef HEXEN2 diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index b8580dd95..9f8eb62a0 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1997,23 +1997,26 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, #endif #ifdef RUNTIMELIGHTING - if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxemapping))) - { - writelitfile = !litdata; - numlightdata = l->filelen; - lightmodel = loadmodel; - relitsurface = 0; - } - else if (!lightmodel && r_deluxemapping_cvar.value>1 && r_deluxemapping && !luxdata + if ((loadmodel->type == mod_brush && loadmodel->fromgame == fg_quake) || loadmodel->type == mod_heightmap) + { //we only support a couple of formats. :( + if (!lightmodel && r_loadlits.value == 2 && (!litdata || (!luxdata && r_deluxemapping))) + { + writelitfile = !litdata; + numlightdata = l->filelen; + lightmodel = loadmodel; + relitsurface = 0; + } + else if (!lightmodel && r_deluxemapping_cvar.value>1 && r_deluxemapping && !luxdata #ifdef RTLIGHTS - && !(r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value<=0) + && !(r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value<=0) #endif - ) - { //if deluxemapping is on, generate missing lux files a little more often, but don't bother if we have rtlights on anyway. - writelitfile = false; - numlightdata = l->filelen; - lightmodel = loadmodel; - relitsurface = 0; + ) + { //if deluxemapping is on, generate missing lux files a little more often, but don't bother if we have rtlights on anyway. + writelitfile = false; + numlightdata = l->filelen; + lightmodel = loadmodel; + relitsurface = 0; + } } /*if we're relighting, make sure there's the proper lit data to be updated*/ diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 8d7e1b5da..ebd161d63 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -27,7 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps; extern cvar_t r_hdr_irisadaptation, r_hdr_irisadaptation_multiplier, r_hdr_irisadaptation_minvalue, r_hdr_irisadaptation_maxvalue, r_hdr_irisadaptation_fade_down, r_hdr_irisadaptation_fade_up; - int r_dlightframecount; int d_lightstylevalue[256]; // 8.8 fraction of base light value @@ -363,9 +362,6 @@ void R_RenderDlights (void) if (!r_coronas.value && !r_flashblend.value) return; -// r_dlightframecount = r_framecount + 1; // because the count hasn't - // advanced yet for this frame - l = cl_dlights+rtlights_first; for (i=rtlights_first; iorigin); - AngleVectors(angles, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorCopy(angles, dl->angles); + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); VectorInverse(dl->axis[1]); dl->radius = radius; VectorCopy(color, dl->color); @@ -1121,7 +1137,8 @@ qboolean R_ImportRTLights(const char *entlump) if (!dl->fov) //default is 40, supposedly dl->fov = 40; - AngleVectors(mangle, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorCopy(mangle, dl->angles); + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); VectorInverse(dl->axis[1]); } else if (*target) @@ -1138,6 +1155,10 @@ qboolean R_ImportRTLights(const char *entlump) VectorVectors(dl->axis[0], dl->axis[1], dl->axis[2]); VectorInverse(dl->axis[1]); //we don't have any control over the inner cone. + + //so queries work properly + VectorAngles(dl->axis[0], dl->axis[2], dl->angles, false); + dl->angles[0] = anglemod(dl->angles[0]); } } @@ -1158,6 +1179,7 @@ qboolean R_LoadRTLights(void) dlight_t *dl; char fname[MAX_QPATH]; char cubename[MAX_QPATH]; + char customstyle[1024]; char *file; char *end; int style; @@ -1273,6 +1295,7 @@ qboolean R_LoadRTLights(void) flags |= file?atoi(com_token):LFLAG_REALTIMEMODE; fov = avel[0] = avel[1] = avel[2] = 0; + *customstyle = 0; while(file) { file = COM_Parse(file); @@ -1284,6 +1307,16 @@ qboolean R_LoadRTLights(void) avel[2] = file?atof(com_token+5):0; else if (!strncmp(com_token, "fov=", 4)) fov = file?atof(com_token+4):0; + else if (!strncmp(com_token, "nostencil=", 10)) + flags |= atoi(com_token+10)?LFLAG_SHADOWMAP:0; + else if (!strncmp(com_token, "crepuscular=", 12)) + flags |= atoi(com_token+12)?LFLAG_CREPUSCULAR:0; + else if (!strncmp(com_token, "ortho=", 6)) + flags |= atoi(com_token+6)?LFLAG_ORTHO:0; + else if (!strncmp(com_token, "stylestring=", 12)) + Q_strncpyz(customstyle, com_token+12, sizeof(customstyle)); + else if (file) + Con_DPrintf("Unknown .rtlights arg \"%s\"\n", com_token); } if (radius) @@ -1313,13 +1346,14 @@ qboolean R_LoadRTLights(void) dl->cubetexture = r_nulltex; dl->style = style+1; + dl->customstyle = (*customstyle)?Z_StrDup(customstyle):NULL; } file = end+1; } return !!file; } -void R_SaveRTLights_f(void) +static void R_SaveRTLights_f(void) { dlight_t *light; vfsfile_t *f; @@ -1327,6 +1361,7 @@ void R_SaveRTLights_f(void) char fname[MAX_QPATH]; char sysname[MAX_OSPATH]; vec3_t ang; + int ver = 0; COM_StripExtension(cl.worldmodel->name, fname, sizeof(fname)); strncat(fname, ".rtlights", MAX_QPATH-1); @@ -1347,24 +1382,46 @@ void R_SaveRTLights_f(void) if (!light->radius) continue; VectorAngles(light->axis[0], light->axis[2], ang, false); - VFS_PUTS(f, va( + + //the .rtlights format is defined by DP, the first few parts cannot be changed without breaking wider compat. + //it got extended a few times. only write what we need for greater compat, just in case. + if ((light->flags & (LFLAG_SHADOWMAP|LFLAG_CREPUSCULAR|LFLAG_ORTHO)) || light->rotation[0] || light->rotation[1] || light->rotation[2] || light->fov || light->customstyle) + ver = 2; //one of our own flags. always spew the full DP stuff to try to avoid confusion + else if (light->coronascale!=0.25 || light->lightcolourscales[0]!=0 || light->lightcolourscales[1]!=1 || light->lightcolourscales[2]!=1 || (light->flags&~LFLAG_NOSHADOWS) != LFLAG_REALTIMEMODE) + ver = 2; + else if (*light->cubemapname || light->corona || ang[0] || ang[1] || ang[2]) + ver = 1; + else + ver = 0; + VFS_PRINTF(f, "%s%f %f %f " "%f %f %f %f " - "%i " - "\"%s\" %f " - "%f %f %f " - "%f %f %f %f %i " - "rotx=%g roty=%g rotz=%g fov=%g " - "\n" - , + "%i", (light->flags & LFLAG_NOSHADOWS)?"!":"", light->origin[0], light->origin[1], light->origin[2], - light->radius, light->color[0], light->color[1], light->color[2], - light->style-1, - light->cubemapname, light->corona, - ang[0], ang[1], ang[2], - light->coronascale, light->lightcolourscales[0], light->lightcolourscales[1], light->lightcolourscales[2], light->flags&~(LFLAG_NOSHADOWS|LFLAG_INTERNAL), - light->rotation[0],light->rotation[1],light->rotation[2],light->fov - )); + light->radius, light->color[0], light->color[1], light->color[2], + light->style-1); + if (ver > 0) + VFS_PRINTF(f, " \"%s\" %f %f %f %f", light->cubemapname, light->corona, ang[0], ang[1], ang[2]); + if (ver > 1) + VFS_PRINTF(f, " %f %f %f %f %i", light->coronascale, light->lightcolourscales[0], light->lightcolourscales[1], light->lightcolourscales[2], light->flags&(LFLAG_NORMALMODE|LFLAG_REALTIMEMODE)); + + //our weird flags + if (light->flags&LFLAG_SHADOWMAP) + VFS_PRINTF(f, " nostencil=1"); + if (light->flags&LFLAG_CREPUSCULAR) + VFS_PRINTF(f, " crepuscular=1"); + if (light->flags&LFLAG_ORTHO) + VFS_PRINTF(f, " ortho=1"); + //spinning lights (for cubemaps) + if (light->rotation[0] || light->rotation[1] || light->rotation[2]) + VFS_PRINTF(f, " rotx=%g roty=%g rotz=%g", light->rotation[0],light->rotation[1],light->rotation[2]); + //spotlights + if (light->fov) + VFS_PRINTF(f, " fov=%g", light->fov); //aka: outer cone + if (light->customstyle) + VFS_PRINTF(f, " \"stylestring=%s\"", light->customstyle); //aka: outer cone + + VFS_PUTS(f, "\n"); } VFS_CLOSE(f); @@ -1412,7 +1469,7 @@ void R_StaticEntityToRTLight(int i) R_LoadNumberedLightTexture(dl, state->skinnum); } -void R_ReloadRTLights_f(void) +static void R_ReloadRTLights_f(void) { int i; @@ -1427,19 +1484,800 @@ void R_ReloadRTLights_f(void) R_ImportRTLights(Mod_GetEntitiesString(cl.worldmodel)); else if (!strcmp(Cmd_Argv(1), "rtlights")) R_LoadRTLights(); + else if (!strcmp(Cmd_Argv(1), "statics")) + { + for (i = 0; i < cl.num_statics; i++) + R_StaticEntityToRTLight(i); + } else if (!strcmp(Cmd_Argv(1), "none")) ; else { - R_LoadRTLights(); + //try to load .rtlights file + if (rtlights_first == rtlights_max) + R_LoadRTLights(); + //if there's a static entity with rtlights set, then assume the mod is taking care of it for us. + if (rtlights_first == rtlights_max) + for (i = 0; i < cl.num_statics; i++) + R_StaticEntityToRTLight(i); + //otherwise try to import. if (rtlights_first == rtlights_max) R_ImportRTLights(Mod_GetEntitiesString(cl.worldmodel)); } +} - for (i = 0; i < cl.num_statics; i++) +//-1 for arg error +static int R_EditLight(dlight_t *dl, const char *cmd, int argc, const char *x, const char *y, const char *z) +{ + if (argc == 1) { - R_StaticEntityToRTLight(i); + y = x; + z = x; } + if (!strcmp(cmd, "origin")) + { + dl->origin[0] = atof(x); + dl->origin[1] = atof(y); + dl->origin[2] = atof(z); + } + else if (!strcmp(cmd, "originscale")) + { + dl->origin[0] *= atof(x); + dl->origin[1] *= atof(y); + dl->origin[2] *= atof(z); + } + else if (!strcmp(cmd, "originx")) + dl->origin[0] = atof(x); + else if (!strcmp(cmd, "originy")) + dl->origin[1] = atof(x); + else if (!strcmp(cmd, "originz")) + dl->origin[2] = atof(x); + else if (!strcmp(cmd, "move")) + { + dl->origin[0] += atof(x); + dl->origin[1] += atof(y); + dl->origin[2] += atof(z); + } + else if (!strcmp(cmd, "movex")) + dl->origin[0] += atof(x); + else if (!strcmp(cmd, "movey")) + dl->origin[1] += atof(x); + else if (!strcmp(cmd, "movez")) + dl->origin[2] += atof(x); + + else if (!strcmp(cmd, "angles")) + { + dl->angles[0] = atof(x); + dl->angles[1] = atof(y); + dl->angles[2] = atof(z); + + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorInverse(dl->axis[1]); + } + else if (!strcmp(cmd, "anglesx")) + { + dl->angles[0] = atof(x); + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorInverse(dl->axis[1]); + } + else if (!strcmp(cmd, "anglesy")) + { + dl->angles[1] = atof(x); + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorInverse(dl->axis[1]); + } + else if (!strcmp(cmd, "anglesz")) + { + dl->angles[2] = atof(x); + AngleVectors(dl->angles, dl->axis[0], dl->axis[1], dl->axis[2]); + VectorInverse(dl->axis[1]); + } + + else if (!strcmp(cmd, "avel")) + { + dl->rotation[0] = atof(x); + dl->rotation[1] = atof(y); + dl->rotation[2] = atof(z); + } + else if (!strcmp(cmd, "avelx")) + dl->rotation[0] = atof(x); + else if (!strcmp(cmd, "avey")) + dl->rotation[1] = atof(x); + else if (!strcmp(cmd, "avelz")) + dl->rotation[2] = atof(x); + + else if (!strcmp(cmd, "outercone") || !strcmp(cmd, "fov")) + dl->fov = atof(x); + else if (!strcmp(cmd, "color") || !strcmp(cmd, "colour")) + { + dl->color[0] = atof(x); + dl->color[1] = atof(y); + dl->color[2] = atof(z); + } + else if (!strcmp(cmd, "colorscale") || !strcmp(cmd, "colourscale")) + { + dl->color[0] *= atof(x); + dl->color[1] *= atof(y); + dl->color[2] *= atof(z); + } + else if (!strcmp(cmd, "radius")) + dl->radius = atof(x); + else if (!strcmp(cmd, "radiusscale") || !strcmp(cmd, "sizescale")) + dl->radius *= atof(x); + else if (!strcmp(cmd, "style")) + dl->style = atoi(x)+1; //fte's styles are internally 1-based, with 0 being a null style that ignores lightstyles entirely, which admittedly isn't often used. + else if (!strcmp(cmd, "stylestring")) + { + Z_Free(dl->customstyle); + dl->customstyle = x?Z_StrDup(x):NULL; + } + else if (!strcmp(cmd, "cubemap")) + { + Q_strncpyz(dl->cubemapname, x, sizeof(dl->cubemapname)); + if (*dl->cubemapname) + dl->cubetexture = R_LoadReplacementTexture(dl->cubemapname, "", IF_CUBEMAP, NULL, 0, 0, TF_INVALID); + else + dl->cubetexture = r_nulltex; + } + else if (!strcmp(cmd, "shadows")) + dl->flags = (dl->flags&~LFLAG_NOSHADOWS) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?0:LFLAG_NOSHADOWS); + else if (!strcmp(cmd, "nostencil")) + dl->flags = (dl->flags&~LFLAG_SHADOWMAP) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?0:LFLAG_SHADOWMAP); + else if (!strcmp(cmd, "crepuscular")) + dl->flags = (dl->flags&~LFLAG_CREPUSCULAR) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?LFLAG_CREPUSCULAR:0); + else if (!strcmp(cmd, "ortho")) + dl->flags = (dl->flags&~LFLAG_ORTHO) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?LFLAG_ORTHO:0); + else if (!strcmp(cmd, "corona")) + dl->corona = atof(x); + else if (!strcmp(cmd, "coronasize")) + dl->coronascale = atof(x); + else if (!strcmp(cmd, "ambient")) + dl->lightcolourscales[0] = atof(x); + else if (!strcmp(cmd, "diffuse")) + dl->lightcolourscales[1] = atof(x); + else if (!strcmp(cmd, "specular")) + dl->lightcolourscales[2] = atof(x); + else if (!strcmp(cmd, "normalmode")) + dl->flags = (dl->flags&~LFLAG_NORMALMODE) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?LFLAG_NORMALMODE:0); + else if (!strcmp(cmd, "realtimemode")) + dl->flags = (dl->flags&~LFLAG_REALTIMEMODE) | ((*x=='y'||*x=='Y'||*x=='t'||atoi(x))?LFLAG_REALTIMEMODE:0); + else + return -2; + dl->rebuildcache = true; //mneh, lets just flag it for everything. + return 1; +} + +void R_EditLights_DrawInfo(void) +{ + float fontscale[2] = {8,8}; + float x = vid.width - 320; + float y = 0; + const char *s; + if (!r_editlights.ival) + return; + + if (r_editlights_selected >= RTL_FIRST && r_editlights_selected < rtlights_max) + { + dlight_t *dl = &cl_dlights[r_editlights_selected]; + s = va( " Origin : %.0f %.0f %.0f\n" + " Angles : %.0f %.0f %.0f\n" + " Colour : %.2f %.2f %.2f\n" + " Radius : %.0f\n" + " Corona : %.0f\n" + " Style : %i\n" + "Style String : %s\n" + " Shadows : %s\n" + " Cubemap : \"%s\"\n" + " CoronaSize : %.2f\n" + " Ambient : %.2f\n" + " Diffuse : %.2f\n" + " Specular : %.2f\n" + " NormalMode : %s\n" + "RealTimeMode : %s\n" + " Spin : %.0f %.0f %.0f\n" + " Cone : %.0f\n" + //"NoStencil : %s\n" + //"Crepuscular : %s\n" + //"Ortho : %s\n" + ,dl->origin[0],dl->origin[1],dl->origin[2] + ,dl->angles[0],dl->angles[1],dl->angles[2] + ,dl->color[0],dl->color[1],dl->color[2] + ,dl->radius, dl->corona, dl->style-1, dl->customstyle?dl->customstyle:"---" + ,((dl->flags&LFLAG_NOSHADOWS)?"no":"yes"), dl->cubemapname, dl->coronascale + ,dl->lightcolourscales[0], dl->lightcolourscales[1], dl->lightcolourscales[2] + ,((dl->flags&LFLAG_NORMALMODE)?"yes":"no"), ((dl->flags&LFLAG_REALTIMEMODE)?"yes":"no") + ,dl->rotation[0],dl->rotation[1],dl->rotation[2], dl->fov + //,((dl->flags&LFLAG_SHADOWMAP)?"no":"yes"),((dl->flags&LFLAG_CREPUSCULAR)?"yes":"no"),((dl->flags&LFLAG_ORTHO)?"yes":"no") + ); + } + else + s = "No light selected"; + R2D_ImageColours(0,0,0,.35); + R2D_FillBlock(x-4, y, 320+4, 16*8+4); + R2D_ImageColours(1,1,1,1); + R_DrawTextField(x, y, 320, 16*8, s, CON_WHITEMASK, CPRINT_LALIGN|CPRINT_TALIGN|CPRINT_NOWRAP, font_default, fontscale); +} +void R_EditLights_DrawLights(void) +{ + const float SPRITE_SIZE = 8; + int i; + dlight_t *l; + enum + { +// ELS_CURSOR, + ELS_SELECTED, + ELS_LIGHT, + ELS_NOSHADOW, + ELS_MAX + }; + char *lightshaderinfo[] = + { +/* "gfx/editlights/cursor", + ".59..95." + "59....95" + "9.9..9.9" + "...99..." + "...99..." + "9.9..9.9" + "59....95" + ".59..95.", +*/ + "gfx/editlights/selected", + "999..999" + "99....99" + "9......9" + "........" + "........" + "9......9" + "99....99" + "999..999", + + "gfx/editlights/light", + "..1221.." + ".245542." + "14677641" + "25799752" + "25799752" + "14677641" + ".245542." + "..1221..", + + "gfx/editlights/noshadow", + "..1221.." + ".245542." + "14644641" + "274..472" //mmm, donuts. + "274..472" + "14644641" + ".247742." + "..1221..", + }; + shader_t *shaders[ELS_MAX], *s; + unsigned int asciipalette[256]; + asciipalette['.'] = 0; + for (i = 0; i < 10; i++) + asciipalette['0'+i] = 0xff000000 | ((int)(255/9.0*i)*0x010101); + + if (!r_editlights.ival) + return; + + for (i = 0; i < ELS_MAX; i++) + { + shaders[i] = R_RegisterShader(lightshaderinfo[i*2+0], SUF_NONE, va( + "{\n" + "program defaultadditivesprite\n" + "{\n" + "map $diffuse\n" + "blendfunc gl_one gl_one\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "%s" + "}\n" + "}\n" + ,(i==ELS_SELECTED)?"nodepth\n":"") + ); + if (!shaders[i]->defaulttextures->base) + shaders[i]->defaulttextures->base = Image_GetTexture(shaders[i]->name, NULL, IF_LINEAR|IF_NOMIPMAP|IF_NOPICMIP|IF_CLAMP, lightshaderinfo[i*2+1], asciipalette, 8, 8, TF_8PAL32); + } + + if (!r_editlights_locked) + { + vec3_t targ, norm; + int ent; + int best = -1; + float bestscore = 0, score; + + VectorMA(r_refdef.vieworg, r_editlights_cursordistance.value, vpn, targ); //try to aim about 1024qu infront of the camera + CL_TraceLine(r_refdef.vieworg, targ, r_editlights_cursor, norm, &ent); //figure out where the cursor ends up + VectorMA(r_editlights_cursor, r_editlights_cursorpushoff.value, norm, r_editlights_cursor); //push off from the surface by 4qu. + VectorMA(r_editlights_cursor, -r_editlights_cursorpushback.value, vpn, r_editlights_cursor);//move it back towards the camera, for no apparent reason + if (r_editlights_cursorgrid.value) + { //snap to a grid, if set + for (i =0; i < 3; i++) + r_editlights_cursor[i] = floor(r_editlights_cursor[i] / r_editlights_cursorgrid.value + 0.5) * r_editlights_cursorgrid.value; + } + +// CLQ1_AddSpriteQuad(shaders[ELS_CURSOR], r_editlights_cursor, SPRITE_SIZE); + + for (i=RTL_FIRST; iradius) //dead light is dead. + continue; + + VectorSubtract(l->origin, r_refdef.vieworg, targ); + score = DotProduct(vpn, targ) / sqrt(DotProduct(targ,targ)); + if (score >= .95) //there's a threshhold required for a light to be selectable. + { + //trace from the light to the view (so startsolid doesn't cause so many problems) + if (score > bestscore && CL_TraceLine(l->origin, r_refdef.vieworg, r_editlights_cursor, norm, &ent) == 1.0) + { + bestscore = score; + best = i; + } + } + } + r_editlights_selected = best; + } + + for (i=RTL_FIRST; iradius) //dead light is dead. + continue; + + //we should probably show spotlights with a special icon or something + //dp has alternate icons for cubemaps. + if (l->flags & LFLAG_NOSHADOWS) + s = shaders[ELS_NOSHADOW]; + else + s = shaders[ELS_LIGHT]; + CLQ1_AddSpriteQuad(s, l->origin, SPRITE_SIZE); + } + + if (r_editlights_selected >= RTL_FIRST && r_editlights_selected < rtlights_max) + { + l = &cl_dlights[r_editlights_selected]; + CLQ1_AddSpriteQuad(shaders[ELS_SELECTED], l->origin, SPRITE_SIZE); + } +} + +static void R_EditLights_Edit_f(void) +{ + int i = r_editlights_selected; + const char *cmd = Cmd_Argv(1); + const char *x = Cmd_Argv(2); + const char *y = Cmd_Argv(3); + const char *z = Cmd_Argv(4); + int argc = Cmd_Argc()-2; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + dl = &cl_dlights[i]; + if (!*cmd) + { + Con_Print("Selected light's properties:\n"); + Con_Printf("Origin : ^[%f %f %f\\type\\r_editlights_edit origin %g %g %g^]\n", dl->origin[0],dl->origin[1],dl->origin[2], dl->origin[0],dl->origin[1],dl->origin[2]); + Con_Printf("Angles : ^[%f %f %f\\type\\r_editlights_edit angles %g %g %g^]\n", dl->angles[0],dl->angles[1],dl->angles[2], dl->angles[0],dl->angles[1],dl->angles[2]); + Con_Printf("Colour : ^[%f %f %f\\type\\r_editlights_edit avel %g %g %g^]\n", dl->color[0],dl->color[1],dl->color[2], dl->color[0],dl->color[1],dl->color[2]); + Con_Printf("Radius : ^[%f\\type\\r_editlights_edit radius %g^]\n", dl->radius, dl->radius); + Con_Printf("Corona : ^[%f\\type\\r_editlights_edit corona %g^]\n", dl->corona, dl->corona); + Con_Printf("Style : ^[%i\\type\\r_editlights_edit style %i^]\n", dl->style-1, dl->style-1); + Con_Printf("Style String : ^[%s\\type\\r_editlights_edit stylestring %s^]\n", dl->customstyle?dl->customstyle:"---", dl->customstyle?dl->customstyle:""); + Con_Printf("Shadows : ^[%s\\type\\r_editlights_edit shadows %s^]\n", ((dl->flags&LFLAG_NOSHADOWS)?"no":"yes"), ((dl->flags&LFLAG_NOSHADOWS)?"no":"yes")); + Con_Printf("Cubemap : ^[\"%s\"\\type\\r_editlights_edit cubemap \"%s\"^]\n", dl->cubemapname, dl->cubemapname); + Con_Printf("CoronaSize : ^[%f\\type\\r_editlights_edit coronasize %g^]\n", dl->coronascale, dl->coronascale); + Con_Printf("Ambient : ^[%f\\type\\r_editlights_edit ambient %g^]\n", dl->lightcolourscales[0], dl->lightcolourscales[0]); + Con_Printf("Diffuse : ^[%f\\type\\r_editlights_edit diffuse %g^]\n", dl->lightcolourscales[1], dl->lightcolourscales[1]); + Con_Printf("Specular : ^[%f\\type\\r_editlights_edit specular %g^]\n", dl->lightcolourscales[2], dl->lightcolourscales[2]); + Con_Printf("NormalMode : ^[%s\\type\\r_editlights_edit normalmode %s^]\n", ((dl->flags&LFLAG_NORMALMODE)?"yes":"no"), ((dl->flags&LFLAG_NORMALMODE)?"yes":"no")); + Con_Printf("RealTimeMode : ^[%s\\type\\r_editlights_edit realtimemode %s^]\n", ((dl->flags&LFLAG_REALTIMEMODE)?"yes":"no"), ((dl->flags&LFLAG_REALTIMEMODE)?"yes":"no")); + Con_Printf("Spin : ^[%f %f %f\\type\\r_editlights_edit avel %g %g %g^]\n", dl->rotation[0],dl->rotation[1],dl->rotation[2], dl->origin[0],dl->origin[1],dl->origin[2]); + Con_Printf("Cone : ^[%f\\type\\r_editlights_edit outercone %g^]\n", dl->fov, dl->fov); +// Con_Printf("NoStencil : ^[%s\\type\\r_editlights_edit nostencil %s^]\n", ((dl->flags&LFLAG_SHADOWMAP)?"no":"yes"), ((dl->flags&LFLAG_SHADOWMAP)?"no":"yes")); +// Con_Printf("Crepuscular : ^[%s\\type\\r_editlights_edit crepuscular %s^]\n", ((dl->flags&LFLAG_CREPUSCULAR)?"yes":"no"), ((dl->flags&LFLAG_CREPUSCULAR)?"yes":"no")); +// Con_Printf("Ortho : ^[%s\\type\\r_editlights_edit ortho %s^]\n", ((dl->flags&LFLAG_ORTHO)?"yes":"no"), ((dl->flags&LFLAG_ORTHO)?"yes":"no")); + return; + } + switch(R_EditLight(dl, cmd, argc, x,y,z)) + { + case -1: + Con_Printf("Not enough args for %s\n", cmd); + return; + case -2: + Con_Printf("Argument not known: %s\n", cmd); + return; + } +} +static void R_EditLights_Remove_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + dl = &cl_dlights[i]; + dl->radius = 0; + r_editlights_selected = -1; +} +static void R_EditLights_EditAll_f(void) +{ + int i = 0; + const char *cmd = Cmd_Argv(1); + const char *x = Cmd_Argv(2); + const char *y = Cmd_Argv(3); + const char *z = Cmd_Argv(4); + int argc = Cmd_Argc()-2; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("No light selected\n"); + return; + } + for (i = RTL_FIRST; i < rtlights_max; i++) + { + dl = &cl_dlights[i]; + if (dl->radius <= 0) + continue; //don't edit dead lights back to life + switch(R_EditLight(dl, cmd, argc, x,y,z)) + { + case -1: + Con_Printf("Not enough args for %s\n", cmd); + return; + case -2: + Con_Printf("Argument not known: %s\n", cmd); + return; + } + } +} +static void R_EditLights_Spawn_f(void) +{ + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + dl = CL_AllocSlight(); + r_editlights_selected = dl - cl_dlights; + + VectorCopy(r_editlights_cursor, dl->origin); + dl->radius = 200; + + dl->style = 1; //0... gah. match DP's results. + dl->lightcolourscales[0] = 0; + dl->lightcolourscales[1] = 1; + dl->lightcolourscales[2] = 1; +} +static void R_EditLights_Clone_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + dlight_t *src; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + src = &cl_dlights[i]; + dl = CL_AllocSlight(); + r_editlights_selected = dl - cl_dlights; + CL_CloneDlight(dl, src); + + VectorCopy(r_editlights_cursor, dl->origin); +} +static void R_EditLights_ToggleShadow_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + dl = &cl_dlights[i]; + dl->flags ^= LFLAG_NOSHADOWS; +} +static void R_EditLights_ToggleCorona_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + dl = &cl_dlights[i]; + dl->corona = !dl->corona; +} +static void R_EditLights_CopyInfo_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + return; + dl = &cl_dlights[i]; + CL_CloneDlight(&r_editlights_copybuffer, dl); +} +static void R_EditLights_PasteInfo_f(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + vec3_t org; + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + if (i < RTL_FIRST || i >= rtlights_max) + { + Con_Printf("No light selected\n"); + return; + } + dl = &cl_dlights[i]; + VectorCopy(dl->origin, org); + CL_CloneDlight(dl, &r_editlights_copybuffer); + VectorCopy(org, dl->origin); //undo the origin's copy. + + //just in case its from a different map... + if (*dl->cubemapname) + dl->cubetexture = R_LoadReplacementTexture(dl->cubemapname, "", IF_CUBEMAP, NULL, 0, 0, TF_INVALID); + else + dl->cubetexture = r_nulltex; +} + +static void R_EditLights_Lock_f(void) +{ + if (!r_editlights.ival) + { + Con_Printf("Toggle r_editlights first\n"); + return; + } + + if ((r_editlights_selected < RTL_FIRST || r_editlights_selected >= rtlights_max) && !r_editlights_locked) + { + Con_Printf("No light selected\n"); + return; + } + r_editlights_locked = !r_editlights_locked; +} + +static char macro_buf[256] = ""; +static char *r_editlights_current_origin(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g %g %g", dl->origin[0], dl->origin[1], dl->origin[2]); + return macro_buf; +} +static char *r_editlights_current_angles(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g %g %g", dl->angles[0], dl->angles[1], dl->angles[2]); + return macro_buf; +} +static char *r_editlights_current_color(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g %g %g", dl->color[0], dl->color[1], dl->color[2]); + return macro_buf; +} +static char *r_editlights_current_radius(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->radius); + return macro_buf; +} +static char *r_editlights_current_corona(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->corona); + return macro_buf; +} +static char *r_editlights_current_coronasize(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->coronascale); + return macro_buf; +} +static char *r_editlights_current_style(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%i", dl->style-1); + return macro_buf; +} +static char *r_editlights_current_shadows(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + if (dl->flags & LFLAG_NOSHADOWS) + return "0"; + return "1"; +} +static char *r_editlights_current_cubemap(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "\"%s\"", dl->cubemapname); + return macro_buf; +} +static char *r_editlights_current_ambient(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->lightcolourscales[0]); + return macro_buf; +} +static char *r_editlights_current_diffuse(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->lightcolourscales[1]); + return macro_buf; +} +static char *r_editlights_current_specular(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + Q_snprintfz (macro_buf, sizeof(macro_buf), "%g", dl->lightcolourscales[2]); + return macro_buf; +} +static char *r_editlights_current_normalmode(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + if (dl->flags & LFLAG_NORMALMODE) + return "1"; + return "0"; +} +static char *r_editlights_current_realtimemode(void) +{ + int i = r_editlights_selected; + dlight_t *dl; + if (i < RTL_FIRST || i >= rtlights_max) + return ""; + dl = &cl_dlights[i]; + + if (dl->flags & LFLAG_REALTIMEMODE) + return "1"; + return "0"; +} + +void R_EditLights_RegisterCommands(void) +{ + Cmd_AddCommandD ("r_editlights_reload", R_ReloadRTLights_f, "Reload static rtlights. Argument can be rtlights|statics|bsp|none to override the source."); + Cmd_AddCommandD ("r_editlights_save", R_SaveRTLights_f, "Saves rtlights to maps/FOO.rtlights"); + Cvar_Register (&r_editlights_import_radius, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_import_ambient, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_import_diffuse, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_import_specular, "Realtime Light editing/importing"); + + Cvar_Register (&r_editlights, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_cursordistance, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_cursorpushoff, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_cursorpushback, "Realtime Light editing/importing"); + Cvar_Register (&r_editlights_cursorgrid, "Realtime Light editing/importing"); + + //the rest is optional stuff that should normally be handled via csqc instead, but hurrah for dp compat... + Cmd_AddCommandD("r_editlights_spawn", R_EditLights_Spawn_f, "Spawn a new light with default properties"); + Cmd_AddCommandD("r_editlights_clone", R_EditLights_Clone_f, "Duplicate the current light (with a new origin)"); + Cmd_AddCommandD("r_editlights_remove", R_EditLights_Remove_f, "Removes the current light."); + Cmd_AddCommandD("r_editlights_edit", R_EditLights_Edit_f, "Changes named properties on the current light."); + Cmd_AddCommandD("r_editlights_editall", R_EditLights_EditAll_f, "Like r_editlights_edit, but affects all lights instead of just the selected one."); + Cmd_AddCommandD("r_editlights_toggleshadow", R_EditLights_ToggleShadow_f, "Toggles the shadow flag on the current light."); + Cmd_AddCommandD("r_editlights_togglecorona", R_EditLights_ToggleCorona_f, "Toggles the current light's corona field."); + Cmd_AddCommandD("r_editlights_copyinfo", R_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light"); + Cmd_AddCommandD("r_editlights_pasteinfo", R_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)"); + Cmd_AddCommandD("r_editlights_lock", R_EditLights_Lock_f, "Blocks changing the current light according the crosshair."); + + //DP has these as cvars. mneh. + Cmd_AddMacroD("r_editlights_current_origin", r_editlights_current_origin, false, "origin of selected light"); + Cmd_AddMacroD("r_editlights_current_angles", r_editlights_current_angles, false, "angles of selected light"); + Cmd_AddMacroD("r_editlights_current_color", r_editlights_current_color, false, "color of selected light"); + Cmd_AddMacroD("r_editlights_current_radius", r_editlights_current_radius, false, "radius of selected light"); + Cmd_AddMacroD("r_editlights_current_corona", r_editlights_current_corona, false, "corona intensity of selected light"); + Cmd_AddMacroD("r_editlights_current_coronasize",r_editlights_current_coronasize,false, "corona size of selected light"); + Cmd_AddMacroD("r_editlights_current_style", r_editlights_current_style, false, "style of selected light"); + Cmd_AddMacroD("r_editlights_current_shadows", r_editlights_current_shadows, false, "shadows flag of selected light"); + Cmd_AddMacroD("r_editlights_current_cubemap", r_editlights_current_cubemap, false, "cubemap of selected light"); + Cmd_AddMacroD("r_editlights_current_ambient", r_editlights_current_ambient, false, "ambient intensity of selected light"); + Cmd_AddMacroD("r_editlights_current_diffuse", r_editlights_current_diffuse, false, "diffuse intensity of selected light"); + Cmd_AddMacroD("r_editlights_current_specular", r_editlights_current_specular, false, "specular intensity of selected light"); + Cmd_AddMacroD("r_editlights_current_normalmode",r_editlights_current_normalmode,false, "normalmode flag of selected light"); + Cmd_AddMacroD("r_editlights_current_realtimemode", r_editlights_current_realtimemode, false, "realtimemode flag of selected light"); } #endif diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index d13926ca4..e5287592f 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1947,7 +1947,7 @@ void GLR_RenderView (void) if (dofbo) forcedfb = false; else if (renderscale != 1) - forcedfb = true; + forcedfb = gl_config.ext_framebuffer_objects && sh_config.texture_non_power_of_two_pic; BE_Scissor(NULL); if (dofbo) @@ -1956,6 +1956,13 @@ void GLR_RenderView (void) texid_t col[R_MAX_RENDERTARGETS], depth = r_nulltex; unsigned int cw=0, ch=0, dw=0, dh=0; int mrt; + + if (!gl_config.ext_framebuffer_objects && sh_config.texture_non_power_of_two_pic) + { + Con_DPrintf(CON_WARNING"Render targets are not supported on this gpu.\n"); + return; //not supported on this gpu. you'll just get black textures or something. + } + //3d views generally ignore source colour+depth. //FIXME: support depth with no colour for (mrt = 0; mrt < R_MAX_RENDERTARGETS; mrt++) diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index e1117650e..0f41c09cb 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -195,7 +195,7 @@ qboolean GLSCR_UpdateScreen (void) if (uimenu != 1) { if (r_worldentity.model && cls.state == ca_active) - V_RenderView (); + V_RenderView (nohud); else { noworld = true; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 96f62be01..1ff23a4b8 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -7298,9 +7298,7 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize) break; } } - } - - if ( parsename ) { + if (!strchr(parsename, ':')) { //if the named shader is a .shader file then just directly load it. diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 38b6749a0..2d666efc1 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -62,10 +62,6 @@ cvar_t r_shadow_realtime_dlight_shadows = CVARFD ("r_shadow_realtime_dlight_sha cvar_t r_shadow_realtime_dlight_ambient = CVAR ("r_shadow_realtime_dlight_ambient", "0"); cvar_t r_shadow_realtime_dlight_diffuse = CVAR ("r_shadow_realtime_dlight_diffuse", "1"); cvar_t r_shadow_realtime_dlight_specular = CVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people -cvar_t r_editlights_import_radius = CVAR ("r_editlights_import_radius", "1"); -cvar_t r_editlights_import_ambient = CVAR ("r_editlights_import_ambient", "0"); -cvar_t r_editlights_import_diffuse = CVAR ("r_editlights_import_diffuse", "1"); -cvar_t r_editlights_import_specular = CVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people cvar_t r_shadow_playershadows = CVARD ("r_shadow_playershadows", "1", "Controls the presence of shadows on the local player."); cvar_t r_shadow_shadowmapping = CVARD ("r_shadow_shadowmapping", "1", "Enables soft shadows instead of stencil shadows."); cvar_t r_shadow_shadowmapping_precision = CVARD ("r_shadow_shadowmapping_precision", "1", "Scales the shadowmap detail level up or down."); @@ -3571,7 +3567,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours) void Sh_PurgeShadowMeshes(void) { dlight_t *dl; - int i; + size_t i; for (dl = cl_dlights, i=0; iworldshadowmesh) @@ -3604,6 +3600,12 @@ void Sh_PreGenerateLights(void) qboolean okay = false; if (!okay) okay |= R_LoadRTLights(); + if (!okay) + { + for (i = 0; i < cl.num_statics; i++) + R_StaticEntityToRTLight(i); + okay |= rtlights_max != RTL_FIRST; + } if (!okay) okay |= R_ImportRTLights(Mod_GetEntitiesString(cl.worldmodel)); if (!okay && r_shadow_realtime_world.ival && r_shadow_realtime_world_lightmaps.value != 1) @@ -3867,6 +3869,54 @@ void Sh_DrawLights(qbyte *vis) colour[0] = dl->color[0]; colour[1] = dl->color[1]; colour[2] = dl->color[2]; + if (dl->customstyle) + { + const char *map = dl->customstyle; + int maplen = strlen(map); + + int idx, v1, v2, vd; + float frac, strength; + + if (!maplen) + { + strength = ('m'-'a')*22 * r_lightstylescale.value/255.0; + } + else if (map[0] == '=') + { + strength = atof(map+1)*r_lightstylescale.value; + } + else + { + frac = (cl.time*r_lightstylespeed.value); + if (*map == '?' && maplen>1) + { + map++; + maplen--; + frac += i*M_PI; + } + frac += i*M_PI; + if (frac < 0) + frac = 0; + idx = (int)frac; + frac -= idx; //this can require updates at 1000 times a second.. Depends on your framerate of course + + v1 = idx % maplen; + v1 = map[v1] - 'a'; + + v2 = (idx+1) % maplen; + v2 = map[v2] - 'a'; + + vd = v1 - v2; + if (/*!r_lightstylesmooth.ival ||*/ vd < -r_lightstylesmooth_limit.ival || vd > r_lightstylesmooth_limit.ival) + strength = v1*(22/255.0)*r_lightstylescale.value; + else + strength = (v1*(1-frac) + v2*(frac))*(22/255.0)*r_lightstylescale.value; + } + strength *= d_lightstylevalue[0]/255.0f; //a lot of QW mods use lightstyle 0 for a global darkening fade-in thing, so be sure to respect that. + colour[0] *= strength; + colour[1] *= strength; + colour[2] *= strength; + } if (dl->style) { colour[0] *= cl_lightstyle[dl->style-1].colours[0] * d_lightstylevalue[dl->style-1]/255.0f; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 23202821f..505fdf1b9 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -3450,7 +3450,7 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int break; } #endif - Con_Printf("Failed to create a vulkan context.\n"); + Con_Printf(CON_ERROR "Failed to create a vulkan context.\n"); GLVID_Shutdown(); return false; #endif diff --git a/engine/gl/gl_vidwayland.c b/engine/gl/gl_vidwayland.c index 9148655b6..96a13d982 100644 --- a/engine/gl/gl_vidwayland.c +++ b/engine/gl/gl_vidwayland.c @@ -375,26 +375,6 @@ static void WL_BindRelativePointerManager(struct wl_registry *registry, uint32_t w.relative_pointer_manager = pwl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1); } -/* -struct zwp_locked_pointer_v1; -static void WL_locked_pointer_locked(void *data, struct zwp_locked_pointer_v1 *locked_pointer) -{ -} -static void WL_locked_pointer_unlocked(void *data, struct zwp_locked_pointer_v1 *locked_pointer) -{ -} -struct zwp_locked_pointer_v1_listener -{ - void (*pointer_locked)(void *data, struct zwp_locked_pointer_v1 *locked_pointer); - void (*pointer_unlocked)(void *data, struct zwp_locked_pointer_v1 *locked_pointer); -}; -static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = -{ - WL_locked_pointer_locked, - WL_locked_pointer_unlocked, -}; -*/ - static void WL_keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { } @@ -490,10 +470,49 @@ static const struct wl_seat_listener seat_listener = WL_seat_handle_capabilities }; + +#if 0 +static void WL_BindDecoraionManager(struct wl_registry *registry, uint32_t id) +{ /*oh hey, I wrote lots of code! pay me more! fuck that shit.*/ + + static const struct wl_interface *types[3]; + static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + { "destroy", "", types + 0 }, + { "get_toplevel_decoration", "no", types + 1 }, + }; + static const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", 1, + 2, zxdg_decoration_manager_v1_requests, + 0, NULL, + }; + static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + { "destroy", "", types + 0 }, + { "set_mode", "u", types + 0 }, + { "unset_mode", "", types + 0 }, + }; + static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + { "configure", "u", types + 0 }, + }; + static const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", 1, + 3, zxdg_toplevel_decoration_v1_requests, + 1, zxdg_toplevel_decoration_v1_events, + }; + + //fix up types... + types[1] = &zxdg_toplevel_decoration_v1_interface; + types[2] = NULL;//&xdg_toplevel_interface; + +// pzwp_relative_pointer_v1_interface = &zxdg_toplevel_decoration_v1_interface; + w.decoration_manager = pwl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); +} +#endif + + static void WL_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { struct wdisplay_s *d = data; -//Sys_Printf("Interface %s id %u\n", interface, id); +Con_DLPrintf(2, "Wayland Interface %s id %u\n", interface, id); if (strcmp(interface, "wl_compositor") == 0) d->compositor = pwl_registry_bind(registry, id, pwl_compositor_interface, 1); else if (strcmp(interface, "wl_shell") == 0) @@ -505,6 +524,8 @@ static void WL_handle_global(void *data, struct wl_registry *registry, uint32_t } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) WL_BindRelativePointerManager(registry, id); +// else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) +// WL_BindDecorationManager(registry, id); // else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) // d->shell = pwl_registry_bind(registry, id, pwl_shell_interface, 1); /* else if (!strcmp(interface, "input_device")) @@ -659,7 +680,10 @@ static qboolean WL_Init (rendererstate_t *info, unsigned char *palette) case QR_VULKAN: { const char *extnames[] = {VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, NULL}; - return VK_Init(info, extnames, WLVK_SetupSurface, NULL); + if (VK_Init(info, extnames, WLVK_SetupSurface, NULL)) + return true; + Con_Printf(CON_ERROR "Unable to initialise vulkan-on-wayland.\n"); + return false; } break; #endif diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 9d8fa0b6c..4f2615b7a 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -405,10 +405,8 @@ void R_InitFlashblends(void); void GLR_MarkQ2Lights (dlight_t *light, int bit, mnode_t *node); #endif void GLQ3_LightGrid(model_t *mod, vec3_t point, vec3_t res_diffuse, vec3_t res_ambient, vec3_t res_dir); -void R_ReloadRTLights_f(void); qboolean R_LoadRTLights(void); qboolean R_ImportRTLights(const char *entlump); -void R_SaveRTLights_f(void); //doom #ifdef MAP_DOOM diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 7c6130e6e..e9f056222 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -947,6 +947,9 @@ void BE_GenerateProgram(shader_t *shader); void Sh_RegisterCvars(void); #ifdef RTLIGHTS +void R_EditLights_DrawLights(void); //3d light previews +void R_EditLights_DrawInfo(void); //2d light info display. +void R_EditLights_RegisterCommands(void); // #ifdef BEF_PUSHDEPTH void GLBE_PolyOffsetStencilShadow(qboolean foobar); @@ -982,6 +985,7 @@ extern struct shader_field_names_s shader_unif_names[]; extern struct shader_field_names_s shader_attr_names[]; +void CLQ1_AddSpriteQuad(shader_t *shader, vec3_t mid, float radius); void CLQ1_DrawLine(shader_t *shader, vec3_t v1, vec3_t v2, float r, float g, float b, float a); void CLQ1_AddOrientedCube(shader_t *shader, vec3_t mins, vec3_t maxs, float *matrix, float r, float g, float b, float a); void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qboolean enqueue); diff --git a/engine/http/iweb.h b/engine/http/iweb.h index 8a78415c6..cf1b9f77b 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -91,7 +91,7 @@ struct dl_download qboolean isquery; //will not be displayed in the download/progress bar stuff. -#ifndef SERVERONLY +#ifdef HAVE_CLIENT qdownload_t qdownload; #endif diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 67a584d65..722940d4b 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -7,7 +7,7 @@ #ifdef WEBSVONLY //we need some functions from quake -char *NET_SockadrToString(char *s, int slen, struct sockaddr_qstorage *addr) +char *NET_SockadrToString(char *s, int slen, struct sockaddr_qstorage *addr, size_t sizeofaddr) { switch(((struct sockaddr*)addr)->sa_family) { @@ -221,8 +221,14 @@ int main(int argc, char **argv) if (arg < argc) autheduserpassword = argv[arg++]; - printf("http port %i\n", httpport); - printf("ftp port %i\n", ftpport); + if (httpport) + printf("http port %i\n", httpport); + else + printf("http not enabled\n"); + if (ftpport) + printf("ftp port %i\n", ftpport); + else + printf("ftp not enabled\n"); if (authedusername || autheduserpassword) printf("Username = \"%s\"\nPassword = \"%s\"\n", authedusername, autheduserpassword); else diff --git a/engine/qclib/packager.c b/engine/qclib/packager.c index 9a4da7ecd..e0499c7a9 100644 --- a/engine/qclib/packager.c +++ b/engine/qclib/packager.c @@ -59,7 +59,7 @@ texa0 struct pkgctx_s { - void (*messagecallback)(void *userctx, char *message, ...); + void (*messagecallback)(void *userctx, const char *message, ...); void *userctx; char *listfile; @@ -1557,7 +1557,7 @@ void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname) PKG_WriteDataset(ctx, dataset); } } -struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message, ...), void *userctx) +struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, const char *message, ...), void *userctx) { struct pkgctx_s *ctx; ctx = malloc(sizeof(*ctx)); diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 2405684ea..7cbdc2530 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -823,6 +823,7 @@ enum { WARN_COMPATIBILITYHACK, //work around old defs.qc or invalid dpextensions.qc WARN_REDECLARATIONMISMATCH, WARN_PARAMWITHNONAME, + WARN_ARGUMENTCHECK, ERR_PARSEERRORS, //caused by qcc_pr_parseerror being called. @@ -1148,7 +1149,7 @@ int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell struct pkgctx_s; -struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, char *message, ...), void *userctx); +struct pkgctx_s *Packager_Create(void (*messagecallback)(void *userctx, const char *message, ...), void *userctx); void Packager_ParseFile(struct pkgctx_s *ctx, char *scriptfilename); void Packager_ParseText(struct pkgctx_s *ctx, char *scripttext); void Packager_WriteDataset(struct pkgctx_s *ctx, char *setname); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 11d3ed3fb..50ea75cda 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4831,6 +4831,107 @@ nolength: } } +static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglist, unsigned int argcount) +{ + static struct + { + const char *name; + int n; + etype_t t1; + etype_t t2; + etype_t t3; + } argtypes[] = + { + {"VF_MIN", 1, ev_vector}, + {"VF_MIN_X", 2, ev_float}, + {"VF_MIN_Y", 3, ev_float}, + {"VF_SIZE", 4, ev_vector}, + {"VF_SIZE_X", 5, ev_float}, + {"VF_SIZE_Y", 6, ev_float}, + {"VF_VIEWPORT", 7, ev_vector}, + {"VF_FOV", 8, ev_vector}, + {"VF_FOVX", 9, ev_float}, + {"VF_FOVY", 10, ev_float}, + {"VF_ORIGIN", 11, ev_vector}, + {"VF_ORIGIN_X", 12, ev_float}, + {"VF_ORIGIN_Y", 13, ev_float}, + {"VF_ORIGIN_Z", 14, ev_float}, + {"VF_ANGLES", 15, ev_vector}, + {"VF_ANGLES_X", 16, ev_float}, + {"VF_ANGLES_Y", 17, ev_float}, + {"VF_ANGLES_Z", 18, ev_float}, + {"VF_DRAWWORLD", 19, ev_float}, + {"VF_ENGINESBAR", 20, ev_float}, + {"VF_DRAWCROSSHAIR", 21, ev_float}, +// {"VF_CARTESIAN_ANGLES", 22, ev_vector}, + {"VF_MINDIST", 23, ev_float}, + {"VF_MAXDIST", 24, ev_float}, + + {"VF_CL_VIEWANGLES_V", 33, ev_vector}, + {"VF_CL_VIEWANGLES_X", 34, ev_float}, + {"VF_CL_VIEWANGLES_X", 35, ev_float}, + {"VF_CL_VIEWANGLES_X", 36, ev_float}, + {"VF_PERSPECTIVE", 200, ev_float}, + //201 + {"VF_ACTIVESEAT", 202, ev_float}, + {"VF_AFOV", 203, ev_float}, +// {"VF_SCREENVSIZE", 204, ev_vector}, +// {"VF_SCREENPSIZE", 205, ev_vector}, + {"VF_VIEWENTITY", 206, ev_float}, +// {"VF_STATSENTITY", 207, ev_float}, +// {"VF_SCREENVOFFSET", 208, ev_float}, + {"VF_RT_SOURCECOLOUR", 209, ev_string}, + {"VF_RT_DEPTH", 210, ev_string, ev_float, ev_vector}, + {"VF_RT_RIPPLE", 211, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR0", 212, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR1", 213, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR2", 214, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR3", 215, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR4", 216, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR5", 217, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR6", 218, ev_string, ev_float, ev_vector}, + {"VF_RT_DESTCOLOUR7", 219, ev_string, ev_float, ev_vector}, + {"VF_ENVMAP", 220, ev_string}, + {"VF_USERDATA", 221, ev_pointer, ev_integer}, + }; + + char temp[256]; + const QCC_eval_t *ev; + int i, vf; + if (!argcount) + return; // o.O + ev = QCC_SRef_EvalConst(arglist[0]->base); + if (!ev) //can't check variables. + return; + vf = ev->_float; + if (!qccwarningaction[WARN_ARGUMENTCHECK]) + return; //don't bother if its not relevant anyway. + + for (i = 0; i < sizeof(argtypes)/sizeof(argtypes[0]); i++) + { + if (argtypes[i].n == vf) + { + if (argcount >= 2 && argtypes[i].t1 != arglist[1]->cast->type) + { + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s(%s, ...): expected %s, got %s", funcname, argtypes[i].name, basictypenames[argtypes[i].t1], TypeName(arglist[1]->cast, temp, sizeof(temp))); + return; + } + if (argcount >= 3 && argtypes[i].t2 != arglist[2]->cast->type) + { + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s(%s, X, ...): expected %s, got %s", funcname, argtypes[i].name, basictypenames[argtypes[i].t2], TypeName(arglist[2]->cast, temp, sizeof(temp))); + return; + } + if (argcount >= 4 && argtypes[i].t3 != arglist[3]->cast->type) + { + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s(%s, X, Y, ...): expected %s, got %s", funcname, argtypes[i].name, basictypenames[argtypes[i].t3], TypeName(arglist[3]->cast, temp, sizeof(temp))); + return; + } + return; + } + } + QCC_PR_ParseWarning(WARN_ARGUMENTCHECK, "%s: unknown argument %i", funcname, vf); +} + #ifdef SUPPORTINLINE struct inlinectx_s { @@ -5336,6 +5437,8 @@ QCC_sref_t QCC_PR_GenerateFunctionCallRef (QCC_sref_t newself, QCC_sref_t func, if (!strcmp(funcname, "sprintf")) QCC_VerifyFormatString(funcname, arglist, argcount); + if (!strcmp(funcname, "setviewprop") || !strcmp(funcname, "setproperty")) + QCC_VerifyArgs_setviewprop(funcname, arglist, argcount); func.sym->timescalled++; diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index bbccf933e..f36af5d71 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -3012,7 +3012,7 @@ static void EditorReload(editor_t *editor) size_t flensz; char *rawfile; char *file; - unsigned int flen; + size_t flen; pbool dofree; rawfile = QCC_ReadFile(editor->filename, NULL, NULL, &flensz); flen = flensz; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index ca0fb0712..210efe95e 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -12022,6 +12022,7 @@ void PR_DumpPlatform_f(void) {"MOVETYPE_6DOF", "const float", QW|NQ|CS, D("A glorified MOVETYPE_FLY. Players using this movetype will get some flightsim-like physics, with fully independant rotations (order-dependant transforms)."), MOVETYPE_6DOF}, {"MOVETYPE_WALLWALK", "const float", QW|NQ|CS, D("Players using this movetype will be able to orient themselves to walls, and then run up them."), MOVETYPE_WALLWALK}, {"MOVETYPE_PHYSICS", "const float", QW|NQ|CS, D("Enable the use of ODE physics upon this entity."), MOVETYPE_PHYSICS}, +// {"MOVETYPE_FLY_WORLDONLY", "const float", QW|NQ|CS, D("A cross between noclip and fly. Basically, this prevents the player/spectator from being able to move into the void, which avoids pvs issues that are common with caulk brushes on q3bsp. ONLY the world model will be solid, all doors/etc will be non-solid."), MOVETYPE_FLY_WORLDONLY}, {"SOLID_NOT", "const float", QW|NQ|CS, NULL, SOLID_NOT}, {"SOLID_TRIGGER", "const float", QW|NQ|CS, NULL, SOLID_TRIGGER}, @@ -12463,6 +12464,7 @@ void PR_DumpPlatform_f(void) {"LFIELD_DIETIME", "const float", CS, NULL, lfield_dietime}, {"LFIELD_RGBDECAY", "const float", CS, NULL, lfield_rgbdecay}, {"LFIELD_RADIUSDECAY", "const float", CS, NULL, lfield_radiusdecay}, + {"LFIELD_STYLESTRING", "const float", CS, NULL, lfield_stylestring}, {"LFLAG_NORMALMODE", "const float", CS, NULL, LFLAG_NORMALMODE}, {"LFLAG_REALTIMEMODE", "const float", CS, NULL, LFLAG_REALTIMEMODE}, @@ -12614,17 +12616,17 @@ void PR_DumpPlatform_f(void) VFS_PRINTF(f, "#pragma noref 1\n"); VFS_PRINTF(f, "//#pragma flag enable logicops\n"); - VFS_PRINTF(f, "#pragma warning error Q101 /*too many parms*/\n"); - VFS_PRINTF(f, "#pragma warning error Q105 /*too few parms*/\n"); - VFS_PRINTF(f, "#pragma warning error Q106 /*assignment to constant/lvalue*/\n"); - VFS_PRINTF(f, "#pragma warning error Q208 /*system crc unknown*/\n"); + VFS_PRINTF(f, "#pragma warning error Q101 /*too many parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/\n"); + VFS_PRINTF(f, "#pragma warning error Q105 /*too few parms. The vanilla qcc didn't validate properly, hence why fteqcc normally treats it as a warning.*/\n"); + VFS_PRINTF(f, "#pragma warning error Q106 /*assignment to constant/lvalue. Define them as var if you want to initialise something.*/\n"); + VFS_PRINTF(f, "#pragma warning error Q208 /*system crc unknown. Compatibility goes out of the window if you disable this.*/\n"); #ifdef NOLEGACY - VFS_PRINTF(f, "#pragma warning error F211 /*system crc outdated (eg: dp's csqc)*/\n"); + VFS_PRINTF(f, "#pragma warning error F211 /*system crc outdated (eg: dp's csqc). Such mods will not run properly in FTE.*/\n"); #else - VFS_PRINTF(f, "#pragma warning disable F211 /*system crc outdated (eg: dp's csqc)*/\n"); + VFS_PRINTF(f, "#pragma warning disable F211 /*system crc outdated (eg: dp's csqc). Note that this may trigger emulation.*/\n"); #endif - VFS_PRINTF(f, "#pragma warning enable F301 /*non-utf-8 strings*/\n"); - VFS_PRINTF(f, "#pragma warning enable F302 /*uninitialised locals*/\n"); + VFS_PRINTF(f, "#pragma warning enable F301 /*non-utf-8 strings. Think of the foreigners! Also think of text editors that insist on screwing up your char encodings.*/\n"); + VFS_PRINTF(f, "#pragma warning enable F302 /*uninitialised locals. They usually default to 0 in qc (except in recursive functions), but its still probably a bug*/\n"); if ((targ&ALL) == H2) { diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 7af08a47c..82d23db42 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -1571,7 +1571,7 @@ void SV_Savegame (const char *savename, qboolean mapchange) #endif if (!okay && r_worldentity.model) { - V_RenderView (); + V_RenderView (false); okay = true; } @@ -1583,7 +1583,7 @@ void SV_Savegame (const char *savename, qboolean mapchange) if (rgbbuffer) { // extern cvar_t scr_sshot_type; - SCR_ScreenShot(savefilename, FS_GAMEONLY, &rgbbuffer, 1, stride, width, height, fmt); + SCR_ScreenShot(savefilename, FS_GAMEONLY, &rgbbuffer, 1, stride, width, height, fmt, false); BZ_Free(rgbbuffer); diff --git a/engine/server/server.h b/engine/server/server.h index b5d8c4f6c..e559f2ed9 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1310,7 +1310,9 @@ void SV_UpdateToReliableMessages (void); void SV_FlushBroadcasts (void); qboolean SV_CanTrack(client_t *client, int entity); +#ifdef NQPROT void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg); +#endif void SV_New_f (void); void SV_PreRunCmd(void); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 703846f48..9adc60a76 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -2639,6 +2639,9 @@ client_t *SVC_DirectConnect(void) } } msg_badread=false; + + if (!*guid) + NET_GetConnectionCertificate(svs.sockets, &net_from, QCERT_PEERFINGERPRINT, guid, sizeof(guid)); /*allow_splitscreen applies only to non-local clients, so that clients have only one enabler*/ if (!sv_allow_splitscreen.ival && net_from.type != NA_LOOPBACK) @@ -3303,8 +3306,10 @@ client_t *SVC_DirectConnect(void) SSV_SavePlayerStats(newcl, 0); #endif +#ifdef IPLOG if (Q_strncasecmp(newcl->name, "unconnected", 11) && Q_strncasecmp(newcl->name, "connecting", 10)) IPLog_Add(NET_AdrToString(adrbuf,sizeof(adrbuf), &newcl->netchan.remote_address), newcl->name); +#endif return newcl; } @@ -5799,8 +5804,10 @@ void SV_Init (quakeparms_t *parms) } #endif - IPLog_Merge_File("iplog.txt"); +#ifdef IPLOG + IPLog_Merge_File("iplog.txt"); //should be compatible with DP's take on the feature. IPLog_Merge_File("iplog.dat"); //legacy crap, for compat with proquake +#endif // if a map wasn't specified on the command line, spawn start.map //aliases require that we flush the cbuf in order to actually see the results. diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 5e23efd0b..d5efb69fa 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -32,7 +32,7 @@ is not a staircase. ============= */ -int c_yes, c_no; +//int c_yes, c_no; hull_t *Q1BSP_ChooseHull(model_t *model, int hullnum, vec3_t mins, vec3_t maxs, vec3_t offset); @@ -92,11 +92,11 @@ qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up) goto realcheck; } - c_yes++; +// c_yes++; return true; // we got out easy realcheck: - c_no++; +// c_no++; // // check it for real... // @@ -128,7 +128,7 @@ realcheck: return false; } - c_yes++; +// c_yes++; return true; } @@ -629,7 +629,7 @@ qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist) #ifdef ENGINE_ROUTING -cvar_t route_shownodes = CVAR("route_shownodes", "0"); +static cvar_t route_shownodes = CVAR("route_shownodes", "0"); #define LF_EDGE 0x00000001 #define LF_JUMP 0x00000002 @@ -648,7 +648,7 @@ struct waypointnetwork_s vec3_t pos; int linkflags; } *displaynode; - int displaynodes; + size_t displaynodes; struct waypoint_s { @@ -660,7 +660,7 @@ struct waypointnetwork_s float linkcost;//might be much lower in the case of teleports, or expensive if someone wanted it to be a lower priority link. int linkflags; //LF_* } *neighbour; - int neighbours; + size_t neighbours; } waypoints[1]; }; void WayNet_Done(struct waypointnetwork_s *net) @@ -814,8 +814,8 @@ int WayNet_FindNearestNode(struct waypointnetwork_s *net, vec3_t pos) struct routecalc_s { world_t *world; - int spawncount; //so we don't confuse stuff if the map gets restarted. wedict_t *ed; + int spawncount; //so we don't confuse stuff if the map gets restarted. // float spawnid; //so the route fails if the ent is removed. func_t callback; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 904329274..e7390352e 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -2831,7 +2831,9 @@ qboolean SV_SendClientDatagram (client_t *client) SZ_Clear (&msg); } +#ifdef NQPROT SV_DarkPlacesDownloadChunk(client, &msg); +#endif // send the datagram sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client)); @@ -3693,7 +3695,9 @@ void SV_SendClientMessages (void) SV_SendClientDatagram (c); else { +#ifdef NQPROT SV_DarkPlacesDownloadChunk(c, &c->datagram); +#endif fnum = c->netchan.outgoing_sequence; sentbytes = Netchan_Transmit (&c->netchan, c->datagram.cursize, c->datagram.data, SV_RateForClient(c)); // just update reliable if (ISQWCLIENT(c) || ISNQCLIENT(c)) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 33912952e..a61b6de02 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -349,7 +349,7 @@ void SV_New_f (void) for (split = host_client; split; split = split->controlled) { playernum = split - svs.clients;// NUM_FOR_EDICT(svprogfuncs, split->edict)-1; - if (sv.state == ss_cinematic) + if (ISQ2CLIENT(host_client) && sv.state == ss_cinematic) playernum = -1; ClientReliableWrite_Byte (host_client, playernum); @@ -391,9 +391,6 @@ void SV_New_f (void) if (split->spectator) playernum |= 128; - if (sv.state == ss_cinematic) - playernum = -1; - split->state = cs_connected; split->connection_started = realtime; #ifdef SVRANKING @@ -403,6 +400,8 @@ void SV_New_f (void) if (ISQ2CLIENT(host_client)) { + if (sv.state == ss_cinematic) + playernum = -1; ClientReliableWrite_Short (host_client, playernum); break; } @@ -462,6 +461,16 @@ void SV_New_f (void) SV_LogPlayer(host_client, "new (QW)"); + if (sv.state == ss_cinematic) + { + char tmp[1024]; + MSG_WriteByte (&host_client->netchan.message, svc_stufftext); + MSG_WriteString(&host_client->netchan.message, va("\nplayfilm %s\n", COM_QuotedString(svs.name, tmp, sizeof(tmp), false))); + host_client->prespawn_stage = PRESPAWN_INVALID; + host_client->prespawn_idx = 0; + return; + } + host_client->prespawn_stage = PRESPAWN_SERVERINFO; host_client->prespawn_idx = 0; } @@ -718,6 +727,16 @@ void SVNQ_New_f (void) MSG_WriteString (&host_client->netchan.message, "cl_serverextension_download 1\n"); } + if (sv.state == ss_cinematic) + { + MSG_WriteByte (&host_client->netchan.message, svc_stufftext); + MSG_WriteString(&host_client->netchan.message, va("\nplayfilm %s\n", COM_QuotedString(svs.name, message, sizeof(message), false))); + host_client->prespawn_stage = PRESPAWN_INVALID; + host_client->prespawn_idx = 0; + host_client->netchan.nqunreliableonly = 2; + return; + } + MSG_WriteByte (&host_client->netchan.message, svc_serverdata); if (protext1) { @@ -2242,6 +2261,7 @@ void SV_Begin_f (void) //============================================================================= +#ifdef NQPROT //dp downloads are a 2-stream system //the server->client stream is as you'd expect. except that its unreliable rather than reliable //the client->server stream contains no actual data. @@ -2349,6 +2369,7 @@ void SV_DarkPlacesDownloadAck(client_t *cl) host_client->downloadsize = 0; } } +#endif static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum, int chunks) { @@ -5485,14 +5506,6 @@ void SV_DisableClientsCSQC(void) } void SV_UserCmdMVDList_f (void); -static void SV_STFU_f(void) -{ - char *msg; - SV_ClientPrintf(host_client, 255, "stfu\n"); - msg = "cl_antilag 0\n"; - ClientReliableWrite_Begin(host_client, svc_stufftext, 2+strlen(msg)); - ClientReliableWrite_String(host_client, msg); -} #ifdef NQPROT static void SVNQ_Spawn_f (void) @@ -5975,9 +5988,6 @@ ucmd_t ucmds[] = {"spawn", SVQW_Spawn_f, true}, {"begin", SV_Begin_f, true}, - /*ezquake warning*/ - {"al", SV_STFU_f, true}, //can probably be removed now. - {"drop", SV_Drop_f}, {"disconnect", SV_Drop_f}, {"pings", SV_Pings_f}, diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 700837f90..c8724984b 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -43,6 +43,9 @@ void *SVQ2_GetGameAPI (void *parms) #endif "game" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, "game" ARCH_DL_POSTFIX, +#if defined(__linux__) //FTE doesn't provide gamecode. Borrow someone else's. Lets just hope that its installed. + "/usr/lib/yamagi-quake2/%s/game.so", +#endif NULL }; void *ret; @@ -70,6 +73,12 @@ void *SVQ2_GetGameAPI (void *parms) continue; Q_snprintfz(name, sizeof(name), "%slibgame_%s"ARCH_DL_POSTFIX, host_parms.binarydir, gamepath); } + else if (*gamename[o] == '/') + { //system path. o.O + if (com_nogamedirnativecode.ival) //just in case they match. + continue; + Q_snprintfz(name, sizeof(name), gamename[o], gamepath); + } else { //gamedir paths as specified above. if (com_nogamedirnativecode.ival) diff --git a/engine/server/world.c b/engine/server/world.c index 744bd8416..e136065db 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -2237,8 +2237,6 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip) trace_t trace; static framestate_t framestate; //meh - if (clip->type == MOVE_WORLDONLY) - return; if (clip->type & MOVE_ENTCHAIN) return; @@ -2565,6 +2563,13 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e wedict_t *other = WEDICT_NUM_UB(w->progs, *w->g.other); return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); } +#ifndef NOLEGACY + if ((type&MOVE_WORLDONLY) == MOVE_WORLDONLY) + { //for compat with DP + wedict_t *other = w->edicts; + return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); + } +#endif // clip to world clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask); diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 0a6b3e90f..61c4e3121 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1750,7 +1750,7 @@ static void T_Gen_CurrentRender(void) if (img->width != vid.fbpwidth || img->height != vid.fbpheight) { //FIXME: free the old image when its safe to do so. - *img = VK_CreateTexture2DArray(vid.fbpwidth, vid.fbpheight, 1, 1, -vk.backbufformat, PTI_2D, true); + *img = VK_CreateTexture2DArray(vid.fbpwidth, vid.fbpheight, 1, 1, -vk.backbufformat, PTI_2D, true, shaderstate.tex_currentrender->ident); if (!img->sampler) VK_CreateSampler(shaderstate.tex_currentrender->flags, img); diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index cb0eff081..5047b4d3f 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -56,8 +56,14 @@ const char *vklayerlist[] = #ifdef VK_NO_PROTOTYPES #define VKFunc(n) PFN_vk##n vk##n; - VKFunc(CreateDebugReportCallbackEXT) - VKFunc(DestroyDebugReportCallbackEXT) + #ifdef VK_EXT_debug_utils + VKFunc(CreateDebugUtilsMessengerEXT) + VKFunc(DestroyDebugUtilsMessengerEXT) + #endif + #ifdef VK_EXT_debug_report + VKFunc(CreateDebugReportCallbackEXT) + VKFunc(DestroyDebugReportCallbackEXT) + #endif VKFuncs #undef VKFunc #endif @@ -97,6 +103,133 @@ do { \ #define DOBACKTRACE() #endif +#ifdef VK_EXT_debug_utils +static void DebugSetName(VkObjectType objtype, uint64_t handle, const char *name) +{ + if (vkSetDebugUtilsObjectNameEXT) + { + VkDebugUtilsObjectNameInfoEXT info = + { + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + NULL, + objtype, + handle, + name + }; + vkSetDebugUtilsObjectNameEXT(vk.device, &info); + } +} +static VkDebugUtilsMessengerEXT vk_debugucallback; +char *DebugAnnotObjectToString(VkObjectType t) +{ + switch(t) + { + case VK_OBJECT_TYPE_UNKNOWN: return "VK_OBJECT_TYPE_UNKNOWN"; + case VK_OBJECT_TYPE_INSTANCE: return "VK_OBJECT_TYPE_INSTANCE"; + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: return "VK_OBJECT_TYPE_PHYSICAL_DEVICE"; + case VK_OBJECT_TYPE_DEVICE: return "VK_OBJECT_TYPE_DEVICE"; + case VK_OBJECT_TYPE_QUEUE: return "VK_OBJECT_TYPE_QUEUE"; + case VK_OBJECT_TYPE_SEMAPHORE: return "VK_OBJECT_TYPE_SEMAPHORE"; + case VK_OBJECT_TYPE_COMMAND_BUFFER: return "VK_OBJECT_TYPE_COMMAND_BUFFER"; + case VK_OBJECT_TYPE_FENCE: return "VK_OBJECT_TYPE_FENCE"; + case VK_OBJECT_TYPE_DEVICE_MEMORY: return "VK_OBJECT_TYPE_DEVICE_MEMORY"; + case VK_OBJECT_TYPE_BUFFER: return "VK_OBJECT_TYPE_BUFFER"; + case VK_OBJECT_TYPE_IMAGE: return "VK_OBJECT_TYPE_IMAGE"; + case VK_OBJECT_TYPE_EVENT: return "VK_OBJECT_TYPE_EVENT"; + case VK_OBJECT_TYPE_QUERY_POOL: return "VK_OBJECT_TYPE_QUERY_POOL"; + case VK_OBJECT_TYPE_BUFFER_VIEW: return "VK_OBJECT_TYPE_BUFFER_VIEW"; + case VK_OBJECT_TYPE_IMAGE_VIEW: return "VK_OBJECT_TYPE_IMAGE_VIEW"; + case VK_OBJECT_TYPE_SHADER_MODULE: return "VK_OBJECT_TYPE_SHADER_MODULE"; + case VK_OBJECT_TYPE_PIPELINE_CACHE: return "VK_OBJECT_TYPE_PIPELINE_CACHE"; + case VK_OBJECT_TYPE_PIPELINE_LAYOUT: return "VK_OBJECT_TYPE_PIPELINE_LAYOUT"; + case VK_OBJECT_TYPE_RENDER_PASS: return "VK_OBJECT_TYPE_RENDER_PASS"; + case VK_OBJECT_TYPE_PIPELINE: return "VK_OBJECT_TYPE_PIPELINE"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: return "VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT"; + case VK_OBJECT_TYPE_SAMPLER: return "VK_OBJECT_TYPE_SAMPLER"; + case VK_OBJECT_TYPE_DESCRIPTOR_POOL: return "VK_OBJECT_TYPE_DESCRIPTOR_POOL"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET: return "VK_OBJECT_TYPE_DESCRIPTOR_SET"; + case VK_OBJECT_TYPE_FRAMEBUFFER: return "VK_OBJECT_TYPE_FRAMEBUFFER"; + case VK_OBJECT_TYPE_COMMAND_POOL: return "VK_OBJECT_TYPE_COMMAND_POOL"; + case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: return "VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION"; + case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: return "VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE"; + case VK_OBJECT_TYPE_SURFACE_KHR: return "VK_OBJECT_TYPE_SURFACE_KHR"; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: return "VK_OBJECT_TYPE_SWAPCHAIN_KHR"; + case VK_OBJECT_TYPE_DISPLAY_KHR: return "VK_OBJECT_TYPE_DISPLAY_KHR"; + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: return "VK_OBJECT_TYPE_DISPLAY_MODE_KHR"; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: return "VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT"; + case VK_OBJECT_TYPE_OBJECT_TABLE_NVX: return "VK_OBJECT_TYPE_OBJECT_TABLE_NVX"; + case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX: return "VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX"; + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: return "VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT"; + case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "VK_OBJECT_TYPE_VALIDATION_CACHE_EXT"; + case VK_OBJECT_TYPE_RANGE_SIZE: + case VK_OBJECT_TYPE_MAX_ENUM: + break; + } + return "UNKNOWNTYPE"; +} +static VKAPI_ATTR VkBool32 VKAPI_CALL mydebugutilsmessagecallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT*pCallbackData, void* pUserData) +{ + char prefix[64]; + int l = 0; //developer level + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) + { //spam? + strcpy(prefix, "VERBOSE:"); + l = 2; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) + { //generally stuff like 'object created' + strcpy(prefix, "INFO:"); + l = 1; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + strcpy(prefix, CON_WARNING"WARNING:"); + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + strcpy(prefix, CON_ERROR "ERROR:"); + + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) + strcat(prefix, "GENERAL"); + else + { + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) + strcat(prefix, "SPEC"); + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + { + if (messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) + { + strcat(prefix, "|"); + } + strcat(prefix,"PERF"); + } + } + Con_DLPrintf(l, "%s[%d] %s - %s\n", prefix, pCallbackData->messageIdNumber, pCallbackData->pMessageIdName?pCallbackData->pMessageIdName:"", pCallbackData->pMessage); + + if (pCallbackData->objectCount > 0) + { + uint32_t object; + for(object = 0; object < pCallbackData->objectCount; ++object) + Con_DLPrintf(l, " Object[%d] - Type %s, Value %"PRIx64", Name \"%s\"\n", object, + DebugAnnotObjectToString(pCallbackData->pObjects[object].objectType), + pCallbackData->pObjects[object].objectHandle, + pCallbackData->pObjects[object].pObjectName); + } + + if (pCallbackData->cmdBufLabelCount > 0) + { + uint32_t label; + for (label = 0; label < pCallbackData->cmdBufLabelCount; ++label) + Con_DLPrintf(l, " Label[%d] - %s { %f, %f, %f, %f}\n", label, + pCallbackData->pCmdBufLabels[label].pLabelName, + pCallbackData->pCmdBufLabels[label].color[0], + pCallbackData->pCmdBufLabels[label].color[1], + pCallbackData->pCmdBufLabels[label].color[2], + pCallbackData->pCmdBufLabels[label].color[3]); + } + return false; +} +#else +#define DebugSetName(objtype,handle,name) +#endif +#ifdef VK_EXT_debug_report static VkDebugReportCallbackEXT vk_debugcallback; static VkBool32 VKAPI_PTR mydebugreportcallback( VkDebugReportFlagsEXT flags, @@ -146,6 +279,7 @@ static VkBool32 VKAPI_PTR mydebugreportcallback( } return false; } +#endif //typeBits is some vulkan requirement thing (like textures must be device-local). //requirements_mask are things that the engine may require (like host-visible). @@ -388,6 +522,7 @@ static qboolean VK_CreateSwapChain(void) ici.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &images[i])); + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)images[i], "backbuffer"); vkGetImageMemoryRequirements(vk.device, images[i], &mem_reqs); @@ -730,6 +865,10 @@ static qboolean VK_CreateSwapChain(void) for (i = 0; i < vk.backbuf_count; i++) { VkImageViewCreateInfo ivci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + + vk.backbufs[i].colour.image = images[i]; + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)vk.backbufs[i].colour.image, "backbuffer"); + ivci.format = vk.backbufformat; // ivci.components.r = VK_COMPONENT_SWIZZLE_R; // ivci.components.g = VK_COMPONENT_SWIZZLE_G; @@ -743,7 +882,6 @@ static qboolean VK_CreateSwapChain(void) ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; ivci.flags = 0; ivci.image = images[i]; - vk.backbufs[i].colour.image = images[i]; if (memories) vk.backbufs[i].colour.mem.memory = memories[i]; vk.backbufs[i].colour.width = swapinfo.imageExtent.width; @@ -773,6 +911,7 @@ static qboolean VK_CreateSwapChain(void) depthinfo.pQueueFamilyIndices = NULL; depthinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkAssert(vkCreateImage(vk.device, &depthinfo, vkallocationcb, &vk.backbufs[i].depth.image)); + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)vk.backbufs[i].depth.image, "backbuffer depth"); } //depth memory @@ -821,6 +960,7 @@ static qboolean VK_CreateSwapChain(void) mscolourinfo.pQueueFamilyIndices = NULL; mscolourinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkAssert(vkCreateImage(vk.device, &mscolourinfo, vkallocationcb, &vk.backbufs[i].mscolour.image)); + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)vk.backbufs[i].mscolour.image, "multisample"); } //mscolour memory @@ -1088,7 +1228,7 @@ qboolean VK_AllocateBindImageMemory(vk_image_t *image, qboolean dedicated) } -vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget) +vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget, const char *debugname) { vk_image_t ret; VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; @@ -1235,6 +1375,7 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay ici.initialLayout = ret.layout; VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &ret.image)); + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)ret.image, debugname); ret.view = VK_NULL_HANDLE; ret.sampler = VK_NULL_HANDLE; @@ -1556,7 +1697,7 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips) } else { - target = VK_CreateTexture2DArray(mips->mip[0].width, mips->mip[0].height, layers, mipcount/layers, mips->encoding, mips->type, !!(tex->flags&IF_RENDERTARGET)); + target = VK_CreateTexture2DArray(mips->mip[0].width, mips->mip[0].height, layers, mipcount/layers, mips->encoding, mips->type, !!(tex->flags&IF_RENDERTARGET), tex->ident); if (target.mem.memory == VK_NULL_HANDLE) { @@ -2663,6 +2804,7 @@ char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight ici.pQueueFamilyIndices = NULL; ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &tempimage)); + DebugSetName(VK_OBJECT_TYPE_IMAGE, (uint64_t)tempimage, "VKVID_GetRGBInfo staging"); vkGetImageMemoryRequirements(vk.device, tempimage, &mem_reqs); memAllocInfo.allocationSize = mem_reqs.size; memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0); @@ -2880,7 +3022,7 @@ static void VK_PaintScreen(void) if (uimenu != 1) { if (r_worldentity.model && cls.state == ca_active) - V_RenderView (); + V_RenderView (nohud); else { noworld = true; @@ -3844,14 +3986,26 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre qboolean surfext = false; uint32_t count, i, j; VkExtensionProperties *ext; +#ifdef VK_EXT_debug_utils + qboolean havedebugutils = false; +#endif +#ifdef VK_EXT_debug_report + qboolean havedebugreport = false; +#endif vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); ext = malloc(sizeof(*ext)*count); vkEnumerateInstanceExtensionProperties(NULL, &count, ext); for (i = 0; i < count && extensions_count < countof(extensions); i++) { - if (!strcmp(ext[i].extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) && vk_debug.ival) - extensions[extensions_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; - else if (!strcmp(ext[i].extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) +#ifdef VK_EXT_debug_utils + if (!strcmp(ext[i].extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) + havedebugutils = true; +#endif +#ifdef VK_EXT_debug_report + if (!strcmp(ext[i].extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) + havedebugreport = true; +#endif + if (!strcmp(ext[i].extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) extensions[extensions_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; else if (sysextnames && !strcmp(ext[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) { @@ -3871,9 +4025,21 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre } } free(ext); + + if (!vk_debug.ival) + ; +#ifdef VK_EXT_debug_utils + else if (havedebugutils) + extensions[extensions_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; +#endif +#ifdef VK_EXT_debug_report + else if (havedebugreport) + extensions[extensions_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; +#endif + if (sysextnames && (!vk.khr_swapchain || !surfext)) { - Con_Printf("Vulkan instance driver lacks support for %s\n", sysextnames[0]); + Con_Printf("Vulkan instance lacks driver support for %s\n", sysextnames[0]); return false; } } @@ -3926,6 +4092,27 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre //set up debug callbacks if (vk_debug.ival) { +#ifdef VK_EXT_debug_utils + vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk.instance, "vkCreateDebugUtilsMessengerEXT"); + vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(vk.instance, "vkDestroyDebugUtilsMessengerEXT"); + if (vkCreateDebugUtilsMessengerEXT) + { + VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo; + memset(&dbgCreateInfo, 0, sizeof(dbgCreateInfo)); + dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + dbgCreateInfo.pfnUserCallback = mydebugutilsmessagecallback; + dbgCreateInfo.pUserData = NULL; + dbgCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + dbgCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + vkCreateDebugUtilsMessengerEXT(vk.instance, &dbgCreateInfo, vkallocationcb, &vk_debugucallback); + } +#endif +#ifdef VK_EXT_debug_report vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(vk.instance, "vkCreateDebugReportCallbackEXT"); vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(vk.instance, "vkDestroyDebugReportCallbackEXT"); if (vkCreateDebugReportCallbackEXT && vkDestroyDebugReportCallbackEXT) @@ -3942,6 +4129,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre VK_DEBUG_REPORT_DEBUG_BIT_EXT; vkCreateDebugReportCallbackEXT(vk.instance, &dbgCreateInfo, vkallocationcb, &vk_debugcallback); } +#endif } //create the platform-specific surface @@ -4461,11 +4649,20 @@ void VK_Shutdown(void) if (vk.device) vkDestroyDevice(vk.device, vkallocationcb); +#ifdef VK_EXT_debug_utils + if (vk_debugucallback) + { + vkDestroyDebugUtilsMessengerEXT(vk.instance, vk_debugucallback, vkallocationcb); + vk_debugucallback = VK_NULL_HANDLE; + } +#endif +#ifdef VK_EXT_debug_report if (vk_debugcallback) { vkDestroyDebugReportCallbackEXT(vk.instance, vk_debugcallback, vkallocationcb); vk_debugcallback = VK_NULL_HANDLE; } +#endif if (vk.surface) vkDestroySurfaceKHR(vk.instance, vk.surface, vkallocationcb); diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 8fc94c60e..10900ee66 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -28,7 +28,7 @@ #endif #define VK_NO_PROTOTYPES -#include "../vulkan/vulkan.h" +#include #if defined(_MSC_VER) && !defined(UINT64_MAX) #define UINT64_MAX _UI64_MAX @@ -51,6 +51,12 @@ #endif #define VKInstArchFuncs VKInstWin32Funcs VKInstXLibFuncs VKInstXCBFuncs VKInstWaylandFuncs +#ifdef VK_EXT_debug_utils +#define VKDebugFuncs \ + VKFunc(SetDebugUtilsObjectNameEXT) +#else +#define VKDebugFuncs +#endif //funcs needed for creating an instance #define VKInstFuncs \ @@ -61,7 +67,6 @@ //funcs specific to an instance #define VKInst2Funcs \ VKFunc(EnumeratePhysicalDevices) \ - VKFunc(EnumeratePhysicalDeviceGroupsKHX) \ VKFunc(EnumerateDeviceExtensionProperties) \ VKFunc(GetPhysicalDeviceProperties) \ VKFunc(GetPhysicalDeviceQueueFamilyProperties) \ @@ -75,6 +80,7 @@ VKFunc(DestroySurfaceKHR) \ VKFunc(CreateDevice) \ VKFunc(DestroyInstance) \ + VKDebugFuncs \ VKInstArchFuncs //funcs specific to a device @@ -169,7 +175,6 @@ VKFunc(CreateImageView) \ VKFunc(DestroyImageView) - //all vulkan funcs #define VKFuncs \ VKInstFuncs \ @@ -488,7 +493,7 @@ struct stagingbuf size_t size; VkBufferUsageFlags usage; }; -vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget); +vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget, const char *debugname); void set_image_layout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkAccessFlags srcaccess, VkPipelineStageFlagBits srcstagemask, VkImageLayout new_image_layout, VkAccessFlags dstaccess, VkPipelineStageFlagBits dststagemask); void VK_CreateSampler(unsigned int flags, vk_image_t *img); void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageFlags usage); diff --git a/iqm/README.txt b/iqm/README.txt index e9cb22b95..3ccce4519 100644 --- a/iqm/README.txt +++ b/iqm/README.txt @@ -20,7 +20,10 @@ Unless you're doing complex stuff like any of the above, there's probably not al Command File Format: - output - specified the output file name. you should only have one of these. + output - specifies the output file name. you should only have one of each type of output. + output_qmdl - specifies which file to write a quake1-format model. May only occur once. + output_md16 - specifies the filename to write a quakeforge 16-bit md16 model to (a upgraded variation of quake's format). May only occur once. + output_md3 - specifies the filename to write a quake3 md3 file to. May only occur once. exec - exec the specified command file, before parsing the rest of the current file. hitbox - generates a hitmesh as a bbox centered around the bone in the base pose (the hitbox will rotate/move with animations). The bodynum will be visible to gamecode, and may merge with other hitboxes with the same group. modelflags - enables the specified bit in the iqm header. supported names include q1_rocket, q1_grenade, q1_gib, q1_rotate, q1_tracer1, q1_zomgib, q1_tracer2, q1_tracer3 @@ -53,4 +56,4 @@ Anim/Import Properties: scale - rescales the model origin - moves the thing event [ANIM,] <"EVENTDATA"> - embeds event info within the animation, for stuff like footsteps. How this is used depends on the engine... If used at global scope, can be reset with 'event reset' in order to not apply to later files. - \ No newline at end of file + diff --git a/iqm/iqm.cpp b/iqm/iqm.cpp index c9a771a21..e93266beb 100644 --- a/iqm/iqm.cpp +++ b/iqm/iqm.cpp @@ -4283,6 +4283,243 @@ bool writeiqm(const char *filename) } +uchar qmdl_bestnorm(Vec3 &v) +{ + //FIXME + return 0; +} +struct qmdl_vertex_t +{ + unsigned char v[3]; + unsigned char normalIndex; +}; +template bool writemdl(const char *filename) +{ + if (meshes.length() != 1) + { + conoutf("warning: mdl output requires exactly one mesh"); + return false; //must have ONE mesh only. + } + auto mesh = meshes[0]; + vertexarray *texcoords = NULL; + vertexarray *vertcoords = NULL; + vertexarray *vertnorm = NULL; + uint skinwidth = 0; + uint skinheight = 0; + Vec3 offset={0,0,0}; + Vec3 scale={1,1,1}; + uint numskins = 0; + vector skindata; + + loopv(varrays) + { + if(varrays[i].type == IQM_TEXCOORD && varrays[i].format == IQM_FLOAT && varrays[i].count == 2) + texcoords = &varrays[i]; + if(varrays[i].type == IQM_POSITION && varrays[i].format == IQM_FLOAT && varrays[i].count == 3) + vertcoords = &varrays[i]; + if(varrays[i].type == IQM_NORMAL && varrays[i].format == IQM_FLOAT && varrays[i].count == 3) + vertnorm = &varrays[i]; +// if(varrays[i].type == IQM_BLENDINDEXES && varrays[i].format == IQM_BYTE && varrays[i].count == 4) +// vertbones = &varrays[i]; +// if(varrays[i].type == IQM_BLENDWEIGHTS && varrays[i].format == IQM_FLOAT && varrays[i].count == 4) +// vertweights = &varrays[i]; + } + if (!texcoords) + { + conoutf("warning: mdl output requires a float texcoord array"); + return false; //must have some vertex coords... + } + float *tcdata = (float*)texcoords->vdata.getbuf(); + + skinwidth = 4; + skinheight = 4; + memset(skindata.reserve(skinwidth*skinheight), 15, skinwidth*skinheight); + skindata.advance(skinwidth*skinheight); + numskins++; + + //we're going to need the transformed pose data, without any bone weights getting in the way. + vector vpos, vnorm; + Vec3 min={FLT_MAX,FLT_MAX,FLT_MAX}, max={-FLT_MAX,-FLT_MAX,-FLT_MAX}; + loopv(anims) + { + anim &a = anims[i]; + Vec3 *outv = vpos.reserve(mesh.numverts*a.numframes); + Vec3 *outn = vnorm.reserve(mesh.numverts*a.numframes); + + Vec3 *invert = (Vec3*)vertcoords->vdata.getbuf(); + Vec3 *innorm = (Vec3*)vertnorm->vdata.getbuf(); +// uchar *inbones = (uchar*)vertbones->vdata.getbuf(); +// Vec4 *inweights = (Vec4*)vertweights->vdata.getbuf(); + + for (int j = 0; j < a.numframes; j++) + { + //FIXME: generate bone matricies + for (int i = mesh.firstvert; i < mesh.numverts; i++, outv++, outn++) + { + //FIXME: generate vert's matrix + + //transform each vert + *outv = invert[i]; + + //bound it to find the model's extents + for (uint c = 0; c < 3; c++) + { + if (min.v[c] > outv->v[c]) + min.v[c] = outv->v[c]; + if (max.v[c] < outv->v[c]) + max.v[c] = outv->v[c]; + } + + *outn = innorm[i]; + } + vpos.advance(mesh.numverts); + vnorm.advance(mesh.numverts); + } + } + + offset = -min; + scale = (max-min)/255; //ignore low order info here + + stream *f = openfile(filename, "wb"); + if(!f) return false; + + if (md16) + f->putlil((uint)(('M'<<0)|('D'<<8)|('1'<<16)|('6'<<24))); + else + f->putlil((uint)(('I'<<0)|('D'<<8)|('P'<<16)|('O'<<24))); + f->putlil((uint)6); //version + f->putlil((float)scale[0]); + f->putlil((float)scale[1]); + f->putlil((float)scale[2]); + f->putlil((float)offset[0]); + f->putlil((float)offset[1]); + f->putlil((float)offset[2]); + f->putlil(0.f); //radius + f->putlil(0.f); //eyeposx, never used afaik + f->putlil(0.f); //eyeposy + f->putlil(0.f); //eyeposz + + f->putlil((uint)numskins); + f->putlil((uint)skinwidth); + f->putlil((uint)skinheight); + + f->putlil((uint)mesh.numverts); + f->putlil((uint)mesh.numtris); + f->putlil((uint)anims.length()); //numanims + + f->putlil((uint)0); //synctype + f->putlil((uint)modelflags); //flags + f->putlil(0.f); //size + + //skins + for (int i = 0; i < numskins; i++) + { + f->putlil((uint)0); //ALIAS_SKIN_SINGLE + f->write(skindata.getbuf()+i*skinwidth*skinheight, skinwidth*skinheight); + } + //texcoords + for (int i = mesh.firstvert; i < mesh.numverts; i++) + { + f->putlil((uint)(0?32:0)); //onseam. no verts are ever onseam for us, as we don't do that nonsense here. + f->putlil((int)((tcdata[i*2+0]+.5)*skinwidth)); //mdl texcoords are ints, in texels. which sucks, but what can you do... + f->putlil((int)((tcdata[i*2+1]+.5)*skinheight)); + } + //tris + for (int i = mesh.firsttri; i < mesh.firsttri+mesh.numtris; i++) + { + f->putlil((uint)1); //faces front. All are effectively front-facing for us. This avoids annoying tc additions. + f->putlil((uint)triangles[i].vert[0]); + f->putlil((uint)triangles[i].vert[1]); + f->putlil((uint)triangles[i].vert[2]); + } + //animations + vector high, low; + size_t voffset = 0; + loopv(anims) + { + anim &a = anims[i]; + for (int j = 0; j < a.numframes; j++) + { + qmdl_vertex_t *th=high.reserve(mesh.numverts),*tl=low.reserve(mesh.numverts); + for (int i = mesh.firstvert; i < mesh.numverts; i++, th++, tl++) + { + int l; + for (uint c = 0; c < 3; c++) + { + l = (((vpos[voffset][c]-offset[c])*256) / scale[c]); + if (l<0) l = 0; + if (l > 0xff00) l = 0xff00; //0xffff would exceed the bounds values, so don't use it. + th->v[c] = l>>8; + tl->v[c] = l&0xff; + } + tl->normalIndex = th->normalIndex = qmdl_bestnorm(vnorm[voffset]); + + voffset++; + } + high.advance(mesh.numverts); + low.advance(mesh.numverts); + } + } + voffset = 0; + loopv(anims) + { + anim &a = anims[i]; + if (a.numframes == 1) + f->putlil((uint)0); //single-pose type + else + { + f->putlil((uint)1); //anim type + f->putlil((uint)a.numframes); + + qmdl_vertex_t min={{255,255,255}}, max={{0,0,0}}; + for (uint k = 0; k < mesh.numverts*a.numframes; k++) + { + for (uint c = 0; c < 3; c++) + { + if (min.v[c] > high[voffset+k].v[c]) + min.v[c] = high[voffset+k].v[c]; + if (max.v[c] < high[voffset+k].v[c]) + max.v[c] = high[voffset+k].v[c]; + } + } + f->put(min); + f->put(max); + for (int j = 0; j < a.numframes; j++) + f->putlil(1.0f/a.fps); //intervals. we use the same value for each + } + + for (int j = 0; j < a.numframes; j++) + { + char name[16]={0}; + qmdl_vertex_t min={{255,255,255}}, max={{0,0,0}}; + for (uint k = 0; k < mesh.numverts; k++) + { + for (uint c = 0; c < 3; c++) + { + if (min.v[c] > high[voffset+k].v[c]) + min.v[c] = high[voffset+k].v[c]; + if (max.v[c] < high[voffset+k].v[c]) + max.v[c] = high[voffset+k].v[c]; + } + } + f->put(min); + f->put(max); + + strncpy(name, &stringdata[a.name], sizeof(name)); + f->put(name); + + f->write(&high[voffset], sizeof(qmdl_vertex_t)*mesh.numverts); + if (md16) + f->write(&low[voffset], sizeof(qmdl_vertex_t)*mesh.numverts); + voffset += mesh.numverts; + } + } + + delete f; + return true; +} + + void help(bool exitstatus = EXIT_SUCCESS) { fprintf(exitstatus != EXIT_SUCCESS ? stderr : stdout, @@ -4568,7 +4805,20 @@ bool parseanimfield(const char *tok, char **line, filespec &spec, bool defaults) return true; } -void parsecommands(char *filename, const char *&outfile, vector &infiles, vector &hitboxes) +struct +{ + bool (*write)(const char *filename); + const char *cmdname; + const char *altcmdname; +} outputtypes[] = +{ + {writeiqm, "output_iqm"}, + {writemdl<0>, "output_qmdl"}, + {writemdl<1>, "output_md16"}, +// {writemd3, "output_md3"}, +}; + +void parsecommands(char *filename, const char *outfiles[countof(outputtypes)], vector &infiles, vector &hitboxes) { filespec defaultspec; defaultspec.reset(); @@ -4586,7 +4836,7 @@ void parsecommands(char *filename, const char *&outfile, vector &infil char buf[2048]; while(f->getline(buf, sizeof(buf))) { - char *tok; + const char *tok; char *line = buf; tok = mystrtok(&line); if (tok && *tok == '$') @@ -4600,8 +4850,6 @@ void parsecommands(char *filename, const char *&outfile, vector &infil } // else if (!strcasecmp(tok, "outputdir")) // (void)mystrtok(&line); - else if (!strcasecmp(tok, "output")) - outfile = newstring(mystrtok(&line)); else if (!strcasecmp(tok, "hitbox") || !strcasecmp(tok, "hbox")) { hitbox &hb = hitboxes.add(); @@ -4613,7 +4861,7 @@ void parsecommands(char *filename, const char *&outfile, vector &infil hb.maxs[i] = atof(mystrtok(&line)); } else if (!strcasecmp(tok, "exec")) - parsecommands(mystrtok(&line), outfile, infiles, hitboxes); + parsecommands(mystrtok(&line), outfiles, infiles, hitboxes); else if (!strcasecmp(tok, "modelflags")) { bitnames modelflagnames[] = { @@ -4691,10 +4939,34 @@ void parsecommands(char *filename, const char *&outfile, vector &infil infiles.add(inspec); } - else if (*tok) + else { - printf("unsupported command \"%s\"\n", tok); - continue; + size_t n, j; + if (!strcasecmp(tok, "output")) + tok = "output_iqm"; + for (n = 0; n < countof(outputtypes); n++) + { + if (!strcasecmp(tok, outputtypes[n].cmdname)) + { + outfiles[n] = newstring(mystrtok(&line)); + for (j = 0; j < countof(outputtypes); j++) + { + if (n!=j && outfiles[j] && !strcasecmp(outfiles[n], outfiles[j])) + { + printf("cancelling %s\n", outputtypes[j].cmdname); + outfiles[j] = NULL; + break; + } + } + tok = ""; + break; + } + } + if (*tok) + { + printf("unsupported command \"%s\"\n", tok); + continue; + } } if ((tok=mystrtok(&line))) @@ -4711,14 +4983,14 @@ int main(int argc, char **argv) vector infiles; vector hitboxes; filespec inspec; - const char *outfile = NULL; + const char *outfiles[countof(outputtypes)] = {}; for(int i = 1; i < argc; i++) { if(argv[i][0] == '-') { if(argv[i][1] == '-') { - if(!strcasecmp(&argv[i][2], "cmd")) { if(i + 1 < argc) parsecommands(argv[++i], outfile, infiles, hitboxes); } + if(!strcasecmp(&argv[i][2], "cmd")) { if(i + 1 < argc) parsecommands(argv[++i], outfiles, infiles, hitboxes); } else if(!strcasecmp(&argv[i][2], "noext")) noext = true; else if(!strcasecmp(&argv[i][2], "fps")) { if(i + 1 < argc) inspec.fps = atof(argv[++i]); } else if(!strcasecmp(&argv[i][2], "name")) { if(i + 1 < argc) inspec.name = argv[++i]; } @@ -4762,9 +5034,9 @@ int main(int argc, char **argv) { const char *type = strrchr(argv[i], '.'); if (type && (!strcasecmp(type, ".cmd")||!strcasecmp(type, ".cfg")||!strcasecmp(type, ".txt")||!strcasecmp(type, ".qc"))) //.qc to humour halflife fanboys - parsecommands(argv[i], outfile, infiles, hitboxes); - else if(!outfile) - outfile = argv[i]; + parsecommands(argv[i], outfiles, infiles, hitboxes); + else if(!outfiles[0] && !outfiles[1] && !outfiles[2]) + outfiles[0] = argv[i]; //first arg is the output name, if its not an export script thingie. else { infiles.add(inspec).file = argv[i]; @@ -4773,8 +5045,10 @@ int main(int argc, char **argv) } } - if(!outfile) fatal("no output file specified"); - else if(infiles.empty()) fatal("no input files specified"); + size_t n; + for (n = 0; n < countof(outputtypes) && !outfiles[n]; n++); + if(n == countof(outfiles)) fatal("no output file specified"); + if(infiles.empty()) fatal("no input files specified"); if(gscale != 1) printf("scale: %f\n", escale); if(gmeshtrans != Vec3(0, 0, 0)) printf("mesh translate: %f, %f, %f\n", gmeshtrans.x, gmeshtrans.y, gmeshtrans.z); @@ -4833,13 +5107,18 @@ int main(int argc, char **argv) if (!quiet) conoutf(""); - if(writeiqm(outfile)) + for (size_t n = 0; n < countof(outputtypes); n++) { - if (!quiet) - conoutf("exported: %s", outfile); + if (outfiles[n] != NULL) + { + if(outputtypes[n].write(outfiles[n])) + { + if (!quiet) + conoutf("exported: %s", outfiles[n]); + } + else fatal("failed writing: %s", outfiles[n]); + } } - else fatal("failed writing: %s", outfile); - return EXIT_SUCCESS; } diff --git a/iqm/util.h b/iqm/util.h index 0b11b63f6..a9196afb9 100644 --- a/iqm/util.h +++ b/iqm/util.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "iqm.h" #define ASSERT(c) if(c) {} @@ -76,6 +77,7 @@ static inline T min(T a, T b) return a < b ? a : b; } +#define countof(n) (sizeof(n)/sizeof(n[0])) #define clamp(a,b,c) (max(b, min(a, c))) #define loop(v,m) for(int v = 0; v57 || (LIBAVCODEC_VERSION_MAJOR==57&&LIBAVCODEC_VERSION_MINOR>=36)) + struct avaudioctx { //raw file @@ -56,6 +58,127 @@ static void S_AV_Purge(sfx_t *s) memset(&s->decoder, 0, sizeof(s->decoder)); } +static void S_AV_ReadFrame(struct avaudioctx *ctx) +{ //reads an audioframe and spits its data into the output sound file for the game engine to use. + int width = 2; + int channels = ctx->pACodecCtx->channels; + unsigned int auddatasize = av_samples_get_buffer_size(NULL, ctx->pACodecCtx->channels, ctx->pAFrame->nb_samples, ctx->pACodecCtx->sample_fmt, 1); + void *auddata = ctx->pAFrame->data[0]; + switch(ctx->pACodecCtx->sample_fmt) + { //we don't support planar audio. we just treat it as mono instead. + default: + auddatasize = 0; + break; + case AV_SAMPLE_FMT_U8P: + auddatasize /= channels; + channels = 1; + case AV_SAMPLE_FMT_U8: + width = 1; + break; + case AV_SAMPLE_FMT_S16P: + auddatasize /= channels; + channels = 1; + case AV_SAMPLE_FMT_S16: + width = 2; + break; + + case AV_SAMPLE_FMT_FLTP: + //FIXME: support float audio internally. + { + float *in[2] = {(float*)ctx->pAFrame->data[0],(float*)ctx->pAFrame->data[1]}; + signed short *out = (void*)auddata; + int v; + unsigned int i, c; + unsigned int frames = ctx->pAFrame->nb_samples; + if (channels > 2) + channels = 2; + for (i = 0; i < frames; i++) + { + for (c = 0; c < channels; c++) + { + v = (short)(in[c][i]*32767); + if (v < -32767) + v = -32767; + else if (v > 32767) + v = 32767; + *out++ = v; + } + } + width = sizeof(*out); + auddatasize = frames*width*channels; + } + break; + case AV_SAMPLE_FMT_FLT: + //FIXME: support float audio internally. + { + float *in = (void*)auddata; + signed short *out = (void*)auddata; + int v; + unsigned int i; + for (i = 0; i < auddatasize/sizeof(*in); i++) + { + v = (short)(in[i]*32767); + if (v < -32767) + v = -32767; + else if (v > 32767) + v = 32767; + out[i] = v; + } + auddatasize/=2; + width = 2; + } + + case AV_SAMPLE_FMT_DBLP: + auddatasize /= channels; + channels = 1; + case AV_SAMPLE_FMT_DBL: + { + double *in = (double*)auddata; + signed short *out = (void*)auddata; + int v; + unsigned int i; + for (i = 0; i < auddatasize/sizeof(*in); i++) + { + v = (short)(in[i]*32767); + if (v < -32767) + v = -32767; + else if (v > 32767) + v = 32767; + out[i] = v; + } + auddatasize/=4; + width = 2; + } + break; + } + if (ctx->samples_channels != channels || ctx->samples_speed != ctx->pACodecCtx->sample_rate || ctx->samples_width != width) + { //something changed, update + ctx->samples_channels = channels; + ctx->samples_speed = ctx->pACodecCtx->sample_rate; + ctx->samples_width = width; + + //and discard any decoded audio. this might loose some. + ctx->samples_start += ctx->samples_count; + ctx->samples_count = 0; + } + if (ctx->samples_max < (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize) + { + ctx->samples_max = (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize; + ctx->samples_max *= 2; //slop + ctx->samples_buffer = realloc(ctx->samples_buffer, ctx->samples_max); + } + if (width == 1) + { //FTE uses signed 8bit audio. ffmpeg uses unsigned 8bit audio. *sigh*. + char *out = (char*)(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels)); + unsigned char *in = auddata; + int i; + for (i = 0; i < auddatasize; i++) + out[i] = in[i]-128; + } + else + memcpy(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels), auddata, auddatasize); + ctx->samples_count += auddatasize/(ctx->samples_width*ctx->samples_channels); +} static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, int length) { //warning: can be called on a different thread. struct avaudioctx *ctx = (struct avaudioctx*)sfx->decoder.buf; @@ -67,12 +190,21 @@ static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, curtime = start + length; -// curtime = (mediatime * ctx->denum) / ctx->num; - while (1) { - if (ctx->lasttime > curtime) - break; + if (start < ctx->samples_start) + break; //o.O rewind! + + if (ctx->samples_start+ctx->samples_count > curtime) + break; //no need yet. + +#ifdef HAVE_DECOUPLED_API + if(0==avcodec_receive_frame(ctx->pACodecCtx, ctx->pAFrame)) + { + S_AV_ReadFrame(ctx); + continue; + } +#endif // We're ahead of the previous frame. try and read the next. if (av_read_frame(ctx->pFormatCtx, &packet) < 0) @@ -81,11 +213,14 @@ static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, // Is this a packet from the video stream? if(packet.stream_index==ctx->audioStream) { +#ifdef HAVE_DECOUPLED_API + avcodec_send_packet(ctx->pACodecCtx, &packet); +#else int okay; int len; void *odata = packet.data; while (packet.size > 0) - { + { //this old api only decodes part of the packet with each itteration, so keep reading until we decoded the entire thing. okay = false; len = avcodec_decode_audio4(ctx->pACodecCtx, ctx->pAFrame, &okay, &packet); if (len < 0) @@ -93,105 +228,10 @@ static sfxcache_t *S_AV_Locate(sfx_t *sfx, sfxcache_t *buf, ssamplepos_t start, packet.size -= len; packet.data += len; if (okay) - { - int width = 2; - int channels = ctx->pACodecCtx->channels; - unsigned int auddatasize = av_samples_get_buffer_size(NULL, ctx->pACodecCtx->channels, ctx->pAFrame->nb_samples, ctx->pACodecCtx->sample_fmt, 1); - void *auddata = ctx->pAFrame->data[0]; - switch(ctx->pACodecCtx->sample_fmt) - { //we don't support planar audio. we just treat it as mono instead. - default: - auddatasize = 0; - break; - case AV_SAMPLE_FMT_U8P: - auddatasize /= channels; - channels = 1; - case AV_SAMPLE_FMT_U8: - width = 1; - break; - case AV_SAMPLE_FMT_S16P: - auddatasize /= channels; - channels = 1; - case AV_SAMPLE_FMT_S16: - width = 2; - break; - - case AV_SAMPLE_FMT_FLTP: - auddatasize /= channels; - channels = 1; - case AV_SAMPLE_FMT_FLT: - //FIXME: support float audio internally. - { - float *in = (void*)auddata; - signed short *out = (void*)auddata; - int v; - unsigned int i; - for (i = 0; i < auddatasize/sizeof(*in); i++) - { - v = (short)(in[i]*32767); - if (v < -32767) - v = -32767; - else if (v > 32767) - v = 32767; - out[i] = v; - } - auddatasize/=2; - width = 2; - } - - case AV_SAMPLE_FMT_DBLP: - auddatasize /= channels; - channels = 1; - case AV_SAMPLE_FMT_DBL: - { - double *in = (double*)auddata; - signed short *out = (void*)auddata; - int v; - unsigned int i; - for (i = 0; i < auddatasize/sizeof(*in); i++) - { - v = (short)(in[i]*32767); - if (v < -32767) - v = -32767; - else if (v > 32767) - v = 32767; - out[i] = v; - } - auddatasize/=4; - width = 2; - } - break; - } - if (ctx->samples_channels != channels || ctx->samples_speed != ctx->pACodecCtx->sample_rate || ctx->samples_width != width) - { //something changed, update - ctx->samples_channels = channels; - ctx->samples_speed = ctx->pACodecCtx->sample_rate; - ctx->samples_width = width; - - //and discard any decoded audio. this might loose some. - ctx->samples_start += ctx->samples_count; - ctx->samples_count = 0; - } - if (ctx->samples_max < (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize) - { - ctx->samples_max = (ctx->samples_count*ctx->samples_width*ctx->samples_channels)+auddatasize; - ctx->samples_max *= 2; //slop - ctx->samples_buffer = realloc(ctx->samples_buffer, ctx->samples_max); - } - if (width == 1) - { //FTE uses signed 8bit audio. ffmpeg uses unsigned 8bit audio. *sigh*. - char *out = (char*)(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels)); - unsigned char *in = auddata; - int i; - for (i = 0; i < auddatasize; i++) - out[i] = in[i]-128; - } - else - memcpy(ctx->samples_buffer + ctx->samples_count*(ctx->samples_width*ctx->samples_channels), auddata, auddatasize); - ctx->samples_count += auddatasize/(ctx->samples_width*ctx->samples_channels); - } + S_AV_ReadFrame(ctx); } packet.data = odata; +#endif } // Free the packet that was allocated by av_read_frame @@ -319,16 +359,29 @@ static qboolean QDECL S_LoadAVSound (sfx_t *s, qbyte *data, size_t datalen, int { ctx->audioStream=-1; for(i=0; ipFormatCtx->nb_streams; i++) +#if LIBAVFORMAT_VERSION_MAJOR >= 57 + if(ctx->pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_AUDIO) +#else if(ctx->pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) +#endif { ctx->audioStream=i; break; } if(ctx->audioStream!=-1) { +#if LIBAVFORMAT_VERSION_MAJOR >= 57 + pCodec=avcodec_find_decoder(ctx->pFormatCtx->streams[ctx->audioStream]->codecpar->codec_id); + ctx->pACodecCtx = avcodec_alloc_context3(pCodec); + if (avcodec_parameters_to_context(ctx->pACodecCtx, ctx->pFormatCtx->streams[ctx->audioStream]->codecpar) < 0) + { + avcodec_free_context(&ctx->pACodecCtx); + pCodec = NULL; + } +#else ctx->pACodecCtx=ctx->pFormatCtx->streams[ctx->audioStream]->codec; pCodec=avcodec_find_decoder(ctx->pACodecCtx->codec_id); - +#endif ctx->pAFrame=av_frame_alloc(); if(pCodec!=NULL && ctx->pAFrame && avcodec_open2(ctx->pACodecCtx, pCodec, NULL) >= 0) { //success @@ -358,11 +411,10 @@ static qboolean AVAudio_Init(void) { if (!pPlug_ExportNative("S_LoadSound", S_LoadAVSound)) { - ffmpeg_audiodecoder = pCvar_GetNVFDG("ffmpeg_audiodecoder_wip", "0", 0, "Enables the use of ffmpeg's decoder for pure audio files.", "ffmpeg"); - Con_Printf("avplug: Engine doesn't support audio decoder plugins\n"); return false; } + ffmpeg_audiodecoder = pCvar_GetNVFDG("ffmpeg_audiodecoder_wip", "0", 0, "Enables the use of ffmpeg's decoder for pure audio files.", "ffmpeg"); return true; } @@ -389,8 +441,10 @@ qintptr_t Plug_Init(qintptr_t *args) okay |= AVEnc_Init(); if (okay) { +#if ( LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,9,100) ) av_register_all(); avcodec_register_all(); +#endif av_log_set_level(AV_LOG_WARNING); av_log_set_callback(AVLogCallback); diff --git a/plugins/avplug/avdecode.c b/plugins/avplug/avdecode.c index 6b66d1776..1b4536b64 100644 --- a/plugins/avplug/avdecode.c +++ b/plugins/avplug/avdecode.c @@ -27,7 +27,7 @@ #define PASSFLOAT(f) *(int*)&(f) #define ARGNAMES ,sourceid, data, speed, samples, channels, width, PASSFLOAT(volume) -BUILTIN(void, S_RawAudio, (int sourceid, void *data, int speed, int samples, int channels, int width, float volume)); +BUILTIN(void, S_RawAudio, (int sourceid, void *data, int speed, int samples, int channels, int width, float volume)) #undef ARGNAMES /*should probably try threading this, though I suppose it should be the engine doing that.*/ diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index fb06a3c5c..d5f791b21 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -119,7 +119,7 @@ static AVStream *add_video_stream(struct encctx *ctx, AVCodec *codec, int fps, i return NULL; st->id = ctx->fc->nb_streams-1; -#if 1//LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 0) +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101) c = st->codec; #else c = avcodec_alloc_context3(codec); @@ -304,7 +304,7 @@ static AVStream *add_audio_stream(struct encctx *ctx, AVCodec *codec, int *sampl return NULL; st->id = ctx->fc->nb_streams-1; -#if 1//LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 0) +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101) c = st->codec; #else c = avcodec_alloc_context3(codec); @@ -613,7 +613,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height ctx->fc = avformat_alloc_context(); ctx->fc->oformat = fmt; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 6, 100) || defined(FF_API_FORMAT_FILENAME) +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 6, 100) Q_strncatz(ctx->fc->filename, streamname, sizeof(ctx->fc->filename)); #else ctx->fc->url = av_strdup(streamname); @@ -684,6 +684,10 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height } } + //different formats have different metadata formats. there's no standards here. + //av_dict_set(&ctx->fc->metadata, "TPFL", "testtest", 0); + //FIXME: use ffmpeg's sidedata stuff, which should handle it in a generic way + //nearly complete, can make the file dirty now. err = avformat_write_header(ctx->fc, NULL); if (err < 0) @@ -742,12 +746,13 @@ static media_encoder_funcs_t encoderfuncs = AVEnc_End }; -/* + qintptr_t AVEnc_ExecuteCommand(qintptr_t *args) { char cmd[256]; - Cmd_Argv(0, cmd, sizeof(cmd)); - if (!strcmp(cmd, "avcapture")) + pCmd_Argv(0, cmd, sizeof(cmd)); +/* + if (!strcmp(cmd, ENCODERNAME"_configure")) { menuclear menualias menucallback @@ -762,9 +767,48 @@ menutext 0 24 "Report in" "radio26" menutext 0 24 "Cancel" return true; } +*/ + if (!strcmp(cmd, ENCODERNAME"_nvidia")) + { + pCvar_SetString("capturedriver", ENCODERNAME); //be sure to use our encoder + pCvar_SetString(ENCODERNAME"_videocodec", "h264_nvenc"); + pCvar_SetString("capturerate", "60"); //we should be able to cope with it, and the default of 30 sucks + pCvar_SetString("capturedemowidth", "1920"); //force a specific size, some codecs need multiples of 16 or whatever. + pCvar_SetString("capturedemoheight", "1080"); //so this avoids issues with various video codecs. + + pCvar_SetString("capturesound", "1"); + pCvar_SetString("capturesoundchannels", "2"); + pCvar_SetString("capturesoundbits", "16"); + + Con_Printf(ENCODERNAME": now configured for nvidia's hardware encoder\n"); + Con_Printf(ENCODERNAME": use ^[/capture foo.mp4^] or ^[/capturedemo foo.mvd foo.mkv^] commands to begin capturing\n"); + } + if (!strcmp(cmd, ENCODERNAME"_defaults")) + { //most formats will end up using the x264 encoder or something + pCvar_SetString(ENCODERNAME"_format_force", ""); + pCvar_SetString(ENCODERNAME"_videocodec", ""); + pCvar_SetString(ENCODERNAME"_videobitrate", ""); + pCvar_SetString(ENCODERNAME"_videoforcewidth", ""); + pCvar_SetString(ENCODERNAME"_videoforceheight", ""); + pCvar_SetString(ENCODERNAME"_videopreset", "veryfast"); + pCvar_SetString(ENCODERNAME"_video_crf", ""); + pCvar_SetString(ENCODERNAME"_audiocodec", ""); + pCvar_SetString(ENCODERNAME"_audiobitrate", ""); + + pCvar_SetString("capturedriver", ENCODERNAME); + pCvar_SetString("capturerate", "30"); + pCvar_SetString("capturedemowidth", "0"); + pCvar_SetString("capturedemoheight", "0"); + pCvar_SetString("capturesound", "1"); + pCvar_SetString("capturesoundchannels", "2"); + pCvar_SetString("capturesoundbits", "16"); + + Con_Printf(ENCODERNAME": capture settings reset to "ENCODERNAME" defaults\n"); + Con_Printf(ENCODERNAME": Note that some codecs may have restrictions on video sizes\n"); + } return false; } -*/ + qboolean AVEnc_Init(void) { @@ -790,8 +834,11 @@ qboolean AVEnc_Init(void) ffmpeg_audiocodec = pCvar_GetNVFDG(ENCODERNAME"_audiocodec", "", 0, "Forces which audio encoder to use. If blank, guesses based upon container defaults.", ENCODERNAME); ffmpeg_audiobitrate = pCvar_GetNVFDG(ENCODERNAME"_audiobitrate", "", 0, "Specifies the target audio bitrate", ENCODERNAME); -// if (Plug_Export("ExecuteCommand", AVEnc_ExecuteCommand)) -// Cmd_AddCommand("avcapture"); + if (Plug_Export("ExecuteCommand", AVEnc_ExecuteCommand)) + { +// pCmd_AddCommand(ENCODERNAME"_configure"); + pCmd_AddCommand(ENCODERNAME"_nvidia"); + } return true; } diff --git a/plugins/ezhud/ezquakeisms.h b/plugins/ezhud/ezquakeisms.h index 17fc3e88f..a04534ab9 100644 --- a/plugins/ezhud/ezquakeisms.h +++ b/plugins/ezhud/ezquakeisms.h @@ -162,3 +162,65 @@ void Draw_Polygon(int x, int y, vec3_t *vertices, int num_vertices, qbool fill, //glue EBUILTIN(cvar_t*, Cvar_GetNVFDG, (const char *name, const char *defaultval, unsigned int flags, const char *description, const char *groupname)); + + +#undef sb_lines //just in case. +#ifndef SBAR_HEIGHT +#define SBAR_HEIGHT 24 +#define STAT_HEALTH 0 +#define STAT_WEAPONMODELI 2 +#define STAT_AMMO 3 +#define STAT_ARMOR 4 +#define STAT_WEAPONFRAME 5 +#define STAT_SHELLS 6 +#define STAT_NAILS 7 +#define STAT_ROCKETS 8 +#define STAT_CELLS 9 +#define STAT_ACTIVEWEAPON 10 +#define STAT_TOTALSECRETS 11 +#define STAT_TOTALMONSTERS 12 +#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret +#define STAT_MONSTERS 14 // bumped by svc_killedmonster +#define STAT_ITEMS 15 +#define STAT_VIEWHEIGHT 16 //same as zquake +#define STAT_TIME 17 //zquake +#define STAT_MATCHSTARTTIME 18 + +#define IT_SHOTGUN (1u<<0) +#define IT_SUPER_SHOTGUN (1u<<1) +#define IT_NAILGUN (1u<<2) +#define IT_SUPER_NAILGUN (1u<<3) + +#define IT_GRENADE_LAUNCHER (1u<<4) +#define IT_ROCKET_LAUNCHER (1u<<5) +#define IT_LIGHTNING (1u<<6) +#define IT_SUPER_LIGHTNING (1u<<7) + +#define IT_SHELLS (1u<<8) +#define IT_NAILS (1u<<9) +#define IT_ROCKETS (1u<<10) +#define IT_CELLS (1u<<11) + +#define IT_AXE (1u<<12) + +#define IT_ARMOR1 (1u<<13) +#define IT_ARMOR2 (1u<<14) +#define IT_ARMOR3 (1u<<15) + +#define IT_SUPERHEALTH (1u<<16) + +#define IT_KEY1 (1u<<17) +#define IT_KEY2 (1u<<18) + +#define IT_INVISIBILITY (1u<<19) + +#define IT_INVULNERABILITY (1u<<20) +#define IT_SUIT (1u<<21) +#define IT_QUAD (1u<<22) + +#define IT_SIGIL1 (1u<<28) + +#define IT_SIGIL2 (1u<<29) +#define IT_SIGIL3 (1u<<30) +#define IT_SIGIL4 (1u<<31) +#endif \ No newline at end of file diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index 7185719eb..63a01b900 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -6393,6 +6393,7 @@ void SCR_HUD_DrawOwnFrags(hud_t *hud) pDraw_Colour4f(1, 1, 1, 1); } +#ifdef QUAKEHUD static struct wstats_s *findweapon(struct wstats_s *w, size_t wc, char *wn) { for (; wc>0; wc--, w++) @@ -6495,6 +6496,7 @@ static void SCR_HUD_DrawWeaponStats(hud_t *hud) Draw_SString(x, y, line, hud_weaponstats_scale->value); } +#endif void SCR_HUD_DrawKeys(hud_t *hud) { @@ -8464,6 +8466,7 @@ void CommonDraw_Init(void) NULL ); +#ifdef QUAKEHUD HUD_Register("weaponstats", NULL, "Weapon Stats", HUD_PLUSMINUS, ca_active, 0, SCR_HUD_DrawWeaponStats, "0", "screen", "right", "center", "0", "0", "0", "0 0 0", NULL, @@ -8471,6 +8474,7 @@ void CommonDraw_Init(void) "fmt", "&c990sg&r:[%sg] &c099ssg&r:[%ssg] &c900rl&r:[#rl] &c009lg&r:[%lg]", NULL ); +#endif /* hexum -> FIXME? this is used only for debug purposes, I wont bother to port it (it shouldnt be too difficult if anyone cares) #ifdef _DEBUG diff --git a/plugins/plugin.h b/plugins/plugin.h index fd5b06cbc..f16aaaf9f 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -61,11 +61,13 @@ void BadBuiltin(void); #else #ifdef _WIN32 -#define strcasecmp stricmp -#define strncasecmp strnicmp +# ifndef strcasecmp +# define strcasecmp stricmp +# define strncasecmp strnicmp +# endif #else -#define stricmp strcasecmp -#define strnicmp strncasecmp +# define stricmp strcasecmp +# define strnicmp strncasecmp #endif #include