From 5b4756f3d93e6f2fe3e466951c460aa989d0734b Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 27 Nov 2018 16:48:19 +0000 Subject: [PATCH] Lazy GLSL loading, for faster load times. Fixed some xim issues, for proper keyboard input under x11. Cmake project can now work for cross compiling win32 targets. Some other fun-but-pointless stuff. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5344 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- CMakeLists.txt | 105 ++- dounifdef.sh | 59 ++ engine/client/cl_main.c | 5 +- engine/client/cl_screen.c | 5 +- engine/client/console.c | 67 +- engine/client/fragstats.c | 2 +- engine/client/image.c | 188 ++++++ engine/client/keys.c | 162 ++++- engine/client/keys.h | 2 + engine/client/m_download.c | 7 +- engine/client/m_items.c | 4 + engine/client/m_mp3.c | 7 +- engine/client/m_options.c | 1 + engine/client/menu.h | 2 + engine/client/pr_menu.c | 2 +- engine/client/r_surf.c | 3 +- engine/client/sbar.c | 4 +- engine/client/snd_dma.c | 2 +- engine/client/snd_sdl.c | 43 +- engine/client/sys_win.c | 2 +- engine/client/textedit.c | 10 +- engine/client/vid.h | 6 + engine/common/cmd.h | 3 +- engine/common/common.c | 22 +- engine/common/common.h | 4 +- engine/common/config_fteqw.h | 9 +- engine/common/config_wastes.h | 3 + engine/common/console.h | 8 +- engine/common/fs.c | 9 +- engine/common/fs.h | 1 + engine/common/fs_vpk.c | 502 +++++++++++++++ engine/common/plugin.c | 4 +- engine/common/pr_bgcmd.c | 12 +- engine/common/sys.h | 2 +- engine/common/world.h | 2 +- engine/d3d/d3d11_backend.c | 47 +- engine/d3d/d3d11_shader.c | 71 +- engine/d3d/d3d_backend.c | 100 ++- engine/d3d/d3d_shader.c | 243 ++++--- engine/gl/gl_backend.c | 62 +- engine/gl/gl_font.c | 31 +- engine/gl/gl_heightmap.c | 2 +- engine/gl/gl_hlmdl.c | 2 +- engine/gl/gl_model.c | 4 +- engine/gl/gl_shader.c | 609 ++++++++---------- engine/gl/gl_shadow.c | 4 +- engine/gl/gl_vidcommon.c | 233 +++---- engine/gl/gl_vidlinuxglx.c | 279 ++++++-- engine/gl/glquake.h | 2 + engine/gl/r_bishaders.h | 500 +++++++------- engine/gl/shader.h | 100 +-- engine/qclib/qcc_pr_comp.c | 2 +- engine/server/pr_cmds.c | 4 +- engine/server/world.c | 4 + engine/shaders/glsl/altwater.glsl | 11 +- engine/shaders/glsl/bloom_blur.glsl | 4 +- engine/shaders/glsl/bloom_filter.glsl | 4 +- engine/shaders/glsl/bloom_final.glsl | 5 +- engine/shaders/glsl/colourtint.glsl | 3 +- engine/shaders/glsl/crepuscular_rays.glsl | 2 +- engine/shaders/glsl/crepuscular_sky.glsl | 3 +- engine/shaders/glsl/default2d.glsl | 2 +- .../shaders/glsl/defaultadditivesprite.glsl | 2 +- engine/shaders/glsl/defaultgammacb.glsl | 2 +- engine/shaders/glsl/defaultskin.glsl | 4 +- engine/shaders/glsl/defaultsky.glsl | 3 +- engine/shaders/glsl/defaultsprite.glsl | 2 +- engine/shaders/glsl/defaultwall.glsl | 9 +- engine/shaders/glsl/drawflat_wall.glsl | 4 +- engine/shaders/glsl/fixedemu.glsl | 4 +- engine/shaders/glsl/menutint.glsl | 4 +- engine/shaders/glsl/postproc_ascii.glsl | 6 +- .../glsl/postproc_equirectangular.glsl | 4 +- engine/shaders/glsl/postproc_fisheye.glsl | 4 +- engine/shaders/glsl/postproc_laea.glsl | 4 +- engine/shaders/glsl/postproc_panorama.glsl | 4 +- .../shaders/glsl/postproc_stereographic.glsl | 4 +- engine/shaders/glsl/terrain.glsl | 22 +- engine/shaders/glsl/underwaterwarp.glsl | 17 +- engine/shaders/hlsl9/defaultskin.hlsl | 6 +- engine/shaders/hlsl9/defaultsky.hlsl | 9 +- engine/shaders/hlsl9/defaultskybox.hlsl | 4 +- engine/shaders/hlsl9/defaultwarp.hlsl | 2 + engine/shaders/hlsl9/drawflat_wall.hlsl | 1 + engine/shaders/hlsl9/rtlight.hlsl | 4 +- engine/shaders/vulkan/underwaterwarp.glsl | 2 +- engine/vk/vk_backend.c | 10 +- engine/vk/vk_init.c | 2 + engine/vk/vkrenderer.h | 3 +- plugins/bullet/bulletplug.cpp | 35 +- 90 files changed, 2474 insertions(+), 1305 deletions(-) create mode 100644 dounifdef.sh create mode 100644 engine/common/fs_vpk.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 94798cf8e..32e250ccd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,16 @@ IF(NOT ZLIB_FOUND) SET(ZLIB_LIBRARIES ) ENDIF() +FIND_PACKAGE(BZip2) +IF(BZIP2_FOUND) + SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};AVAIL_BZLIB) + SET(FTE_LIBS ${FTE_LIBS} bz2) + SET(FTESV_LIBS ${FTESV_LIBS} bz2) + MESSAGE(STATUS "bzip2 library found. bz2-compressed pk3s will work for the price of extra bloat! yay!") +ELSE() + MESSAGE(WARNING "bzip2 library NOT available. bz2-compressed pk3s will not be available, as if anyone cares.") +ENDIF() + SET(OpenGL_GL_PREFERENCE LEGACY) FIND_PACKAGE(OpenGL) IF(OpenGL_FOUND) @@ -93,14 +103,13 @@ 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_PATH(VULKAN_INCLUDE_DIR vulkan/vulkan.h) +IF(VULKAN_INCLUDE_DIR) + INCLUDE_DIRECTORIES( ${VULKAN_INCLUDE_DIR} ) + SET(FTE_DEFINES ${FTE_DEFINES};VKQUAKE) #no libs required, thankfully +ELSE() + MESSAGE(WARNING "Vulkan headers NOT available.") +ENDIF() FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile) IF(NOT VORBISFILE_LIBRARY) @@ -132,7 +141,7 @@ IF(${ANDROID}) # INCLUDE_DIRECTORIES( ${FREETYPE_INCLUDE_DIRS} ) 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_LIBS ${FTE_LIBS} android log EGL ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS}) SET(FTE_ARCH_FILES engine/client/sys_droid.c engine/common/sys_linux_threads.c @@ -146,7 +155,7 @@ ELSEIF(${WIN32}) # engine/server/sv_sys_win.c - SET(FTE_LIBS ${ZLIB_LIBRARIES} ole32 gdi32 wsock32 winmm dxguid) + SET(FTE_LIBS ${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 @@ -177,7 +186,7 @@ ELSEIF(${WIN32}) engine/d3d/vid_d3d8.c ) - SET(FTESV_LIBS ${ZLIB_LIBRARIES} wsock32 winmm) + SET(FTESV_LIBS ${FTESV_LIBS} ${ZLIB_LIBRARIES} wsock32 winmm) SET(FTESV_ARCH_FILES engine/client/winquake.rc engine/common/sys_win_threads.c @@ -213,7 +222,7 @@ ELSEIF(${UNIX}) #linux(ish) 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_LIBS ${FTE_LIBS} ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread ${SDL2_LIBRARIES}) SET(FTE_ARCH_FILES engine/client/sys_linux.c engine/common/sys_linux_threads.c @@ -267,7 +276,7 @@ ELSEIF(${UNIX}) #linux(ish) engine/common/net_ssl_gnutls.c # engine/common/net_ssl_openssl.c ) - SET(FTESV_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread) + SET(FTESV_LIBS ${FTESV_LIBS} ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread) # SET(FTE_DEFINES ${FTE_DEFINES};HAVE_OPENSSL) # SET(FTESV_DEFINES ${FTESV_DEFINES};HAVE_OPENSSL) @@ -286,7 +295,7 @@ ELSEIF(1) #SDL #SDL2.0.7 supports vulkan, so lets use it. 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_LIBS ${FTE_LIBS} ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES}) SET(FTE_ARCH_FILES engine/client/sys_sdl.c engine/client/snd_al.c @@ -297,7 +306,7 @@ ELSEIF(1) #SDL ) SET(FTESV_DEFINES FTE_SDL;stricmp=strcasecmp;strnicmp=strncasecmp) - SET(FTESV_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES}) + SET(FTESV_LIBS ${FTESV_LIBS} ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES}) IF(WIN32) SET(FTE_LIBS ${FTE_LIBS} wsock32 gdi32 ole32) @@ -375,6 +384,7 @@ SET(FTE_COMMON_FILES engine/common/fs_stdio.c engine/common/fs_xz.c engine/common/fs_zip.c + engine/common/fs_vpk.c engine/common/gl_q2bsp.c engine/common/huff.c engine/common/log.c @@ -394,6 +404,11 @@ SET(FTE_COMMON_FILES engine/common/sha1.c engine/common/translate.c engine/common/zone.c + + engine/common/config_fteqw.h + engine/common/config_minimal.h + engine/common/config_nocompat.h + engine/common/config_wastes.h #sigh engine/client/pr_skelobj.c @@ -542,6 +557,31 @@ SET(FTE_CLIENT_FILES engine/vk/vk_init.c ) +FILE(STRINGS "${FTE_BUILD_CONFIG}" BULLET_INTERNAL REGEX "^#define[\t ]+USE_INTERNAL_BULLET") +IF(BULLET_INTERNAL) + #Built-in bullet physics plugin... + FIND_PACKAGE(Bullet REQUIRED) + SET(FTE_COMMON_FILES ${FTE_COMMON_FILES} plugins/bullet/bulletplug.cpp) + INCLUDE_DIRECTORIES( ${BULLET_INCLUDE_DIRS} ) + SET(FTE_LIBS ${FTE_LIBS} ${BULLET_LIBRARIES}) + SET(FTESV_LIBS ${FTESV_LIBS} ${BULLET_LIBRARIES}) +ELSE() + #Bullet Physics library plugin + FIND_PACKAGE(Bullet) + IF (BULLET_FOUND) + ADD_LIBRARY(bullet MODULE + plugins/qvm_api.c + plugins/plugin.c + plugins/bullet/bulletplug.cpp + ) + TARGET_INCLUDE_DIRECTORIES(bullet PUBLIC ${BULLET_INCLUDE_DIRS}) + SET_TARGET_PROPERTIES(bullet PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") + SET_TARGET_PROPERTIES(bullet PROPERTIES PREFIX "fteplug_") + SET_TARGET_PROPERTIES(bullet PROPERTIES LINK_FLAGS "-Wl,--no-undefined") + TARGET_LINK_LIBRARIES(bullet m ${BULLET_LIBRARIES}) + ENDIF() +ENDIF() + 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 @@ -581,6 +621,9 @@ ELSE() engine/http/ftpserver.c ) SET_TARGET_PROPERTIES(httpserver PROPERTIES COMPILE_DEFINITIONS "WEBSERVER;WEBSVONLY;${FTE_REVISON};stricmp=strcasecmp;strnicmp=strncasecmp") + IF(WIN32) + TARGET_LINK_LIBRARIES(httpserver ${ZLIB_LIBRARIES} ws2_32) + ENDIF() ADD_EXECUTABLE(fteqcc engine/qclib/qcctui.c @@ -626,31 +669,24 @@ ADD_LIBRARY(qi MODULE ) SET_TARGET_PROPERTIES(qi PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(qi PROPERTIES PREFIX "fteplug_") - -#Bullet Physics library plugin -#FIND_PACKAGE(Bullet) -IF (BULLET_FOUND) - ADD_LIBRARY(bullet MODULE - plugins/qvm_api.c - plugins/plugin.c - plugins/bullet/bulletplug.cpp - ) - TARGET_INCLUDE_DIRECTORIES(bullet PUBLIC ${BULLET_INCLUDE_DIRS}) - SET_TARGET_PROPERTIES(bullet PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN") - SET_TARGET_PROPERTIES(bullet PROPERTIES PREFIX "fteplug_") -ENDIF() +SET_TARGET_PROPERTIES(qi PROPERTIES LINK_FLAGS "-Wl,--no-undefined") +TARGET_LINK_LIBRARIES(qi m) #ODE Physics library plugin -#FIND_PACKAGE(ode) -IF (ODE_FOUND) +FIND_PATH(LIBODE_INCLUDE_DIR ode/ode.h) +FIND_LIBRARY(LIBODE_LIBRARY ode) +IF (LIBODE_INCLUDE_DIR) ADD_LIBRARY(ode MODULE plugins/qvm_api.c plugins/plugin.c engine/common/com_phys_ode.c + engine/common/mathlib.c ) TARGET_INCLUDE_DIRECTORIES(ode PUBLIC ${ODE_INCLUDE_DIRS}) SET_TARGET_PROPERTIES(ode PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;ODE_STATIC") SET_TARGET_PROPERTIES(ode PROPERTIES PREFIX "fteplug_") + SET_TARGET_PROPERTIES(ode PROPERTIES LINK_FLAGS "-Wl,--no-undefined") + TARGET_LINK_LIBRARIES(ode m ${LIBODE_LIBRARY}) ENDIF() #EzQuake Hud port plugin @@ -664,6 +700,8 @@ ADD_LIBRARY(ezhud MODULE ) SET_TARGET_PROPERTIES(ezhud PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(ezhud PROPERTIES PREFIX "fteplug_") +SET_TARGET_PROPERTIES(ezhud PROPERTIES LINK_FLAGS "-Wl,--no-undefined") +TARGET_LINK_LIBRARIES(ezhud m) #IRC client plugin ADD_LIBRARY(irc MODULE @@ -673,6 +711,8 @@ ADD_LIBRARY(irc MODULE ) SET_TARGET_PROPERTIES(irc PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(irc PROPERTIES PREFIX "fteplug_") +SET_TARGET_PROPERTIES(irc PROPERTIES LINK_FLAGS "-Wl,--no-undefined") +TARGET_LINK_LIBRARIES(irc m) #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) @@ -715,6 +755,11 @@ IF(NOT ANDROID) ) SET_TARGET_PROPERTIES(xmpp PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(xmpp PROPERTIES PREFIX "fteplug_") + SET_TARGET_PROPERTIES(xmpp PROPERTIES LINK_FLAGS "-Wl,--no-undefined") + IF(${WIN32}) + ELSE() + TARGET_LINK_LIBRARIES(xmpp m resolv) + ENDIF() ENDIF() #cef plugin diff --git a/dounifdef.sh b/dounifdef.sh new file mode 100644 index 000000000..ba7b2d2e8 --- /dev/null +++ b/dounifdef.sh @@ -0,0 +1,59 @@ +#!/bin/sh +#this script is DANGEROUS +#be sure to have committed *BEFORE* running this script. + +#Note: This script does not understand dead files (including botlib). +#expect '-Wmisleading-indentation' warnings (that were previously muted by nearby ifdefs). +#DO NOT COMMIT THE RESULTS TO FTE'S TRUNK + +CONFIG=wastes + +#must have trailing slashes +SRCDIR=./ +NEWDIR=/tmp/fte-$CONFIG/ + +echo "WARNING: This script will lock-in a build config upon your C files." +echo "The resulting files will support only your choice of feature set, instead of having lots of unused code mixed in." +echo "THIS IS DESTRUCTIVE SO MUST ONLY BE USED FOR FORKS." +read -p "Press name the build config (or ctrl+c to abort)" CONFIG + +if [ "$foo" == "" ]; then + echo "no config specified." + exit 1 +fi + +mkdir -p $NEWDIR +cat $SRCDIR/engine/common/config_$CONFIG.h | grep "#define" | sed "s/\/\/#define/#undef/g" > $NEWDIR/unifdefrules +cat $SRCDIR/engine/common/config_$CONFIG.h | grep "#undef" >> $NEWDIR/unifdefrules + +if [ "$SRCDIR" != "$NEWDIR" ]; then + echo "Copying files to strip to $NEWDIR." + cp -r $SRCDIR* $NEWDIR +else + echo "WARNING: WRITING FILES IN PLACE MUST ONLY BE USED FOR FORKS." + read -p "Press y to confirm (or ctrl+c to abort)" foo + if [ "$foo" != "y" ]; then + exit 1 + fi +fi +cd $NEWDIR + +for FILENAME in engine/*/*.c; do + unifdef -f unifdefrules -m $FILENAME +done + +#headers keep any defines that will be expanded in code. +cat $NEWDIR/unifdefrules | grep -v FULLENGINENAME | grep -v DISTRIBUTION | grep -v ENGINEWEBSITE | grep -v MAX_SPLITS | grep GAME_SHORTNAME > $NEWDIR/unifdefhrules + +for FILENAME in engine/*/*.h; do + unifdef -f unifdefhrules -m $FILENAME +done + +rm $NEWDIR/unifdefrules + +echo "Files in $NEWDIR have now been stripped down." +echo "Some things may require hand-editing to remove warnings (or just compile with CFLAGS=-Wno-misleading-indentation)." +echo "You still need to set FTE_CONFIG too." +read -p "Press enter to test-compile" foo + +cd $NEWDIR/engine && make sv-rel m-rel -j8 FTE_CONFIG=$CONFIG -k diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 7abe171a9..35bf48445 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -382,11 +382,13 @@ void CL_MakeActive(char *gamename) //kill models left over from the last map. Mod_Purge(MP_MAPCHANGED); - Image_Purge(); //and reload shaders now if needed (this was blocked earlier) Shader_DoReload(); + //and now free any textures that were not still needed. + Image_Purge(); + SCR_EndLoadingPlaque(); CL_UpdateWindowTitle(); @@ -5911,6 +5913,7 @@ double Host_Frame (double time) { RSpeedMark(); + vid.ime_allow = false; if (SCR_UpdateScreen()) fps_count++; if (R2D_Flush) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 387851257..0d115ea54 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1638,9 +1638,9 @@ void SCR_SizeDown_f (void) //============================================================================ -void SCR_StringXY(char *str, float x, float y) +void SCR_StringXY(const char *str, float x, float y) { - char *s2; + const char *s2; int px, py; unsigned int codepoint; int error; @@ -3448,6 +3448,7 @@ void SCR_DeInit (void) Cmd_RemoveCommand ("screenshot_mega"); Cmd_RemoveCommand ("screenshot_stereo"); Cmd_RemoveCommand ("screenshot_vr"); + Cmd_RemoveCommand ("screenshot_360"); Cmd_RemoveCommand ("screenshot_cubemap"); Cmd_RemoveCommand ("envmap"); Cmd_RemoveCommand ("sizeup"); diff --git a/engine/client/console.c b/engine/client/console.c index 46bb36088..346a2df82 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1339,6 +1339,20 @@ DRAWING ============================================================================== */ +qboolean COM_InsertIME(conchar_t *buffer, size_t buffersize, conchar_t **cursor, conchar_t **textend) +{ + conchar_t *in = vid.ime_preview; + if (in && *in && *textend+vid.ime_previewlen < buffer+buffersize) + { + memmove(buffer + (*cursor-buffer) + vid.ime_previewlen, *cursor, ((*textend-*cursor)+1)*sizeof(conchar_t)); + memcpy(buffer + (*cursor-buffer), in, vid.ime_previewlen*sizeof(conchar_t)); + *cursor += vid.ime_caret; + *textend += vid.ime_previewlen; + + return true; + } + return false; +} /* ================ @@ -1364,9 +1378,18 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, size_t textsize; qboolean cursorframe; unsigned int codeflags, codepoint; + int cursorpos; + qboolean hidecomplete; int x; + if (focused) + { + vid.ime_allow = true; + vid.ime_position[0] = ((float)left/vid.pixelwidth)*vid.width; + vid.ime_position[1] = ((float)y/vid.pixelheight)*vid.height; + } + if (!con->linebuffered || con->linebuffered == Con_Navigate) { if (con->footerline) @@ -1383,6 +1406,8 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, text = key_lines[edit_line]; + cursorpos = key_linepos; + //copy it to an alternate buffer and fill in text colouration escape codes. //if it's recognised as a command, colour it yellow. //if it's not a command, and the cursor is at the end of the line, leave it as is, @@ -1390,13 +1415,24 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, textstart = COM_ParseFunString(CON_WHITEMASK, con->prompt, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), PFS_FORCEUTF8); textsize = (countof(maskedtext) - (textstart-maskedtext) - 1) * sizeof(maskedtext[0]); - i = text[key_linepos]; - text[key_linepos] = 0; + i = text[cursorpos]; + text[cursorpos] = 0; cursor = COM_ParseFunString(CON_WHITEMASK, text, textstart, textsize, PFS_KEEPMARKUP | PFS_FORCEUTF8); - text[key_linepos] = i; + //okay, so that's where the cursor is. heal the input string and reparse (so we don't mess up escapes) + text[cursorpos] = i; endmtext = COM_ParseFunString(CON_WHITEMASK, text, textstart, textsize, PFS_KEEPMARKUP | PFS_FORCEUTF8); // endmtext = COM_ParseFunString(CON_WHITEMASK, text+key_linepos, cursor, ((char*)maskedtext)+sizeof(maskedtext) - (char*)(cursor+1), PFS_KEEPMARKUP | PFS_FORCEUTF8); + hidecomplete = COM_InsertIME(maskedtext, countof(maskedtext), &cursor, &endmtext); +/* if (cursorpos == strlen(text) && vid.ime_preview) + { + endmtext = COM_ParseFunString(COLOR_MAGENTA<commandcompletion && con_showcompletion.ival && text[0] && !(text[0] == '/' && !text[1])) + if (!hidecomplete && con->commandcompletion && con_showcompletion.ival && text[0] && !(text[0] == '/' && !text[1])) { if (cl_chatmode.ival && (text[0] == '/' || (cl_chatmode.ival == 2 && Cmd_IsCommand(text)))) { //color the first token yellow, it's a valid command @@ -1447,10 +1483,10 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, fname = Cmd_CompleteCommand(text+cmdstart, true, true, max(1, con_commandmatch), NULL); if (fname && strlen(fname) < 256) //we can compleate it to: { - for (p = min(strlen(fname), key_linepos-cmdstart); fname[p]>0; p++) + for (p = min(strlen(fname), cursorpos-cmdstart); fname[p]>0; p++) textstart[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<mouseover || !mouseconsole->mouseover(mouseconsole, &tiptext, &shader)) { - mouseover = Con_CopyConsole(mouseconsole, false, true); + mouseover = Con_CopyConsole(mouseconsole, false, true, true); if (mouseover) { char *end = strstr(mouseover, "^]"); @@ -3131,7 +3172,7 @@ void Con_ExpandConsoleSelection(console_t *con) con->selstartoffset = cur-(conchar_t*)(l+1); } -char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink) +char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink, qboolean forceutf8) { conchar_t *cur; conline_t *l; @@ -3229,7 +3270,7 @@ char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink) else lend = (conchar_t*)(l+1) + l->length; - outlen = COM_DeFunString(cur, lend, result + outlen, maxlen - outlen, nomarkup, !!(con->parseflags & PFS_FORCEUTF8)) - result; + outlen = COM_DeFunString(cur, lend, result + outlen, maxlen - outlen, nomarkup, forceutf8||!!(con->parseflags & PFS_FORCEUTF8)) - result; if (l == con->selendline) break; diff --git a/engine/client/fragstats.c b/engine/client/fragstats.c index 247a22a4f..2ba4f4eef 100644 --- a/engine/client/fragstats.c +++ b/engine/client/fragstats.c @@ -146,7 +146,7 @@ static void Stats_OwnFrag(char *name) void VARGS Stats_Message(char *msg, ...); -qboolean Stats_TrackerImageLoaded(char *in) +qboolean Stats_TrackerImageLoaded(const char *in) { int error; if (in) diff --git a/engine/client/image.c b/engine/client/image.c index b94835a79..26e0b3568 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -4030,6 +4030,190 @@ static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, const ch } #endif +#ifdef IMAGEFMT_VTF +//many of these look like dupes, not really sure how they're meant to work. probably legacy. +typedef enum { + VMF_INVALID=-1, +// VMF_RGBA8=0, +// VMF_ABGR8=1, + VMF_RGB8=2, + VMF_BGR8=3, +// VMF_RGB565=4, +// VMF_I8=5, +// VMF_IA8=6, +// VMF_P8=7, +// VMF_A8=8, +// VMF_RGB8_BS=9, +// VMF_BGR8_BS=10, +// VMF_ARGB_BS=11, + VMF_BGRA8=12, + VMF_BC1=13, + VMF_BC2=14, + VMF_BC3=15, + VMF_BGRX8=16, +// VMF_BGR565=17, +// VMF_BGRX5551=18, +// VMF_BGRA4444=19, + VMF_BC1A=20, +// VMF_BGRA5551=21, + VMF_UV88=22, +// VMF_UVWQ8=23, + VMF_RGBA16F=24, +// VMF_RGBA16N=25, +// VMF_UVLX8=26, + VMF_MAX +} fmtfmt_t; +static uploadfmt_t ImageVTF_VtfToFTE(fmtfmt_t f) +{ + switch(f) + { + case VMF_BC1: + return PTI_BC1_RGB; + case VMF_BC1A: + return PTI_BC1_RGBA; + case VMF_BC2: + return PTI_BC2_RGBA; + case VMF_BC3: + return PTI_BC3_RGBA; + case VMF_RGB8: + return PTI_RGB8; + case VMF_BGR8: + return PTI_BGR8; + case VMF_BGRA8: + return PTI_BGRA8; + case VMF_BGRX8: + return PTI_BGRX8; + case VMF_RGBA16F: + return PTI_RGBA16F; + case VMF_UV88: + return PTI_RG8; + case VMF_INVALID: + return PTI_INVALID; + + default: + return PTI_INVALID; + } +} +static struct pendingtextureinfo *Image_ReadVTFFile(unsigned int flags, const char *fname, qbyte *filedata, size_t filesize) +{ + //FIXME: cba with endian. + struct vtf_s + { + char magic[4]; + unsigned int major,minor; + unsigned int headersize; + + unsigned short width, height; + unsigned int flags; + unsigned short numframes, firstframe; + unsigned int pad1; + + vec3_t reflectivity; + float pad2; + + float bumpmapscale; + unsigned int imgformat; + unsigned char mipmapcount; + unsigned char lowresfmt_misaligned[4]; + unsigned char lowreswidth; + unsigned char lowresheight; + + //7.2 + unsigned char depth_misaligned[2]; + //7.3 + unsigned char pad3[3]; + unsigned int numresources; + } *vtf; + fmtfmt_t vmffmt, lrfmt; + unsigned int bw, bh, bb; + qbyte *end = filedata + filesize; + unsigned int face, faces, frame, frames, miplevel, miplevels, img; + unsigned int w, h; + size_t datasize; + unsigned int version; + + struct pendingtextureinfo *mips; + + vtf = (void*)filedata; + + if (memcmp(vtf->magic, "VTF\0", 4)) + return NULL; + + version = (vtf->major<<16)|vtf->minor; + if (version >= 0x00070003) + return NULL; //we don't support the whole resources thing. + + lrfmt = (vtf->lowresfmt_misaligned[0]<<0)|(vtf->lowresfmt_misaligned[1]<<16)|(vtf->lowresfmt_misaligned[2]<<16)|(vtf->lowresfmt_misaligned[3]<<24); + vmffmt = vtf->imgformat; + + if (vtf->lowreswidth && vtf->lowresheight) + Image_BlockSizeForEncoding(ImageVTF_VtfToFTE(lrfmt), &bb, &bw, &bh); + else + bb=bw=bh=1; + datasize = ((vtf->lowreswidth+bw-1)/bw) * ((vtf->lowresheight+bh-1)/bh) * bb; + + mips = Z_Malloc(sizeof(*mips)); + mips->type = (vtf->flags & 0x4000)?PTI_CUBEMAP:PTI_2D; + + mips->extrafree = filedata; + filedata += vtf->headersize; //skip the header + filedata += datasize; //and skip the low-res image too. + + mips->encoding = ImageVTF_VtfToFTE(vmffmt); + Image_BlockSizeForEncoding(mips->encoding, &bb, &bw, &bh); + + miplevels = vtf->mipmapcount; + frames = 1;//vtf->numframes; + faces = ((mips->type==PTI_CUBEMAP)?6:1); //no cubemaps yet. + + mips->mipcount = miplevels * frames * faces; + while (mips->mipcount > countof(mips->mip)) + { + if (miplevels > 1) + miplevels--; + else + frames--; + mips->mipcount = miplevels * frames * faces; + } + if (!mips->mipcount) + { + Z_Free(mips); + return NULL; + } + for (miplevel = vtf->mipmapcount; miplevel-- > 0;) + { //smallest to largest, which is awkward. + w = vtf->width>>miplevel; + h = vtf->height>>miplevel; + if (!w) + w = 1; + if (!h) + h = 1; + datasize = ((w+bw-1)/bw) * ((h+bh-1)/bh) * bb; + for (frame = 0; frame < vtf->numframes; frame++) + { + for (face = 0; face < faces; face++) + { + if (miplevel < miplevels && face < faces) + { + img = face+miplevel*faces + frame*miplevels*faces; + if (img >= countof(mips->mip)) + break; //erk? + if (filedata + datasize > end) + break; //no more data here... + mips->mip[img].width = w; + mips->mip[img].height = h; + mips->mip[img].depth = 1; + mips->mip[img].data = filedata; + mips->mip[img].datasize = datasize; + } + filedata += datasize; + } + } + } + return mips; +} +#endif + //if force_rgba8 then it guarentees rgba8 or rgbx8, otherwise can return l8, etc qbyte *ReadRawImageFile(qbyte *buf, int len, int *width, int *height, uploadfmt_t *format, qboolean force_rgba8, const char *fname) { @@ -6957,6 +7141,10 @@ static struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char if (!mips && filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') mips = Image_ReadBLPFile(flags, fname, filedata, filesize); #endif +#ifdef IMAGEFMT_VTF + if (!mips && filedata[0] == 'V' && filedata[1] == 'T' && filedata[2] == 'F' && filedata[3] == '\0') + mips = Image_ReadVTFFile(flags, fname, filedata, filesize); +#endif //the above formats are assumed to have consumed filedata somehow (probably storing into mips->extradata) if (mips) diff --git a/engine/client/keys.c b/engine/client/keys.c index 23056f133..68724d8b4 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -541,7 +541,7 @@ void CompleteCommand (qboolean force, int direction) Key_UpdateCompletionDesc(); } -int Con_Navigate(console_t *con, char *line) +int Con_Navigate(console_t *con, const char *line) { if (con->backshader) { @@ -558,7 +558,7 @@ int Con_Navigate(console_t *con, char *line) } //lines typed at the main console enter here -int Con_ExecuteLine(console_t *con, char *line) +int Con_ExecuteLine(console_t *con, const char *line) { qboolean waschat = false; char *deutf8 = NULL; @@ -598,7 +598,7 @@ int Con_ExecuteLine(console_t *con, char *line) Cbuf_AddText (line, RESTRICT_LOCAL); else { - char *exec = NULL; + const char *exec = NULL; if (line[0] == '\\' || line[0] == '/') exec = line+1; // skip the slash else if (cl_chatmode.value == 2 && Cmd_IsCommand(line)) @@ -1128,6 +1128,19 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) { if (con->selstartline) { + if (con->userline) + { + if (con->flags & CONF_BACKSELECTION) + { + con->userline = con->selendline; + con->useroffset = con->selendoffset; + } + else + { + con->userline = con->selstartline; + con->useroffset = con->selstartoffset; + } + } if (con->selstartline == con->selendline && con->selendoffset <= con->selstartoffset+1) { con->flags &= ~CONF_KEEPSELECTION; @@ -1135,7 +1148,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) ; else { - buffer = Con_CopyConsole(con, false, true); + buffer = Con_CopyConsole(con, false, true, false); if (buffer) { Key_HandleConsoleLink(con, buffer); @@ -1146,21 +1159,8 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) else { con->flags |= CONF_KEEPSELECTION; - if (con->userdata) - { - if (con->flags & CONF_BACKSELECTION) - { - con->userline = con->selendline; - con->useroffset = con->selendoffset; - } - else - { - con->userline = con->selstartline; - con->useroffset = con->selstartoffset; - } - } - buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard if (buffer) { Sys_SaveClipboard(CBT_SELECTION, buffer); @@ -1175,7 +1175,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) con->buttonsdown = CB_NONE; if (abs(con->mousedown[0] - con->mousecursor[0]) < 5 && abs(con->mousedown[1] - con->mousecursor[1]) < 5) { - buffer = Con_CopyConsole(con, false, false); + buffer = Con_CopyConsole(con, false, false, false); Con_Footerf(con, false, ""); if (!buffer) return; @@ -1208,7 +1208,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) if (key == K_MOUSE2 && con->buttonsdown == CB_COPY) { con->buttonsdown = CB_NONE; - buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard if (!buffer) return; Sys_SaveClipboard(CBT_CLIPBOARD, buffer); @@ -1236,6 +1236,111 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) } #endif } + +const char *Key_Demoji(char *buffer, size_t buffersize, const char *in) +{ + static const struct + { + const char *pattern; + const char *repl; + } emoji[] = + { + //https://www.webpagefx.com/tools/emoji-cheat-sheet/ +// {":)", "\xE2\x98\xBA"}, + +#ifdef QUAKEHUD + {":sg:", "\xEE\x84\x82"}, + {":ssg:", "\xEE\x84\x83"}, + {":ng:", "\xEE\x84\x84"}, + {":sng:", "\xEE\x84\x85"}, + {":gl:", "\xEE\x84\x86"}, + {":rl:", "\xEE\x84\x87"}, + {":lg:", "\xEE\x84\x88"}, + + {":sg2:", "\xEE\x84\x92"}, + {":ssg2:", "\xEE\x84\x93"}, + {":ng2:", "\xEE\x84\x94"}, + {":sng2:", "\xEE\x84\x95"}, + {":gl2:", "\xEE\x84\x96"}, + {":rl2:", "\xEE\x84\x97"}, + {":lg2:", "\xEE\x84\x98"}, + + {":shells:", "\xEE\x84\xA0"}, + {":nails:", "\xEE\x84\xA1"}, + {":rocket:", "\xEE\x84\xA2"}, + {":cells:", "\xEE\x84\xA3"}, + {":ga:", "\xEE\x84\xA4"}, + {":ya:", "\xEE\x84\xA5"}, + {":ra:", "\xEE\x84\xA6"}, + + {":key1:", "\xEE\x84\xB0"}, + {":key2:", "\xEE\x84\xB1"}, + {":ring:", "\xEE\x84\xB2"}, + {":pent:", "\xEE\x84\xB3"}, + {":suit:", "\xEE\x84\xB4"}, + {":quad:", "\xEE\x84\xB5"}, + {":sigil1:", "\xEE\x84\xB6"}, + {":sigil2:", "\xEE\x84\xB7"}, + {":sigil3:", "\xEE\x84\xB8"}, + {":sigil4:", "\xEE\x84\xB9"}, + + {":face1:", "\xEE\x85\x80"}, + {":face_p1:", "\xEE\x85\x81"}, + {":face2:", "\xEE\x85\x82"}, + {":face_p2:", "\xEE\x85\x83"}, + {":face3:", "\xEE\x85\x84"}, + {":face_p3:", "\xEE\x85\x85"}, + {":face4:", "\xEE\x85\x86"}, + {":face_p4:", "\xEE\x85\x87"}, + {":face5:", "\xEE\x85\x88"}, + {":face_p5:", "\xEE\x85\x89"}, + {":face_invis:", "\xEE\x85\x8A"}, + {":face_invul2:", "\xEE\x85\x8B"}, + {":face_inv2:", "\xEE\x85\x8C"}, + {":face_quad:", "\xEE\x85\x8D"}, +#endif + }; + char *estart = strchr(in, ':'); + size_t i; + char *out = buffer, *outend = buffer+buffersize-1; + if (!estart) + return in; + for(; estart; ) + { + if (out + (estart-in) >= outend) + break; //not enough space + memcpy(out, in, estart-in); + out += estart-in; + in = estart; + + for (i = 0; i < countof(emoji); i++) + { + if (!strncmp(in, emoji[i].pattern, strlen(emoji[i].pattern))) + break; //its this one! + } + if (i < countof(emoji)) + { + if (out + strlen(emoji[i].repl) >= outend) + { + in = ""; //no half-emoji + break; + } + in += strlen(emoji[i].pattern); + memcpy(out, emoji[i].repl, strlen(emoji[i].repl)); + out += strlen(emoji[i].repl); + estart = strchr(in, ':'); + } + else + { + estart = strchr(in+1, ':'); + } + } + while (*in && out < outend) + *out++ = *in++; + *out = 0; + return buffer; +} + //if the referenced (trailing) chevron is doubled up, then it doesn't act as part of any markup and should be ignored for such things. static qboolean utf_specialchevron(unsigned char *start, unsigned char *chev) { @@ -1456,7 +1561,7 @@ qboolean Key_EntryLine(console_t *con, unsigned char **line, int lineoffset, int { if (con && (con->flags & CONF_KEEPSELECTION)) { //copy selected text to the system clipboard - char *buffer = Con_CopyConsole(con, true, false); + char *buffer = Con_CopyConsole(con, true, false, true); if (buffer) { Sys_SaveClipboard(CBT_CLIPBOARD, buffer); @@ -1666,7 +1771,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) Con_ExpandConsoleSelection(con); con->flags |= CONF_KEEPSELECTION; - buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard if (buffer) { Sys_SaveClipboard(CBT_SELECTION, buffer); @@ -1789,16 +1894,16 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START) { // backslash text are commands, else chat - int oldl = edit_line; + char demoji[8192]; + const char *txt = Key_Demoji(demoji, sizeof(demoji), key_lines[edit_line]); #ifndef FTE_TARGET_WEB if (keydown[K_LALT] || keydown[K_RALT]) Cbuf_AddText("\nvid_toggle\n", RESTRICT_LOCAL); #endif - if ((con_commandmatch && !strchr(key_lines[edit_line], ' ')) || shift) + if ((con_commandmatch && !strchr(txt, ' ')) || shift) { //if that isn't actually a command, and we can actually complete it to something, then lets try to complete it. - char *txt = key_lines[edit_line]; if (*txt == '/') txt++; @@ -1814,7 +1919,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) if (con->linebuffered) { - if (con->linebuffered(con, key_lines[oldl]) != 2) + if (con->linebuffered(con, txt) != 2) { edit_line = (edit_line + 1) & (CON_EDIT_LINES_MASK); history_line = edit_line; @@ -1946,8 +2051,11 @@ void Key_Message (int key, int unicode) { if (chat_buffer && chat_buffer[0]) { //send it straight into the command. - char *line = chat_buffer; + const char *line = chat_buffer; char deutf8[8192]; + char demoji[8192]; + line = Key_Demoji(demoji, sizeof(demoji), line); + if (com_parseutf8.ival <= 0) { unsigned int unicode; diff --git a/engine/client/keys.h b/engine/client/keys.h index 50bf114ca..f0ba1aaf6 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -316,6 +316,8 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode); struct console_s; qboolean Key_GetConsoleSelectionBox(struct console_s *con, int *sx, int *sy, int *ex, int *ey); qboolean Key_MouseShouldBeFree(void); + +const char *Key_Demoji(char *buffer, size_t buffersize, const char *in); //strips out :smile: stuff. #endif #endif diff --git a/engine/client/m_download.c b/engine/client/m_download.c index f78765ad8..c001714a5 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -385,7 +385,7 @@ void PM_ValidatePackage(package_t *p) else #endif { -#ifdef AVAIL_ZLIB //assume zip/pk3/pk4/apk/etc +#ifdef PACKAGE_PK3 //assume zip/pk3/pk4/apk/etc archive = FSZIP_LoadArchive(pf, NULL, n, n, NULL); #else archive = NULL; @@ -2011,6 +2011,7 @@ static void PM_Download_Got(struct dl_download *dl) if (p->extract == EXTRACT_ZIP) { +#ifdef PACKAGE_PK3 vfsfile_t *f = FS_OpenVFS(tempname, "rb", p->fsroot); if (f) { @@ -2038,7 +2039,9 @@ static void PM_Download_Got(struct dl_download *dl) VFS_CLOSE(f); } PM_ValidatePackage(p); - +#else + Con_Printf("zip format not supported in this build - %s (from %s)\n", p->name, dl->url); +#endif FS_Remove (tempname, p->fsroot); Z_Free(tempname); PM_StartADownload(); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 84cba2d7f..33c79f90f 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -559,6 +559,10 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu if (menu->selecteditem == option && (int)(realtime*4) & 1) { + vid.ime_allow = true; + vid.ime_position[0] = x; + vid.ime_position[1] = y+8; + x += strlen(option->edit.text)*8; Draw_FunString(x, y, "^Ue00b"); } diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index d3a371532..8bd72832a 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -101,6 +101,7 @@ static qboolean qacmStartup(void) #endif static char media_currenttrack[MAX_QPATH]; +static cvar_t music_fade = CVAR("music_fade", "1"); //higher bits have priority (if they have something to play). #define MEDIA_GAMEMUSIC (1u<<0) //cd music. also music command etc. @@ -295,7 +296,7 @@ static qboolean Media_Changed (unsigned int mediatype) CDAudio_Stop(); } #endif - media_fadeout = true; + media_fadeout = music_fade.ival; media_fadeouttime = realtime; return true; } @@ -2450,9 +2451,10 @@ cin_t *Media_StartCin(char *name) if (!name || !*name) //clear only. return NULL; +#ifndef MINIMAL if (!cin) cin = Media_Static_TryLoad(name); - +#endif #ifdef Q2CLIENT if (!cin) cin = Media_Cin_TryLoad(name); @@ -5130,6 +5132,7 @@ void Media_Init(void) Cmd_AddCommand ("menu_media", M_Menu_Media_f); #endif #endif + Cvar_Register(&music_fade, "Media player things"); #ifdef HAVE_SPEECHTOTEXT Cmd_AddCommand("tts", TTS_Say_f); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index a743acfb4..41edf5f41 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1394,6 +1394,7 @@ qboolean M_VideoApplyShadowLighting (union menuoption_s *op,struct menu_s *menu, break; } #ifdef MINIMAL + (void)cvarv; Cbuf_AddText(va("r_shadow_realtime_world %s;r_shadow_realtime_world_shadows %s\n", cvarsrw, cvarsrws), RESTRICT_LOCAL); #else Cbuf_AddText(va("r_vertexlight %s;r_shadow_realtime_world %s;r_shadow_realtime_world_shadows %s\n", cvarv, cvarsrw, cvarsrws), RESTRICT_LOCAL); diff --git a/engine/client/menu.h b/engine/client/menu.h index bd4b3e780..00230abaf 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -485,11 +485,13 @@ int MP_GetServerCategory(int index); #endif #ifdef MENU_NATIVECODE +#ifdef HAVE_CLIENT #include "api_menu.h" extern menu_export_t *mn_entry; void MN_Shutdown(void); qboolean MN_Init(void); #endif +#endif #define MGT_BAD ~0 #define MGT_QUAKE1 0 diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 94e9d7f15..2bcac1ee2 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -870,7 +870,7 @@ void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s while(*text) { if (1)//VMUTF8) - c = unicode_decode(&error, text, (char**)&text, false); + c = unicode_decode(&error, text, &text, false); else { //FIXME: which charset is this meant to be using? diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index cc2f796ac..4b711bb34 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3689,7 +3689,8 @@ uploadfmt_t Surf_LightmapMode(model_t *model) } - Con_DPrintf("%s: Using lightmap format %s\n", model->name, Image_FormatName(fmt)); + if (!model->submodelof) + Con_DPrintf("%s: Using lightmap format %s\n", model->name, Image_FormatName(fmt)); return fmt; } diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 6f6de70c3..90d71ab39 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1232,7 +1232,7 @@ void Draw_TinyString (float x, float y, const qbyte *str) while (*str) { - codepoint = unicode_decode(&error, str, (char**)&str, true); + codepoint = unicode_decode(&error, str, (char const**)&str, true); if (codepoint == '\n') { @@ -2728,7 +2728,7 @@ static void Sbar_Voice(int y) #endif } -void SCR_StringXY(char *str, float x, float y); +void SCR_StringXY(const char *str, float x, float y); void SCR_DrawClock(void); void SCR_DrawGameClock(void); static void Sbar_DrawUPS(playerview_t *pv) diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 9171a9e4a..873a86431 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -916,7 +916,7 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un if (decodesamps > 0) { //calculate levels of other people. eukara demanded this. - float level; + float level = 0; float f; for (len = 0; len < decodesamps; len++) { diff --git a/engine/client/snd_sdl.c b/engine/client/snd_sdl.c index b9f1f8c6e..f243c24d4 100644 --- a/engine/client/snd_sdl.c +++ b/engine/client/snd_sdl.c @@ -1,6 +1,6 @@ #include "quakedef.h" -#ifdef HAVE_MIXER +#if defined(HAVE_MIXER) || defined(VOICECHAT) #include "winquake.h" #ifdef DYNAMIC_SDL @@ -87,8 +87,8 @@ static dllhandle_t *libsdl; #else #include #endif - -#define SELFPAINT +#define SDRVNAME "SDL" +#endif //SDL calls a callback each time it needs to repaint the 'hardware' buffers //This results in extra latency due it needing to buffer that much data. @@ -133,7 +133,8 @@ static qboolean SSDL_InitAudio(void) return true; } - +#ifdef HAVE_MIXER +#define SELFPAINT static void SSDL_Shutdown(soundcardinfo_t *sc) { Con_DPrintf("Shutdown SDL sound\n"); @@ -328,7 +329,6 @@ static qboolean QDECL SDL_InitCard(soundcardinfo_t *sc, const char *devicename) return true; } -#define SDRVNAME "SDL" static qboolean QDECL SDL_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename)) { #if SDL_MAJOR_VERSION >= 2 @@ -355,6 +355,7 @@ sounddriver_t SDL_Output = SDL_InitCard, SDL_Enumerate }; +#endif #if SDL_VERSION_ATLEAST(2,0,5) && defined(VOICECHAT) //Requires SDL 2.0.5+ supposedly. @@ -403,20 +404,24 @@ static void *QDECL SDL_Capture_Init (int rate, const char *devname) SDL_AudioSpec want, have; sdlcapture_t c, *r; - memset(&want, 0, sizeof(want)); - want.freq = rate; - want.format = AUDIO_S16SYS; - want.channels = 1; - want.samples = 256; //this seems to be chunk sizes rather than total buffer size, so lets keep it reasonably small for lower latencies - want.callback = NULL; + if (SSDL_InitAudio()) + { + memset(&want, 0, sizeof(want)); + want.freq = rate; + want.format = AUDIO_S16SYS; + want.channels = 1; + want.samples = 256; //this seems to be chunk sizes rather than total buffer size, so lets keep it reasonably small for lower latencies + want.callback = NULL; - c.dev = SDL_OpenAudioDevice(devname, true, &want, &have, 0); - if (!c.dev) //failed? - return NULL; - - r = Z_Malloc(sizeof(*r)); - *r = c; - return r; + c.dev = SDL_OpenAudioDevice(devname, true, &want, &have, 0); + if (c.dev) + { + r = Z_Malloc(sizeof(*r)); + *r = c; + return r; + } + } + return NULL; } /*minbytes is a hint to not bother wasting time*/ @@ -444,4 +449,4 @@ snd_capture_driver_t SDL_Capture = SDL_Capture_Shutdown }; #endif -#endif + diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 04169cae5..0a26c3b3e 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -1928,7 +1928,7 @@ void Sys_Clipboard_PasteText(clipboardtype_t cbt, void (*callback)(void *cb, cha CloseClipboard(); } } -void Sys_SaveClipboard(clipboardtype_t cbt, char *text) +void Sys_SaveClipboard(clipboardtype_t cbt, const char *text) { HANDLE glob; char *temp; diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 49a06c11f..fd6e1e1a7 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -97,7 +97,7 @@ conline_t *Con_Editor_FindLine(console_t *con, int line) return NULL; } -int Con_Editor_Evaluate(console_t *con, char *evalstring) +int Con_Editor_Evaluate(console_t *con, const char *evalstring) { char *eq, *term; @@ -304,7 +304,7 @@ static void Con_Editor_Save(console_t *con) } qboolean Con_Editor_MouseOver(struct console_s *con, char **out_tiptext, shader_t **out_shader) { - char *mouseover = Con_CopyConsole(con, true, false); + char *mouseover = Con_CopyConsole(con, true, false, false); if (mouseover) { @@ -618,7 +618,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key) } if (ctrldown && (con->flags & CONF_KEEPSELECTION)) { - char *buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + char *buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard if (buffer) { Sys_SaveClipboard(CBT_CLIPBOARD, buffer); @@ -803,7 +803,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key) } if (ctrldown && key =='c' && (con->flags & CONF_KEEPSELECTION)) { - char *buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + char *buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard if (buffer) { Sys_SaveClipboard(CBT_CLIPBOARD, buffer); @@ -820,7 +820,7 @@ qboolean Con_Editor_Key(console_t *con, unsigned int unicode, int key) c[l++] = CON_WHITEMASK | (unicode&0xffff); if (con->flags & CONF_KEEPSELECTION) Con_Editor_DeleteSelection(con); - if (Con_InsertConChars(con, con->userline, con->useroffset, c, l)) + if (con->userline && Con_InsertConChars(con, con->userline, con->useroffset, c, l)) { con->useroffset += l; Con_Editor_LineChanged(con, con->userline); diff --git a/engine/client/vid.h b/engine/client/vid.h index 486351941..c800e6b27 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -107,6 +107,12 @@ typedef struct float dpi_x; float dpi_y; + + conchar_t *ime_preview; //pending IME preview text that has been entered but isn't committed yet. set by video code. + size_t ime_previewlen; + size_t ime_caret; + float ime_position[2]; //where to display any ime popups (virtual coords) + qboolean ime_allow; //enable the ime (ie: at the console or messagemode) } viddef_t; extern viddef_t vid; // global video state diff --git a/engine/common/cmd.h b/engine/common/cmd.h index 6f347fdba..12ded8ea9 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -194,4 +194,5 @@ qboolean If_EvaluateBoolean(const char *text, int restriction); extern cvar_t rcon_level; -void Cmd_AddTimer(float delay, void(*callback)(int iarg, void *data), int iarg, void *data, size_t datasize); //wrong place, gah \ No newline at end of file +void Cmd_AddTimer(float delay, void(*callback)(int iarg, void *data), int iarg, void *data, size_t datasize); //wrong place, gah + diff --git a/engine/common/common.c b/engine/common/common.c index c59c6bedc..cacf37199 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2259,7 +2259,7 @@ qboolean COM_RequireExtension(char *path, const char *extension, int maxlen) //3 invalid unicode char //4 invalid utf-16 lead/high surrogate //5 invalid utf-16 tail/low surrogate -unsigned int utf8_decode(int *error, const void *in, char **out) +unsigned int utf8_decode(int *error, const void *in, char const**out) { //uc is the output unicode char unsigned int uc = 0xfffdu; //replacement character @@ -2375,7 +2375,7 @@ unsigned int utf8_decode(int *error, const void *in, char **out) uc = *str; } - *out = (void*)(str + l); + *out = (const void*)(str + l); if (!*error) { @@ -2384,7 +2384,7 @@ unsigned int utf8_decode(int *error, const void *in, char **out) { #if 1 //cesu-8 - char *lowend; + const char *lowend; unsigned int lowsur = utf8_decode(error, str + l, &lowend); if (*error == 4) { @@ -2409,7 +2409,7 @@ unsigned int utf8_decode(int *error, const void *in, char **out) return uc; } -unsigned int unicode_decode(int *error, const void *in, char **out, qboolean markup) +unsigned int unicode_decode(int *error, const void *in, char const**out, qboolean markup) { unsigned int charcode; if (markup && ((char*)in)[0] == '^' && ((char*)in)[1] == 'U' && ishexcode(((char*)in)[2]) && ishexcode(((char*)in)[3]) && ishexcode(((char*)in)[4]) && ishexcode(((char*)in)[5])) @@ -2636,7 +2636,7 @@ unsigned int unicode_charcount(const char *in, size_t buffersize, qboolean marku int chars = 0; for(chars = 0; in < end && *in; chars+=1) { - unicode_decode(&error, in, (char**)&in, markup); + unicode_decode(&error, in, &in, markup); if (in > end) break; //exceeded buffer size uncleanly @@ -2655,7 +2655,7 @@ unsigned int unicode_byteofsfromcharofs(const char *str, unsigned int charofs, q if (chars >= charofs) return in - str; - unicode_decode(&error, in, (char**)&in, markup); + unicode_decode(&error, in, &in, markup); } return in - str; } @@ -2667,7 +2667,7 @@ unsigned int unicode_charofsfrombyteofs(const char *str, unsigned int byteofs, q int chars = 0; for(chars = 0; str < end && *str; chars+=1) { - unicode_decode(&error, str, (char**)&str, markup); + unicode_decode(&error, str, &str, markup); if (str > end) break; //exceeded buffer size uncleanly @@ -2722,7 +2722,7 @@ size_t unicode_strtoupper(const char *in, char *out, size_t outsize, qboolean ma while(*in) { - c = unicode_decode(&error, in, (char**)&in, markup); + c = unicode_decode(&error, in, &in, markup); if (c >= 0xe020 && c <= 0xe07f) //quake-char-aware. c = towupper(c & 0x7f) + (c & 0xff80); else @@ -2746,7 +2746,7 @@ size_t unicode_strtolower(const char *in, char *out, size_t outsize, qboolean ma while(*in) { - c = unicode_decode(&error, in, (char**)&in, markup); + c = unicode_decode(&error, in, &in, markup); if (c >= 0xe020 && c <= 0xe07f) //quake-char-aware. c = towlower(c & 0x7f) + (c & 0xff80); else @@ -3274,7 +3274,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t if ((*str & 0x80) && utf8 > 0) { //check for utf-8 int decodeerror; - char *end; + const char *end; uc = utf8_decode(&decodeerror, str, &end); if (decodeerror && !(utf8 & 2)) { @@ -5882,7 +5882,7 @@ unsigned int COM_RemapMapChecksum(model_t *model, unsigned int checksum) { #ifndef NOLEGACY static const struct { - char *name; + const char *name; unsigned int gpl2; unsigned int id11; unsigned int id12; diff --git a/engine/common/common.h b/engine/common/common.h index 86a2d8966..925b66511 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -405,7 +405,7 @@ char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, q #define PFS_CENTERED 16 //flag used by console prints (text should remain centered) #define PFS_NONOTIFY 32 //flag used by console prints (text won't be visible other than by looking at the console) conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator -unsigned int utf8_decode(int *error, const void *in, char **out); +unsigned int utf8_decode(int *error, const void *in, char const**out); unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen); unsigned int iso88591_encode(char *out, unsigned int unicode, int maxlen, qboolean markup); unsigned int qchar_encode(char *out, unsigned int unicode, int maxlen, qboolean markup); @@ -420,7 +420,7 @@ void COM_BiDi_Shutdown(void); unsigned int unicode_byteofsfromcharofs(const char *str, unsigned int charofs, qboolean markup); unsigned int unicode_charofsfrombyteofs(const char *str, unsigned int byteofs, qboolean markup); unsigned int unicode_encode(char *out, unsigned int unicode, int maxlen, qboolean markup); -unsigned int unicode_decode(int *error, const void *in, char **out, qboolean markup); +unsigned int unicode_decode(int *error, const void *in, char const**out, qboolean markup); size_t unicode_strtolower(const char *in, char *out, size_t outsize, qboolean markup); size_t unicode_strtoupper(const char *in, char *out, size_t outsize, qboolean markup); unsigned int unicode_charcount(const char *in, size_t buffersize, qboolean markup); diff --git a/engine/common/config_fteqw.h b/engine/common/config_fteqw.h index 0ebdb2a8a..af2ac40b7 100644 --- a/engine/common/config_fteqw.h +++ b/engine/common/config_fteqw.h @@ -51,13 +51,15 @@ #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 +#define PACKAGE_PK3 //aka zips. we support utf8,zip64,spans,weakcrypto,deflate,(bzip2),symlinks. we do not support strongcrypto nor any of the other compression schemes. #define PACKAGE_Q1PAK //also q2 //#define PACKAGE_DOOMWAD //doom wad support (generates various file names, and adds support for doom's audio, sprites, etc) +//#define PACKAGE_VPK //hl2 packages #define AVAIL_XZDEC //.xz decompression #define AVAIL_GZDEC //.gz decompression #define AVAIL_ZLIB //whether pk3s can be compressed or not. -#define AVAIL_DZIP //.dzip support for smaller demos (which are actually more like pak files and can store ANY type of file) +//#define AVAIL_BZLIB //whether pk3s can use bz2 compression +#define PACKAGE_DZIP //.dzip support for smaller demos (which are actually more like pak files and can store ANY type of file) //Map formats #define Q1BSPS //Quake1 @@ -87,9 +89,10 @@ #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. doesn't support mips. #define IMAGEFMT_DDS //.dds files embed mipmaps and texture compression. faster to load. -#define IMAGEFMT_BLP //legacy crap +//#define IMAGEFMT_BLP //legacy crap #define IMAGEFMT_BMP //windows bmp. yuck. #define IMAGEFMT_PCX //paletted junk. required for qw player skins, q2 and a few old skyboxes. +//#define IMAGEFMT_VTF //hl2 image format #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 diff --git a/engine/common/config_wastes.h b/engine/common/config_wastes.h index 36611c934..21c774882 100644 --- a/engine/common/config_wastes.h +++ b/engine/common/config_wastes.h @@ -71,6 +71,7 @@ #define PACKAGE_TEXWAD // HL content support, WAD3 #define PACKAGE_Q1PAK // HL content support, PAK #undef PACKAGE_DOOMWAD +#undef PACKAGE_VPK //legacy crap // Map formats #define Q3BSPS // What we use exclusively @@ -113,6 +114,7 @@ #undef IMAGEFMT_KTX #undef IMAGEFMT_PKM #undef IMAGEFMT_BLP //legacy crap +#undef IMAGEFMT_VTF //legacy crap #define 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). @@ -164,6 +166,7 @@ #undef HEADLESSQUAKE #undef WAYLANDQUAKE #undef AVAIL_FREETYPE // for truetype font rendering +#undef SERVER_DEMO_PLAYBACK //outdated crap #ifdef COMPILE_OPTS //things to configure qclib, which annoyingly doesn't include this file itself diff --git a/engine/common/console.h b/engine/common/console.h index 19e7c40d9..1898a23ba 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -179,7 +179,7 @@ typedef struct console_s int commandcompletion; //allows tab completion of quake console commands //WARNING: note that links do NOT represent any sort of security. text can be inserted from anywhere. Its fine to use such things for context, but don't treat them as sescure. - int (*linebuffered) (struct console_s *con, char *line); //if present, called on enter, causes the standard console input to appear. return 2 to not save the line in history. + int (*linebuffered) (struct console_s *con, const char *line); //if present, called on enter, causes the standard console input to appear. return 2 to not save the line in history. qboolean (*redirect) (struct console_s *con, unsigned int unicode, int key); //if present, called every character. qboolean (*mouseover)(struct console_s *con, char **out_tiptext, struct shader_s **out_shader); qboolean (*close) (struct console_s *con, qboolean force); @@ -232,7 +232,7 @@ struct font_s; void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, float fx, float fy, float fsx, float fsy, float lineagelimit); void Con_DrawConsole (int lines, qboolean noback); void Con_ExpandConsoleSelection(console_t *con); -char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink); +char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink, qboolean forceutf8); void Con_Print (const char *txt); void Con_CenterPrint(const char *txt); void Con_PrintFlags(const char *text, unsigned int setflags, unsigned int clearflags); @@ -249,8 +249,8 @@ void Con_ClearNotify (void); void Con_ToggleConsole_f (void);//note: allows csqc to intercept the toggleconsole void Con_ToggleConsole_Force(void); -int Con_ExecuteLine(console_t *con, char *line); //takes normal console commands -int Con_Navigate(console_t *con, char *line); //special webbrowser hacks +int Con_ExecuteLine(console_t *con, const char *line); //takes normal console commands +int Con_Navigate(console_t *con, const char *line); //special webbrowser hacks vfsfile_t *Con_POpen(char *conname); void Con_CycleConsole (void); diff --git a/engine/common/fs.c b/engine/common/fs.c index 09f44095f..472bafdae 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -810,9 +810,11 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void || !Q_strcasecmp(link, "txt") || !Q_strcasecmp(link, "log") || !Q_strcasecmp(link, "ent") || !Q_strcasecmp(link, "rtlights") || !Q_strcasecmp(link, "glsl") || !Q_strcasecmp(link, "hlsl") - || !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups")) + || !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups") + || !Q_strcasecmp(link, "vmt") + ) Q_snprintfz(link, sizeof(link), "\\tip\\Open in Text Editor\\edit\\%s", name); - else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds") || !Q_strcasecmp(link, "ktx")) + else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds") || !Q_strcasecmp(link, "ktx") || !Q_strcasecmp(link, "vtf")) { //FIXME: image replacements are getting in the way here. Q_snprintfz(link, sizeof(link), "\\tiprawimg\\%s\\tip\\(note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader)", name); @@ -6427,6 +6429,9 @@ void FS_RegisterDefaultFileSystems(void) FS_RegisterFileSystemType(NULL, "zip", FSZIP_LoadArchive, false); FS_RegisterFileSystemType(NULL, "exe", FSZIP_LoadArchive, false); //for self-extracting zips. #endif +#ifdef PACKAGE_VPK + FS_RegisterFileSystemType(NULL, "vpk", FSVPK_LoadArchive, true); +#endif #ifdef PACKAGE_DOOMWAD FS_RegisterFileSystemType(NULL, "wad", FSDWD_LoadArchive, true); #endif diff --git a/engine/common/fs.h b/engine/common/fs.h index a9ead967f..c615c128a 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -59,6 +59,7 @@ struct searchpathfuncs_s //warning: the handle is known to be a string pointer to the dir name extern searchpathfuncs_t *(QDECL VFSOS_OpenPath) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSZIP_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); +extern searchpathfuncs_t *(QDECL FSVPK_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSPAK_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSDWD_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); extern searchpathfuncs_t *(QDECL FSDZ_LoadArchive) (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix); diff --git a/engine/common/fs_vpk.c b/engine/common/fs_vpk.c new file mode 100644 index 000000000..545353feb --- /dev/null +++ b/engine/common/fs_vpk.c @@ -0,0 +1,502 @@ +#include "quakedef.h" +#include "fs.h" + +#ifdef PACKAGE_VPK + +// +// in memory +// + +typedef struct +{ + fsbucket_t bucket; + + char name[MAX_QPATH]; + const struct dvpkfile_s *file; +} mvpkfile_t; + +typedef struct vpk_s +{ + searchpathfuncs_t pub; + char descname[MAX_OSPATH]; + + qbyte *treedata; //raw file list + size_t treesize; + + struct vpk_s **fragments; + size_t numfragments; + + void *mutex; + vfsfile_t *handle; + unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek) + int references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed. + + size_t numfiles; + mvpkfile_t files[1]; //processed file list +} vpk_t; + +// +// on disk +// +typedef struct dvpkfile_s +{ //chars because these are misaligned. + unsigned char crc[4]; + unsigned char preloadsize[2]; + unsigned char archiveindex[2]; + unsigned char archiveoffset[4]; + unsigned char archivesize[4]; + unsigned char sentinal[2];//=0xffff; +} dvpkfile_t; + +typedef struct +{ + //v1 + unsigned int magic; + unsigned int version; + unsigned int tablesize; + + //v2 + unsigned int filedatasize; + unsigned int archivemd5size; + unsigned int globalmd5size; + unsigned int signaturesize; +} dvpkheader_t; + +static void QDECL FSVPK_GetPathDetails(searchpathfuncs_t *handle, char *out, size_t outlen) +{ + vpk_t *pak = (void*)handle; + + *out = 0; + if (pak->references != 1) + Q_snprintfz(out, outlen, "(%i)", pak->references-1); +} +static void QDECL FSVPK_ClosePath(searchpathfuncs_t *handle) +{ + qboolean stillopen; + size_t i; + vpk_t *pak = (void*)handle; + + if (!Sys_LockMutex(pak->mutex)) + return; //ohnoes + stillopen = --pak->references > 0; + Sys_UnlockMutex(pak->mutex); + if (stillopen) + return; //not free yet + + + VFS_CLOSE (pak->handle); + + Sys_DestroyMutex(pak->mutex); + for (i = 0; i < pak->numfragments; i++) + { + if (pak->fragments[i]) + pak->fragments[i]->Close(pak->fragments[i]); + pak->fragments[i] = NULL; + } + Z_Free(pak->fragments); + Z_Free(pak->treedata); + Z_Free(pak); +} +static void QDECL FSVPK_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)) +{ + vpk_t *pak = (void*)handle; + int i; + + for (i = 0; i < pak->numfiles; i++) + { + AddFileHash(depth, pak->files[i].name, &pak->files[i].bucket, &pak->files[i]); + } +} +static unsigned int QDECL FSVPK_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +{ + mvpkfile_t *pf = hashedresult; + int i; + vpk_t *pak = (void*)handle; + +// look through all the pak file elements + + if (pf) + { //is this a pointer to a file in this pak? + if (pf < pak->files || pf > pak->files + pak->numfiles) + return FF_NOTFOUND; //was found in a different path + } + else + { + for (i=0 ; inumfiles ; i++) //look for the file + { + if (!Q_strcasecmp (pak->files[i].name, filename)) + { + pf = &pak->files[i]; + break; + } + } + } + + if (pf) + { + if (loc) + { + loc->fhandle = pf; + *loc->rawname = 0; + loc->offset = (qofs_t)-1; + loc->len = ((pf->file->preloadsize[0]<<0)|(pf->file->preloadsize[1]<<8)) + +((pf->file->archivesize[0]<<0)|(pf->file->archivesize[1]<<8)|(pf->file->archivesize[2]<<16)|(pf->file->archivesize[3]<<24)); + } + return FF_FOUND; + } + return FF_NOTFOUND; +} +static int QDECL FSVPK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *spath), void *parm) +{ + vpk_t *pak = (void*)handle; + int num; + mvpkfile_t *file; + qofs_t size; + + for (num = 0; num<(int)pak->numfiles; num++) + { + if (wildcmp(match, pak->files[num].name)) + { + file = &pak->files[num]; + //FIXME: time 0? maybe use the pak's mtime? + size = ((file->file->preloadsize[0]<<0)|(file->file->preloadsize[1]<<8)) + +((file->file->archivesize[0]<<0)|(file->file->archivesize[1]<<8)|(file->file->archivesize[2]<<16)|(file->file->archivesize[3]<<24)); + if (!func(file->name, size, 0, parm, handle)) + return false; + } + } + + return true; +} + +static int QDECL FSVPK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) +{ + vpk_t *pak = (void*)handle; + + return Com_BlockChecksum(pak->treedata, pak->treesize); +} + +typedef struct { + vfsfile_t funcs; + vpk_t *parentpak; + const qbyte *preloaddata; + size_t preloadsize; + qofs_t startpos; + qofs_t length; + qofs_t currentpos; +} vfsvpk_t; +static int QDECL VFSVPK_ReadBytes (struct vfsfile_s *vfs, void *buffer, int bytestoread) +{ + vfsvpk_t *vfsp = (void*)vfs; + int read; + + if (bytestoread <= 0) + return 0; + + if (vfsp->currentpos < vfsp->preloadsize) + { + read = bytestoread; + if (read > vfsp->preloadsize-vfsp->currentpos) + read = vfsp->preloadsize-vfsp->currentpos; + memcpy(buffer, vfsp->preloaddata, read); + vfsp->currentpos += read; + if (read == bytestoread) + return read; //we're done, no need to seek etc + bytestoread -= read; + } + + if (vfsp->currentpos-vfsp->preloadsize + bytestoread > vfsp->length) + bytestoread = vfsp->length - (vfsp->currentpos-vfsp->preloadsize); + if (bytestoread <= 0) + { + return -1; + } + + if (Sys_LockMutex(vfsp->parentpak->mutex)) + { + if (vfsp->parentpak->filepos != vfsp->startpos+vfsp->currentpos-vfsp->preloadsize) + VFS_SEEK(vfsp->parentpak->handle, vfsp->startpos+vfsp->currentpos-vfsp->preloadsize); + read = VFS_READ(vfsp->parentpak->handle, buffer, bytestoread); + if (read > 0) + vfsp->currentpos += read; + vfsp->parentpak->filepos = vfsp->startpos+vfsp->currentpos-vfsp->preloadsize; + Sys_UnlockMutex(vfsp->parentpak->mutex); + } + else + read = 0; + + return read; +} +static int QDECL VFSVPK_WriteBytes (struct vfsfile_s *vfs, const void *buffer, int bytestoread) +{ //not supported. + Sys_Error("Cannot write to vpk files\n"); + return 0; +} +static qboolean QDECL VFSVPK_Seek (struct vfsfile_s *vfs, qofs_t pos) +{ + vfsvpk_t *vfsp = (void*)vfs; + if (pos > vfsp->length) + return false; + vfsp->currentpos = pos + vfsp->startpos; + + return true; +} +static qofs_t QDECL VFSVPK_Tell (struct vfsfile_s *vfs) +{ + vfsvpk_t *vfsp = (void*)vfs; + return vfsp->currentpos - vfsp->startpos; +} +static qofs_t QDECL VFSVPK_GetLen (struct vfsfile_s *vfs) +{ + vfsvpk_t *vfsp = (void*)vfs; + return vfsp->length; +} +static qboolean QDECL VFSVPK_Close(vfsfile_t *vfs) +{ + vfsvpk_t *vfsp = (void*)vfs; + FSVPK_ClosePath(&vfsp->parentpak->pub); //tell the parent that we don't need it open any more (reference counts) + Z_Free(vfsp); //free ourselves. + return true; +} +static vfsfile_t *QDECL FSVPK_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) +{ + vpk_t *pack = (void*)handle; + vfsvpk_t *vfs; + mvpkfile_t *f = loc->fhandle; + unsigned int frag; + + if (strcmp(mode, "rb")) + return NULL; //urm, unable to write/append + + frag = (f->file->archiveindex[0]<<0)|(f->file->archiveindex[1]<<8); + if (frag >= pack->numfragments || !pack->fragments[frag]) + return NULL; + pack = pack->fragments[frag]; + + vfs = Z_Malloc(sizeof(vfsvpk_t)); + + vfs->parentpak = pack; + if (!Sys_LockMutex(pack->mutex)) + { + Z_Free(vfs); + return NULL; + } + vfs->parentpak->references++; + Sys_UnlockMutex(pack->mutex); + + vfs->preloaddata = (const qbyte*)f->file + sizeof(*f->file); + vfs->preloadsize = (f->file->preloadsize[0]<<0) | (f->file->preloadsize[1]<<8); + + vfs->startpos = (f->file->archiveoffset[0]<<0)|(f->file->archiveoffset[1]<<8)|(f->file->archiveoffset[2]<<16)|(f->file->archiveoffset[3]<<24); + vfs->length = loc->len; + vfs->currentpos = 0; + +#ifdef _DEBUG + { + mpackfile_t *pf = loc->fhandle; + Q_strncpyz(vfs->funcs.dbgname, pf->name, sizeof(vfs->funcs.dbgname)); + } +#endif + vfs->funcs.Close = VFSVPK_Close; + vfs->funcs.GetLen = VFSVPK_GetLen; + vfs->funcs.ReadBytes = VFSVPK_ReadBytes; + vfs->funcs.Seek = VFSVPK_Seek; + vfs->funcs.Tell = VFSVPK_Tell; + vfs->funcs.WriteBytes = VFSVPK_WriteBytes; //not supported + + return (vfsfile_t *)vfs; +} + +static void QDECL FSVPK_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer) +{ + vfsfile_t *f; + f = FSVPK_OpenVFS(handle, loc, "rb"); + if (!f) //err... + return; + VFS_READ(f, buffer, loc->len); + VFS_CLOSE(f); +} + +static unsigned int FSVPK_WalkTree(vpk_t *vpk, const char *start, const char *end) +{ //the weird arrangement of these files is presumably an indicator of how source handles its file types. + const char *ext, *path, *name; + const dvpkfile_t *file; + size_t preloadsize; + unsigned int files = 0; + while(start < end) + { //extensions + ext = start; + if (!*ext) + { + start++; + break; + } + if (ext[0] == ' ' && !ext[1]) + ext = ""; + start += strlen(start)+1; + while(start < end) + { //paths + path = start; + if (!*path) + { + start++; + break; + } + if (path[0] == ' ' && !path[1]) + path = ""; + start += strlen(start)+1; + while(start < end) + { //names + name = start; + if (!*name) + { + start++; + break; + } + if (name[0] == ' ' && !name[1]) + name = ""; + start += strlen(start)+1; + + file = (const dvpkfile_t*)start; + preloadsize = (file->preloadsize[0]<<0) | (file->preloadsize[1]<<8); + start += sizeof(*file)+preloadsize; + if (start > end) + return 0; //truncated... + if (file->sentinal[0] != 0xff || file->sentinal[1] != 0xff) + return 0; //sentinal failure +// Con_Printf("Found file %s%s%s%s%s\n", path, *path?"/":"", name, *ext?".":"", ext); + if (!vpk) + files++; + else if (files < vpk->numfiles) + { + unsigned int frag = (file->archiveindex[0]<<0)|(file->archiveindex[1]<<8); + Q_snprintfz(vpk->files[files].name, sizeof(vpk->files[files].name), "%s%s%s%s%s", path, *path?"/":"", name, *ext?".":"", ext); + COM_CleanUpPath(vpk->files[files].name); //just in case... + vpk->files[files].file = file; + + if (vpk->numfragments < frag+1) + vpk->numfragments = frag+1; + files++; + } + } + } + } + return files; +} + +/* +================= +COM_LoadPackFile + +Takes an explicit (not game tree related) path to a pak file. + +Loads the header and directory, adding the files at the beginning +of the list so they override previous pack files. +================= +*/ +searchpathfuncs_t *QDECL FSVPK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) +{ + dvpkheader_t header; + int i; + int numpackfiles; + vpk_t *vpk, *f; + vfsfile_t *packhandle; + int read; + qbyte *tree; + unsigned int frag; + + packhandle = file; + if (packhandle == NULL) + return NULL; + + if (prefix && *prefix) + return NULL; //not supported at this time + + read = VFS_READ(packhandle, &header, sizeof(header)); + header.magic = LittleLong(header.magic); + header.version = LittleLong(header.version); + header.tablesize = LittleLong(header.tablesize); + + header.filedatasize = LittleLong(header.filedatasize); + header.archivemd5size = LittleLong(header.archivemd5size); + header.globalmd5size = LittleLong(header.globalmd5size); + header.signaturesize = LittleLong(header.signaturesize); + + if (read < 12 || header.magic != 0x55aa1234 || header.tablesize <= 0) + { //this will include the non-dir files too. +// Con_Printf("%s is not a vpk\n", desc); + return NULL; + } + i = LittleLong(header.version); + if (i == 2) + ;//VFS_SEEK(packhandle, 7*sizeof(int)); +// else if (i == 1) +// VFS_SEEK(packhandle, 3*sizeof(int)); + else + { + Con_Printf("vpk %s is version %x (unspported)\n", desc, i); + return NULL; + } + + tree = BZ_Malloc(header.tablesize); + read = VFS_READ(packhandle, tree, header.tablesize); + + numpackfiles = FSVPK_WalkTree(NULL, tree, tree+read); + + vpk = (vpk_t*)Z_Malloc (sizeof (*vpk) + sizeof(*vpk->files)*(numpackfiles-1)); + vpk->treedata = tree; + vpk->treesize = read; + vpk->numfiles = numpackfiles; + vpk->numfragments = 0; + vpk->numfiles = FSVPK_WalkTree(vpk, tree, tree+read); + + strcpy (vpk->descname, desc); + vpk->handle = packhandle; + vpk->filepos = 0; + VFS_SEEK(packhandle, vpk->filepos); + + vpk->references++; + + vpk->mutex = Sys_CreateMutex(); + + Con_TPrintf ("Added vpkfile %s (%i files)\n", desc, numpackfiles); + + vpk->pub.fsver = FSVER; + vpk->pub.GetPathDetails = FSVPK_GetPathDetails; + vpk->pub.ClosePath = FSVPK_ClosePath; + vpk->pub.BuildHash = FSVPK_BuildHash; + vpk->pub.FindFile = FSVPK_FLocate; + vpk->pub.ReadFile = FSVPK_ReadFile; + vpk->pub.EnumerateFiles = FSVPK_EnumerateFiles; + vpk->pub.GeneratePureCRC = FSVPK_GeneratePureCRC; + vpk->pub.OpenVFS = FSVPK_OpenVFS; + + vpk->fragments = Z_Malloc(vpk->numfragments*sizeof(*vpk->fragments)); + for(frag = 0; frag < vpk->numfragments; frag++) + { + flocation_t loc; + char fragname[MAX_OSPATH], *ext; + Q_strncpyz(fragname, filename, sizeof(fragname)); + ext = strrchr(fragname, '.'); + if (!ext) + ext = fragname + strlen(fragname); + if (ext-fragname>4 && !strncmp(ext-4, "_dir", 4)) + ext-=4; + Q_snprintfz(ext, sizeof(fragname)-(ext-fragname), "_%03u.vpk", frag); + if (parent->FindFile(parent, &loc, fragname, NULL) != FF_FOUND) + continue; + packhandle = parent->OpenVFS(parent, &loc, "rb"); + if (!packhandle) + continue; + + vpk->fragments[frag] = f = (vpk_t*)Z_Malloc(sizeof(*f)); +// Q_strncpyz(f->descname, splitname, sizeof(f->descname)); + f->handle = packhandle; +// f->rawsize = VFS_GETLEN(f->raw); + f->references = 1; + f->mutex = Sys_CreateMutex(); + f->pub.ClosePath = FSVPK_ClosePath; + } + return &vpk->pub; +} +#endif diff --git a/engine/common/plugin.c b/engine/common/plugin.c index f4bc64988..163512717 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -75,7 +75,7 @@ typedef struct plugin_s { struct plugin_s *next; } plugin_t; -int Plug_SubConsoleCommand(console_t *con, char *line); +int Plug_SubConsoleCommand(console_t *con, const char *line); plugin_t *currentplug; @@ -1826,7 +1826,7 @@ qboolean Plug_ConsoleLink(char *text, char *info, const char *consolename) return result; } -int Plug_SubConsoleCommand(console_t *con, char *line) +int Plug_SubConsoleCommand(console_t *con, const char *line) { int ret; char buffer[2048]; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 47df20dc9..fd7a68d85 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -2318,7 +2318,7 @@ static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, const char *msg } } -static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *msg, size_t len) +static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *buf, size_t len) { if (fnum < 0 || fnum >= MAX_QC_FILES) { @@ -2347,7 +2347,7 @@ static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *msg, size_ if (pf_fopen_files[fnum].ofs + len > pf_fopen_files[fnum].len) len = pf_fopen_files[fnum].len - pf_fopen_files[fnum].ofs; - memcpy(msg, pf_fopen_files[fnum].data + pf_fopen_files[fnum].ofs, len); + memcpy(buf, pf_fopen_files[fnum].data + pf_fopen_files[fnum].ofs, len); pf_fopen_files[fnum].ofs+=len; return len; } @@ -2380,7 +2380,7 @@ void QCBUILTIN PF_fread (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX; int ptr = G_INT(OFS_PARM1); int size = G_INT(OFS_PARM2); - if (ptr < 0 || size < 0 || ptr+size >= prinst->stringtablesize) + if (ptr <= 0 || size < 0 || (unsigned)ptr+(unsigned)size >= (unsigned)prinst->stringtablesize) { PR_BIError(prinst, "PF_fread: invalid ptr / size\n"); return; @@ -3391,7 +3391,7 @@ void QCBUILTIN PF_chr2str (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa void QCBUILTIN PF_str2chr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int err; - char *next; + const char *next; const char *instr = PR_GetStringOfs(prinst, OFS_PARM0); int ofs = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):0; @@ -6306,14 +6306,14 @@ void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s * { wedict_t*e = G_WEDICT(prinst, OFS_PARM0); float *force = G_VECTOR(OFS_PARM1); - float *relative_ofs = G_VECTOR(OFS_PARM2); + float *impactpos = G_VECTOR(OFS_PARM2); //world coord of impact. world_t *world = prinst->parms->user; rbecommandqueue_t cmd; cmd.command = RBECMD_FORCE; cmd.edict = e; VectorCopy(force, cmd.v1); - VectorCopy(relative_ofs, cmd.v2); + VectorCopy(impactpos, cmd.v2); if (world->rbe) world->rbe->PushCommand(world, &cmd); diff --git a/engine/common/sys.h b/engine/common/sys.h index 8f9052c69..b15b7f7c2 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -80,7 +80,7 @@ typedef enum CBT_CLIPBOARD //ctrl+c, ctrl+v } clipboardtype_t; void Sys_Clipboard_PasteText(clipboardtype_t clipboardtype, void (*callback)(void *cb, char *utf8), void *ctx); //calls the callback once the text is available (maybe instantly). utf8 arg may be NULL if the clipboard was unavailable. -void Sys_SaveClipboard(clipboardtype_t clipboardtype, char *text); //a stub would do nothing. +void Sys_SaveClipboard(clipboardtype_t clipboardtype, const char *text); //a stub would do nothing. //stuff for dynamic dedicated console -> gfx and back. void Sys_CloseTerminal (void); diff --git a/engine/common/world.h b/engine/common/world.h index 3a48dfddf..7ae9b73b8 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -194,7 +194,7 @@ typedef struct void (QDECL *RunFrame)(struct world_s *world, double frametime, double gravity); void (QDECL *PushCommand)(struct world_s *world, rbecommandqueue_t *cmd); // void (QDECL *ExpandBodyAABB)(struct world_s *world, rbebody_t *bodyptr, float *mins, float *maxs); //expands an aabb to include the size of the body. -// void (QDECL *Trace) (); + void (QDECL *Trace) (struct world_s *world, wedict_t *ed, vec3_t start, vec3_t end, trace_t *trace); } rigidbodyengine_t; #endif diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index db88b95d5..c66992c9a 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -1908,7 +1908,7 @@ static void deformgen(const deformv_t *deformv, int cnt, vecV_t *src, vecV_t *ds } -static void BE_ApplyUniforms(program_t *prog, int permu) +static void BE_ApplyUniforms(program_t *prog, struct programpermu_s *permu) { ID3D11Buffer *cbuf[3] = { @@ -1917,20 +1917,20 @@ static void BE_ApplyUniforms(program_t *prog, int permu) shaderstate.lcbuffer //light buffer that changes rarelyish }; //FIXME: how many of these calls can we avoid? - ID3D11DeviceContext_IASetInputLayout(d3ddevctx, prog->permu[permu].h.hlsl.layouts[shaderstate.stream_rgbaf]); - ID3D11DeviceContext_VSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.vert, NULL, 0); - ID3D11DeviceContext_HSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.hull, NULL, 0); - ID3D11DeviceContext_DSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.domain, NULL, 0); - ID3D11DeviceContext_GSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.geom, NULL, 0); - ID3D11DeviceContext_PSSetShader(d3ddevctx, prog->permu[permu].h.hlsl.frag, NULL, 0); - ID3D11DeviceContext_IASetPrimitiveTopology(d3ddevctx, prog->permu[permu].h.hlsl.topology); + ID3D11DeviceContext_IASetInputLayout(d3ddevctx, permu->h.hlsl.layouts[shaderstate.stream_rgbaf]); + ID3D11DeviceContext_VSSetShader(d3ddevctx, permu->h.hlsl.vert, NULL, 0); + ID3D11DeviceContext_HSSetShader(d3ddevctx, permu->h.hlsl.hull, NULL, 0); + ID3D11DeviceContext_DSSetShader(d3ddevctx, permu->h.hlsl.domain, NULL, 0); + ID3D11DeviceContext_GSSetShader(d3ddevctx, permu->h.hlsl.geom, NULL, 0); + ID3D11DeviceContext_PSSetShader(d3ddevctx, permu->h.hlsl.frag, NULL, 0); + ID3D11DeviceContext_IASetPrimitiveTopology(d3ddevctx, permu->h.hlsl.topology); ID3D11DeviceContext_VSSetConstantBuffers(d3ddevctx, 0, 3, cbuf); - if (prog->permu[permu].h.hlsl.hull) + if (permu->h.hlsl.hull) ID3D11DeviceContext_HSSetConstantBuffers(d3ddevctx, 0, 3, cbuf); - if (prog->permu[permu].h.hlsl.domain) + if (permu->h.hlsl.domain) ID3D11DeviceContext_DSSetConstantBuffers(d3ddevctx, 0, 3, cbuf); - if (prog->permu[permu].h.hlsl.geom) + if (permu->h.hlsl.geom) ID3D11DeviceContext_GSSetConstantBuffers(d3ddevctx, 0, 3, cbuf); ID3D11DeviceContext_PSSetConstantBuffers(d3ddevctx, 0, 3, cbuf); } @@ -1940,18 +1940,29 @@ static void BE_RenderMeshProgram(program_t *p, shaderpass_t *pass, unsigned int int passno; int perm = 0; - if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) + struct programpermu_s *pp; + + if (TEXLOADED(shaderstate.curtexnums->bump)) perm |= PERMUTATION_BUMPMAP; - if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->fullbright)) perm |= PERMUTATION_FULLBRIGHT; - if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) + if ((TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) perm |= PERMUTATION_UPPERLOWER; - if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].h.loaded) + if (r_refdef.globalfog.density) perm |= PERMUTATION_FOG; -// if (r_glsl_offsetmapping.ival && TEXLOADED(shaderstate.curtexnums->bump) && p->handle[perm|PERMUTATION_OFFSET.hlsl.vert) +// if (r_glsl_offsetmapping.ival && TEXLOADED(shaderstate.curtexnums->bump)) // perm |= PERMUTATION_OFFSET; - BE_ApplyUniforms(p, perm); + perm &= p->supportedpermutations; + pp = p->permu[perm]; + if (!pp) + { + pp = Shader_LoadPermutation(p, perm); + if (!pp) + pp = p->permu[perm=0]; + } + + BE_ApplyUniforms(p, pp); D3D11BE_ApplyShaderBits(pass->shaderbits, &pass->becache); @@ -3622,7 +3633,7 @@ void D3D11BE_RenderShadowBuffer(unsigned int numverts, void *vbuf, unsigned int ID3D11DeviceContext_IASetVertexBuffers(d3ddevctx, 0, 1, vbufs, vstrides, voffsets); ID3D11DeviceContext_IASetIndexBuffer(d3ddevctx, ibuf, DXGI_FORMAT_INDEX_UINT, 0); - BE_ApplyUniforms(shaderstate.depthonly->prog, 0); + BE_ApplyUniforms(shaderstate.depthonly->prog, shaderstate.depthonly->prog->permu[0]); ID3D11DeviceContext_DrawIndexed(d3ddevctx, numindicies, 0, 0); } diff --git a/engine/d3d/d3d11_shader.c b/engine/d3d/d3d11_shader.c index 9af39fc56..1f8bf4585 100644 --- a/engine/d3d/d3d11_shader.c +++ b/engine/d3d/d3d11_shader.c @@ -211,17 +211,21 @@ void D3D11Shader_DeleteProg(program_t *prog) ID3D11PixelShader *frag; ID3D11VertexShader *vert; unsigned int permu, l; + struct programpermu_s *pp; for (permu = 0; permu < countof(prog->permu); permu++) { - vert = prog->permu[permu].h.hlsl.vert; - frag = prog->permu[permu].h.hlsl.frag; + pp = prog->permu[permu]; + if (!pp) + continue; + vert = pp->h.hlsl.vert; + frag = pp->h.hlsl.frag; if (vert) ID3D11VertexShader_Release(vert); if (frag) ID3D11PixelShader_Release(frag); - for (l = 0; l < countof(prog->permu[permu].h.hlsl.layouts); l++) + for (l = 0; l < countof(pp->h.hlsl.layouts); l++) { - layout = prog->permu[permu].h.hlsl.layouts[l]; + layout = pp->h.hlsl.layouts[l]; if (layout) ID3D11InputLayout_Release(layout); } @@ -229,7 +233,7 @@ void D3D11Shader_DeleteProg(program_t *prog) } //create a program from two blobs. -static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int permu, +static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, struct programpermu_s *permu, void *vblob, size_t vsize, void *hblob, size_t hsize, void *dblob, size_t dsize, @@ -239,25 +243,25 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int int l; qboolean success = true; - if (FAILED(ID3D11Device_CreateVertexShader(pD3DDev11, vblob, vsize, NULL, (ID3D11VertexShader**)&prog->permu[permu].h.hlsl.vert))) + if (FAILED(ID3D11Device_CreateVertexShader(pD3DDev11, vblob, vsize, NULL, (ID3D11VertexShader**)&permu->h.hlsl.vert))) success = false; if (hblob || dblob) { - prog->permu[permu].h.hlsl.topology = D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; - if (FAILED(ID3D11Device_CreateHullShader(pD3DDev11, hblob, hsize, NULL, (ID3D11HullShader**)&prog->permu[permu].h.hlsl.hull))) + permu->h.hlsl.topology = D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; + if (FAILED(ID3D11Device_CreateHullShader(pD3DDev11, hblob, hsize, NULL, (ID3D11HullShader**)&permu->h.hlsl.hull))) success = false; - if (FAILED(ID3D11Device_CreateDomainShader(pD3DDev11, dblob, dsize, NULL, (ID3D11DomainShader**)&prog->permu[permu].h.hlsl.domain))) + if (FAILED(ID3D11Device_CreateDomainShader(pD3DDev11, dblob, dsize, NULL, (ID3D11DomainShader**)&permu->h.hlsl.domain))) success = false; } else - prog->permu[permu].h.hlsl.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + permu->h.hlsl.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - if (gblob && FAILED(ID3D11Device_CreateGeometryShader(pD3DDev11, gblob, gsize, NULL, (ID3D11GeometryShader**)&prog->permu[permu].h.hlsl.geom))) + if (gblob && FAILED(ID3D11Device_CreateGeometryShader(pD3DDev11, gblob, gsize, NULL, (ID3D11GeometryShader**)&permu->h.hlsl.geom))) success = false; - if (FAILED(ID3D11Device_CreatePixelShader(pD3DDev11, fblob, fsize, NULL, (ID3D11PixelShader**)&prog->permu[permu].h.hlsl.frag))) + if (FAILED(ID3D11Device_CreatePixelShader(pD3DDev11, fblob, fsize, NULL, (ID3D11PixelShader**)&permu->h.hlsl.frag))) success = false; for (l = 0; l < 2 && success; l++) @@ -347,7 +351,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int decl[elements].InstanceDataStepRate = 0; elements++; */ - if (FAILED(ID3D11Device_CreateInputLayout(pD3DDev11, decl, elements, vblob, vsize, (ID3D11InputLayout**)&prog->permu[permu].h.hlsl.layouts[l]))) + if (FAILED(ID3D11Device_CreateInputLayout(pD3DDev11, decl, elements, vblob, vsize, (ID3D11InputLayout**)&permu->h.hlsl.layouts[l]))) { Con_Printf("HLSL Shader %s requires unsupported inputs\n", name); success = false; @@ -356,7 +360,7 @@ static qboolean D3D11Shader_CreateShaders(program_t *prog, const char *name, int return success; } -static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile) +static qboolean D3D11Shader_LoadBlob(program_t *prog, unsigned int permu, vfsfile_t *blobfile) { qboolean success; char *vblob, *hblob, *dblob, *gblob, *fblob; @@ -398,7 +402,7 @@ static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned VFS_READ(blobfile, fblob, fsz); - success = D3D11Shader_CreateShaders(prog, name, permu, vblob, vsz, hblob, hsz, dblob, dsz, gblob, gsz, fblob, fsz); + success = D3D11Shader_CreateShaders(prog, prog->name, prog->permu[permu], vblob, vsz, hblob, hsz, dblob, dsz, gblob, gsz, fblob, fsz); Z_Free(vblob); Z_Free(hblob); Z_Free(dblob); @@ -407,7 +411,7 @@ static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned return success; } -qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *hull, const char *domain, const char *geom, const char *frag, qboolean silenterrors, vfsfile_t *blobfile) +qboolean D3D11Shader_CreateProgram (program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *hull, const char *domain, const char *geom, const char *frag, qboolean silenterrors, vfsfile_t *blobfile) { char *vsformat; char *hsformat = NULL; @@ -452,12 +456,12 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned fsformat = "ps_4_0_level_9_1"; } - prog->permu[permu].h.hlsl.vert = NULL; - prog->permu[permu].h.hlsl.frag = NULL; - prog->permu[permu].h.hlsl.hull = NULL; - prog->permu[permu].h.hlsl.domain = NULL; - prog->permu[permu].h.hlsl.geom = NULL; - memset(prog->permu[permu].h.hlsl.layouts, 0, sizeof(prog->permu[permu].h.hlsl.layouts)); + permu->h.hlsl.vert = NULL; + permu->h.hlsl.frag = NULL; + permu->h.hlsl.hull = NULL; + permu->h.hlsl.domain = NULL; + permu->h.hlsl.geom = NULL; + memset(permu->h.hlsl.layouts, 0, sizeof(permu->h.hlsl.layouts)); if (pD3DCompile) { @@ -517,12 +521,12 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned success = true; defines[0].Name = "VERTEX_SHADER"; - if (FAILED(pD3DCompile(vert, strlen(vert), name, defines, &myd3dinclude, "main", vsformat, 0, 0, &vcode, &errors))) + if (FAILED(pD3DCompile(vert, strlen(vert), prog->name, defines, &myd3dinclude, "main", vsformat, 0, 0, &vcode, &errors))) success = false; if (errors && !silenterrors) { char *messages = ID3DBlob_GetBufferPointer(errors); - Con_Printf("vertex shader %s:\n%s", name, messages); + Con_Printf("vertex shader %s:\n%s", prog->name, messages); ID3DBlob_Release(errors); } @@ -533,12 +537,12 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned else { defines[0].Name = "HULL_SHADER"; - if (FAILED(pD3DCompile(hull, strlen(hull), name, defines, &myd3dinclude, "main", hsformat, 0, 0, &hcode, &errors))) + if (FAILED(pD3DCompile(hull, strlen(hull), prog->name, defines, &myd3dinclude, "main", hsformat, 0, 0, &hcode, &errors))) success = false; if (errors && !silenterrors) { char *messages = ID3DBlob_GetBufferPointer(errors); - Con_Printf("hull shader %s:\n%s", name, messages); + Con_Printf("hull shader %s:\n%s", prog->name, messages); ID3DBlob_Release(errors); } } @@ -551,12 +555,12 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned else { defines[0].Name = "DOMAIN_SHADER"; - if (FAILED(pD3DCompile(domain, strlen(domain), name, defines, &myd3dinclude, "main", dsformat, 0, 0, &dcode, &errors))) + if (FAILED(pD3DCompile(domain, strlen(domain), prog->name, defines, &myd3dinclude, "main", dsformat, 0, 0, &dcode, &errors))) success = false; if (errors && !silenterrors) { char *messages = ID3DBlob_GetBufferPointer(errors); - Con_Printf("domain shader %s:\n%s", name, messages); + Con_Printf("domain shader %s:\n%s", prog->name, messages); ID3DBlob_Release(errors); } } @@ -569,24 +573,24 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned else { defines[0].Name = "GEOMETRY_SHADER"; - if (FAILED(pD3DCompile(domain, strlen(domain), name, defines, &myd3dinclude, "main", gsformat, 0, 0, &gcode, &errors))) + if (FAILED(pD3DCompile(domain, strlen(domain), prog->name, defines, &myd3dinclude, "main", gsformat, 0, 0, &gcode, &errors))) success = false; if (errors && !silenterrors) { char *messages = ID3DBlob_GetBufferPointer(errors); - Con_Printf("geometry shader %s:\n%s", name, messages); + Con_Printf("geometry shader %s:\n%s", prog->name, messages); ID3DBlob_Release(errors); } } } defines[0].Name = "FRAGMENT_SHADER"; - if (FAILED(pD3DCompile(frag, strlen(frag), name, defines, &myd3dinclude, "main", fsformat, 0, 0, &fcode, &errors))) + if (FAILED(pD3DCompile(frag, strlen(frag), prog->name, defines, &myd3dinclude, "main", fsformat, 0, 0, &fcode, &errors))) success = false; if (errors && !silenterrors) { char *messages = ID3DBlob_GetBufferPointer(errors); - Con_Printf("fragment shader %s:\n%s", name, messages); + Con_Printf("fragment shader %s:\n%s", prog->name, messages); ID3DBlob_Release(errors); } @@ -597,7 +601,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned } if (success) - success = D3D11Shader_CreateShaders(prog, name, permu, + success = D3D11Shader_CreateShaders(prog, prog->name, permu, ID3DBlob_GetBufferPointer(vcode), ID3DBlob_GetBufferSize(vcode), hcode?ID3DBlob_GetBufferPointer(hcode):NULL, hcode?ID3DBlob_GetBufferSize(hcode):0, dcode?ID3DBlob_GetBufferPointer(dcode):NULL, dcode?ID3DBlob_GetBufferSize(dcode):0, @@ -712,6 +716,7 @@ qboolean D3D11Shader_Init(unsigned int flevel) {NULL,NULL} }; + //FIXME: wine's d3dcompiler dlls don't work properly right now, and winetricks installs ms' only up to 43 (which works, but we loaded 47 instead) for (ver = 47; ver >= 33; ver--) { shaderlib = Sys_LoadLibrary(va("D3dcompiler_%i.dll", ver), (ver>=40)?funcsnew:funcsold); diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 2037d3f55..2ab14947f 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -817,6 +817,9 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) { int last; extern texid_t missing_texture; + extern texid_t missing_texture_gloss; + extern texid_t missing_texture_normal; + extern texid_t r_blackimage; switch(pass->texgen) { @@ -828,25 +831,46 @@ static void SelectPassTexture(unsigned int tu, shaderpass_t *pass) BindTexture(tu, missing_texture); break; case T_GEN_NORMALMAP: - BindTexture( tu, shaderstate.curtexnums->bump); + if (TEXLOADED(shaderstate.curtexnums->bump)) + BindTexture(tu, shaderstate.curtexnums->bump); + else + BindTexture(tu, missing_texture_normal); break; case T_GEN_SPECULAR: - BindTexture(tu, shaderstate.curtexnums->specular); + if (TEXLOADED(shaderstate.curtexnums->specular)) + BindTexture(tu, shaderstate.curtexnums->specular); + else + BindTexture(tu, missing_texture_gloss); break; case T_GEN_UPPEROVERLAY: - BindTexture(tu, shaderstate.curtexnums->upperoverlay); + if (TEXLOADED(shaderstate.curtexnums->upperoverlay)) + BindTexture(tu, shaderstate.curtexnums->upperoverlay); + else + BindTexture(tu, r_blackimage); break; case T_GEN_LOWEROVERLAY: - BindTexture(tu, shaderstate.curtexnums->loweroverlay); + if (TEXLOADED(shaderstate.curtexnums->loweroverlay)) + BindTexture(tu, shaderstate.curtexnums->loweroverlay); + else + BindTexture(tu, r_blackimage); break; case T_GEN_FULLBRIGHT: - BindTexture(tu, shaderstate.curtexnums->fullbright); + if (TEXLOADED(shaderstate.curtexnums->fullbright)) + BindTexture(tu, shaderstate.curtexnums->fullbright); + else + BindTexture(tu, r_blackimage); break; case T_GEN_REFLECTCUBE: - BindTexture(tu, shaderstate.curtexnums->reflectcube); + if (TEXLOADED(shaderstate.curtexnums->reflectcube)) + BindTexture(tu, shaderstate.curtexnums->reflectcube); + else + BindTexture(tu, r_whiteimage); break; case T_GEN_REFLECTMASK: - BindTexture(tu, shaderstate.curtexnums->reflectmask); + if (TEXLOADED(shaderstate.curtexnums->reflectmask)) + BindTexture(tu, shaderstate.curtexnums->reflectmask); + else + BindTexture(tu, r_whiteimage); break; case T_GEN_ANIMMAP: BindTexture(tu, pass->anim_frames[(int)(pass->anim_fps * shaderstate.curtime) % pass->anim_numframes]); @@ -1902,9 +1926,8 @@ static void R_FetchPlayerColour(unsigned int cv, vec3_t rgb) *retblue = gammatable[*retblue]; }*/ } -static void BE_ApplyUniforms(program_t *prog, int permu) +static void BE_ApplyUniforms(program_t *prog, struct programpermu_s *perm) { - struct programpermu_s *perm = &prog->permu[permu]; shaderprogparm_t *pp; vec4_t param4; int h; @@ -2082,23 +2105,21 @@ static unsigned int BE_DrawMeshChain_SetupProgram(program_t *p) { unsigned int vdec = 0; unsigned int perm = 0; + struct programpermu_s *pp; #ifdef SKELETALMODELS if (shaderstate.batchvbo && shaderstate.batchvbo->numbones) - { - if (p->permu[perm|PERMUTATION_SKELETAL].h.loaded) - perm |= PERMUTATION_SKELETAL; - } + perm |= PERMUTATION_SKELETAL; #endif - if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->bump)) perm |= PERMUTATION_BUMPMAP; - if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->fullbright)) perm |= PERMUTATION_FULLBRIGHT; - if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) + if ((TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) perm |= PERMUTATION_UPPERLOWER; - if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].h.loaded) + if (r_refdef.globalfog.density) perm |= PERMUTATION_FOG; #ifdef NONSKELETALMODELS - if (p->permu[perm|PERMUTATION_FRAMEBLEND].h.loaded && shaderstate.batchvbo && shaderstate.batchvbo->coord2.d3d.buff) + if (shaderstate.batchvbo && shaderstate.batchvbo->coord2.d3d.buff) { perm |= PERMUTATION_FRAMEBLEND; vdec |= D3D_VDEC_POS2; @@ -2107,13 +2128,24 @@ static unsigned int BE_DrawMeshChain_SetupProgram(program_t *p) // if (p->permu[perm|PERMUTATION_DELUXE].h.loaded && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) // perm |= PERMUTATION_DELUXE; #if MAXRLIGHTMAPS > 1 - if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded) + if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0) perm |= PERMUTATION_LIGHTSTYLES; #endif vdec |= D3D_VDEC_COL4B;//BE_GenerateColourMods(vertcount, s->passes); - BE_ApplyUniforms(p, perm); + perm &= p->supportedpermutations; + pp = p->permu[perm]; + if (!pp) + { + pp = p->permu[perm] = Shader_LoadPermutation(p, perm); + if (!pp) + pp = p->permu[perm=0]; + } + + if (perm & PERMUTATION_FRAMEBLEND) + vdec |= D3D_VDEC_POS2; + BE_ApplyUniforms(p, pp); return vdec; } @@ -2287,26 +2319,27 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in int perm = 0; program_t *p = s->prog; + struct programpermu_s *pp; #ifdef SKELETALMODELS if (shaderstate.batchvbo && shaderstate.batchvbo->numbones) { - if (p->permu[perm|PERMUTATION_SKELETAL].h.loaded) + if (p->supportedpermutations & PERMUTATION_SKELETAL) perm |= PERMUTATION_SKELETAL; else return; } #endif - if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->bump)) perm |= PERMUTATION_BUMPMAP; - if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) + if (TEXLOADED(shaderstate.curtexnums->fullbright)) perm |= PERMUTATION_FULLBRIGHT; - if (p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded && (TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) + if ((TEXLOADED(shaderstate.curtexnums->upperoverlay) || TEXLOADED(shaderstate.curtexnums->loweroverlay))) perm |= PERMUTATION_UPPERLOWER; - if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].h.loaded) + if (r_refdef.globalfog.density) perm |= PERMUTATION_FOG; #ifdef NONSKELETALMODELS - if (p->permu[perm|PERMUTATION_FRAMEBLEND].h.loaded && shaderstate.batchvbo && shaderstate.batchvbo->coord2.d3d.buff) + if (shaderstate.batchvbo && shaderstate.batchvbo->coord2.d3d.buff) { perm |= PERMUTATION_FRAMEBLEND; vdec |= D3D_VDEC_POS2; @@ -2315,13 +2348,24 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertbase, unsigned in // if (p->permu[perm|PERMUTATION_DELUXE].h.loaded && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) // perm |= PERMUTATION_DELUXE; #if MAXRLIGHTMAPS > 1 - if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded) + if (shaderstate.curbatch && shaderstate.curbatch->lightmap[1] >= 0) perm |= PERMUTATION_LIGHTSTYLES; #endif vdec |= D3D_VDEC_COL4B;//BE_GenerateColourMods(vertcount, s->passes); - BE_ApplyUniforms(p, perm); + perm &= p->supportedpermutations; + pp = p->permu[perm]; + if (!pp) + { + pp = Shader_LoadPermutation(p, perm); + if (!pp) + pp = p->permu[perm=0]; + } + + if (perm & PERMUTATION_FRAMEBLEND) + vdec |= D3D_VDEC_POS2; + BE_ApplyUniforms(p, pp); BE_ApplyShaderBits(s->passes->shaderbits); diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index 919cb8c77..01226fb31 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -256,7 +256,7 @@ static struct myID3DXIncludeVtbl myID3DXIncludeVtbl_C = }; static struct myID3DXInclude myID3DXIncludeVtbl_Instance = {&myID3DXIncludeVtbl_C}; -static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile) +static qboolean D3D9Shader_CreateProgram (program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile) { D3DXMACRO defines[64]; @@ -267,12 +267,12 @@ static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, un if (geom || tcs || tes) { - Con_Printf("geometry and tessellation shaders are not availale in d3d9 (%s)\n", sname); + Con_Printf("geometry and tessellation shaders are not availale in d3d9 (%s)\n", prog->name); return false; } - prog->permu[permu].h.hlsl.vert = NULL; - prog->permu[permu].h.hlsl.frag = NULL; + permu->h.hlsl.vert = NULL; + permu->h.hlsl.frag = NULL; if (pD3DXCompileShader) { @@ -325,32 +325,36 @@ static qboolean D3D9Shader_CreateProgram (program_t *prog, const char *sname, un success = true; defines[0].Name = "VERTEX_SHADER"; - if (FAILED(pD3DXCompileShader(vert, strlen(vert), defines, &myID3DXIncludeVtbl_Instance, "main", "vs_2_0", 0, &code, &errors, (LPD3DXCONSTANTTABLE*)&prog->permu[permu].h.hlsl.ctabv))) + if (FAILED(pD3DXCompileShader(vert, strlen(vert), defines, &myID3DXIncludeVtbl_Instance, "main", "vs_2_0", 0, &code, &errors, (LPD3DXCONSTANTTABLE*)&permu->h.hlsl.ctabv))) success = false; else { - IDirect3DDevice9_CreateVertexShader(pD3DDev9, code->lpVtbl->GetBufferPointer(code), (IDirect3DVertexShader9**)&prog->permu[permu].h.hlsl.vert); + IDirect3DDevice9_CreateVertexShader(pD3DDev9, code->lpVtbl->GetBufferPointer(code), (IDirect3DVertexShader9**)&permu->h.hlsl.vert); code->lpVtbl->Release(code); } if (errors) { char *messages = errors->lpVtbl->GetBufferPointer(errors); - Con_Printf("Error compiling vertex shader %s:\n%s", sname, messages); + //int i; + // for (i = 0; i < consts; i++) + // Con_Printf("%s %i: %s==%s\n", prog->name, i, defines[i].Name, defines[i].Definition); +// Con_Printf("%s\n", vert); + Con_Printf("Error compiling vertex shader %s:\n%s", prog->name, messages); errors->lpVtbl->Release(errors); } defines[0].Name = "FRAGMENT_SHADER"; - if (FAILED(pD3DXCompileShader(frag, strlen(frag), defines, &myID3DXIncludeVtbl_Instance, "main", "ps_2_0", 0, &code, &errors, (LPD3DXCONSTANTTABLE*)&prog->permu[permu].h.hlsl.ctabf))) + if (FAILED(pD3DXCompileShader(frag, strlen(frag), defines, &myID3DXIncludeVtbl_Instance, "main", "ps_2_0", 0, &code, &errors, (LPD3DXCONSTANTTABLE*)&permu->h.hlsl.ctabf))) success = false; else { - IDirect3DDevice9_CreatePixelShader(pD3DDev9, code->lpVtbl->GetBufferPointer(code), (IDirect3DPixelShader9**)&prog->permu[permu].h.hlsl.frag); + IDirect3DDevice9_CreatePixelShader(pD3DDev9, code->lpVtbl->GetBufferPointer(code), (IDirect3DPixelShader9**)&permu->h.hlsl.frag); code->lpVtbl->Release(code); } if (errors) { char *messages = errors->lpVtbl->GetBufferPointer(errors); - Con_Printf("Error compiling pixel shader %s:\n%s", sname, messages); + Con_Printf("Error compiling pixel shader %s:\n%s", prog->name, messages); errors->lpVtbl->Release(errors); } } @@ -389,134 +393,117 @@ static int D3D9Shader_FindUniform(union programhandle_u *h, int type, const char return -1; } -static void D3D9Shader_ProgAutoFields(program_t *prog, const char *progname, cvar_t **cvarrefs, char **cvarnames, int *cvartypes) +static void D3D9Shader_ProgAutoFields(program_t *prog, struct programpermu_s *pp, cvar_t **cvarrefs, char **cvarnames, int *cvartypes) { - struct programpermu_s *pp; - unsigned int i, p; + unsigned int i; int uniformloc; char tmpbuffer[256]; #define ALTLIGHTMAPSAMP 13 #define ALTDELUXMAPSAMP 16 - prog->nofixedcompat = true; +/* prog->nofixedcompat = true; prog->defaulttextures = 0; prog->numsamplers = 0; +*/ + int maxparms = 0; + pp->parm = NULL; + pp->numparms = 0; + IDirect3DDevice9_SetVertexShader(pD3DDev9, pp->h.hlsl.vert); + IDirect3DDevice9_SetPixelShader(pD3DDev9, pp->h.hlsl.frag); - for (p = 0; p < PERMUTATIONS; p++) + for (i = 0; shader_unif_names[i].name; i++) { - int maxparms = 0; - pp = &prog->permu[p]; - pp->parm = NULL; - pp->numparms = 0; - if (!pp->h.loaded) - continue; - IDirect3DDevice9_SetVertexShader(pD3DDev9, pp->h.hlsl.vert); - IDirect3DDevice9_SetPixelShader(pD3DDev9, pp->h.hlsl.frag); - - for (i = 0; shader_unif_names[i].name; i++) + uniformloc = D3D9Shader_FindUniform(&pp->h, 0, shader_unif_names[i].name); + if (uniformloc != -1) { - uniformloc = D3D9Shader_FindUniform(&pp->h, 0, shader_unif_names[i].name); - if (uniformloc != -1) + if (pp->numparms == maxparms) { - if (pp->numparms == maxparms) - { - maxparms = maxparms?maxparms*2:8; - pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); - } - pp->parm[pp->numparms].handle = uniformloc; - pp->parm[pp->numparms].type = shader_unif_names[i].ptype; - pp->numparms++; + maxparms = maxparms?maxparms*2:8; + pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); } - } - - for (i = 0; cvarnames[i]; i++) - { - if (!cvarrefs[i]) - continue; - //just directly sets uniforms. can't cope with cvars dynamically changing. - cvarrefs[i]->flags |= CVAR_SHADERSYSTEM; - - Q_snprintfz(tmpbuffer, sizeof(tmpbuffer), "cvar_%s", cvarnames[i]); - uniformloc = D3D9Shader_FindUniform(&prog->permu[p].h, 1, tmpbuffer); - if (uniformloc != -1) - { - if (cvartypes[i] == SP_CVARI) - { - int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; - IDirect3DDevice9_SetVertexShaderConstantI(pD3DDev9, 0, v, 1); - } - else - IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); - } - uniformloc = D3D9Shader_FindUniform(&prog->permu[p].h, 2, tmpbuffer); - if (uniformloc != -1) - { - if (cvartypes[i] == SP_CVARI) - { - int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; - IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); - } - else - IDirect3DDevice9_SetPixelShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); - } - } - - /*set texture uniforms*/ - for (i = 0; i < 8; i++) - { - Q_snprintfz(tmpbuffer, sizeof(tmpbuffer), "s_t%i", i); - uniformloc = D3D9Shader_FindUniform(&pp->h, 2, tmpbuffer); - if (uniformloc != -1) - { - int v[4] = {i}; - IDirect3DDevice9_SetPixelShader(pD3DDev9, pp->h.hlsl.frag); - IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); - - if (prog->numsamplers < i+1) - prog->numsamplers = i+1; - } - } - - for (i = 0; sh_defaultsamplers[i].name; i++) - { - //figure out which ones are needed. - if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) - continue; //don't spam - uniformloc = D3D9Shader_FindUniform(&pp->h, 2, sh_defaultsamplers[i].name); - if (uniformloc != -1) - prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits; + pp->parm[pp->numparms].handle = uniformloc; + pp->parm[pp->numparms].type = shader_unif_names[i].ptype; + pp->numparms++; } } - //multiple lightmaps is kinda hacky. if any are set, all must be. - if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2)))) - prog->defaulttextures |=((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))); - if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2)))) - prog->defaulttextures |=((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))); + for (i = 0; cvarnames[i]; i++) + { + if (!cvarrefs[i]) + continue; + //just directly sets uniforms. can't cope with cvars dynamically changing. + cvarrefs[i]->flags |= CVAR_SHADERSYSTEM; + + Q_snprintfz(tmpbuffer, sizeof(tmpbuffer), "cvar_%s", cvarnames[i]); + uniformloc = D3D9Shader_FindUniform(&pp->h, 1, tmpbuffer); + if (uniformloc != -1) + { + if (cvartypes[i] == SP_CVARI) + { + int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; + IDirect3DDevice9_SetVertexShaderConstantI(pD3DDev9, 0, v, 1); + } + else + IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); + } + uniformloc = D3D9Shader_FindUniform(&pp->h, 2, tmpbuffer); + if (uniformloc != -1) + { + if (cvartypes[i] == SP_CVARI) + { + int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; + IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); + } + else + IDirect3DDevice9_SetPixelShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); + } + } + + /*set texture uniforms*/ + for (i = 0; i < prog->numsamplers; i++) + { + Q_snprintfz(tmpbuffer, sizeof(tmpbuffer), "s_t%i", i); + uniformloc = D3D9Shader_FindUniform(&pp->h, 2, tmpbuffer); + if (uniformloc != -1) + { + int v[4] = {i}; + IDirect3DDevice9_SetPixelShader(pD3DDev9, pp->h.hlsl.frag); + IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); + +// if (prog->numsamplers < i+1) +// prog->numsamplers = i+1; + } + } + +/* for (i = 0; sh_defaultsamplers[i].name; i++) + { + //figure out which ones are needed. + if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) + continue; //don't spam + uniformloc = D3D9Shader_FindUniform(&pp->h, 2, sh_defaultsamplers[i].name); + if (uniformloc != -1) + prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits; + } +*/ if (prog->defaulttextures) { unsigned int sampnum; /*set default texture uniforms*/ - for (p = 0; p < PERMUTATIONS; p++) + sampnum = prog->numsamplers; + for (i = 0; sh_defaultsamplers[i].name; i++) { - if (!prog->permu[p].h.loaded) - continue; - sampnum = prog->numsamplers; - for (i = 0; sh_defaultsamplers[i].name; i++) + if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) { - if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) + uniformloc = D3D9Shader_FindUniform(&pp->h, 2, sh_defaultsamplers[i].name); + if (uniformloc != -1) { - uniformloc = D3D9Shader_FindUniform(&prog->permu[p].h, 2, sh_defaultsamplers[i].name); - if (uniformloc != -1) - { - int v[4] = {sampnum}; - IDirect3DDevice9_SetPixelShader(pD3DDev9, prog->permu[p].h.hlsl.frag); - IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); - } - sampnum++; + int v[4] = {sampnum}; + IDirect3DDevice9_SetPixelShader(pD3DDev9, pp->h.hlsl.frag); + IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); } + sampnum++; } } } @@ -527,34 +514,38 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, const char *progname, cva void D3D9Shader_DeleteProg(program_t *prog) { unsigned int permu; + struct programpermu_s *pp; for (permu = 0; permu < countof(prog->permu); permu++) { - if (prog->permu[permu].h.hlsl.vert) + pp = prog->permu[permu]; + if (!pp) + continue; + if (pp->h.hlsl.vert) { - IDirect3DVertexShader9 *vs = prog->permu[permu].h.hlsl.vert; - prog->permu[permu].h.hlsl.vert = NULL; + IDirect3DVertexShader9 *vs = pp->h.hlsl.vert; + pp->h.hlsl.vert = NULL; IDirect3DVertexShader9_Release(vs); } - if (prog->permu[permu].h.hlsl.frag) + if (pp->h.hlsl.frag) { - IDirect3DPixelShader9 *fs = prog->permu[permu].h.hlsl.frag; - prog->permu[permu].h.hlsl.frag = NULL; + IDirect3DPixelShader9 *fs = pp->h.hlsl.frag; + pp->h.hlsl.frag = NULL; IDirect3DPixelShader9_Release(fs); } - if (prog->permu[permu].h.hlsl.ctabv) + if (pp->h.hlsl.ctabv) { - LPD3DXCONSTANTTABLE vct = prog->permu[permu].h.hlsl.ctabv; - prog->permu[permu].h.hlsl.ctabv = NULL; + LPD3DXCONSTANTTABLE vct = pp->h.hlsl.ctabv; + pp->h.hlsl.ctabv = NULL; IUnknown_Release(vct); } - if (prog->permu[permu].h.hlsl.ctabf) + if (pp->h.hlsl.ctabf) { - LPD3DXCONSTANTTABLE fct = prog->permu[permu].h.hlsl.ctabf; - prog->permu[permu].h.hlsl.ctabf = NULL; + LPD3DXCONSTANTTABLE fct = pp->h.hlsl.ctabf; + pp->h.hlsl.ctabf = NULL; IUnknown_Release(fct); } - prog->permu[permu].numparms = 0; - BZ_Free(prog->permu[permu].parm); + pp->numparms = 0; + BZ_Free(pp->parm); } } diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a4b6aa6d4..d4efb5d3d 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -675,6 +675,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend { shaderstate.sha_attr &= ~(1u<permu[perm].parm; - for (i = prog->permu[perm].numparms; i > 0; i--, p++) + p = perm->parm; + for (i = perm->numparms; i > 0; i--, p++) { ph = p->handle; switch(p->type) @@ -3472,7 +3473,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, case SP_E_VLSCALE: #if MAXRLIGHTMAPS > 1 - if (perm & PERMUTATION_LIGHTSTYLES) + if (perm->permutation & PERMUTATION_LIGHTSTYLES) { vec4_t colscale[MAXRLIGHTMAPS]; int j, s; @@ -3524,7 +3525,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, break; case SP_E_LMSCALE: #if MAXRLIGHTMAPS > 1 - if (perm & PERMUTATION_LIGHTSTYLES) + if (perm->permutation & PERMUTATION_LIGHTSTYLES) { vec4_t colscale[MAXRLIGHTMAPS]; int j, s; @@ -3777,8 +3778,9 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas int perm; + struct programpermu_s *permu; + perm = 0; -#if 0 if (shaderstate.sourcevbo->numbones) perm |= PERMUTATION_SKELETAL; #ifdef NONSKELETALMODELS @@ -3793,7 +3795,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas perm |= PERMUTATION_UPPERLOWER; if (r_refdef.globalfog.density) perm |= PERMUTATION_FOG; -// if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl.handle && TEXLOADED(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) +// if (TEXLOADED(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) // perm |= PERMUTATION_DELUXE; if ((TEXLOADED(shaderstate.curtexnums->reflectcube) || TEXLOADED(shaderstate.curtexnums->reflectmask))) perm |= PERMUTATION_REFLECTCUBEMASK; @@ -3803,45 +3805,15 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas #endif perm &= p->supportedpermutations; - if (!p->permu[perm].h.loaded) + permu = p->permu[perm]; + if (!permu) { - perm = 0; - if (!p->permu[perm].h.loaded) + p->permu[perm] = permu = Shader_LoadPermutation(p, perm); + if (!permu) return; } -#else - if (shaderstate.sourcevbo->numbones) - { - if (p->permu[perm|PERMUTATION_SKELETAL].h.loaded) - perm |= PERMUTATION_SKELETAL; - else - return; - } - -#ifdef NONSKELETALMODELS - if (p->permu[perm|PERMUTATION_FRAMEBLEND].h.loaded && shaderstate.sourcevbo->coord2.gl.addr) - perm |= PERMUTATION_FRAMEBLEND; -#endif - if (TEXLOADED(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].h.loaded) - perm |= PERMUTATION_BUMPMAP; - if (TEXLOADED(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].h.loaded) - perm |= PERMUTATION_FULLBRIGHT; - if ((TEXLOADED(shaderstate.curtexnums->loweroverlay) || TEXLOADED(shaderstate.curtexnums->upperoverlay)) && p->permu[perm|PERMUTATION_UPPERLOWER].h.loaded) - perm |= PERMUTATION_UPPERLOWER; - if (r_refdef.globalfog.density && p->permu[perm|PERMUTATION_FOG].h.loaded) - perm |= PERMUTATION_FOG; -// if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl.handle && TEXLOADED(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) -// perm |= PERMUTATION_DELUXE; - if ((TEXLOADED(shaderstate.curtexnums->reflectcube) || TEXLOADED(shaderstate.curtexnums->reflectmask)) && p->permu[perm|PERMUTATION_REFLECTCUBEMASK].h.loaded) - perm |= PERMUTATION_REFLECTCUBEMASK; -#if MAXRLIGHTMAPS > 1 - if (shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].h.loaded) - perm |= PERMUTATION_LIGHTSTYLES; -#endif -#endif - - GL_SelectProgram(p->permu[perm].h.glsl.handle); + GL_SelectProgram(permu->h.glsl.handle); #ifndef FORCESTATE if (shaderstate.lastuniform == shaderstate.currentprogram) i = true; @@ -3851,7 +3823,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas i = false; shaderstate.lastuniform = shaderstate.currentprogram; } - BE_Program_Set_Attributes(p, perm, i); + BE_Program_Set_Attributes(p, permu, i); BE_SendPassBlendDepthMask(pass->shaderbits); @@ -3892,8 +3864,8 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); shaderstate.lastpasstmus = i; //in case it was already lower } - BE_EnableShaderAttributes(p->permu[perm].attrmask, shaderstate.sourcevbo->vao); - BE_SubmitMeshChain(p->permu[perm].h.glsl.usetesselation); + BE_EnableShaderAttributes(permu->attrmask, shaderstate.sourcevbo->vao); + BE_SubmitMeshChain(permu->h.glsl.usetesselation); } qboolean GLBE_LightCullModel(vec3_t org, model_t *model) diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index f6fe0eb24..962aa5aeb 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -84,6 +84,7 @@ typedef unsigned int FT_Pixel_Mode; //for consistency even without freetype supp #define FT_PIXEL_MODE_RGBA_SA (100) //RGBA, straight alpha. not in freetype. #define FT_PIXEL_MODE_RGBA (101) //RGBA, premultiplied alpha. not in freetype. +#ifdef QUAKEHUD static const char *imgs[] = { //0xe10X @@ -188,6 +189,7 @@ static const char *imgs[] = "e16e", "e16f" }; +#endif #define FONT_MAXCHARS 0x110000 //as defined by UTF-16, and thus applied to all unicode because UTF-16 is the crappy limited one. #define FONTBLOCKS ((FONT_MAXCHARS+FONTBLOCKSIZE-1)/FONTBLOCKSIZE) @@ -288,7 +290,8 @@ typedef struct font_s //texture/screen pixel sizes. unsigned char bmw; unsigned char bmh; - //unsigned short pad; + unsigned short flags; +#define CHARF_FORCEWHITE (1u<<0) //coloured emoji should not be tinted. //screen offsets. short top; @@ -643,6 +646,7 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT fontplanes.oldestchar = c; fontplanes.newestchar = c; c->nextchar = NULL; + c->flags = 0; c->texplane = fontplanes.activeplane; c->bmx = fontplanes.planerowx+pad; @@ -748,6 +752,8 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT *(unsigned int *)&out[x*4] = BORDERCOLOUR; out += PLANEWIDTH*4; } + + c->flags = CHARF_FORCEWHITE; //private glyph colours } else if ((unsigned int)pixelmode == FT_PIXEL_MODE_RGBA) { //bgra srgb font, already premultiplied @@ -774,6 +780,8 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT *(unsigned int *)&out[x*4] = BORDERCOLOUR; out += PLANEWIDTH*4; } + + c->flags = CHARF_FORCEWHITE; //private glyph colours } fontplanes.planechanged = true; return c; @@ -976,6 +984,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) } #endif +#ifdef QUAKEHUD if (charidx >= 0xe100 && charidx <= 0xe1ff) { qpic_t *wadimg; @@ -1029,6 +1038,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA_SA, img, nw, nh, 64*4); if (c) { + c->flags = CHARF_FORCEWHITE; //private glyph colours c->left = 0; c->top = f->charheight - nh; c->advance = nw; @@ -1036,6 +1046,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) } } } +#endif /*make tab invisible*/ if (charidx == '\t' || charidx == '\n') { @@ -2866,10 +2877,20 @@ int Font_DrawChar(int px, int py, unsigned int charflags, unsigned int codepoint font_coord[v+3][0] = sx; font_coord[v+3][1] = sy+sh; - *(int*)font_forecoloura[v+0] = *(int*)font_forecolour; - *(int*)font_forecoloura[v+1] = *(int*)font_forecolour; - *(int*)font_forecoloura[v+2] = *(int*)font_forecolour; - *(int*)font_forecoloura[v+3] = *(int*)font_forecolour; + if (c->flags&CHARF_FORCEWHITE) + { + *(int*)font_forecoloura[v+0] = + *(int*)font_forecoloura[v+1] = + *(int*)font_forecoloura[v+2] = + *(int*)font_forecoloura[v+3] = 0xffffffff; + } + else + { + *(int*)font_forecoloura[v+0] = + *(int*)font_forecoloura[v+1] = + *(int*)font_forecoloura[v+2] = + *(int*)font_forecoloura[v+3] = *(int*)font_forecolour; + } if (font_colourmask & CON_NONCLEARBG) { diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 422b81a56..b50d8ae21 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -5486,10 +5486,10 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) size_t numindicies = 0; int w, h, lmnum; float scale[2]; +#ifdef RUNTIMELIGHTING lightmapinfo_t *lm; qboolean dorelight = true; -#ifdef RUNTIMELIGHTING //FIXME: lightmaps //if we're enabling lightmaps, make sure all surfaces have known sizes first. //allocate lightmap space for all surfaces, and then rebuild all textures. diff --git a/engine/gl/gl_hlmdl.c b/engine/gl/gl_hlmdl.c index 651009f1a..b6678cef4 100644 --- a/engine/gl/gl_hlmdl.c +++ b/engine/gl/gl_hlmdl.c @@ -269,7 +269,7 @@ qboolean QDECL Mod_LoadHLModel (model_t *mod, void *buffer, size_t fsize) if (header->version != 10) { - Con_Printf(CON_ERROR "Cannot load model %s - unknown version %i\n", mod->name, header->version); + Con_Printf(CON_ERROR "Cannot load halflife model %s - unknown version %i\n", mod->name, header->version); return false; } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 9f8eb62a0..ec97ac2e5 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -4950,7 +4950,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) mod->textures[a]->shader = R_RegisterShader_Lightmap(va("%s#BUMPMODELSPACE", mod->textures[a]->name)); R_BuildDefaultTexnums(NULL, mod->textures[a]->shader, IF_WORLDTEX); - mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (mod->textures[a+mod->numtexinfo]->name); + mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (va("%s#VERTEXLIT", mod->textures[a+mod->numtexinfo]->name)); R_BuildDefaultTexnums(NULL, mod->textures[a+mod->numtexinfo]->shader, IF_WORLDTEX); } } @@ -4961,7 +4961,7 @@ void ModBrush_LoadGLStuff(void *ctx, void *data, size_t a, size_t b) mod->textures[a]->shader = R_RegisterShader_Lightmap(mod->textures[a]->name); R_BuildDefaultTexnums(NULL, mod->textures[a]->shader, IF_WORLDTEX); - mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (mod->textures[a+mod->numtexinfo]->name); + mod->textures[a+mod->numtexinfo]->shader = R_RegisterShader_Vertex (va("%s#VERTEXLIT", mod->textures[a+mod->numtexinfo]->name)); R_BuildDefaultTexnums(NULL, mod->textures[a+mod->numtexinfo]->shader, IF_WORLDTEX); } } diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index a75fa4214..a6ba66bda 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include extern texid_t missing_texture; -texid_t r_whiteimage; +texid_t r_whiteimage, r_blackimage; qboolean shader_reload_needed; static qboolean shader_rescan_needed; static char **saveshaderbody; @@ -189,15 +189,15 @@ skipwhite: return com_token; } -static float Shader_FloatArgument(shader_t *shader, char *arg) +static float Com_FloatArgument(const char *shadername, char *arg, size_t arglen) { - char *var; - int arglen = strlen(arg); + const char *var; //grab an argument instead, otherwise 0 - var = shader->name; + var = shadername; while((var = strchr(var, '#'))) { + var++; if (!strnicmp(var, arg, arglen)) { if (var[arglen] == '=') @@ -209,6 +209,7 @@ static float Shader_FloatArgument(shader_t *shader, char *arg) } return 0; //not present. } +#define Shader_FloatArgument(s,k) (Com_FloatArgument(s->name,k,strlen(k))) @@ -315,7 +316,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) token++; if (*token == '#') - lhs = !!Shader_FloatArgument(shader, token); + lhs = !!Shader_FloatArgument(shader, token+1); else if (!Q_stricmp(token, "lpp")) lhs = r_lightprepass; else if (!Q_stricmp(token, "lightmap")) @@ -495,7 +496,7 @@ static float Shader_ParseFloat(shader_t *shader, char **ptr, float defaultval) { if (token[1] == '#') { - return Shader_FloatArgument(shader, token+1); + return Shader_FloatArgument(shader, token+2); } else { @@ -1121,7 +1122,6 @@ static qboolean Shader_ParseProgramCvar(char *script, cvar_t **cvarrefs, char ** cvarnames[0] = Z_Malloc(script - namestart + 1); memcpy(cvarnames[0], namestart, script - namestart); cvarnames[0][script - namestart] = 0; - cvarnames[1] = NULL; while (*script == ' ' || *script == '\t') script++; @@ -1176,46 +1176,127 @@ const struct sh_defaultsamplers_s sh_defaultsamplers[] = {NULL} }; -/*program text is already loaded, this function parses the 'header' of it to see which permutations it provides, and how many times we need to recompile it*/ +static struct +{ + char *name; + unsigned int bitmask; +} permutations[] = +{ + {"BUMP", PERMUTATION_BUMPMAP}, + {"FULLBRIGHT", PERMUTATION_FULLBRIGHT}, + {"UPPERLOWER", PERMUTATION_UPPERLOWER}, + {"REFLECTCUBEMASK", PERMUTATION_REFLECTCUBEMASK}, + {"SKELETAL", PERMUTATION_SKELETAL}, + {"FOG", PERMUTATION_FOG}, + {"FRAMEBLEND", PERMUTATION_FRAMEBLEND}, + {"LIGHTSTYLED", PERMUTATION_LIGHTSTYLES} +}; +#define MAXMODIFIERS 64 + +void VARGS Q_strlcatfz (char *dest, size_t *offset, size_t size, const char *fmt, ...) LIKEPRINTF(4); +void VARGS Q_strlcatfz (char *dest, size_t *offset, size_t size, const char *fmt, ...) +{ + va_list argptr; + + dest += *offset; + size -= *offset; + + va_start (argptr, fmt); + Q_vsnprintfz(dest, size, fmt, argptr); + va_end (argptr); + *offset += strlen(dest); +} +struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p) +{ + const char *permutationdefines[3]; + struct programpermu_s *pp; + size_t n, pn = 0; + char defines[8192]; + size_t offset; + + extern cvar_t gl_specular, gl_specular_power; + + if (~prog->supportedpermutations & p) + return NULL; //o.O + pp = Z_Malloc(sizeof(*pp)); + pp->permutation = p; + *defines = 0; + offset = 0; + if (p & PERMUTATION_SKELETAL) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define MAX_GPU_BONES %i\n", sh_config.max_gpu_bones); + if (gl_specular.value) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define SPECULAR\n#define SPECULAR_BASE_MUL %f\n#define SPECULAR_BASE_POW %f\n", 1.0*gl_specular.value, max(1,gl_specular_power.value)); + + for (n = 0; n < countof(permutations); n++) + { + if (p & permutations[n].bitmask) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define %s\n", permutations[n].name); + } + if (p & PERMUTATION_UPPERLOWER) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define UPPER\n#define LOWER\n"); + if (p & PERMUTATION_BUMPMAP) + { + if (r_glsl_offsetmapping.ival) + { + Q_strlcatfz(defines, &offset, sizeof(defines), "#define OFFSETMAPPING\n"); + if (r_glsl_offsetmapping_reliefmapping.ival && (p & PERMUTATION_BUMPMAP)) + Q_strlcatfz(defines, &offset, sizeof(defines), "#define RELIEFMAPPING\n"); + } + + if (r_deluxemapping) //fixme: should be per-model really + Q_strlcatfz(defines, &offset, sizeof(defines), "#define DELUXE\n"); + } + permutationdefines[pn++] = defines; + permutationdefines[pn++] = prog->preshade; + permutationdefines[pn++] = NULL; + + if (!sh_config.pCreateProgram(prog, pp, prog->shaderver, permutationdefines, prog->shadertext, prog->tess?prog->shadertext:NULL, prog->tess?prog->shadertext:NULL, prog->geom?prog->shadertext:NULL, prog->shadertext, prog->warned, NULL)) + prog->warned = true; + + //extra loop to validate the programs actually linked properly. + //delaying it like this gives certain threaded drivers a chance to compile them all while we're messing around with other junk + if (sh_config.pValidateProgram && !sh_config.pValidateProgram(prog, pp, prog->warned, NULL)) + prog->warned = true; + + if (sh_config.pProgAutoFields) + { + cvar_t *cvarrefs[64]; + char *cvarnames[64+1]; + int cvartypes[64]; + + unsigned char *cvardata = prog->cvardata; + size_t size = prog->cvardatasize, i; + for (i = 0; i < countof(cvartypes) && size; i++) + { + memcpy(&cvartypes[i], cvardata, sizeof(int)); + cvarnames[i] = cvardata+sizeof(int); + size -= sizeof(int)+strlen(cvarnames[i])+1; + cvardata += sizeof(int)+strlen(cvarnames[i])+1; + cvarrefs[i] = Cvar_FindVar(cvarnames[i]); + } + cvarnames[i] = NULL; //no more + sh_config.pProgAutoFields(prog, pp, cvarrefs, cvarnames, cvartypes); + } + return pp; +} + static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *script, int qrtype, int ver, char *blobfilename) { #if defined(GLQUAKE) || defined(D3DQUAKE) - static struct - { - char *name; - unsigned int bitmask; - } permutations[] = - { - {"#define BUMP\n", PERMUTATION_BUMPMAP}, - {"#define FULLBRIGHT\n", PERMUTATION_FULLBRIGHT}, - {"#define UPPERLOWER\n", PERMUTATION_UPPERLOWER}, - {"#define REFLECTCUBEMASK\n", PERMUTATION_REFLECTCUBEMASK}, - {"#define SKELETAL\n", PERMUTATION_SKELETAL}, - {"#define FOG\n", PERMUTATION_FOG}, - {"#define FRAMEBLEND\n", PERMUTATION_FRAMEBLEND}, - {"#define LIGHTSTYLED\n", PERMUTATION_LIGHTSTYLES} - }; -#define MAXMODIFIERS 64 - const char *permutationdefines[countof(permutations) + MAXMODIFIERS + 1]; +// const char *permutationdefines[countof(permutations) + MAXMODIFIERS + 1]; unsigned int nopermutation = PERMUTATIONS-1; - int nummodifiers = 0; - int p, n, pn; +// int nummodifiers = 0; + int p; char *end; - vfsfile_t *blobfile; - unsigned int permuoffsets[PERMUTATIONS], initoffset=0; - unsigned int blobheaderoffset=0; - qboolean blobadded; - qboolean geom = false; - qboolean tess = false; - qboolean cantess = false; - char maxgpubones[128]; cvar_t *cvarrefs[64]; char *cvarnames[64]; int cvartypes[64]; - int cvarcount = 0; - qboolean onefailed = false; + size_t cvarcount = 0, i; extern cvar_t gl_specular, gl_specular_power; + qboolean cantess; //not forced. + char prescript[8192]; + size_t offset = 0; #endif #ifdef VKQUAKE @@ -1237,8 +1318,15 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (!sh_config.pCreateProgram && !sh_config.pLoadBlob) return false; - cvarnames[cvarcount] = NULL; + if (prog->name) + return false; //o.O + *prescript = 0; + offset = 0; + memset(prog->permu, 0, sizeof(prog->permu)); + prog->name = Z_StrDup(name); + prog->geom = false; + prog->tess = false; prog->nofixedcompat = true; prog->numsamplers = 0; prog->defaulttextures = 0; @@ -1253,52 +1341,94 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip } else if (!strncmp(script, "!!geom", 6)) { - geom = true; + prog->geom = true; script += 6; } else if (!strncmp(script, "!!tess", 6)) { - tess = true; + prog->tess = true; script += 6; } else if (!strncmp(script, "!!samps", 7)) { + com_tokentype_t tt; + qboolean ignore = false; script += 7; - while (*script != '\n' && *script != '\r') + for(;;) { size_t len; int i; - char *start; - while (*script == ' ' || *script == '\t') - script++; - start = script; - while (*script != ' ' && *script != '\t' && *script != '\r' && *script != '\n') - script++; + char *type, *idx, *next; + char *token = com_token; + next = COM_ParseTokenOut(script, "", com_token, sizeof(com_token), &tt); + if (tt == TTP_LINEENDING || tt == TTP_EOF) + break; + script = next; + + if (*token == '=' || *token == '!') + { + len = strlen(token); + if (*token == (Com_FloatArgument(name, token+1, len-1)?'!':'=')) + ignore = true; + continue; + } + else if (ignore) + continue; #ifndef NOLEGACY - if (script-start >= 8 && !strncmp(start, "deluxmap", 8)) + else if (!strncmp(token, "deluxmap", 8)) { //FIXME: remove this some time. - start = va("deluxemap%s",start+8); - len = strlen(start); + token = va("deluxemap%s",token+8); + } +#endif + type = strchr(token, ':'); + idx = strchr(token, '='); + if (type || idx) + { //name:type=idx + if (type) + *type++ = 0; + else + type = "sampler2D"; + if (idx) + { + *idx++ = 0; + i = atoi(idx); + } + else + i = prog->numsamplers; + if (prog->numsamplers < i+1) + prog->numsamplers = i+1; + + //I really want to use layout(binding = %i) here, but its specific to the glsl version (which we don't really know yet) + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define s_%s s_t%u\nuniform %s s_%s;\n", token, i, type, token); } else -#endif - len = script-start; - for (i = 0; sh_defaultsamplers[i].name; i++) { - if (!strncmp(start, sh_defaultsamplers[i].name+2, len) && sh_defaultsamplers[i].name[2+len] == 0) + len = strlen(token); + for (i = 0; sh_defaultsamplers[i].name; i++) { - prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits; - break; + if (!strcmp(token, sh_defaultsamplers[i].name+2)) + { + prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits; + break; + } + } + if (!sh_defaultsamplers[i].name) + { //this path is deprecated. + i = atoi(token); + if (i) + { + if (qrenderer == QR_OPENGL) + { + while (prog->numsamplers < i) + Q_strlcatfz(prescript, &offset, sizeof(prescript), "uniform sampler2D s_t%u;\n", prog->numsamplers++); + } + else if (prog->numsamplers < i) + prog->numsamplers = i; + } + else + Con_Printf("Unknown texture name in %s\n", name); } - } - if (!sh_defaultsamplers[i].name) - { - i = atoi(start); - if (i) - prog->numsamplers = i; - else - Con_Printf("Unknown texture name in %s\n", name); } } } @@ -1350,7 +1480,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip end = script; while ((*end >= 'A' && *end <= 'Z') || (*end >= 'a' && *end <= 'z') || (*end >= '0' && *end <= '9') || *end == '_') end++; - if (nummodifiers < MAXMODIFIERS && end - script < 64) + if (end - script < 64) { cvar_t *var; char namebuf[64]; @@ -1375,20 +1505,20 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (srgb) { if (type == '4') - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div), var->vec4[3]/div)); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div), var->vec4[3]/div); else if (type == '3') - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div))); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), SRGBf(var->vec4[0]/div), SRGBf(var->vec4[1]/div), SRGBf(var->vec4[2]/div)); else - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, SRGBf(var->value/div))); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %g\n", namebuf, SRGBf(var->value/div)); } else { if (type == '4') - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div, var->vec4[3]/div)); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %s(%g,%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec4":"float4"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div, var->vec4[3]/div); else if (type == '3') - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div)); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %s(%g,%g,%g)\n", namebuf, ((qrenderer == QR_OPENGL)?"vec3":"float3"), var->vec4[0]/div, var->vec4[1]/div, var->vec4[2]/div); else - permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, var->value/div)); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define %s %g\n", namebuf, var->value/div); } } } @@ -1396,17 +1526,17 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip } else if (!strncmp(script, "!!cvarf", 7)) { - if (cvarcount+1 != sizeof(cvarnames)/sizeof(cvarnames[0])) + if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVARF); } else if (!strncmp(script, "!!cvari", 7)) { - if (cvarcount+1 != sizeof(cvarnames)/sizeof(cvarnames[0])) + if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVARI); } else if (!strncmp(script, "!!cvarv", 7)) { - if (cvarcount+1 != sizeof(cvarnames)/sizeof(cvarnames[0])) + if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVAR3F); } else if (!strncmp(script, "!!permu", 7)) @@ -1419,7 +1549,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip end++; for (p = 0; p < countof(permutations); p++) { - if (!strncmp(permutations[p].name+8, script, end - script) && permutations[p].name[8+end-script] == '\n') + if (!strncmp(permutations[p].name, script, end - script) && permutations[p].name[end-script] == '\0') { nopermutation &= ~permutations[p].bitmask; break; @@ -1451,7 +1581,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip minver = strtol(script, &script, 0); while (*script == ' ' || *script == '\t') script++; - maxver = strtol(script, NULL, 0); + maxver = strtol(script, NULL, 0); if (!maxver) maxver = minver; @@ -1481,284 +1611,86 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip while (*script && *script != '\n') script++; }; + prog->shadertext = Z_StrDup(script); if (qrenderer == qrtype && ver < 150) - tess = cantess = false; //GL_ARB_tessellation_shader requires glsl 150(gl3.2) (or glessl 3.1). nvidia complains about layouts if you try anyway - - if (sh_config.pLoadBlob && blobfilename && *blobfilename) - blobfile = FS_OpenVFS(blobfilename, "w+b", FS_GAMEONLY); - else - blobfile = NULL; + prog->tess = cantess = false; //GL_ARB_tessellation_shader requires glsl 150(gl3.2) (or glessl 3.1). nvidia complains about layouts if you try anyway if (!r_fog_permutation.ival) nopermutation |= PERMUTATION_BIT_FOG; - - if (blobfile) - { - unsigned int magic; - unsigned int corrupt = false; - char ever[MAX_QPATH]; - char *thisever = version_string(); - corrupt |= VFS_READ(blobfile, &magic, sizeof(magic)) != sizeof(magic); - corrupt |= magic != *(unsigned int*)"FBLB"; - corrupt |= VFS_READ(blobfile, &blobheaderoffset, sizeof(blobheaderoffset)) != sizeof(blobheaderoffset); - corrupt |= VFS_READ(blobfile, ever, sizeof(ever)) != sizeof(ever); - - corrupt |= strcmp(ever, thisever); - //if the magic or header didn't read properly then the file is corrupt - if (corrupt) - { - //close and reopen it without the + flag, to replace it with a new file. - VFS_CLOSE(blobfile); - blobfile = FS_OpenVFS(blobfilename, "wb", FS_GAMEONLY); - - if (blobfile) - { - blobheaderoffset = 0; - VFS_SEEK(blobfile, 0); - magic = *(unsigned int*)"FBLB"; //magic - VFS_WRITE(blobfile, &magic, sizeof(magic)); - VFS_WRITE(blobfile, &blobheaderoffset, sizeof(blobheaderoffset)); - memset(ever, 0, sizeof(ever)); //make sure we don't leak stuff. - Q_strncpyz(ever, thisever, sizeof(ever)); - VFS_WRITE(blobfile, ever, sizeof(ever)); - blobheaderoffset = 0; - } - } - } - blobadded = false; - if (!sh_config.max_gpu_bones) - { - Q_snprintfz(maxgpubones, sizeof(maxgpubones), ""); nopermutation |= PERMUTATION_SKELETAL; - } - else if (qrenderer == QR_OPENGL && sh_config.maxver < 120) //with old versions of glsl (including gles), mat3x4 is not supported, and we have to emulate it with 3*vec4. maybe we should just do that unconditionally, but whatever. - Q_snprintfz(maxgpubones, sizeof(maxgpubones), "#define MAX_GPU_BONES %i\n#define PACKEDBONES\n", sh_config.max_gpu_bones); - else - Q_snprintfz(maxgpubones, sizeof(maxgpubones), "#define MAX_GPU_BONES %i\n", sh_config.max_gpu_bones); - if (gl_specular.value) - { - if (nummodifiers < MAXMODIFIERS) - permutationdefines[nummodifiers++] = Z_StrDup(va("#define SPECULAR\n#define SPECULAR_BASE_MUL %f\n#define SPECULAR_BASE_POW %f\n", 1.0*gl_specular.value, max(1,gl_specular_power.value))); - } + + //multiple lightmaps is kinda hacky. if any are set, all must be. +#define ALTLIGHTMAPSAMP 13 + if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2)))) + prog->defaulttextures |=((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))); +#define ALTDELUXMAPSAMP 16 + if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2)))) + prog->defaulttextures |=((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))); + for (end = strchr(name, '#'); end && *end; ) { - char *start = end+1, *d; + char *start = end+1; end = strchr(start, '#'); if (!end) end = start + strlen(start); if (end-start == 7 && !Q_strncasecmp(start, "usemods", 7)) prog->nofixedcompat = false; - if (nummodifiers < MAXMODIFIERS) + + if (end-start == 4 && !Q_strncasecmp(start, "tess", 4)) + prog->tess |= cantess; + + Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define "); + while (offset < sizeof(prescript) && start < end) { - if (end-start == 4 && !Q_strncasecmp(start, "tess", 4)) - tess |= cantess; - - permutationdefines[nummodifiers] = d = BZ_Malloc(10 + end - start); - memcpy(d, "#define ", 8); - memcpy(d+8, start, end - start); - memcpy(d+8+(end-start), "\n", 2); - - start = strchr(d+8, '='); - if (start) - *start = ' '; - - for (start = d+8; *start; start++) - *start = toupper(*start); - nummodifiers++; - permutationdefines[nummodifiers] = NULL; - } - } - - if (blobfile) - { - unsigned int next; - unsigned int argsz; - char *args, *mp; - const char *mv; - int ml, mi; - unsigned int bloblink = 4; - - //walk through looking for an argset match - while (blobheaderoffset) - { - VFS_SEEK(blobfile, blobheaderoffset); - VFS_READ(blobfile, &next, sizeof(next)); - VFS_READ(blobfile, &argsz, sizeof(argsz)); - args = Z_Malloc(argsz+1); - VFS_READ(blobfile, args, argsz); - args[argsz] = 0; - for (mi = 0, mp = args; mi < nummodifiers; mi++) + if (*start == '=') { - mv = permutationdefines[mi]+8; - ml = strlen(mv); - if (mp+ml > args+argsz) - break; - if (strncmp(mp, mv, ml)) - break; - mp += ml; - } - //this one is a match. - if (mi == nummodifiers && mp == args+argsz) - { - blobheaderoffset = VFS_TELL(blobfile); - VFS_READ(blobfile, permuoffsets, sizeof(permuoffsets)); + start++; + prescript[offset++] = ' '; break; } - - bloblink = blobheaderoffset; - blobheaderoffset = next; - } - - //these arguments have never been seen before. add a new argset. - if (!blobheaderoffset) - { - unsigned int link = 0; - initoffset = VFS_GETLEN(blobfile); - VFS_SEEK(blobfile, initoffset); - VFS_WRITE(blobfile, &link, sizeof(link)); - - for (mi = 0, argsz = 0; mi < nummodifiers; mi++) - { - mv = permutationdefines[mi]+8; - ml = strlen(mv); - argsz += ml; - } - VFS_WRITE(blobfile, &argsz, sizeof(argsz)); - for (mi = 0; mi < nummodifiers; mi++) - { - mv = permutationdefines[mi]+8; - ml = strlen(mv); - VFS_WRITE(blobfile, mv, ml); - } - - //and the offsets come here - blobheaderoffset = VFS_TELL(blobfile); - memset(permuoffsets, 0, sizeof(permuoffsets)); - VFS_WRITE(blobfile, permuoffsets, sizeof(permuoffsets)); - - //now rewrite the link to add us. the value in the file should always be set to 0. - VFS_SEEK(blobfile, bloblink); - VFS_WRITE(blobfile, &initoffset, sizeof(initoffset)); + prescript[offset++] = toupper(*start++); } + while (offset < sizeof(prescript) && start < end) + prescript[offset++] = toupper(*start++); + Q_strlcatfz(prescript, &offset, sizeof(prescript), "\n"); } - prog->tess = tess; - prog->supportedpermutations = ~nopermutation; - for (p = 0; p < PERMUTATIONS; p++) + prog->preshade = Z_StrDup(prescript); + prog->supportedpermutations = (~nopermutation) & (PERMUTATIONS-1); + + if (cvarcount) { - qboolean isprimary; - memset(&prog->permu[p].h, 0, sizeof(prog->permu[p].h)); - if (nopermutation & p) + *prescript = 0; + offset = 0; + for (i = 0; i < cvarcount && offset < sizeof(prescript); i++) { - continue; - } - pn = nummodifiers; - for (n = 0; n < countof(permutations); n++) - { - if (p & permutations[n].bitmask) - permutationdefines[pn++] = permutations[n].name; - } - isprimary = (pn-nummodifiers)==1; - if (p & PERMUTATION_UPPERLOWER) - permutationdefines[pn++] = "#define UPPER\n#define LOWER\n"; - if (p & PERMUTATION_SKELETAL) - permutationdefines[pn++] = maxgpubones; - if (p & PERMUTATION_BUMPMAP) - { - if (r_glsl_offsetmapping.ival) + if (cvarrefs[i]) { - permutationdefines[pn++] = "#define OFFSETMAPPING\n"; - if (r_glsl_offsetmapping_reliefmapping.ival && (p & PERMUTATION_BUMPMAP)) - permutationdefines[pn++] = "#define RELIEFMAPPING\n"; + memcpy(prescript+offset, &cvartypes[i], sizeof(int)); + offset+=4; + Q_strlcatfz(prescript, &offset, sizeof(prescript), "%s", cvarnames[i]); + offset++; } - - if (r_deluxemapping) //fixme: should be per-model really - permutationdefines[pn++] = "#define DELUXE\n"; - } - permutationdefines[pn++] = NULL; - - - if (blobfile && permuoffsets[p]) - { - VFS_SEEK(blobfile, permuoffsets[p]); - if (sh_config.pLoadBlob(prog, name, p, blobfile)) - continue; //blob was loaded from disk, yay. - //otherwise fall through. - } - if (blobfile && !sh_config.pValidateProgram) - { - initoffset = VFS_GETLEN(blobfile); - VFS_SEEK(blobfile, initoffset); - } -#define SILENTPERMUTATIONS (developer.ival?0:PERMUTATION_SKELETAL) - if (!sh_config.pCreateProgram(prog, name, p, ver, permutationdefines, script, tess?script:NULL, tess?script:NULL, geom?script:NULL, script, (p & SILENTPERMUTATIONS)?true:onefailed, sh_config.pValidateProgram?NULL:blobfile)) - { - if (isprimary) - prog->supportedpermutations &= ~p; - if (!(p & SILENTPERMUTATIONS)) - onefailed = true; //don't flag it if skeletal failed. - if (!p) //give up if permutation 0 failed. that one failing is fatal. - break; - } - if (!sh_config.pValidateProgram && blobfile && initoffset != VFS_GETLEN(blobfile)) - { - permuoffsets[p] = initoffset; - blobadded = true; } + prog->cvardata = Z_Malloc(offset); + prog->cvardatasize = offset; + memcpy(prog->cvardata, prescript, prog->cvardatasize); } - while(nummodifiers) - Z_Free((char*)permutationdefines[--nummodifiers]); - - //extra loop to validate the programs actually linked properly. - //delaying it like this gives certain threaded drivers a chance to compile them all while we're messing around with other junk - if (sh_config.pValidateProgram) - for (p = 0; p < PERMUTATIONS; p++) - { - if (nopermutation & p) - continue; - if (blobfile) - { - initoffset = VFS_GETLEN(blobfile); - VFS_SEEK(blobfile, initoffset); - } - if (!sh_config.pValidateProgram(prog, name, p, (p & PERMUTATION_SKELETAL)?true:onefailed, blobfile)) - { - if (!(p & PERMUTATION_SKELETAL)) - { - onefailed = true; //don't flag it if skeletal failed. - continue; - } - if (!p) - break; - } - if (blobfile && initoffset != VFS_GETLEN(blobfile)) - { - permuoffsets[p] = initoffset; - blobadded = true; - } - } - - if (sh_config.pProgAutoFields) - sh_config.pProgAutoFields(prog, name, cvarrefs, cvarnames, cvartypes); while(cvarcount) Z_Free((char*)cvarnames[--cvarcount]); - if (blobfile && blobadded) - { - VFS_SEEK(blobfile, blobheaderoffset); - VFS_WRITE(blobfile, permuoffsets, sizeof(permuoffsets)); - } - if (blobfile) - VFS_CLOSE(blobfile); - - if (p == PERMUTATIONS) - return true; -#endif + //ensure that permutation 0 works correctly as a fallback. + //FIXME: add debug mode to compile all. + prog->permu[0] = Shader_LoadPermutation(prog, 0); + return !!prog->permu[0]; +#else return false; +#endif } + typedef struct sgeneric_s { program_t prog; @@ -1783,6 +1715,10 @@ void Shader_UnloadProg(program_t *prog) if (sh_config.pDeleteProg) sh_config.pDeleteProg(prog); + Z_Free(prog->name); + Z_Free(prog->preshade); + Z_Free(prog->shadertext); + Z_Free(prog); } static void Shader_FlushGenerics(void) @@ -1847,6 +1783,12 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) { sh_config.pDeleteProg(&g->prog); } + Z_Free(g->prog.name); + g->prog.name = NULL; + Z_Free(g->prog.preshade); + g->prog.preshade = NULL; + Z_Free(g->prog.shadertext); + g->prog.shadertext = NULL; if (file) { @@ -1879,17 +1821,6 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) } } -const char *Shader_NameForGeneric(program_t *prog) -{ - sgeneric_t *g; - for (g = sgenerics; g; g = g->next) - { - if (prog == &g->prog) - return g->name; - } - return "INLINE"; -} - program_t *Shader_FindGeneric(char *name, int qrtype) { sgeneric_t *g; @@ -3743,6 +3674,8 @@ qboolean Shader_Init (void) r_whiteimage = r_nulltex; else r_whiteimage = R_LoadTexture("$whiteimage", 4, 4, TF_RGBA32, wibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA); + memset(wibuf, 0, sizeof(wibuf)); + r_blackimage = R_LoadTexture("$blackimage", 4, 4, TF_RGBA32, wibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA); Shader_NeedReload(true); Shader_DoReload(); @@ -6029,7 +5962,7 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname, char *buffer, s type = 3; else type = 0; - alpha = Shader_FloatArgument(s, "#ALPHA"); + alpha = Shader_FloatArgument(s, "ALPHA"); if (alpha) explicitalpha = true; else @@ -6212,12 +6145,12 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args) "}\n" ); } - else if (Shader_FloatArgument(s, "#WARP"))//!strncmp(shortname, "warp/", 5) || !strncmp(shortname, "warp33/", 7) || !strncmp(shortname, "warp66/", 7)) + else if (Shader_FloatArgument(s, "WARP"))//!strncmp(shortname, "warp/", 5) || !strncmp(shortname, "warp33/", 7) || !strncmp(shortname, "warp66/", 7)) { char tmpbuffer[2048]; Shader_DefaultScript(shortname, s, Shader_DefaultBSPWater(s, shortname, tmpbuffer, sizeof(tmpbuffer))); } - else if (Shader_FloatArgument(s, "#ALPHA"))// !strncmp(shortname, "trans/", 6)) + else if (Shader_FloatArgument(s, "ALPHA"))// !strncmp(shortname, "trans/", 6)) { Shader_DefaultScript(shortname, s, "{\n" @@ -6966,7 +6899,7 @@ static char *Shader_DecomposePass(char *o, shaderpass_t *p, qboolean simple) if (p->prog) { - sprintf(o, "program %s\n", Shader_NameForGeneric(p->prog)); + sprintf(o, "program %s\n", p->prog->name); o+=strlen(o); } @@ -7198,7 +7131,7 @@ char *Shader_Decompose(shader_t *s) if (s->prog) { - sprintf(o, "program %s\n", Shader_NameForGeneric(s->prog)); + sprintf(o, "program %s\n", s->prog->name); o+=strlen(o); p = s->passes; diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 8b0ca9bc9..fb7e01f39 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -3713,7 +3713,7 @@ void Sh_CheckSettings(void) #endif #ifdef D3D9QUAKE case QR_DIRECT3D9: - canshadowless = true; +// canshadowless = true; //the code still has a lot of ifdefs, so will crash if you try it in a merged build. //its not really usable in d3d-only builds either, so no great loss. // canstencil = true; @@ -3739,7 +3739,7 @@ void Sh_CheckSettings(void) { //can't even do lighting if (r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival) - Con_Printf("Missing rendering features: realtime lighting is not possible.\n"); + Con_Printf("Missing rendering features: realtime %s lighting is not possible.\n", r_shadow_realtime_world.ival?"world":"dynamic"); r_shadow_realtime_world.ival = 0; r_shadow_realtime_dlight.ival = 0; } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index ccaae6319..81404a46f 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -58,6 +58,7 @@ void (APIENTRY *qglBindFramebufferEXT)(GLenum target, GLuint id); void (APIENTRY *qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint* ids); void (APIENTRY *qglFramebufferTexture2DEXT)(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint textureId, GLint level); FTEPFNGLVERTEXATTRIBPOINTER qglVertexAttribPointer; +FTEPFNGLVERTEXATTRIB4FARBPROC qglVertexAttrib4f; FTEPFNGLGETVERTEXATTRIBIV qglGetVertexAttribiv; FTEPFNGLENABLEVERTEXATTRIBARRAY qglEnableVertexAttribArray; FTEPFNGLDISABLEVERTEXATTRIBARRAY qglDisableVertexAttribArray; @@ -948,6 +949,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglLinkProgramARB = NULL; qglBindAttribLocationARB = NULL; qglGetAttribLocationARB = NULL; + qglVertexAttrib4f = NULL; qglVertexAttribPointer = NULL; qglGetVertexAttribiv = NULL; qglGetVertexAttribPointerv = NULL; @@ -1009,6 +1011,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglUniform2fvARB = (void *)getglext("glUniform2fv"); qglUniform1iARB = (void *)getglext("glUniform1i"); qglUniform1fARB = (void *)getglext("glUniform1f"); + qglVertexAttrib4f = (void *)getglext("glVertexAttrib4f"); qglVertexAttribPointer = (void *)getglext("glVertexAttribPointer"); qglGetVertexAttribiv = (void *)getglext("glGetVertexAttribiv"); qglGetVertexAttribPointerv = (void *)getglext("glGetVertexAttribPointerv"); @@ -1037,6 +1040,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name)) qglLinkProgramARB = (void *)getglext("glLinkProgramARB"); qglBindAttribLocationARB = (void *)getglext("glBindAttribLocationARB"); qglGetAttribLocationARB = (void *)getglext("glGetAttribLocationARB"); + qglVertexAttrib4f = (void *)getglext("glVertexAttrib4fARB"); qglVertexAttribPointer = (void *)getglext("glVertexAttribPointerARB"); qglGetVertexAttribiv = (void *)getglext("glGetVertexAttribivARB"); qglGetVertexAttribPointerv = (void *)getglext("glGetVertexAttribPointervARB"); @@ -1340,7 +1344,7 @@ static const char *glsl_hdrs[] = "#define SPECMUL 1.0\n" "#endif\n" "#define FTE_SPECULAR_MULTIPLIER (SPECULAR_BASE_MUL*float(SPECMUL))\n" -#ifndef NOLEGACY +#if 0//ndef NOLEGACY "uniform sampler2DShadow s_shadowmap;" "uniform samplerCube s_projectionmap;" "uniform sampler2D s_diffuse;" @@ -2118,19 +2122,8 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int } if (prog) - { //for compat with vulkan, that injects samplers... - const char *numberedsamplernames[] = - { - "uniform sampler2D s_t0;\n", - "uniform sampler2D s_t1;\n", - "uniform sampler2D s_t2;\n", - "uniform sampler2D s_t3;\n", - "uniform sampler2D s_t4;\n", - "uniform sampler2D s_t5;\n", - "uniform sampler2D s_t6;\n", - "uniform sampler2D s_t7;\n", - }; -#ifdef NOLEGACY + { //for compat with our vulkan processor, which injects samplers in order to control layouts. +#if 1//def NOLEGACY const char *defaultsamplernames[] = { "uniform sampler2DShadow s_shadowmap;\n", @@ -2160,8 +2153,6 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int GLSlang_GenerateInternal(&glsl, defaultsamplernames[i]); } #endif - for (i = 0; i < prog->numsamplers && i < countof(numberedsamplernames); i++) - GLSlang_GenerateInternal(&glsl, numberedsamplernames[i]); } break; case GL_GEOMETRY_SHADER_ARB: @@ -2210,6 +2201,9 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int "#define varying out\n" ); } + else if (ver < 120) + GLSlang_GenerateInternal(&glsl, "#define PACKEDBONES\n"); + if (gl_config_nofixedfunc) { GLSlang_GenerateInternal(&glsl, @@ -2363,13 +2357,13 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL typedesc = "???"; break; } - Con_Printf("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); + Con_Printf("%s shader (%s) compilation error:\n"CON_ERROR"%s"CON_DEFAULT"----------\n", typedesc, name, str); //if there's no fixed function then failure to compile the default2d shader should be considered fatal. this should help avoid black screens on android. if (gl_config_nofixedfunc && !strcmp(name, "default2d")) Sys_Error("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str); - if (developer.ival) + if (developer.ival>1) { //could use echo console-link I guess (with embedded line numbers). shaders can get quite big though. unsigned int line; char *eol, *start; @@ -2582,11 +2576,13 @@ union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, i return ret; } -qboolean GLSlang_ValidateProgramPermu(program_t *prog, const char *name, unsigned int permu, qboolean noerrors, vfsfile_t *blobfile) +qboolean GLSlang_ValidateProgramPermu(program_t *prog, struct programpermu_s *permu, qboolean noerrors, vfsfile_t *blobfile) { - return GLSlang_ValidateProgram(&prog->permu[permu].h, name, noerrors, blobfile); + if (!permu) + return false; + return GLSlang_ValidateProgram(&permu->h, prog->name, noerrors, blobfile); } -qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile) +qboolean GLSlang_CreateProgramPermu(program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile) { if (!ver) { @@ -2595,19 +2591,19 @@ qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned else { ver = 110; - if (sh_config.maxver>=120 && (permu & PERMUTATION_SKELETAL)) + if (sh_config.maxver>=120 && (permu->permutation & PERMUTATION_SKELETAL)) ver = 120; } } - if ((permu & PERMUTATION_SKELETAL) && gl_config.maxattribs < 10) + if ((permu->permutation & PERMUTATION_SKELETAL) && gl_config.maxattribs < 10) return false; //can happen in gles2 #if MAXRLIGHTMAPS > 1 - if ((permu & PERMUTATION_LIGHTSTYLES) && gl_config.maxattribs < 16) + if ((permu->permutation & PERMUTATION_LIGHTSTYLES) && gl_config.maxattribs < 16) return false; //can happen in gles2 #endif - prog->permu[permu].h = GLSlang_CreateProgram(prog, name, ver, precompilerconstants, vert, tcs, tes, geom, frag, noerrors, blobfile); - if (prog->permu[permu].h.glsl.handle) + permu->h = GLSlang_CreateProgram(prog, prog->name, ver, precompilerconstants, vert, tcs, tes, geom, frag, noerrors, blobfile); + if (permu->h.glsl.handle) return true; return false; } @@ -2622,8 +2618,10 @@ GLint GLSlang_GetUniformLocation (int prog, char *name) return i; } -static qboolean GLSlang_LoadBlob(program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile) +static qboolean GLSlang_LoadBlob(program_t *prog, unsigned int permu, vfsfile_t *blobfile) { + return false; +/* unsigned int fmt; unsigned int length; void *binary; @@ -2647,120 +2645,107 @@ static qboolean GLSlang_LoadBlob(program_t *prog, const char *name, unsigned int memset(&prog->permu[permu].h, 0, sizeof(prog->permu[permu].h)); } return !!success; +*/ } static void GLSlang_DeleteProg(program_t *prog) { unsigned int permu; + struct programpermu_s *pp; for (permu = 0; permu < countof(prog->permu); permu++) { - if (prog->permu[permu].h.loaded) + pp = prog->permu[permu]; + if (pp) { - qglDeleteProgramObject_(prog->permu[permu].h.glsl.handle); - prog->permu[permu].h.glsl.handle = 0; + qglDeleteProgramObject_(pp->h.glsl.handle); + pp->h.glsl.handle = 0; - BZ_Free(prog->permu[permu].parm); - prog->permu[permu].parm = NULL; - prog->permu[permu].numparms = 0; + BZ_Free(pp->parm); + pp->parm = NULL; + pp->numparms = 0; } } } -static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t **cvars, char **cvarnames, int *cvartypes) +static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, cvar_t **cvars, char **cvarnames, int *cvartypes) { -#define ALTLIGHTMAPSAMP 13 -#define ALTDELUXMAPSAMP 16 - - unsigned int i, p; + unsigned int i; int uniformloc; char tmpname[128]; - struct programpermu_s *pp; + int maxparms = 0; //figure out visible attributes - for (p = 0; p < PERMUTATIONS; p++) + GLSlang_UseProgram(pp->h.glsl.handle); + for (i = 0; shader_attr_names[i].name; i++) { - if (!prog->permu[p].h.loaded) - continue; - GLSlang_UseProgram(prog->permu[p].h.glsl.handle); - for (i = 0; shader_attr_names[i].name; i++) + uniformloc = qglGetAttribLocationARB(pp->h.glsl.handle, shader_attr_names[i].name); + if (uniformloc != -1) { - uniformloc = qglGetAttribLocationARB(prog->permu[p].h.glsl.handle, shader_attr_names[i].name); - if (uniformloc != -1) - { - if (shader_attr_names[i].ptype != uniformloc) - Con_Printf("Bad attribute: %s\n", shader_attr_names[i].name); - else - prog->permu[p].attrmask |= 1u<attrmask |= 1u<numsamplers = 0; - prog->defaulttextures = 0; - for (p = 0; p < PERMUTATIONS; p++) + pp->numparms = 0; + pp->parm = NULL; + + for (i = 0; shader_unif_names[i].name; i++) { - int maxparms = 0; - pp = &prog->permu[p]; - if (!pp->h.loaded) + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, shader_unif_names[i].name); + if (uniformloc >= 0) + { + if (pp->numparms >= maxparms) + { + maxparms = pp->numparms?pp->numparms * 2:8; + pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); + } + pp->parm[pp->numparms].type = shader_unif_names[i].ptype; + pp->parm[pp->numparms].handle = uniformloc; + pp->parm[pp->numparms].pval = NULL; + pp->numparms++; + } + } + + /*set cvar uniforms*/ + /*FIXME: enumerate cvars automatically instead*/ + for (i = 0; cvarnames[i]; i++) + { + if (!cvars[i]) continue; - pp->numparms = 0; - pp->parm = NULL; - GLSlang_UseProgram(prog->permu[p].h.glsl.handle); //we'll probably be setting samplers anyway. - for (i = 0; shader_unif_names[i].name; i++) + Q_snprintfz(tmpname, sizeof(tmpname), "cvar_%s", cvarnames[i]); + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); + if (uniformloc >= 0) { - uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, shader_unif_names[i].name); - if (uniformloc >= 0) + if (pp->numparms >= maxparms) { - if (pp->numparms >= maxparms) - { - maxparms = pp->numparms?pp->numparms * 2:8; - pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); - } - pp->parm[pp->numparms].type = shader_unif_names[i].ptype; - pp->parm[pp->numparms].handle = uniformloc; - pp->parm[pp->numparms].pval = NULL; - pp->numparms++; + maxparms = pp->numparms?pp->numparms * 2:8; + pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); } + pp->parm[pp->numparms].type = cvartypes[i]; + pp->parm[pp->numparms].pval = cvars[i]; + pp->parm[pp->numparms].handle = uniformloc; + pp->numparms++; } + } - /*set cvar uniforms*/ - /*FIXME: enumerate cvars automatically instead*/ - for (i = 0; cvarnames[i]; i++) - { - if (!cvars[i]) - continue; - - Q_snprintfz(tmpname, sizeof(tmpname), "cvar_%s", cvarnames[i]); - uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); - if (uniformloc >= 0) - { - if (pp->numparms >= maxparms) - { - maxparms = pp->numparms?pp->numparms * 2:8; - pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); - } - pp->parm[pp->numparms].type = cvartypes[i]; - pp->parm[pp->numparms].pval = cvars[i]; - pp->parm[pp->numparms].handle = uniformloc; - pp->numparms++; - } - } - - //now scan/set texture uniforms - if (!(pp->attrmask & (1u<attrmask |= (1u<attrmask & (1u<attrmask |= (1u<numsamplers; i++) + { + Q_snprintfz(tmpname, sizeof(tmpname), "s_t%i", i); + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); + if (uniformloc != -1) { - Q_snprintfz(tmpname, sizeof(tmpname), "s_t%i", i); - uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); - if (uniformloc != -1) - { - qglUniform1iARB(uniformloc, i); - if (prog->numsamplers < i+1) - prog->numsamplers = i+1; - } + qglUniform1iARB(uniformloc, i); +// if (prog->numsamplers < i+1) +// prog->numsamplers = i+1; } + } + if (developer.ival) for (i = 0; sh_defaultsamplers[i].name; i++) { //figure out which ones are needed. @@ -2768,35 +2753,22 @@ static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t continue; //don't spam uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, sh_defaultsamplers[i].name); if (uniformloc != -1) - prog->defaulttextures |= sh_defaultsamplers[i].defaulttexbits; + Con_Printf("glsl \"%s\" needs %s but doesn't declare so\n", prog->name, sh_defaultsamplers[i].name); } - } - - //multiple lightmaps is kinda hacky. if any are set, all must be. - if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2)))) - prog->defaulttextures |=((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))); - if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2)))) - prog->defaulttextures |=((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))); if (prog->defaulttextures) { - unsigned int sampnum; + unsigned int sampnum = prog->numsamplers; /*set default texture uniforms now that we know the right sampler ids*/ - for (p = 0; p < PERMUTATIONS; p++) + + for (i = 0; sh_defaultsamplers[i].name; i++) { - if (!prog->permu[p].h.glsl.handle) - continue; - sampnum = prog->numsamplers; - GLSlang_UseProgram(prog->permu[p].h.glsl.handle); - for (i = 0; sh_defaultsamplers[i].name; i++) + if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) { - if (prog->defaulttextures & sh_defaultsamplers[i].defaulttexbits) - { - uniformloc = qglGetUniformLocationARB(prog->permu[p].h.glsl.handle, sh_defaultsamplers[i].name); - if (uniformloc != -1) - qglUniform1iARB(uniformloc, sampnum); - sampnum++; - } + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, sh_defaultsamplers[i].name); + if (uniformloc != -1) + qglUniform1iARB(uniformloc, sampnum); + sampnum++; } } } @@ -3019,6 +2991,7 @@ void GL_ForgetPointers(void) qglLinkProgramARB = NULL; qglBindAttribLocationARB = NULL; qglGetAttribLocationARB = NULL; + qglVertexAttrib4f = NULL; qglVertexAttribPointer = NULL; qglGetVertexAttribiv = NULL; qglGetVertexAttribPointerv = NULL; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 505fdf1b9..5805124a9 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -84,6 +84,7 @@ static qboolean XVK_SetupSurface_XCB(void); #include #include +#include static Display *vid_dpy = NULL; static Cursor vid_nullcursor; //'cursor' to use when none should be shown @@ -210,15 +211,18 @@ static struct XIC (*pXCreateIC)(XIM im, ...); void (*pXSetICFocus)(XIC ic); void (*pXUnsetICFocus)(XIC ic); - char * (*pXGetICValues)(XIC ic, ...); + char * (*pXGetICValues)(XIC ic, ...); + char * (*pXSetICValues)(XIC ic, ...); Bool (*pXFilterEvent)(XEvent *event, Window w); int (*pXutf8LookupString)(XIC ic, XKeyPressedEvent *event, char *buffer_return, int bytes_buffer, KeySym *keysym_return, Status *status_return); int (*pXwcLookupString)(XIC ic, XKeyPressedEvent *event, wchar_t *buffer_return, int bytes_buffer, KeySym *keysym_return, Status *status_return); void (*pXDestroyIC)(XIC ic); Status (*pXCloseIM)(XIM im); qboolean dounicode; + int ime_shown; XIC unicodecontext; XIM inputmethod; + XPoint ime_pos; struct { @@ -325,6 +329,7 @@ static qboolean x11_initlib(void) x11.pXSetICFocus = Sys_GetAddressForName(x11.lib, "XSetICFocus"); x11.pXUnsetICFocus = Sys_GetAddressForName(x11.lib, "XUnsetICFocus"); x11.pXGetICValues = Sys_GetAddressForName(x11.lib, "XGetICValues"); + x11.pXSetICValues = Sys_GetAddressForName(x11.lib, "XSetICValues"); x11.pXFilterEvent = Sys_GetAddressForName(x11.lib, "XFilterEvent"); x11.pXutf8LookupString = Sys_GetAddressForName(x11.lib, "Xutf8LookupString"); x11.pXwcLookupString = Sys_GetAddressForName(x11.lib, "XwcLookupString"); @@ -1687,6 +1692,171 @@ static void X_ShutdownUnicode(void) x11.inputmethod = NULL; x11.dounicode = false; } +static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data) +{ + Z_Free(vid.ime_preview); //just in case + vid.ime_preview = NULL; + vid.ime_previewlen = 0; +// Con_Printf("XIMPreEditStartCallback\n"); + return -1; //length of string we can handle (negative for unlimited) +} +static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) +{ +// Con_Printf("XIMPreEditDoneCallback\n"); + + Z_Free(vid.ime_preview); + vid.ime_preview = NULL; + vid.ime_previewlen = 0; +} +static void XIMPreEditDrawCallback(XIM ic, XPointer client_data, XIMPreeditDrawCallbackStruct *d) +{ + //if chg_length, wipe chg_length chars @chg_first. + //if text, insert at chg_first (with per-char feedback properties) + //if feedback (without text) then change text char flags + //caret should then be moved accordingly. +// Con_Printf("XIMPreEditDrawCallback %i %i %i %i %s\n", d->caret, d->chg_first, d->chg_length, d->text?d->text->encoding_is_wchar:0, d->text?d->text->string.multi_byte:"???"); + conchar_t *part[3]; + size_t clen[3], c; + conchar_t *n; + unsigned int wc; + unsigned int defaultfl = CON_WHITEMASK, fl; + + if (d->chg_length || (d->text && d->text->length)) + { + //so inputs are in terms of chars. + //our conchar_t struct is variable-sized (*sigh*), so we always use our longchar encoding. + //so we end up with two conchars per wchar. + part[0] = vid.ime_preview; + clen[0] = bound(0, d->chg_first, vid.ime_previewlen/2)*2; + part[1] = NULL; + clen[1] = 0; + part[2] = part[0]+clen[0] + bound(0, d->chg_length, vid.ime_previewlen/2)*2; + clen[2] = 0; + if (part[2]) + while (part[2][clen[2]]) + clen[2]+=1; + if (d->text && d->text->encoding_is_wchar && d->text->string.wide_char) + { + part[1] = alloca(d->text->length * 2*sizeof(wchar_t)); + for (c = 0; c < d->text->length; c++) + { + wc = d->text->string.wide_char[c]; + if (!wc) + break; //erk? nulls confuse things + part[1][c*2+0] = CON_LONGCHAR|(wc>>16); + part[1][c*2+1] = defaultfl|(wc&CON_CHARMASK); + } + clen[1] = c*2; + } + else if (d->text && !d->text->encoding_is_wchar && d->text->string.multi_byte) + { + const char *in = d->text->string.multi_byte; + int error; + part[1] = alloca(d->text->length * 2*sizeof(wchar_t)); + //FIXME: d->text->length is meant to be chars, but fcitx always reports 1. + for (c = 0; c < d->text->length; c++) + { + //FIXME: This should use mbcstowcs, but that would require switching locales all the frikkin time, which isn't thread-safe. + wc = utf8_decode(&error, in, &in); + if (!wc) + break; //abort if there's a null... + part[1][c*2+0] = CON_LONGCHAR|(wc>>16); + part[1][c*2+1] = defaultfl|(wc&CON_CHARMASK); + } + clen[1] = c*2; + } + + n = Z_Malloc((clen[0]+clen[1]+clen[2]+1)*sizeof(*n)); + memcpy(n, part[0], clen[0]*sizeof(*n)); + memcpy(n+clen[0], part[1], clen[1]*sizeof(*n)); + memcpy(n+clen[0]+clen[1], part[2], clen[2]*sizeof(*n)); + n[clen[0]+clen[1]+clen[2]] = 0; + Z_Free(vid.ime_preview); + vid.ime_preview = n; + vid.ime_previewlen = clen[0]+clen[1]+clen[2]; + } + + if (d->text && d->text->feedback && d->chg_first >= 0 && d->chg_first+d->text->length <= vid.ime_previewlen/2) + { + for (c = 0; c < d->text->length; c++) + { + fl = defaultfl; + if (d->text->feedback[c] & XIMPrimary) + fl = COLOR_RED<text->feedback[c] & XIMSecondary) + fl = COLOR_GREEN<text->feedback[c] & XIMTertiary) + fl = COLOR_BLUE<text->feedback[c] & XIMUnderline) + fl = COLOR_MAGENTA<text->feedback[c] & XIMReverse) + fl = ((fl&CON_FGMASK) << (CON_BGSHIFT-CON_FGSHIFT)) | ((fl&CON_BGMASK) >> (CON_BGSHIFT-CON_FGSHIFT)); + if (d->text->feedback[c] & XIMHighlight) + fl |= CON_2NDCHARSETTEXT; + vid.ime_preview[(d->chg_first+c)*2+1] = ((vid.ime_preview[(d->chg_first+c)*2+1])&~CON_FLAGSMASK)|fl; + } + } + + vid.ime_caret = bound(0, d->caret, vid.ime_previewlen/2)*2; +} +static void XIMPreEditCaretCallback(XIC ic, XPointer client_data, XIMPreeditCaretCallbackStruct *d) +{ +// Con_Printf("XIMPreEditCaretCallback %i %i %i\n", d->direction, d->position, d->style); +} +static qboolean XIMSupportedStyle(XIMStyle preedit, XIMStyle status) +{ + if (!( //preedit==XIMPreeditCallbacks|| //FIXME: this should actually work, but we still need an ime that actually supports it properly to be sure. + //preedit==XIMPreeditPosition|| + //preedit==XIMPreeditArea|| //FIXME: assume the bottom half of the screen + preedit==XIMPreeditNothing|| + preedit==XIMPreeditNone)) + return false; + if (!( //status==XIMStatusCallbacks|| + //status==XIMStatusArea|| + status==XIMStatusNothing|| + status==XIMStatusNone)) + return false; + + return true; +} +static XIMStyle XIMPreferredStyle(XIMStyle old, XIMStyle new) +{ //favour the more complicated (supported) preedit styles, *THEN* choose the preferred status style. + XIMStyle p1 = old&0x00ff; + XIMStyle p2 = new&0x00ff; + XIMStyle s1 = old&0xff00; + XIMStyle s2 = new&0xff00; + if (!XIMSupportedStyle(p2, s2)) + return old; + if (!XIMSupportedStyle(p1, s1)) + return new; + if (p1 != p2) + { //choose based upon the preedit flags + if ((p1^p2)&XIMPreeditCallbacks) //FIXME: support this one properly some time. + return (p1&XIMPreeditCallbacks)?old:new; + if ((p1^p2)&XIMPreeditPosition) + return (p1&XIMPreeditPosition)?old:new; + if ((p1^p2)&XIMPreeditArea) + return (p1&XIMPreeditArea)?old:s2; + if ((p1^p2)&XIMPreeditNothing) + return (p1&XIMPreeditNothing)?old:new; + if ((p1^p2)&XIMPreeditNone) + return (p1&XIMPreeditNone)?old:new; + } + else + { //preedit flags are equal, now pick the better + if ((s1^s2)&XIMStatusCallbacks) + return (s1&XIMStatusCallbacks)?old:new; + if ((s1^s2)&XIMStatusArea) + return (s1&XIMStatusArea)?old:new; + if ((s1^s2)&XIMStatusNothing) + return (s1&XIMStatusNothing)?old:new; + if ((s1^s2)&XIMStatusNone) + return (s1&XIMStatusNone)?old:new; + } + + //difference not known. stick with the first + return old; +} #include static long X_InitUnicode(void) { @@ -1694,12 +1864,13 @@ static long X_InitUnicode(void) X_ShutdownUnicode(); //FIXME: enable by default if ubuntu's issue can ever be resolved. - if (X11_CheckFeature("xim", false)) + if (X11_CheckFeature("xim", true)) { - if (x11.pXSetLocaleModifiers && x11.pXSupportsLocale && x11.pXOpenIM && x11.pXGetIMValues && x11.pXCreateIC && x11.pXSetICFocus && x11.pXUnsetICFocus && x11.pXGetICValues && x11.pXFilterEvent && (x11.pXutf8LookupString || x11.pXwcLookupString) && x11.pXDestroyIC && x11.pXCloseIM) + if (x11.pXSetLocaleModifiers && x11.pXSupportsLocale && x11.pXOpenIM && x11.pXGetIMValues && x11.pXCreateIC && x11.pXSetICFocus && x11.pXUnsetICFocus && x11.pXGetICValues && x11.pXSetICValues && x11.pXFilterEvent && (x11.pXutf8LookupString || x11.pXwcLookupString) && x11.pXDestroyIC && x11.pXCloseIM) { - setlocale(LC_CTYPE, ""); //just in case. + setlocale(LC_ALL, ""); //just in case. x11.pXSetLocaleModifiers(""); + if (x11.pXSupportsLocale()) { x11.inputmethod = x11.pXOpenIM(vid_dpy, NULL, XI_RESOURCENAME, XI_RESOURCECLASS); @@ -1710,48 +1881,49 @@ static long X_InitUnicode(void) int i; x11.pXGetIMValues(x11.inputmethod, XNQueryInputStyle, &sup, NULL); for (i = 0; sup && i < sup->count_styles; i++) - { //each style will have one of each bis set. -#define prestyles (XIMPreeditNothing|XIMPreeditNone) -#define statusstyles (XIMStatusNothing|XIMStatusNone) -#define supstyles (prestyles|statusstyles) - if ((sup->supported_styles[i] & supstyles) != sup->supported_styles[i]) - continue; - if ((st & prestyles) != (sup->supported_styles[i] & prestyles)) - { - if ((sup->supported_styles[i] & XIMPreeditNothing) && !(st & XIMPreeditNothing)) - st = sup->supported_styles[i]; - else if ((sup->supported_styles[i] & XIMPreeditNone) && !(st & (XIMPreeditNone|XIMPreeditNothing))) - st = sup->supported_styles[i]; - } - else - { - if ((sup->supported_styles[i] & XIMStatusNothing) && !(st & XIMStatusNothing)) - st = sup->supported_styles[i]; - else if ((sup->supported_styles[i] & XIMStatusNone) && !(st & (XIMStatusNone|XIMStatusNothing))) - st = sup->supported_styles[i]; - } - } + st = XIMPreferredStyle(st, sup->supported_styles[i]); x11.pXFree(sup); + Con_DPrintf("Chosen XIM Input Style: %x\n", (unsigned)st); +// st=XIMPreeditCallbacks|XIMStatusArea; +// st=XIMPreeditCallbacks|XIMStatusNothing; if (st != 0) { + XIMCallback pe_cb_start={NULL,(XIMProc)XIMPreEditStartCallback}; + XIMCallback pe_cb_done={NULL,(XIMProc)XIMPreEditDoneCallback}; + XIMCallback pe_cb_draw={NULL,(XIMProc)XIMPreEditDrawCallback}; + XIMCallback pe_cb_caret={NULL,(XIMProc)XIMPreEditCaretCallback}; + void *preedit[] = { + //should probably add in fonts, but that's kinda messy if we don't know the language/charset very well + XNPreeditStartCallback, &pe_cb_start, + XNPreeditDoneCallback, &pe_cb_done, + XNPreeditDrawCallback, &pe_cb_draw, + XNPreeditCaretCallback, &pe_cb_caret, + XNSpotLocation, &x11.ime_pos, + NULL}; + void *status[] = { + NULL}; + x11.unicodecontext = x11.pXCreateIC(x11.inputmethod, XNInputStyle, st, XNClientWindow, vid_window, - XNFocusWindow, vid_window, +// XNFocusWindow, vid_window, XNResourceName, XI_RESOURCENAME, XNResourceClass, XI_RESOURCECLASS, + XNPreeditAttributes, preedit, + XNStatusAttributes, status, NULL); if (x11.unicodecontext) { -// x11.pXSetICFocus(x11.unicodecontext); + x11.ime_shown = -1; x11.dounicode = true; x11.pXGetICValues(x11.unicodecontext, XNFilterEvents, &requiredevents, NULL); + requiredevents |= KeyPressMask; } } } } - setlocale(LC_CTYPE, "C"); + setlocale(LC_ALL, "C"); } } @@ -1772,13 +1944,14 @@ static void X_KeyEvent(XKeyEvent *ev, qboolean pressed, qboolean filtered) keysym = x11.pXLookupKeysym(ev, 0); if (pressed && !filtered) { - if (x11.dounicode) + if (x11.dounicode && vid.ime_allow) { Status status = XLookupNone; if (x11.pXutf8LookupString) { - char buf1[4] = {0}; - char *buf = buf1, *c; + char buf1[512] = {0}; + char *buf = buf1; + const char *c; int count = x11.pXutf8LookupString(x11.unicodecontext, (XKeyPressedEvent*)ev, buf1, sizeof(buf1), NULL, &status); if (status == XBufferOverflow) { @@ -1796,7 +1969,7 @@ static void X_KeyEvent(XKeyEvent *ev, qboolean pressed, qboolean filtered) else { //is allowed some weird encodings... - wchar_t buf1[4] = {0}; + wchar_t buf1[512] = {0}; wchar_t *buf = buf1; int count = x11.pXwcLookupString(x11.unicodecontext, (XKeyPressedEvent*)ev, buf, sizeof(buf1), &shifted, &status); if (status == XBufferOverflow) @@ -2073,8 +2246,14 @@ static void GetEvent(void) x11.pXNextEvent(vid_dpy, &event); if (x11.dounicode) - if (x11.pXFilterEvent(&event, vid_window)) + { + if (x11.pXFilterEvent(&event, None))//vid_window)) + { + if (vid.ime_allow) + return; filtered = true; + } + } switch (event.type) { @@ -2324,8 +2503,8 @@ static void GetEvent(void) modeswitchtime = Sys_Milliseconds() + 1500; /*fairly slow, to make sure*/ } - if (event.xfocus.window == vid_window && x11.unicodecontext) - x11.pXSetICFocus(x11.unicodecontext); + if (event.xfocus.window == vid_window) + x11.ime_shown = -1; //we we're focusing onto the game window and we're currently fullscreen, hide the other one so alt-tab won't select that instead of a real alternate app. // if ((fullscreenflags & FULLSCREEN_ACTIVE) && (fullscreenflags & FULLSCREEN_LEGACY) && event.xfocus.window == vid_window) @@ -2333,8 +2512,8 @@ static void GetEvent(void) break; case FocusOut: //if we're already active, the decoy window shouldn't be focused anyway. - if (event.xfocus.window == vid_window && x11.unicodecontext) - x11.pXSetICFocus(x11.unicodecontext); + if (event.xfocus.window == vid_window) + x11.ime_shown = -1; if ((fullscreenflags & FULLSCREEN_ACTIVE) && event.xfocus.window == vid_decoywindow) { @@ -2571,7 +2750,7 @@ static void GetEvent(void) else if (event.xselectionrequest.property != None && event.xselectionrequest.target == xa_l1string) { //STRING == latin1. convert as needed. char *latin1 = alloca(strlen(cliptext)+1); //may shorten - char *in = cliptext; + const char *in = cliptext; int c = 0; int err; while (*in && c < sizeof(latin1)) @@ -2993,7 +3172,7 @@ static void X_StoreIcon(Window wnd) data[0] = icon.width; data[1] = icon.height; for (i = 0; i < data[0]*data[1]; i++) - data[i+2] = ((unsigned int*)icon.pixel_data)[i]; + data[i+2] = ((const unsigned int*)icon.pixel_data)[i]; x11.pXChangeProperty(vid_dpy, wnd, propname, proptype, 32, PropModeReplace, (void*)data, data[0]*data[1]+2); } @@ -3840,6 +4019,28 @@ void Sys_SendKeyEvents(void) } if (vid_dpy && vid_window) { + if (x11.unicodecontext) + { + qboolean want = vid.ime_allow && vid.activeapp; + XPoint pos; + if (want != x11.ime_shown) + { + x11.ime_shown = want; + if (x11.ime_shown) + x11.pXSetICFocus(x11.unicodecontext); + else + x11.pXUnsetICFocus(x11.unicodecontext); + } + pos.x = (vid.ime_position[0] * vid.pixelwidth)/vid.width; + pos.y = (vid.ime_position[1] * vid.pixelheight)/vid.height; + if (/*x11.ime_shown &&*/ (x11.ime_pos.x != pos.x || x11.ime_pos.y != pos.y)) + { + void *attr[] = {XNSpotLocation, &x11.ime_pos, NULL}; + x11.ime_pos = pos; + x11.pXSetICValues(x11.unicodecontext, XNPreeditAttributes, attr, NULL); + } + } + while (x11.pXPending(vid_dpy)) GetEvent(); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 4f2615b7a..9e12e33d5 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -175,6 +175,7 @@ typedef void (APIENTRYP FTEPFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP FTEPFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, GLcharARB *name); typedef GLint (APIENTRYP FTEPFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); typedef void (APIENTRYP FTEPFNGLVERTEXATTRIBPOINTER) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP FTEPFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP FTEPFNGLENABLEVERTEXATTRIBARRAY) (GLuint index); typedef void (APIENTRYP FTEPFNGLDISABLEVERTEXATTRIBARRAY) (GLuint index); typedef GLint (APIENTRYP FTEPFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); @@ -715,6 +716,7 @@ extern FTEPFNGLUNIFORM3FVARBPROC qglUniform3fvARB; extern FTEPFNGLUNIFORM2FVARBPROC qglUniform2fvARB; extern FTEPFNGLUNIFORM1IARBPROC qglUniform1iARB; extern FTEPFNGLUNIFORM1FARBPROC qglUniform1fARB; +extern FTEPFNGLVERTEXATTRIB4FARBPROC qglVertexAttrib4f; extern FTEPFNGLVERTEXATTRIBPOINTER qglVertexAttribPointer; extern FTEPFNGLGETVERTEXATTRIBIV qglGetVertexAttribiv; extern FTEPFNGLENABLEVERTEXATTRIBARRAY qglEnableVertexAttribArray; diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 18e312203..868f7072a 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -6,6 +6,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "fixedemu", "!!ver 100-450\n" +"!!samps sourcetex:0\n" //this shader is present for support for gles/gl3core contexts //it is single-texture-with-vertex-colours, and doesn't do anything special. @@ -29,7 +30,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "varying vec2 tc;\n" "#ifndef UC\n" "varying vec4 vc;\n" @@ -40,7 +40,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "float e_time;\n" "void main ()\n" "{\n" -"vec4 fc = texture2D(s_t0, tc) * vc;\n" +"vec4 fc = texture2D(s_sourcetex, tc) * vc;\n" "#ifdef ALPHATEST\n" "if (!(fc.a ALPHATEST))\n" "discard;\n" @@ -358,7 +358,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND {QR_OPENGL, 110, "altwater", "!!cvardf r_glsl_turbscale_reflect=1 //simpler scaler\n" "!!cvardf r_glsl_turbscale_refract=1 //simpler scaler\n" -"!!samps 4 diffuse normalmap\n" +"!!samps diffuse normalmap\n" +"!!samps refract=0 //always present\n" +"!!samps =REFLECT reflect=1\n" +"!!samps =RIPPLEMAP ripplemap=2\n" +"!!samps =DEPTH refractdepth=3\n" "#include \"sys/defs.h\"\n" @@ -446,11 +450,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" -"#define s_refract s_t0\n" -"#define s_reflect s_t1\n" -"#define s_ripplemap s_t2\n" -"#define s_refractdepth s_t3\n" - "void main (void)\n" "{\n" "vec2 stc; //screen tex coords\n" @@ -1108,6 +1107,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "bloom_blur", +"!!samps 1\n" //apply gaussian filter "varying vec2 tc;\n" @@ -1123,7 +1123,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" /*offset should be 1.2 pixels away from the center*/ "uniform vec3 e_glowmod;\n" -"uniform sampler2D s_t0;\n" "void main ()\n" "{\n" "gl_FragColor =\n" @@ -1355,6 +1354,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "bloom_filter", "!!cvarv r_bloom_filter\n" +"!!samps 1\n" //the bloom filter //filter out any texels which are not to bloom @@ -1370,7 +1370,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#ifdef FRAGMENT_SHADER\n" "uniform vec3 cvar_r_bloom_filter;\n" -"uniform sampler2D s_t0;\n" "void main ()\n" "{\n" "gl_FragColor.rgb = (texture2D(s_t0, tc).rgb - cvar_r_bloom_filter)/(1.0-cvar_r_bloom_filter);\n" @@ -1611,6 +1610,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND {QR_OPENGL, 110, "bloom_final", "!!cvarf r_bloom\n" "!!cvarf r_bloom_retain=1.0\n" +"!!samps 4\n" //add them together //optionally apply tonemapping @@ -1625,10 +1625,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" -"uniform sampler2D s_t1;\n" -"uniform sampler2D s_t2;\n" -"uniform sampler2D s_t3;\n" "uniform float cvar_r_bloom;\n" "uniform float cvar_r_bloom_retain;\n" "void main ()\n" @@ -1872,6 +1868,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "colourtint", +"!!samps 2\n" //this glsl shader is useful for cubemapped post processing effects (see csaddon for an example) "varying vec4 tf;\n" "#ifdef VERTEX_SHADER\n" @@ -1881,8 +1878,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" -"uniform sampler3D s_t1;\n" "void main()\n" "{\n" "vec2 fc;\n" @@ -1918,6 +1913,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!cvarf crep_decay\n" "!!cvarf crep_density\n" "!!cvarf crep_weight\n" +"!!samps 1\n" //this is a post-processing shader, drawn in 2d //there will be a render target containing sky surfaces drawn with crepuscular_sky, and everything else drawn with crepuscular_opaque (to mask out the sky) @@ -1939,7 +1935,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "const float crep_weight = 0.2;\n" "uniform vec3 l_lightcolour;\n" "uniform vec3 l_lightscreen;\n" -"uniform sampler2D s_t0;\n" "const int NUM_SAMPLES = 100;\n" "void main()\n" "{\n" @@ -1963,6 +1958,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "crepuscular_sky", +"!!samps 2\n" //pretty much a regular sky shader //though in reality we should render a sun circle in the middle. //still, its kinda cool to have scrolling clouds masking out parts of the sun. @@ -1979,8 +1975,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform float e_time;\n" "uniform vec3 e_eyepos;\n" "varying vec3 pos;\n" -"uniform sampler2D s_t0;\n" -"uniform sampler2D s_t1;\n" "void main ()\n" "{\n" "vec2 tccoord;\n" @@ -2337,6 +2331,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "default2d", "!!ver 100-450\n" +"!!samps 1\n" //this shader is present for support for gles/gl3core contexts //it is single-texture-with-vertex-colours, and doesn't do anything special. @@ -2357,7 +2352,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "void main ()\n" "{\n" "vec4 f = vc;\n" @@ -2642,6 +2636,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "defaultadditivesprite", "!!permu FOG\n" +"!!samps 1\n" //meant to be used for additive stuff. presumably particles and sprites. though actually its only flashblend effects that use this at the time of writing. //includes fog, apparently. @@ -2660,7 +2655,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "varying vec2 tc;\n" "varying vec4 vc;\n" "uniform vec4 e_colourident;\n" @@ -2686,7 +2680,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!cvarf gl_specular\n" "!!cvardf gl_affinemodels=0\n" "!!cvardf r_tessellation_level=5\n" -"!!samps diffuse normalmap specular fullbright upper lower paletted reflectmask reflectcube\n" +"!!samps !EIGHTBIT diffuse normalmap specular fullbright upper lower reflectmask reflectcube\n" +"!!samps =EIGHTBIT paletted 1\n" "#include \"sys/defs.h\"\n" @@ -2883,7 +2878,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef EIGHTBIT\n" "#define s_colourmap s_t0\n" -"uniform sampler2D s_colourmap;\n" "#endif\n" "affine varying vec2 tc;\n" @@ -3589,6 +3583,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND {QR_DIRECT3D9, 9, "defaultskin", "!!permu FRAMEBLEND\n" "!!permu UPPERLOWER\n" +//!!permu FULLBRIGHT +"!!samps diffuse upper lower\n" +// fullbright + "struct a2v\n" "{\n" "float3 pos: POSITION0;\n" @@ -3659,7 +3657,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "col.rgb *= inp.light;\n" "#ifdef FULLBRIGHT\n" "float4 fb = tex2D(s_fullbright, inp.tc);\n" -"col.rgb = mix(col.rgb, fb.rgb, fb.a);\n" +"col.rgb = lerp(col.rgb, fb.rgb, fb.a);\n" "#endif\n" "return col * e_colourident;\n" // return fog4(col * e_colourident); @@ -3753,6 +3751,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "defaultsky", "!!permu FOG\n" +"!!samps 2\n" "#include \"sys/fog.h\"\n" //regular sky shader for scrolling q1 skies @@ -3770,8 +3769,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform float e_time;\n" "uniform vec3 e_eyepos;\n" "varying vec3 pos;\n" -"uniform sampler2D s_t0;\n" -"uniform sampler2D s_t1;\n" "void main ()\n" "{\n" "vec2 tccoord;\n" @@ -4094,6 +4091,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef D3D9QUAKE {QR_DIRECT3D9, 9, "defaultsky", +"!!samps 2\n" + "struct a2v\n" "{\n" "float4 pos: POSITION;\n" @@ -4108,11 +4107,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef VERTEX_SHADER\n" "float4x4 m_modelviewprojection;\n" -"v2f main (a2v inp)\n" +"v2f main (in a2v inp)\n" "{\n" "v2f outp;\n" "outp.pos = mul(m_modelviewprojection, inp.pos);\n" -"outp.vpos = inp.pos;\n" +"outp.vpos = inp.pos.xyz;\n" "return outp;\n" "}\n" "#endif\n" @@ -4137,7 +4136,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tccoord = (dir.xy + e_time*0.0625);\n" "float4 clouds = tex2D(s_fullbright, tccoord);\n" - "return float4((solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb), 1);\n" "}\n" "#endif\n" @@ -4498,6 +4496,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef D3D9QUAKE {QR_DIRECT3D9, 9, "defaultskybox", +"!!samps reflectcube\n" + "struct a2v\n" "{\n" "float4 pos: POSITION;\n" @@ -4834,6 +4834,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "defaultsprite", "!!permu FOG\n" +"!!samps 1\n" //used by both particles and sprites. //note the fog blending mode is all that differs from defaultadditivesprite @@ -4851,7 +4852,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "varying vec2 tc;\n" "varying vec4 vc;\n" "uniform vec4 e_colourident;\n" @@ -5204,7 +5204,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!permu REFLECTCUBEMASK\n" "!!cvarf r_glsl_offsetmapping_scale\n" "!!cvardf r_tessellation_level=5\n" -"!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3\n" +"!!samps !EIGHTBIT diffuse specular normalmap fullbright reflectmask reflectcube\n" +//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse. +"!!samps =EIGHTBIT paletted 1 specular diffuse\n" +"!!samps lightmap deluxemap\n" +"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3\n" "#include \"sys/defs.h\"\n" @@ -5419,10 +5423,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" - -//samplers "#define s_colourmap s_t0\n" -"uniform sampler2D s_colourmap;\n" "#ifdef OFFSETMAPPING\n" "#include \"sys/offsetmapping.h\"\n" @@ -6958,6 +6959,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef D3D9QUAKE {QR_DIRECT3D9, 9, "defaultwarp", "!!cvarf r_wateralpha\n" +"!!samps diffuse\n" + "struct a2v {\n" "float4 pos: POSITION;\n" "float2 tc: TEXCOORD0;\n" @@ -7054,6 +7057,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "defaultgammacb", "!!ver 100-450\n" +"!!samps 1\n" //this shader is applies gamma/contrast/brightness to the source image, and dumps it out. "varying vec2 tc;\n" @@ -7070,7 +7074,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "void main ()\n" "{\n" "gl_FragColor = pow(texture2D(s_t0, tc) * vc.g, vec4(vc.r)) + vc.b;\n" @@ -7300,6 +7303,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!cvard_srgb_b r_floorcolor\n" "!!cvard_srgb_b r_wallcolor\n" "!!permu FOG\n" +"!!samps lm:0\n" //this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals. @@ -7322,11 +7326,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform sampler2D s_t0;\n" "varying vec2 lm;\n" "void main ()\n" "{\n" -"gl_FragColor = fog4(col * texture2D(s_t0, lm));\n" +"gl_FragColor = fog4(col * texture2D(s_lm, lm));\n" "}\n" "#endif\n" }, @@ -7665,6 +7668,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND {QR_DIRECT3D9, 9, "drawflat_wall", "!!cvard3 r_floorcolour\n" "!!cvard3 r_wallcolour\n" +"!!samps 1\n" //FIXME !!permu FOG "struct a2v {\n" @@ -8146,6 +8150,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_fisheye", "!!cvarf ffov\n" +"!!samps screen:samplerCube=0\n" //fisheye view rendering, for silly fovs that are still playable. @@ -8159,7 +8164,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform samplerCube s_t0;\n" "varying vec2 texcoord;\n" "uniform float cvar_ffov;\n" "void main()\n" @@ -8173,7 +8177,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tc.x = sin(ang.x) * cos(ang.y); \n" "tc.y = sin(ang.x) * sin(ang.y); \n" "tc.z = cos(ang.x); \n" -"gl_FragColor = textureCube(s_t0, tc);\n" +"gl_FragColor = textureCube(s_screen, tc);\n" "}\n" "#endif\n" }, @@ -8423,6 +8427,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_panorama", "!!cvarf ffov\n" +"!!samps screen:samplerCube=0\n" //panoramic view rendering, for promo map shots or whatever. @@ -8436,7 +8441,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform samplerCube s_t0;\n" "varying vec2 texcoord;\n" "uniform float cvar_ffov;\n" "void main()\n" @@ -8447,7 +8451,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tc.x = sin(ang); \n" "tc.y = -texcoord.y; \n" "tc.z = cos(ang); \n" -"gl_FragColor = textureCube(s_t0, tc);\n" +"gl_FragColor = textureCube(s_screen, tc);\n" "}\n" "#endif\n" }, @@ -8678,6 +8682,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_laea", "!!cvarf ffov\n" +"!!samps screen:samplerCube=0\n" //my attempt at lambert azimuthal equal-area view rendering, because you'll remember that name easily. @@ -8696,7 +8701,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform samplerCube s_t0;\n" "varying vec2 texcoord;\n" "void main()\n" "{\n" @@ -8718,7 +8722,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tc.y *= -1.0;\n" "tc.z *= -1.0;\n" -"gl_FragColor = textureCube(s_t0, tc);\n" +"gl_FragColor = textureCube(s_screen, tc);\n" "}\n" "}\n" "#endif\n" @@ -8727,6 +8731,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_stereographic", "!!cvarf ffov\n" +"!!samps screen:samplerCube=0\n" //stereographic view rendering, for high fovs that are still playable. @@ -8745,7 +8750,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform samplerCube s_t0;\n" "varying vec2 texcoord;\n" "void main()\n" "{\n" @@ -8760,7 +8764,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tc.y = -2.0*d.y/div;\n" "tc.z = -(-1.0 + d.x*d.x + d.y*d.y)/div;\n" -"gl_FragColor = textureCube(s_t0, tc);\n" +"gl_FragColor = textureCube(s_screen, tc);\n" "}\n" "#endif\n" }, @@ -9012,6 +9016,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_equirectangular", "!!cvarf ffov\n" +"!!samps screen:samplerCube=0\n" //equirectangular view rendering, commonly used for sphere->2d map projections. @@ -9025,7 +9030,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"uniform samplerCube s_t0;\n" "varying vec2 texcoord;\n" "uniform float cvar_ffov;\n" @@ -9039,7 +9043,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "tc.z = cos(lng) * sin(lat); \n" "tc.x = sin(lng) * sin(lat);\n" "tc.y = cos(lat);\n" -"gl_FragColor = textureCube(s_t0, tc);\n" +"gl_FragColor = textureCube(s_screen, tc);\n" "}\n" "#endif\n" }, @@ -9047,7 +9051,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "postproc_ascii", "!!cvardf r_glsl_ascii_mono=0\n" -"!!samps 1\n" +"!!samps screen=0\n" //derived from https://www.shadertoy.com/view/lssGDj @@ -9078,7 +9082,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "void main(void)\n" "{\n" "vec2 uv = floor(texcoord.xy * e_sourcesize); //in pixels.\n" -"vec3 col = texture2D(s_t0, (floor(uv/8.0)*8.0+4.0)/e_sourcesize.xy).rgb; \n" +"vec3 col = texture2D(s_screen, (floor(uv/8.0)*8.0+4.0)/e_sourcesize.xy).rgb; \n" "float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;\n" @@ -9541,15 +9545,16 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "underwaterwarp", "!!cvarf r_waterwarp\n" +"!!samps screen=0 warp=1 edge=2\n" //this is a post processing shader that is drawn fullscreen whenever the view is underwater. //its generally expected to warp the view a little. -"#ifdef VERTEX_SHADER\n" -"attribute vec2 v_texcoord;\n" "varying vec2 v_stc;\n" "varying vec2 v_warp;\n" "varying vec2 v_edge;\n" +"#ifdef VERTEX_SHADER\n" +"attribute vec2 v_texcoord;\n" "uniform float e_time;\n" "void main ()\n" "{\n" @@ -9561,20 +9566,14 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" -"varying vec2 v_stc;\n" -"varying vec2 v_warp;\n" -"varying vec2 v_edge;\n" -"uniform sampler2D s_t0;/*$currentrender*/\n" -"uniform sampler2D s_t1;/*warp image*/\n" -"uniform sampler2D s_t2;/*edge image*/\n" "uniform vec4 e_rendertexturescale;\n" "uniform float cvar_r_waterwarp;\n" "void main ()\n" "{\n" -"vec2 amp = (0.010 / 0.625) * cvar_r_waterwarp * texture2D(s_t2, v_edge).rg;\n" -"vec3 offset = (texture2D(s_t1, v_warp).rgb - 0.5) * 2.0;\n" +"vec2 amp = (0.010 / 0.625) * cvar_r_waterwarp * texture2D(s_edge, v_edge).rg;\n" +"vec3 offset = (texture2D(s_warp, v_warp).rgb - 0.5) * 2.0;\n" "vec2 temp = v_stc + offset.xy * amp;\n" -"gl_FragColor = texture2D(s_t0, temp*e_rendertexturescale.st);\n" +"gl_FragColor = texture2D(s_screen, temp*e_rendertexturescale.st);\n" "}\n" "#endif\n" }, @@ -9582,11 +9581,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef VKQUAKE {QR_VULKAN, -1, "underwaterwarp", "\xFF\x53\x50\x56\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x14\x00\x00\x00\x40\x00\x00\x00" -"\x34\x11\x00\x00\x74\x11\x00\x00\xF4\x0D\x00\x00\x01\x00\x66\x31\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x00" -"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x69\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00" +"\x20\x11\x00\x00\x60\x11\x00\x00\xF4\x0D\x00\x00\x01\x00\x66\x31\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x00" +"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x68\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00" "\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00" "\x0F\x00\x10\x00\x00\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x1C\x00\x00\x00\x3A\x00\x00\x00\x3F\x00\x00\x00" -"\x41\x00\x00\x00\x4A\x00\x00\x00\x5D\x00\x00\x00\x64\x00\x00\x00\x65\x00\x00\x00\x66\x00\x00\x00\x67\x00\x00\x00\x68\x00\x00\x00" +"\x41\x00\x00\x00\x49\x00\x00\x00\x5C\x00\x00\x00\x63\x00\x00\x00\x64\x00\x00\x00\x65\x00\x00\x00\x66\x00\x00\x00\x67\x00\x00\x00" "\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x05\x00\x06\x00" "\x09\x00\x00\x00\x66\x74\x65\x74\x72\x61\x6E\x73\x66\x6F\x72\x6D\x28\x00\x00\x00\x05\x00\x04\x00\x0C\x00\x00\x00\x70\x72\x6F\x6A" "\x00\x00\x00\x00\x05\x00\x05\x00\x13\x00\x00\x00\x65\x6E\x74\x69\x74\x79\x62\x6C\x6F\x63\x6B\x00\x06\x00\x07\x00\x13\x00\x00\x00" @@ -9611,20 +9610,20 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x38\x00\x00\x00\x67\x6C\x5F\x50\x65\x72\x56\x65\x72\x74\x65\x78\x00\x00\x00\x00\x06\x00\x06\x00\x38\x00\x00\x00\x00\x00\x00\x00" "\x67\x6C\x5F\x50\x6F\x73\x69\x74\x69\x6F\x6E\x00\x05\x00\x03\x00\x3A\x00\x00\x00\x00\x00\x00\x00\x05\x00\x04\x00\x3F\x00\x00\x00" "\x76\x5F\x73\x74\x63\x00\x00\x00\x05\x00\x05\x00\x41\x00\x00\x00\x76\x5F\x74\x65\x78\x63\x6F\x6F\x72\x64\x00\x00\x05\x00\x04\x00" -"\x4A\x00\x00\x00\x76\x5F\x77\x61\x72\x70\x00\x00\x05\x00\x04\x00\x5D\x00\x00\x00\x76\x5F\x65\x64\x67\x65\x00\x00\x05\x00\x07\x00" -"\x5F\x00\x00\x00\x63\x76\x61\x72\x5F\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x05\x00\x05\x00\x60\x00\x00\x00" -"\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\x60\x00\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75\x62\x65\x6D\x61" -"\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\x60\x00\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70\x6F\x73\x69\x74" -"\x69\x6F\x6E\x00\x06\x00\x05\x00\x60\x00\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00\x60\x00\x00\x00" -"\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\x60\x00\x00\x00\x04\x00\x00\x00" -"\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\x60\x00\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75" -"\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\x60\x00\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72\x61\x64\x69\x75" -"\x73\x00\x00\x00\x06\x00\x07\x00\x60\x00\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70\x72\x6F\x6A\x00" -"\x06\x00\x08\x00\x60\x00\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65\x00\x00\x00\x00" -"\x06\x00\x05\x00\x60\x00\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\x62\x00\x00\x00\x00\x00\x00\x00" -"\x05\x00\x05\x00\x64\x00\x00\x00\x76\x5F\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x00\x05\x00\x05\x00\x65\x00\x00\x00\x76\x5F\x6C\x6D" -"\x63\x6F\x6F\x72\x64\x00\x00\x00\x05\x00\x05\x00\x66\x00\x00\x00\x76\x5F\x6E\x6F\x72\x6D\x61\x6C\x00\x00\x00\x00\x05\x00\x05\x00" -"\x67\x00\x00\x00\x76\x5F\x73\x76\x65\x63\x74\x6F\x72\x00\x00\x00\x05\x00\x05\x00\x68\x00\x00\x00\x76\x5F\x74\x76\x65\x63\x74\x6F" +"\x49\x00\x00\x00\x76\x5F\x77\x61\x72\x70\x00\x00\x05\x00\x04\x00\x5C\x00\x00\x00\x76\x5F\x65\x64\x67\x65\x00\x00\x05\x00\x07\x00" +"\x5E\x00\x00\x00\x63\x76\x61\x72\x5F\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x05\x00\x05\x00\x5F\x00\x00\x00" +"\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\x5F\x00\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75\x62\x65\x6D\x61" +"\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\x5F\x00\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70\x6F\x73\x69\x74" +"\x69\x6F\x6E\x00\x06\x00\x05\x00\x5F\x00\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00\x5F\x00\x00\x00" +"\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\x5F\x00\x00\x00\x04\x00\x00\x00" +"\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\x5F\x00\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75" +"\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\x5F\x00\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72\x61\x64\x69\x75" +"\x73\x00\x00\x00\x06\x00\x07\x00\x5F\x00\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70\x72\x6F\x6A\x00" +"\x06\x00\x08\x00\x5F\x00\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65\x00\x00\x00\x00" +"\x06\x00\x05\x00\x5F\x00\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\x61\x00\x00\x00\x00\x00\x00\x00" +"\x05\x00\x05\x00\x63\x00\x00\x00\x76\x5F\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x00\x05\x00\x05\x00\x64\x00\x00\x00\x76\x5F\x6C\x6D" +"\x63\x6F\x6F\x72\x64\x00\x00\x00\x05\x00\x05\x00\x65\x00\x00\x00\x76\x5F\x6E\x6F\x72\x6D\x61\x6C\x00\x00\x00\x00\x05\x00\x05\x00" +"\x66\x00\x00\x00\x76\x5F\x73\x76\x65\x63\x74\x6F\x72\x00\x00\x00\x05\x00\x05\x00\x67\x00\x00\x00\x76\x5F\x74\x76\x65\x63\x74\x6F" "\x72\x00\x00\x00\x47\x00\x04\x00\x11\x00\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x13\x00\x00\x00\x00\x00\x00\x00" "\x05\x00\x00\x00\x48\x00\x05\x00\x13\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x13\x00\x00\x00" "\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x13\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00" @@ -9647,19 +9646,19 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x15\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x1C\x00\x00\x00" "\x1E\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x38\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x47\x00\x03\x00" "\x38\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x3F\x00\x00\x00\x1E\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x41\x00\x00\x00" -"\x1E\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x4A\x00\x00\x00\x1E\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x5D\x00\x00\x00" -"\x1E\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x5F\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x48\x00\x04\x00\x60\x00\x00\x00" -"\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00" -"\x60\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00" -"\x40\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x02\x00\x00\x00\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00" -"\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00" -"\x48\x00\x05\x00\x60\x00\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00\x60\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x06\x00\x00\x00" -"\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00" -"\x60\x00\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00\x48\x00\x05\x00\x60\x00\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00" -"\x88\x00\x00\x00\x47\x00\x03\x00\x60\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x62\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00" -"\x47\x00\x04\x00\x62\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x64\x00\x00\x00\x1E\x00\x00\x00\x02\x00\x00\x00" -"\x47\x00\x04\x00\x65\x00\x00\x00\x1E\x00\x00\x00\x03\x00\x00\x00\x47\x00\x04\x00\x66\x00\x00\x00\x1E\x00\x00\x00\x04\x00\x00\x00" -"\x47\x00\x04\x00\x67\x00\x00\x00\x1E\x00\x00\x00\x05\x00\x00\x00\x47\x00\x04\x00\x68\x00\x00\x00\x1E\x00\x00\x00\x06\x00\x00\x00" +"\x1E\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x49\x00\x00\x00\x1E\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x5C\x00\x00\x00" +"\x1E\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x5E\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x48\x00\x04\x00\x5F\x00\x00\x00" +"\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00" +"\x5F\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00" +"\x40\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x02\x00\x00\x00\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00" +"\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00" +"\x48\x00\x05\x00\x5F\x00\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00\x60\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x06\x00\x00\x00" +"\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00" +"\x5F\x00\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00\x48\x00\x05\x00\x5F\x00\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00" +"\x88\x00\x00\x00\x47\x00\x03\x00\x5F\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x61\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00" +"\x47\x00\x04\x00\x61\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x63\x00\x00\x00\x1E\x00\x00\x00\x02\x00\x00\x00" +"\x47\x00\x04\x00\x64\x00\x00\x00\x1E\x00\x00\x00\x03\x00\x00\x00\x47\x00\x04\x00\x65\x00\x00\x00\x1E\x00\x00\x00\x04\x00\x00\x00" +"\x47\x00\x04\x00\x66\x00\x00\x00\x1E\x00\x00\x00\x05\x00\x00\x00\x47\x00\x04\x00\x67\x00\x00\x00\x1E\x00\x00\x00\x06\x00\x00\x00" "\x13\x00\x02\x00\x02\x00\x00\x00\x21\x00\x03\x00\x03\x00\x00\x00\x02\x00\x00\x00\x16\x00\x03\x00\x06\x00\x00\x00\x20\x00\x00\x00" "\x17\x00\x04\x00\x07\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x21\x00\x03\x00\x08\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00" "\x0B\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00\x18\x00\x04\x00\x0D\x00\x00\x00\x07\x00\x00\x00\x04\x00\x00\x00\x17\x00\x04\x00" @@ -9680,164 +9679,164 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "\x3C\x00\x00\x00\x03\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00\x3E\x00\x00\x00\x03\x00\x00\x00\x12\x00\x00\x00\x3B\x00\x04\x00" "\x3E\x00\x00\x00\x3F\x00\x00\x00\x03\x00\x00\x00\x20\x00\x04\x00\x40\x00\x00\x00\x01\x00\x00\x00\x12\x00\x00\x00\x3B\x00\x04\x00" "\x40\x00\x00\x00\x41\x00\x00\x00\x01\x00\x00\x00\x2B\x00\x04\x00\x0F\x00\x00\x00\x42\x00\x00\x00\x00\x00\x00\x00\x20\x00\x04\x00" -"\x43\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x04\x00\x3E\x00\x00\x00\x4A\x00\x00\x00\x03\x00\x00\x00\x2B\x00\x04\x00" -"\x16\x00\x00\x00\x4B\x00\x00\x00\x04\x00\x00\x00\x20\x00\x04\x00\x4C\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x2B\x00\x04\x00" -"\x06\x00\x00\x00\x4F\x00\x00\x00\x00\x00\x80\x3E\x20\x00\x04\x00\x54\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x04\x00" -"\x3E\x00\x00\x00\x5D\x00\x00\x00\x03\x00\x00\x00\x32\x00\x04\x00\x06\x00\x00\x00\x5F\x00\x00\x00\x00\x00\x80\x43\x1E\x00\x0C\x00" -"\x60\x00\x00\x00\x0D\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00" -"\x07\x00\x00\x00\x12\x00\x00\x00\x12\x00\x00\x00\x20\x00\x04\x00\x61\x00\x00\x00\x02\x00\x00\x00\x60\x00\x00\x00\x3B\x00\x04\x00" -"\x61\x00\x00\x00\x62\x00\x00\x00\x02\x00\x00\x00\x20\x00\x04\x00\x63\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00" -"\x63\x00\x00\x00\x64\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00\x40\x00\x00\x00\x65\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00" -"\x1B\x00\x00\x00\x66\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00\x1B\x00\x00\x00\x67\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00" -"\x1B\x00\x00\x00\x68\x00\x00\x00\x01\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" +"\x43\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x04\x00\x3E\x00\x00\x00\x49\x00\x00\x00\x03\x00\x00\x00\x2B\x00\x04\x00" +"\x16\x00\x00\x00\x4A\x00\x00\x00\x04\x00\x00\x00\x20\x00\x04\x00\x4B\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x2B\x00\x04\x00" +"\x06\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x80\x3E\x20\x00\x04\x00\x53\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x04\x00" +"\x3E\x00\x00\x00\x5C\x00\x00\x00\x03\x00\x00\x00\x32\x00\x04\x00\x06\x00\x00\x00\x5E\x00\x00\x00\x00\x00\x80\x43\x1E\x00\x0C\x00" +"\x5F\x00\x00\x00\x0D\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00\x0E\x00\x00\x00\x06\x00\x00\x00" +"\x07\x00\x00\x00\x12\x00\x00\x00\x12\x00\x00\x00\x20\x00\x04\x00\x60\x00\x00\x00\x02\x00\x00\x00\x5F\x00\x00\x00\x3B\x00\x04\x00" +"\x60\x00\x00\x00\x61\x00\x00\x00\x02\x00\x00\x00\x20\x00\x04\x00\x62\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00" +"\x62\x00\x00\x00\x63\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00\x40\x00\x00\x00\x64\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00" +"\x1B\x00\x00\x00\x65\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00\x1B\x00\x00\x00\x66\x00\x00\x00\x01\x00\x00\x00\x3B\x00\x04\x00" +"\x1B\x00\x00\x00\x67\x00\x00\x00\x01\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00" "\xF8\x00\x02\x00\x05\x00\x00\x00\x39\x00\x04\x00\x07\x00\x00\x00\x3B\x00\x00\x00\x09\x00\x00\x00\x41\x00\x05\x00\x3C\x00\x00\x00" "\x3D\x00\x00\x00\x3A\x00\x00\x00\x17\x00\x00\x00\x3E\x00\x03\x00\x3D\x00\x00\x00\x3B\x00\x00\x00\x41\x00\x05\x00\x43\x00\x00\x00" "\x44\x00\x00\x00\x41\x00\x00\x00\x42\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x45\x00\x00\x00\x44\x00\x00\x00\x41\x00\x05\x00" "\x43\x00\x00\x00\x46\x00\x00\x00\x41\x00\x00\x00\x25\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x47\x00\x00\x00\x46\x00\x00\x00" -"\x83\x00\x05\x00\x06\x00\x00\x00\x48\x00\x00\x00\x1E\x00\x00\x00\x47\x00\x00\x00\x50\x00\x05\x00\x12\x00\x00\x00\x49\x00\x00\x00" -"\x45\x00\x00\x00\x48\x00\x00\x00\x3E\x00\x03\x00\x3F\x00\x00\x00\x49\x00\x00\x00\x41\x00\x05\x00\x4C\x00\x00\x00\x4D\x00\x00\x00" -"\x15\x00\x00\x00\x4B\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x4E\x00\x00\x00\x4D\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00" -"\x50\x00\x00\x00\x4E\x00\x00\x00\x4F\x00\x00\x00\x41\x00\x05\x00\x43\x00\x00\x00\x51\x00\x00\x00\x41\x00\x00\x00\x42\x00\x00\x00" -"\x3D\x00\x04\x00\x06\x00\x00\x00\x52\x00\x00\x00\x51\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x53\x00\x00\x00\x50\x00\x00\x00" -"\x52\x00\x00\x00\x41\x00\x05\x00\x54\x00\x00\x00\x55\x00\x00\x00\x4A\x00\x00\x00\x42\x00\x00\x00\x3E\x00\x03\x00\x55\x00\x00\x00" -"\x53\x00\x00\x00\x41\x00\x05\x00\x4C\x00\x00\x00\x56\x00\x00\x00\x15\x00\x00\x00\x4B\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00" -"\x57\x00\x00\x00\x56\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x58\x00\x00\x00\x57\x00\x00\x00\x4F\x00\x00\x00\x41\x00\x05\x00" -"\x43\x00\x00\x00\x59\x00\x00\x00\x41\x00\x00\x00\x25\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x5A\x00\x00\x00\x59\x00\x00\x00" -"\x81\x00\x05\x00\x06\x00\x00\x00\x5B\x00\x00\x00\x58\x00\x00\x00\x5A\x00\x00\x00\x41\x00\x05\x00\x54\x00\x00\x00\x5C\x00\x00\x00" -"\x4A\x00\x00\x00\x25\x00\x00\x00\x3E\x00\x03\x00\x5C\x00\x00\x00\x5B\x00\x00\x00\x3D\x00\x04\x00\x12\x00\x00\x00\x5E\x00\x00\x00" -"\x41\x00\x00\x00\x3E\x00\x03\x00\x5D\x00\x00\x00\x5E\x00\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00\x36\x00\x05\x00\x07\x00\x00\x00" -"\x09\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\xF8\x00\x02\x00\x0A\x00\x00\x00\x3B\x00\x04\x00\x0B\x00\x00\x00\x0C\x00\x00\x00" -"\x07\x00\x00\x00\x41\x00\x05\x00\x18\x00\x00\x00\x19\x00\x00\x00\x15\x00\x00\x00\x17\x00\x00\x00\x3D\x00\x04\x00\x0D\x00\x00\x00" -"\x1A\x00\x00\x00\x19\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00\x1D\x00\x00\x00\x1C\x00\x00\x00\x51\x00\x05\x00\x06\x00\x00\x00" -"\x1F\x00\x00\x00\x1D\x00\x00\x00\x00\x00\x00\x00\x51\x00\x05\x00\x06\x00\x00\x00\x20\x00\x00\x00\x1D\x00\x00\x00\x01\x00\x00\x00" -"\x51\x00\x05\x00\x06\x00\x00\x00\x21\x00\x00\x00\x1D\x00\x00\x00\x02\x00\x00\x00\x50\x00\x07\x00\x07\x00\x00\x00\x22\x00\x00\x00" -"\x1F\x00\x00\x00\x20\x00\x00\x00\x21\x00\x00\x00\x1E\x00\x00\x00\x91\x00\x05\x00\x07\x00\x00\x00\x23\x00\x00\x00\x1A\x00\x00\x00" -"\x22\x00\x00\x00\x3E\x00\x03\x00\x0C\x00\x00\x00\x23\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x27\x00\x00\x00\x0C\x00\x00\x00" -"\x25\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x28\x00\x00\x00\x27\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x29\x00\x00\x00" -"\x28\x00\x00\x00\x24\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x2A\x00\x00\x00\x0C\x00\x00\x00\x25\x00\x00\x00\x3E\x00\x03\x00" -"\x2A\x00\x00\x00\x29\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x2C\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3D\x00\x04\x00" -"\x06\x00\x00\x00\x2D\x00\x00\x00\x2C\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x2F\x00\x00\x00\x0C\x00\x00\x00\x2E\x00\x00\x00" -"\x3D\x00\x04\x00\x06\x00\x00\x00\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00" -"\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00" -"\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00" -"\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00" -"\x42\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64" -"\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00" -"\x6D\x61\x69\x6E\x00\x00\x00\x00\x13\x00\x00\x00\x1E\x00\x00\x00\x28\x00\x00\x00\x30\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00" -"\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00" -"\x05\x00\x03\x00\x09\x00\x00\x00\x61\x6D\x70\x00\x05\x00\x07\x00\x0B\x00\x00\x00\x63\x76\x61\x72\x5F\x72\x5F\x77\x61\x74\x65\x72" -"\x77\x61\x72\x70\x00\x00\x00\x00\x05\x00\x04\x00\x10\x00\x00\x00\x73\x5F\x74\x32\x00\x00\x00\x00\x05\x00\x04\x00\x13\x00\x00\x00" -"\x76\x5F\x65\x64\x67\x65\x00\x00\x05\x00\x04\x00\x1B\x00\x00\x00\x6F\x66\x66\x73\x65\x74\x00\x00\x05\x00\x04\x00\x1C\x00\x00\x00" -"\x73\x5F\x74\x31\x00\x00\x00\x00\x05\x00\x04\x00\x1E\x00\x00\x00\x76\x5F\x77\x61\x72\x70\x00\x00\x05\x00\x04\x00\x27\x00\x00\x00" -"\x74\x65\x6D\x70\x00\x00\x00\x00\x05\x00\x04\x00\x28\x00\x00\x00\x76\x5F\x73\x74\x63\x00\x00\x00\x05\x00\x05\x00\x30\x00\x00\x00" -"\x6F\x75\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x05\x00\x04\x00\x31\x00\x00\x00\x73\x5F\x74\x30\x00\x00\x00\x00\x05\x00\x05\x00" -"\x3C\x00\x00\x00\x65\x6E\x74\x69\x74\x79\x62\x6C\x6F\x63\x6B\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x00\x00\x00\x00\x6D\x5F\x6D\x6F" -"\x64\x65\x6C\x76\x69\x65\x77\x70\x72\x6F\x6A\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x6D\x5F\x6D\x6F\x64\x65\x6C\x00" -"\x06\x00\x06\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x6D\x5F\x6D\x6F\x64\x65\x6C\x69\x6E\x76\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00" -"\x03\x00\x00\x00\x65\x5F\x65\x79\x65\x70\x6F\x73\x00\x00\x00\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x04\x00\x00\x00\x65\x5F\x74\x69" -"\x6D\x65\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x05\x00\x00\x00\x65\x5F\x6C\x69\x67\x68\x74\x5F\x61\x6D\x62\x69\x65\x6E\x74\x00" -"\x06\x00\x05\x00\x3C\x00\x00\x00\x06\x00\x00\x00\x65\x70\x61\x64\x31\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x07\x00\x00\x00" -"\x65\x5F\x6C\x69\x67\x68\x74\x5F\x64\x69\x72\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x08\x00\x00\x00\x65\x70\x61\x64\x32\x00\x00\x00" -"\x06\x00\x06\x00\x3C\x00\x00\x00\x09\x00\x00\x00\x65\x5F\x6C\x69\x67\x68\x74\x5F\x6D\x75\x6C\x00\x06\x00\x05\x00\x3C\x00\x00\x00" -"\x0A\x00\x00\x00\x65\x70\x61\x64\x33\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x0B\x00\x00\x00\x65\x5F\x6C\x6D\x73\x63\x61\x6C" -"\x65\x73\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x0C\x00\x00\x00\x65\x5F\x75\x70\x70\x65\x72\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00" -"\x06\x00\x05\x00\x3C\x00\x00\x00\x0D\x00\x00\x00\x65\x70\x61\x64\x34\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x0E\x00\x00\x00" -"\x65\x5F\x6C\x6F\x77\x65\x72\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x0F\x00\x00\x00\x65\x70\x61\x64" -"\x35\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x10\x00\x00\x00\x65\x5F\x67\x6C\x6F\x77\x6D\x6F\x64\x00\x00\x00\x06\x00\x05\x00" -"\x3C\x00\x00\x00\x11\x00\x00\x00\x65\x70\x61\x64\x36\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x12\x00\x00\x00\x65\x5F\x63\x6F" -"\x6C\x6F\x75\x72\x69\x64\x65\x6E\x74\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x13\x00\x00\x00\x77\x5F\x66\x6F\x67\x63\x6F\x6C" -"\x6F\x75\x72\x73\x00\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x14\x00\x00\x00\x77\x5F\x66\x6F\x67\x64\x65\x6E\x73\x69\x74\x79" -"\x00\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x15\x00\x00\x00\x77\x5F\x66\x6F\x67\x64\x65\x70\x74\x68\x62\x69\x61\x73\x00\x00" -"\x06\x00\x05\x00\x3C\x00\x00\x00\x16\x00\x00\x00\x65\x70\x61\x64\x37\x00\x00\x00\x05\x00\x03\x00\x3E\x00\x00\x00\x00\x00\x00\x00" -"\x05\x00\x05\x00\x3F\x00\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00\x00\x00\x00\x00" -"\x6C\x5F\x63\x75\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69" -"\x67\x68\x74\x70\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\x3F\x00\x00\x00\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00" -"\x06\x00\x07\x00\x3F\x00\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00" -"\x3F\x00\x00\x00\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00\x3F\x00\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69" -"\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69" -"\x67\x68\x74\x72\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77" -"\x6D\x61\x70\x70\x72\x6F\x6A\x00\x06\x00\x08\x00\x3F\x00\x00\x00\x08\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73" -"\x63\x61\x6C\x65\x00\x00\x00\x00\x06\x00\x05\x00\x3F\x00\x00\x00\x09\x00\x00\x00\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00" -"\x41\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x0B\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x47\x00\x04\x00\x10\x00\x00\x00" -"\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x10\x00\x00\x00\x21\x00\x00\x00\x04\x00\x00\x00\x47\x00\x04\x00\x13\x00\x00\x00" -"\x1E\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x1C\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x1C\x00\x00\x00" -"\x21\x00\x00\x00\x03\x00\x00\x00\x47\x00\x04\x00\x1E\x00\x00\x00\x1E\x00\x00\x00\x01\x00\x00\x00\x47\x00\x04\x00\x28\x00\x00\x00" -"\x1E\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x30\x00\x00\x00\x1E\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x31\x00\x00\x00" -"\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x31\x00\x00\x00\x21\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x3B\x00\x00\x00" -"\x06\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x3C\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" -"\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00" -"\x48\x00\x04\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00" -"\x40\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x3C\x00\x00\x00" -"\x02\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00\x48\x00\x05\x00" -"\x3C\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00" -"\xC0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\xCC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" -"\x05\x00\x00\x00\x23\x00\x00\x00\xD0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\xDC\x00\x00\x00" -"\x48\x00\x05\x00\x3C\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\xE0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x08\x00\x00\x00" -"\x23\x00\x00\x00\xEC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\xF0\x00\x00\x00\x48\x00\x05\x00" -"\x3C\x00\x00\x00\x0A\x00\x00\x00\x23\x00\x00\x00\xFC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0B\x00\x00\x00\x23\x00\x00\x00" -"\x00\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0C\x00\x00\x00\x23\x00\x00\x00\x40\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" -"\x0D\x00\x00\x00\x23\x00\x00\x00\x4C\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0E\x00\x00\x00\x23\x00\x00\x00\x50\x01\x00\x00" -"\x48\x00\x05\x00\x3C\x00\x00\x00\x0F\x00\x00\x00\x23\x00\x00\x00\x5C\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x10\x00\x00\x00" -"\x23\x00\x00\x00\x60\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x11\x00\x00\x00\x23\x00\x00\x00\x6C\x01\x00\x00\x48\x00\x05\x00" -"\x3C\x00\x00\x00\x12\x00\x00\x00\x23\x00\x00\x00\x70\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x13\x00\x00\x00\x23\x00\x00\x00" -"\x80\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x14\x00\x00\x00\x23\x00\x00\x00\x90\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" -"\x15\x00\x00\x00\x23\x00\x00\x00\x94\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x16\x00\x00\x00\x23\x00\x00\x00\x98\x01\x00\x00" -"\x47\x00\x03\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x3E\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00" -"\x3E\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x48\x00\x04\x00\x3F\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00" -"\x3F\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00" -"\x10\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00" -"\x02\x00\x00\x00\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00" -"\x48\x00\x05\x00\x3F\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x05\x00\x00\x00" -"\x23\x00\x00\x00\x60\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x06\x00\x00\x00\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00" -"\x3F\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00" -"\x80\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00\x88\x00\x00\x00\x47\x00\x03\x00\x3F\x00\x00\x00" -"\x02\x00\x00\x00\x47\x00\x04\x00\x41\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x41\x00\x00\x00\x21\x00\x00\x00" -"\x01\x00\x00\x00\x13\x00\x02\x00\x02\x00\x00\x00\x21\x00\x03\x00\x03\x00\x00\x00\x02\x00\x00\x00\x16\x00\x03\x00\x06\x00\x00\x00" -"\x20\x00\x00\x00\x17\x00\x04\x00\x07\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x20\x00\x04\x00\x08\x00\x00\x00\x07\x00\x00\x00" -"\x07\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x0A\x00\x00\x00\x6F\x12\x83\x3C\x32\x00\x04\x00\x06\x00\x00\x00\x0B\x00\x00\x00" -"\x00\x00\x80\x43\x19\x00\x09\x00\x0D\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" -"\x01\x00\x00\x00\x00\x00\x00\x00\x1B\x00\x03\x00\x0E\x00\x00\x00\x0D\x00\x00\x00\x20\x00\x04\x00\x0F\x00\x00\x00\x00\x00\x00\x00" -"\x0E\x00\x00\x00\x3B\x00\x04\x00\x0F\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x20\x00\x04\x00\x12\x00\x00\x00\x01\x00\x00\x00" -"\x07\x00\x00\x00\x3B\x00\x04\x00\x12\x00\x00\x00\x13\x00\x00\x00\x01\x00\x00\x00\x17\x00\x04\x00\x15\x00\x00\x00\x06\x00\x00\x00" -"\x04\x00\x00\x00\x17\x00\x04\x00\x19\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x20\x00\x04\x00\x1A\x00\x00\x00\x07\x00\x00\x00" -"\x19\x00\x00\x00\x3B\x00\x04\x00\x0F\x00\x00\x00\x1C\x00\x00\x00\x00\x00\x00\x00\x3B\x00\x04\x00\x12\x00\x00\x00\x1E\x00\x00\x00" -"\x01\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x3F\x2B\x00\x04\x00\x06\x00\x00\x00\x25\x00\x00\x00" -"\x00\x00\x00\x40\x3B\x00\x04\x00\x12\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x20\x00\x04\x00\x2F\x00\x00\x00\x03\x00\x00\x00" -"\x15\x00\x00\x00\x3B\x00\x04\x00\x2F\x00\x00\x00\x30\x00\x00\x00\x03\x00\x00\x00\x3B\x00\x04\x00\x0F\x00\x00\x00\x31\x00\x00\x00" -"\x00\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x34\x00\x00\x00\x00\x00\x80\x3F\x2C\x00\x05\x00\x07\x00\x00\x00\x35\x00\x00\x00" -"\x34\x00\x00\x00\x34\x00\x00\x00\x18\x00\x04\x00\x38\x00\x00\x00\x15\x00\x00\x00\x04\x00\x00\x00\x15\x00\x04\x00\x39\x00\x00\x00" -"\x20\x00\x00\x00\x00\x00\x00\x00\x2B\x00\x04\x00\x39\x00\x00\x00\x3A\x00\x00\x00\x04\x00\x00\x00\x1C\x00\x04\x00\x3B\x00\x00\x00" -"\x15\x00\x00\x00\x3A\x00\x00\x00\x1E\x00\x19\x00\x3C\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00\x00\x38\x00\x00\x00\x19\x00\x00\x00" -"\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x00\x00" -"\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x15\x00\x00\x00\x15\x00\x00\x00" -"\x06\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00\x3D\x00\x00\x00\x02\x00\x00\x00\x3C\x00\x00\x00\x3B\x00\x04\x00" -"\x3D\x00\x00\x00\x3E\x00\x00\x00\x02\x00\x00\x00\x1E\x00\x0C\x00\x3F\x00\x00\x00\x38\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00" -"\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x15\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00" -"\x40\x00\x00\x00\x02\x00\x00\x00\x3F\x00\x00\x00\x3B\x00\x04\x00\x40\x00\x00\x00\x41\x00\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00" -"\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xF8\x00\x02\x00\x05\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" -"\x09\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x1A\x00\x00\x00\x1B\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00" -"\x27\x00\x00\x00\x07\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x0C\x00\x00\x00\x0A\x00\x00\x00\x0B\x00\x00\x00\x3D\x00\x04\x00" -"\x0E\x00\x00\x00\x11\x00\x00\x00\x10\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x14\x00\x00\x00\x13\x00\x00\x00\x57\x00\x05\x00" -"\x15\x00\x00\x00\x16\x00\x00\x00\x11\x00\x00\x00\x14\x00\x00\x00\x4F\x00\x07\x00\x07\x00\x00\x00\x17\x00\x00\x00\x16\x00\x00\x00" -"\x16\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x8E\x00\x05\x00\x07\x00\x00\x00\x18\x00\x00\x00\x17\x00\x00\x00\x0C\x00\x00\x00" -"\x3E\x00\x03\x00\x09\x00\x00\x00\x18\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00\x1D\x00\x00\x00\x1C\x00\x00\x00\x3D\x00\x04\x00" -"\x07\x00\x00\x00\x1F\x00\x00\x00\x1E\x00\x00\x00\x57\x00\x05\x00\x15\x00\x00\x00\x20\x00\x00\x00\x1D\x00\x00\x00\x1F\x00\x00\x00" -"\x4F\x00\x08\x00\x19\x00\x00\x00\x21\x00\x00\x00\x20\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00" -"\x50\x00\x06\x00\x19\x00\x00\x00\x23\x00\x00\x00\x22\x00\x00\x00\x22\x00\x00\x00\x22\x00\x00\x00\x83\x00\x05\x00\x19\x00\x00\x00" -"\x24\x00\x00\x00\x21\x00\x00\x00\x23\x00\x00\x00\x8E\x00\x05\x00\x19\x00\x00\x00\x26\x00\x00\x00\x24\x00\x00\x00\x25\x00\x00\x00" -"\x3E\x00\x03\x00\x1B\x00\x00\x00\x26\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x29\x00\x00\x00\x28\x00\x00\x00\x3D\x00\x04\x00" -"\x19\x00\x00\x00\x2A\x00\x00\x00\x1B\x00\x00\x00\x4F\x00\x07\x00\x07\x00\x00\x00\x2B\x00\x00\x00\x2A\x00\x00\x00\x2A\x00\x00\x00" -"\x00\x00\x00\x00\x01\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x2C\x00\x00\x00\x09\x00\x00\x00\x85\x00\x05\x00\x07\x00\x00\x00" -"\x2D\x00\x00\x00\x2B\x00\x00\x00\x2C\x00\x00\x00\x81\x00\x05\x00\x07\x00\x00\x00\x2E\x00\x00\x00\x29\x00\x00\x00\x2D\x00\x00\x00" -"\x3E\x00\x03\x00\x27\x00\x00\x00\x2E\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00\x32\x00\x00\x00\x31\x00\x00\x00\x3D\x00\x04\x00" -"\x07\x00\x00\x00\x33\x00\x00\x00\x27\x00\x00\x00\x85\x00\x05\x00\x07\x00\x00\x00\x36\x00\x00\x00\x33\x00\x00\x00\x35\x00\x00\x00" -"\x57\x00\x05\x00\x15\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00\x36\x00\x00\x00\x3E\x00\x03\x00\x30\x00\x00\x00\x37\x00\x00\x00" -"\xFD\x00\x01\x00\x38\x00\x01\x00"}, +"\x50\x00\x05\x00\x12\x00\x00\x00\x48\x00\x00\x00\x45\x00\x00\x00\x47\x00\x00\x00\x3E\x00\x03\x00\x3F\x00\x00\x00\x48\x00\x00\x00" +"\x41\x00\x05\x00\x4B\x00\x00\x00\x4C\x00\x00\x00\x15\x00\x00\x00\x4A\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x4D\x00\x00\x00" +"\x4C\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x4F\x00\x00\x00\x4D\x00\x00\x00\x4E\x00\x00\x00\x41\x00\x05\x00\x43\x00\x00\x00" +"\x50\x00\x00\x00\x41\x00\x00\x00\x42\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x51\x00\x00\x00\x50\x00\x00\x00\x81\x00\x05\x00" +"\x06\x00\x00\x00\x52\x00\x00\x00\x4F\x00\x00\x00\x51\x00\x00\x00\x41\x00\x05\x00\x53\x00\x00\x00\x54\x00\x00\x00\x49\x00\x00\x00" +"\x42\x00\x00\x00\x3E\x00\x03\x00\x54\x00\x00\x00\x52\x00\x00\x00\x41\x00\x05\x00\x4B\x00\x00\x00\x55\x00\x00\x00\x15\x00\x00\x00" +"\x4A\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x56\x00\x00\x00\x55\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x57\x00\x00\x00" +"\x56\x00\x00\x00\x4E\x00\x00\x00\x41\x00\x05\x00\x43\x00\x00\x00\x58\x00\x00\x00\x41\x00\x00\x00\x25\x00\x00\x00\x3D\x00\x04\x00" +"\x06\x00\x00\x00\x59\x00\x00\x00\x58\x00\x00\x00\x81\x00\x05\x00\x06\x00\x00\x00\x5A\x00\x00\x00\x57\x00\x00\x00\x59\x00\x00\x00" +"\x41\x00\x05\x00\x53\x00\x00\x00\x5B\x00\x00\x00\x49\x00\x00\x00\x25\x00\x00\x00\x3E\x00\x03\x00\x5B\x00\x00\x00\x5A\x00\x00\x00" +"\x3D\x00\x04\x00\x12\x00\x00\x00\x5D\x00\x00\x00\x41\x00\x00\x00\x3E\x00\x03\x00\x5C\x00\x00\x00\x5D\x00\x00\x00\xFD\x00\x01\x00" +"\x38\x00\x01\x00\x36\x00\x05\x00\x07\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\xF8\x00\x02\x00\x0A\x00\x00\x00" +"\x3B\x00\x04\x00\x0B\x00\x00\x00\x0C\x00\x00\x00\x07\x00\x00\x00\x41\x00\x05\x00\x18\x00\x00\x00\x19\x00\x00\x00\x15\x00\x00\x00" +"\x17\x00\x00\x00\x3D\x00\x04\x00\x0D\x00\x00\x00\x1A\x00\x00\x00\x19\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00\x1D\x00\x00\x00" +"\x1C\x00\x00\x00\x51\x00\x05\x00\x06\x00\x00\x00\x1F\x00\x00\x00\x1D\x00\x00\x00\x00\x00\x00\x00\x51\x00\x05\x00\x06\x00\x00\x00" +"\x20\x00\x00\x00\x1D\x00\x00\x00\x01\x00\x00\x00\x51\x00\x05\x00\x06\x00\x00\x00\x21\x00\x00\x00\x1D\x00\x00\x00\x02\x00\x00\x00" +"\x50\x00\x07\x00\x07\x00\x00\x00\x22\x00\x00\x00\x1F\x00\x00\x00\x20\x00\x00\x00\x21\x00\x00\x00\x1E\x00\x00\x00\x91\x00\x05\x00" +"\x07\x00\x00\x00\x23\x00\x00\x00\x1A\x00\x00\x00\x22\x00\x00\x00\x3E\x00\x03\x00\x0C\x00\x00\x00\x23\x00\x00\x00\x41\x00\x05\x00" +"\x26\x00\x00\x00\x27\x00\x00\x00\x0C\x00\x00\x00\x25\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x28\x00\x00\x00\x27\x00\x00\x00" +"\x85\x00\x05\x00\x06\x00\x00\x00\x29\x00\x00\x00\x28\x00\x00\x00\x24\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x2A\x00\x00\x00" +"\x0C\x00\x00\x00\x25\x00\x00\x00\x3E\x00\x03\x00\x2A\x00\x00\x00\x29\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x2C\x00\x00\x00" +"\x0C\x00\x00\x00\x2B\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x2D\x00\x00\x00\x2C\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00" +"\x2F\x00\x00\x00\x0C\x00\x00\x00\x2E\x00\x00\x00\x3D\x00\x04\x00\x06\x00\x00\x00\x30\x00\x00\x00\x2F\x00\x00\x00\x81\x00\x05\x00" +"\x06\x00\x00\x00\x31\x00\x00\x00\x2D\x00\x00\x00\x30\x00\x00\x00\x88\x00\x05\x00\x06\x00\x00\x00\x33\x00\x00\x00\x31\x00\x00\x00" +"\x32\x00\x00\x00\x41\x00\x05\x00\x26\x00\x00\x00\x34\x00\x00\x00\x0C\x00\x00\x00\x2B\x00\x00\x00\x3E\x00\x03\x00\x34\x00\x00\x00" +"\x33\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x35\x00\x00\x00\x0C\x00\x00\x00\xFE\x00\x02\x00\x35\x00\x00\x00\x38\x00\x01\x00" +"\x03\x02\x23\x07\x00\x00\x01\x00\x06\x00\x08\x00\x42\x00\x00\x00\x00\x00\x00\x00\x11\x00\x02\x00\x01\x00\x00\x00\x0B\x00\x06\x00" +"\x01\x00\x00\x00\x47\x4C\x53\x4C\x2E\x73\x74\x64\x2E\x34\x35\x30\x00\x00\x00\x00\x0E\x00\x03\x00\x00\x00\x00\x00\x01\x00\x00\x00" +"\x0F\x00\x09\x00\x04\x00\x00\x00\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x13\x00\x00\x00\x1E\x00\x00\x00\x28\x00\x00\x00" +"\x30\x00\x00\x00\x10\x00\x03\x00\x04\x00\x00\x00\x07\x00\x00\x00\x03\x00\x03\x00\x02\x00\x00\x00\xC2\x01\x00\x00\x05\x00\x04\x00" +"\x04\x00\x00\x00\x6D\x61\x69\x6E\x00\x00\x00\x00\x05\x00\x03\x00\x09\x00\x00\x00\x61\x6D\x70\x00\x05\x00\x07\x00\x0B\x00\x00\x00" +"\x63\x76\x61\x72\x5F\x72\x5F\x77\x61\x74\x65\x72\x77\x61\x72\x70\x00\x00\x00\x00\x05\x00\x04\x00\x10\x00\x00\x00\x73\x5F\x74\x32" +"\x00\x00\x00\x00\x05\x00\x04\x00\x13\x00\x00\x00\x76\x5F\x65\x64\x67\x65\x00\x00\x05\x00\x04\x00\x1B\x00\x00\x00\x6F\x66\x66\x73" +"\x65\x74\x00\x00\x05\x00\x04\x00\x1C\x00\x00\x00\x73\x5F\x74\x31\x00\x00\x00\x00\x05\x00\x04\x00\x1E\x00\x00\x00\x76\x5F\x77\x61" +"\x72\x70\x00\x00\x05\x00\x04\x00\x27\x00\x00\x00\x74\x65\x6D\x70\x00\x00\x00\x00\x05\x00\x04\x00\x28\x00\x00\x00\x76\x5F\x73\x74" +"\x63\x00\x00\x00\x05\x00\x05\x00\x30\x00\x00\x00\x6F\x75\x74\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x05\x00\x04\x00\x31\x00\x00\x00" +"\x73\x5F\x74\x30\x00\x00\x00\x00\x05\x00\x05\x00\x3C\x00\x00\x00\x65\x6E\x74\x69\x74\x79\x62\x6C\x6F\x63\x6B\x00\x06\x00\x07\x00" +"\x3C\x00\x00\x00\x00\x00\x00\x00\x6D\x5F\x6D\x6F\x64\x65\x6C\x76\x69\x65\x77\x70\x72\x6F\x6A\x00\x06\x00\x05\x00\x3C\x00\x00\x00" +"\x01\x00\x00\x00\x6D\x5F\x6D\x6F\x64\x65\x6C\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x6D\x5F\x6D\x6F\x64\x65\x6C\x69" +"\x6E\x76\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x03\x00\x00\x00\x65\x5F\x65\x79\x65\x70\x6F\x73\x00\x00\x00\x00\x06\x00\x05\x00" +"\x3C\x00\x00\x00\x04\x00\x00\x00\x65\x5F\x74\x69\x6D\x65\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x05\x00\x00\x00\x65\x5F\x6C\x69" +"\x67\x68\x74\x5F\x61\x6D\x62\x69\x65\x6E\x74\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x06\x00\x00\x00\x65\x70\x61\x64\x31\x00\x00\x00" +"\x06\x00\x06\x00\x3C\x00\x00\x00\x07\x00\x00\x00\x65\x5F\x6C\x69\x67\x68\x74\x5F\x64\x69\x72\x00\x06\x00\x05\x00\x3C\x00\x00\x00" +"\x08\x00\x00\x00\x65\x70\x61\x64\x32\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x09\x00\x00\x00\x65\x5F\x6C\x69\x67\x68\x74\x5F" +"\x6D\x75\x6C\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x0A\x00\x00\x00\x65\x70\x61\x64\x33\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00" +"\x0B\x00\x00\x00\x65\x5F\x6C\x6D\x73\x63\x61\x6C\x65\x73\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x0C\x00\x00\x00\x65\x5F\x75\x70" +"\x70\x65\x72\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x0D\x00\x00\x00\x65\x70\x61\x64\x34\x00\x00\x00" +"\x06\x00\x07\x00\x3C\x00\x00\x00\x0E\x00\x00\x00\x65\x5F\x6C\x6F\x77\x65\x72\x63\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00" +"\x3C\x00\x00\x00\x0F\x00\x00\x00\x65\x70\x61\x64\x35\x00\x00\x00\x06\x00\x06\x00\x3C\x00\x00\x00\x10\x00\x00\x00\x65\x5F\x67\x6C" +"\x6F\x77\x6D\x6F\x64\x00\x00\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x11\x00\x00\x00\x65\x70\x61\x64\x36\x00\x00\x00\x06\x00\x07\x00" +"\x3C\x00\x00\x00\x12\x00\x00\x00\x65\x5F\x63\x6F\x6C\x6F\x75\x72\x69\x64\x65\x6E\x74\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00" +"\x13\x00\x00\x00\x77\x5F\x66\x6F\x67\x63\x6F\x6C\x6F\x75\x72\x73\x00\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x14\x00\x00\x00" +"\x77\x5F\x66\x6F\x67\x64\x65\x6E\x73\x69\x74\x79\x00\x00\x00\x00\x06\x00\x07\x00\x3C\x00\x00\x00\x15\x00\x00\x00\x77\x5F\x66\x6F" +"\x67\x64\x65\x70\x74\x68\x62\x69\x61\x73\x00\x00\x06\x00\x05\x00\x3C\x00\x00\x00\x16\x00\x00\x00\x65\x70\x61\x64\x37\x00\x00\x00" +"\x05\x00\x03\x00\x3E\x00\x00\x00\x00\x00\x00\x00\x05\x00\x05\x00\x3F\x00\x00\x00\x6C\x69\x67\x68\x74\x62\x6C\x6F\x63\x6B\x00\x00" +"\x06\x00\x07\x00\x3F\x00\x00\x00\x00\x00\x00\x00\x6C\x5F\x63\x75\x62\x65\x6D\x61\x74\x72\x69\x78\x00\x00\x00\x00\x06\x00\x07\x00" +"\x3F\x00\x00\x00\x01\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x70\x6F\x73\x69\x74\x69\x6F\x6E\x00\x06\x00\x05\x00\x3F\x00\x00\x00" +"\x02\x00\x00\x00\x6C\x70\x61\x64\x31\x00\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00\x03\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63" +"\x6F\x6C\x6F\x75\x72\x00\x00\x00\x06\x00\x05\x00\x3F\x00\x00\x00\x04\x00\x00\x00\x6C\x70\x61\x64\x32\x00\x00\x00\x06\x00\x08\x00" +"\x3F\x00\x00\x00\x05\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x63\x6F\x6C\x6F\x75\x72\x73\x63\x61\x6C\x65\x00\x00\x06\x00\x07\x00" +"\x3F\x00\x00\x00\x06\x00\x00\x00\x6C\x5F\x6C\x69\x67\x68\x74\x72\x61\x64\x69\x75\x73\x00\x00\x00\x06\x00\x07\x00\x3F\x00\x00\x00" +"\x07\x00\x00\x00\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x70\x72\x6F\x6A\x00\x06\x00\x08\x00\x3F\x00\x00\x00\x08\x00\x00\x00" +"\x6C\x5F\x73\x68\x61\x64\x6F\x77\x6D\x61\x70\x73\x63\x61\x6C\x65\x00\x00\x00\x00\x06\x00\x05\x00\x3F\x00\x00\x00\x09\x00\x00\x00" +"\x6C\x70\x61\x64\x33\x00\x00\x00\x05\x00\x03\x00\x41\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x0B\x00\x00\x00\x01\x00\x00\x00" +"\x00\x01\x00\x00\x47\x00\x04\x00\x10\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x10\x00\x00\x00\x21\x00\x00\x00" +"\x04\x00\x00\x00\x47\x00\x04\x00\x13\x00\x00\x00\x1E\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x1C\x00\x00\x00\x22\x00\x00\x00" +"\x00\x00\x00\x00\x47\x00\x04\x00\x1C\x00\x00\x00\x21\x00\x00\x00\x03\x00\x00\x00\x47\x00\x04\x00\x1E\x00\x00\x00\x1E\x00\x00\x00" +"\x01\x00\x00\x00\x47\x00\x04\x00\x28\x00\x00\x00\x1E\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x30\x00\x00\x00\x1E\x00\x00\x00" +"\x00\x00\x00\x00\x47\x00\x04\x00\x31\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x31\x00\x00\x00\x21\x00\x00\x00" +"\x02\x00\x00\x00\x47\x00\x04\x00\x3B\x00\x00\x00\x06\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x3C\x00\x00\x00\x00\x00\x00\x00" +"\x05\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" +"\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x04\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00" +"\x3C\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00\x40\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00" +"\x10\x00\x00\x00\x48\x00\x04\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x02\x00\x00\x00" +"\x23\x00\x00\x00\x80\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x05\x00" +"\x3C\x00\x00\x00\x03\x00\x00\x00\x23\x00\x00\x00\xC0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00" +"\xCC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00\xD0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" +"\x06\x00\x00\x00\x23\x00\x00\x00\xDC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\xE0\x00\x00\x00" +"\x48\x00\x05\x00\x3C\x00\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\xEC\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x09\x00\x00\x00" +"\x23\x00\x00\x00\xF0\x00\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0A\x00\x00\x00\x23\x00\x00\x00\xFC\x00\x00\x00\x48\x00\x05\x00" +"\x3C\x00\x00\x00\x0B\x00\x00\x00\x23\x00\x00\x00\x00\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0C\x00\x00\x00\x23\x00\x00\x00" +"\x40\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0D\x00\x00\x00\x23\x00\x00\x00\x4C\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" +"\x0E\x00\x00\x00\x23\x00\x00\x00\x50\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x0F\x00\x00\x00\x23\x00\x00\x00\x5C\x01\x00\x00" +"\x48\x00\x05\x00\x3C\x00\x00\x00\x10\x00\x00\x00\x23\x00\x00\x00\x60\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x11\x00\x00\x00" +"\x23\x00\x00\x00\x6C\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x12\x00\x00\x00\x23\x00\x00\x00\x70\x01\x00\x00\x48\x00\x05\x00" +"\x3C\x00\x00\x00\x13\x00\x00\x00\x23\x00\x00\x00\x80\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x14\x00\x00\x00\x23\x00\x00\x00" +"\x90\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00\x15\x00\x00\x00\x23\x00\x00\x00\x94\x01\x00\x00\x48\x00\x05\x00\x3C\x00\x00\x00" +"\x16\x00\x00\x00\x23\x00\x00\x00\x98\x01\x00\x00\x47\x00\x03\x00\x3C\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x3E\x00\x00\x00" +"\x22\x00\x00\x00\x00\x00\x00\x00\x47\x00\x04\x00\x3E\x00\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x48\x00\x04\x00\x3F\x00\x00\x00" +"\x00\x00\x00\x00\x05\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x48\x00\x05\x00" +"\x3F\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x10\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x01\x00\x00\x00\x23\x00\x00\x00" +"\x40\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x02\x00\x00\x00\x23\x00\x00\x00\x4C\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00" +"\x03\x00\x00\x00\x23\x00\x00\x00\x50\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x04\x00\x00\x00\x23\x00\x00\x00\x5C\x00\x00\x00" +"\x48\x00\x05\x00\x3F\x00\x00\x00\x05\x00\x00\x00\x23\x00\x00\x00\x60\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x06\x00\x00\x00" +"\x23\x00\x00\x00\x6C\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x07\x00\x00\x00\x23\x00\x00\x00\x70\x00\x00\x00\x48\x00\x05\x00" +"\x3F\x00\x00\x00\x08\x00\x00\x00\x23\x00\x00\x00\x80\x00\x00\x00\x48\x00\x05\x00\x3F\x00\x00\x00\x09\x00\x00\x00\x23\x00\x00\x00" +"\x88\x00\x00\x00\x47\x00\x03\x00\x3F\x00\x00\x00\x02\x00\x00\x00\x47\x00\x04\x00\x41\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00" +"\x47\x00\x04\x00\x41\x00\x00\x00\x21\x00\x00\x00\x01\x00\x00\x00\x13\x00\x02\x00\x02\x00\x00\x00\x21\x00\x03\x00\x03\x00\x00\x00" +"\x02\x00\x00\x00\x16\x00\x03\x00\x06\x00\x00\x00\x20\x00\x00\x00\x17\x00\x04\x00\x07\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00" +"\x20\x00\x04\x00\x08\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x0A\x00\x00\x00\x6F\x12\x83\x3C" +"\x32\x00\x04\x00\x06\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x80\x43\x19\x00\x09\x00\x0D\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x1B\x00\x03\x00\x0E\x00\x00\x00\x0D\x00\x00\x00" +"\x20\x00\x04\x00\x0F\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x3B\x00\x04\x00\x0F\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00" +"\x20\x00\x04\x00\x12\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x12\x00\x00\x00\x13\x00\x00\x00\x01\x00\x00\x00" +"\x17\x00\x04\x00\x15\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x17\x00\x04\x00\x19\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00" +"\x20\x00\x04\x00\x1A\x00\x00\x00\x07\x00\x00\x00\x19\x00\x00\x00\x3B\x00\x04\x00\x0F\x00\x00\x00\x1C\x00\x00\x00\x00\x00\x00\x00" +"\x3B\x00\x04\x00\x12\x00\x00\x00\x1E\x00\x00\x00\x01\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x3F" +"\x2B\x00\x04\x00\x06\x00\x00\x00\x25\x00\x00\x00\x00\x00\x00\x40\x3B\x00\x04\x00\x12\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00" +"\x20\x00\x04\x00\x2F\x00\x00\x00\x03\x00\x00\x00\x15\x00\x00\x00\x3B\x00\x04\x00\x2F\x00\x00\x00\x30\x00\x00\x00\x03\x00\x00\x00" +"\x3B\x00\x04\x00\x0F\x00\x00\x00\x31\x00\x00\x00\x00\x00\x00\x00\x2B\x00\x04\x00\x06\x00\x00\x00\x34\x00\x00\x00\x00\x00\x80\x3F" +"\x2C\x00\x05\x00\x07\x00\x00\x00\x35\x00\x00\x00\x34\x00\x00\x00\x34\x00\x00\x00\x18\x00\x04\x00\x38\x00\x00\x00\x15\x00\x00\x00" +"\x04\x00\x00\x00\x15\x00\x04\x00\x39\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x2B\x00\x04\x00\x39\x00\x00\x00\x3A\x00\x00\x00" +"\x04\x00\x00\x00\x1C\x00\x04\x00\x3B\x00\x00\x00\x15\x00\x00\x00\x3A\x00\x00\x00\x1E\x00\x19\x00\x3C\x00\x00\x00\x38\x00\x00\x00" +"\x38\x00\x00\x00\x38\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00" +"\x19\x00\x00\x00\x06\x00\x00\x00\x3B\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00" +"\x06\x00\x00\x00\x15\x00\x00\x00\x15\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00\x3D\x00\x00\x00" +"\x02\x00\x00\x00\x3C\x00\x00\x00\x3B\x00\x04\x00\x3D\x00\x00\x00\x3E\x00\x00\x00\x02\x00\x00\x00\x1E\x00\x0C\x00\x3F\x00\x00\x00" +"\x38\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x19\x00\x00\x00\x06\x00\x00\x00\x15\x00\x00\x00" +"\x07\x00\x00\x00\x07\x00\x00\x00\x20\x00\x04\x00\x40\x00\x00\x00\x02\x00\x00\x00\x3F\x00\x00\x00\x3B\x00\x04\x00\x40\x00\x00\x00" +"\x41\x00\x00\x00\x02\x00\x00\x00\x36\x00\x05\x00\x02\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xF8\x00\x02\x00" +"\x05\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00\x09\x00\x00\x00\x07\x00\x00\x00\x3B\x00\x04\x00\x1A\x00\x00\x00\x1B\x00\x00\x00" +"\x07\x00\x00\x00\x3B\x00\x04\x00\x08\x00\x00\x00\x27\x00\x00\x00\x07\x00\x00\x00\x85\x00\x05\x00\x06\x00\x00\x00\x0C\x00\x00\x00" +"\x0A\x00\x00\x00\x0B\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00\x11\x00\x00\x00\x10\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00" +"\x14\x00\x00\x00\x13\x00\x00\x00\x57\x00\x05\x00\x15\x00\x00\x00\x16\x00\x00\x00\x11\x00\x00\x00\x14\x00\x00\x00\x4F\x00\x07\x00" +"\x07\x00\x00\x00\x17\x00\x00\x00\x16\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x8E\x00\x05\x00\x07\x00\x00\x00" +"\x18\x00\x00\x00\x17\x00\x00\x00\x0C\x00\x00\x00\x3E\x00\x03\x00\x09\x00\x00\x00\x18\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00" +"\x1D\x00\x00\x00\x1C\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x1F\x00\x00\x00\x1E\x00\x00\x00\x57\x00\x05\x00\x15\x00\x00\x00" +"\x20\x00\x00\x00\x1D\x00\x00\x00\x1F\x00\x00\x00\x4F\x00\x08\x00\x19\x00\x00\x00\x21\x00\x00\x00\x20\x00\x00\x00\x20\x00\x00\x00" +"\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x50\x00\x06\x00\x19\x00\x00\x00\x23\x00\x00\x00\x22\x00\x00\x00\x22\x00\x00\x00" +"\x22\x00\x00\x00\x83\x00\x05\x00\x19\x00\x00\x00\x24\x00\x00\x00\x21\x00\x00\x00\x23\x00\x00\x00\x8E\x00\x05\x00\x19\x00\x00\x00" +"\x26\x00\x00\x00\x24\x00\x00\x00\x25\x00\x00\x00\x3E\x00\x03\x00\x1B\x00\x00\x00\x26\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00" +"\x29\x00\x00\x00\x28\x00\x00\x00\x3D\x00\x04\x00\x19\x00\x00\x00\x2A\x00\x00\x00\x1B\x00\x00\x00\x4F\x00\x07\x00\x07\x00\x00\x00" +"\x2B\x00\x00\x00\x2A\x00\x00\x00\x2A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x2C\x00\x00\x00" +"\x09\x00\x00\x00\x85\x00\x05\x00\x07\x00\x00\x00\x2D\x00\x00\x00\x2B\x00\x00\x00\x2C\x00\x00\x00\x81\x00\x05\x00\x07\x00\x00\x00" +"\x2E\x00\x00\x00\x29\x00\x00\x00\x2D\x00\x00\x00\x3E\x00\x03\x00\x27\x00\x00\x00\x2E\x00\x00\x00\x3D\x00\x04\x00\x0E\x00\x00\x00" +"\x32\x00\x00\x00\x31\x00\x00\x00\x3D\x00\x04\x00\x07\x00\x00\x00\x33\x00\x00\x00\x27\x00\x00\x00\x85\x00\x05\x00\x07\x00\x00\x00" +"\x36\x00\x00\x00\x33\x00\x00\x00\x35\x00\x00\x00\x57\x00\x05\x00\x15\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00\x36\x00\x00\x00" +"\x3E\x00\x03\x00\x30\x00\x00\x00\x37\x00\x00\x00\xFD\x00\x01\x00\x38\x00\x01\x00"}, #endif #ifdef GLQUAKE {QR_OPENGL, 110, "menutint", "!!cvari r_menutint_inverse\n" "!!cvard_srgb r_menutint\n" +"!!samps 1\n" "#ifdef VERTEX_SHADER\n" "attribute vec2 v_texcoord;\n" @@ -9853,7 +9852,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" "varying vec2 texcoord;\n" -"uniform sampler2D s_t0;\n" "uniform int cvar_r_menutint_inverse;\n" "const vec3 lumfactors = vec3(0.299, 0.587, 0.114);\n" "const vec3 invertvec = vec3(1.0, 1.0, 1.0);\n" @@ -10176,6 +10174,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "terrain", "!!permu FOG\n" +//t0-t3 are the diffusemaps, t4 is the blend factors +"!!samps 5\n" +"!!samps =PCF 6\n" +"!!samps =CUBE 7\n" + +//light levels + "#include \"sys/fog.h\"\n" "varying vec2 tc;\n" "varying vec2 lm;\n" @@ -10249,22 +10254,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef FRAGMENT_SHADER\n" -//four texture passes -"uniform sampler2D s_t0;\n" -"uniform sampler2D s_t1;\n" -"uniform sampler2D s_t2;\n" -"uniform sampler2D s_t3;\n" - -//mix values -"uniform sampler2D s_t4;\n" - "#ifdef PCF\n" -"uniform sampler2DShadow s_t5;\n" "#include \"sys/pcf.h\"\n" "#endif\n" -"#ifdef CUBE\n" -"uniform samplerCube s_t6;\n" -"#endif\n" //light levels "uniform vec4 e_lmscale;\n" @@ -11828,7 +11820,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!permu OFFSETMAPPING\n" "!!permu SKELETAL\n" "!!permu FOG\n" - +"!!samps diffuse\n" // texture units: // s0=diffuse, s1=normal, s2=specular, s3=shadowmap diff --git a/engine/gl/shader.h b/engine/gl/shader.h index e9f056222..3ed883ff7 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -479,61 +479,71 @@ typedef struct { unsigned int handle; } shaderprogparm_t; +struct programpermu_s +{ + union programhandle_u + { + #ifdef GLQUAKE + struct + { + int handle; + qboolean usetesselation; + } glsl; + #endif + #ifdef D3DQUAKE + struct + { + void *vert; + void *frag; + #ifdef D3D9QUAKE + void *ctabf; + void *ctabv; + #endif + #ifdef D3D11QUAKE + int topology; //D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST + void *hull; + void *domain; + void *geom; + void *layouts[2]; + #endif + } hlsl; + #endif + } h; + unsigned int permutation; + unsigned int attrmask; + unsigned int texmask; //'standard' textures that are in use + unsigned int numparms; + shaderprogparm_t *parm; +}; + typedef struct programshared_s { + char *name; int refs; - qboolean nofixedcompat; - qboolean tess; + unsigned nofixedcompat:1; + unsigned tess:2; + unsigned geom:1; + unsigned warned:1; //one of the permutations of this shader has already been warned about. don't warn about all of them because that's potentially spammy. unsigned short numsamplers; //shader system can strip any passes above this unsigned int defaulttextures; //diffuse etc unsigned int supportedpermutations; -#ifdef VKQUAKE unsigned char *cvardata; unsigned int cvardatasize; +#ifdef VKQUAKE qVkShaderModule vert; //for slightly faster regeneration qVkShaderModule frag; qVkPipelineLayout layout; //all permutations share the same layout. I'm too lazy not to. qVkDescriptorSetLayout desclayout; struct pipeline_s *pipelines; #endif -#if defined(GLQUAKE) || defined(D3DQUAKE) - struct programpermu_s - { - union programhandle_u - { - qintptr_t loaded; //generic code must be able to test this to see if its valid. if not 0, then its considered loaded - #ifdef GLQUAKE - struct - { - int handle; - qboolean usetesselation; - } glsl; - #endif - #ifdef D3DQUAKE - struct - { - void *vert; - void *frag; - #ifdef D3D9QUAKE - void *ctabf; - void *ctabv; - #endif - #ifdef D3D11QUAKE - int topology; //D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST - void *hull; - void *domain; - void *geom; - void *layouts[2]; - #endif - } hlsl; - #endif - } h; - unsigned int attrmask; - unsigned int texmask; //'standard' textures that are in use - unsigned int numparms; - shaderprogparm_t *parm; - } permu[PERMUTATIONS]; +#define DELAYEDSHADERCOMPILE +#ifdef DELAYEDSHADERCOMPILE + int shaderver; //glsl version + char *preshade; //general prefixed #defines + char *shadertext; //the glsl text + unsigned char failed[(PERMUTATIONS+7)/8]; //so we don't try recompiling endlessly + struct programpermu_s *permu[PERMUTATIONS]; //set once compiled. #endif } program_t; @@ -716,7 +726,7 @@ void Shader_RemapShader_f(void); void Shader_ShowShader_f(void); program_t *Shader_FindGeneric(char *name, int qrtype); -const char *Shader_NameForGeneric(program_t *prog); +struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p); void Shader_ReleaseGeneric(program_t *prog); image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org); @@ -780,10 +790,10 @@ typedef struct qboolean havecubemaps; //since gl1.3, so pretty much everyone will have this... should probably only be set if we also have seamless or clamp-to-edge. void (*pDeleteProg) (program_t *prog); - qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile); - qboolean (*pCreateProgram) (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); - qboolean (*pValidateProgram)(program_t *prog, const char *name, unsigned int permu, qboolean noerrors, vfsfile_t *blobfile); - void (*pProgAutoFields) (program_t *prog, const char *name, cvar_t **cvars, char **cvarnames, int *cvartypes); + qboolean (*pLoadBlob) (program_t *prog, unsigned int permu, vfsfile_t *blobfile); + qboolean (*pCreateProgram) (program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); + qboolean (*pValidateProgram)(program_t *prog, struct programpermu_s *permu, qboolean noerrors, vfsfile_t *blobfile); + void (*pProgAutoFields) (program_t *prog, struct programpermu_s *permu, cvar_t **cvars, char **cvarnames, int *cvartypes); } sh_config_t; extern sh_config_t sh_config; #endif diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 50ea75cda..0f301fae5 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4848,7 +4848,7 @@ static void QCC_VerifyArgs_setviewprop (const char *funcname, QCC_ref_t **arglis {"VF_SIZE", 4, ev_vector}, {"VF_SIZE_X", 5, ev_float}, {"VF_SIZE_Y", 6, ev_float}, - {"VF_VIEWPORT", 7, ev_vector}, + {"VF_VIEWPORT", 7, ev_vector, ev_vector}, {"VF_FOV", 8, ev_vector}, {"VF_FOVX", 9, ev_float}, {"VF_FOVY", 10, ev_float}, diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 85845c755..ce54a54d4 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -7231,7 +7231,7 @@ static void QCBUILTIN PF_logtext(pubprogfuncs_t *prinst, struct globalvars_s *pr otext = text = PF_VarString(prinst, 2, pr_globals); while (*text) { - int cp = unicode_decode(&err, text, (char**)&text, false); + int cp = unicode_decode(&err, text, &text, false); if ((cp >= 0xe000 && cp < 0xe100) || cp == '\r') cp = readable2[cp&0xff]; //dequake it out += utf8_encode(out, cp, sizeof(unitext)-1-(out-unitext)); @@ -11162,7 +11162,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs // {"matchpattern", PF_Fixme, 0, 0, 0, 538, "float(string s, string pattern, float matchrule)"}, // {"undefined", PF_Fixme, 0, 0, 0, 539, ""}, - {"physics_supported",PF_physics_supported,0, 0, 0, 0, D("float(optional float force)", "Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is used then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map.")}, + {"physics_supported",PF_physics_supported,0, 0, 0, 0, D("float(optional float forcestate)", "Queries whether rigid body physics is enabled or not. CSQC and SSQC may report different values. If the force argument is specified then the engine will try to activate or release physics (returning the new state, which may fail if plugins or dlls are missing). Note that restarting the physics engine is likely to result in hitches when collision trees get generated. The state may change if a plugin is disabled mid-map.")}, #ifdef USERBE {"physics_enable", PF_physics_enable, 0, 0, 0, 540, D("void(entity e, float physics_enabled)", "Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time.")}, {"physics_addforce",PF_physics_addforce,0, 0, 0, 541, D("void(entity e, vector force, vector relative_ofs)", "Apply some impulse directional force upon a MOVETYPE_PHYSICS entity.")}, diff --git a/engine/server/world.c b/engine/server/world.c index e136065db..40d49807e 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -2724,6 +2724,10 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e } } } + /*else if (w->rbe_hasphysicsents && passedict->rbe.body.body) + { + w->rbe->Trace(w, clip.passedict, clip.start, clip.end, &clip.trace); + }*/ else { #ifdef USEAREAGRID diff --git a/engine/shaders/glsl/altwater.glsl b/engine/shaders/glsl/altwater.glsl index 04f2dec33..ca221c385 100644 --- a/engine/shaders/glsl/altwater.glsl +++ b/engine/shaders/glsl/altwater.glsl @@ -1,6 +1,10 @@ !!cvardf r_glsl_turbscale_reflect=1 //simpler scaler !!cvardf r_glsl_turbscale_refract=1 //simpler scaler -!!samps 4 diffuse normalmap +!!samps diffuse normalmap +!!samps refract=0 //always present +!!samps =REFLECT reflect=1 +!!samps =RIPPLEMAP ripplemap=2 +!!samps =DEPTH refractdepth=3 #include "sys/defs.h" @@ -88,11 +92,6 @@ void main (void) #endif -#define s_refract s_t0 -#define s_reflect s_t1 -#define s_ripplemap s_t2 -#define s_refractdepth s_t3 - void main (void) { vec2 stc; //screen tex coords diff --git a/engine/shaders/glsl/bloom_blur.glsl b/engine/shaders/glsl/bloom_blur.glsl index fb9772c19..a3122ddda 100644 --- a/engine/shaders/glsl/bloom_blur.glsl +++ b/engine/shaders/glsl/bloom_blur.glsl @@ -1,3 +1,4 @@ +!!samps 1 //apply gaussian filter varying vec2 tc; @@ -13,7 +14,6 @@ void main () #ifdef FRAGMENT_SHADER /*offset should be 1.2 pixels away from the center*/ uniform vec3 e_glowmod; -uniform sampler2D s_t0; void main () { gl_FragColor = @@ -21,4 +21,4 @@ void main () 0.375 * texture2D(s_t0, tc) + 0.3125 * texture2D(s_t0, tc + e_glowmod.st); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/glsl/bloom_filter.glsl b/engine/shaders/glsl/bloom_filter.glsl index 531b4e9de..f558723c4 100644 --- a/engine/shaders/glsl/bloom_filter.glsl +++ b/engine/shaders/glsl/bloom_filter.glsl @@ -1,4 +1,5 @@ !!cvarv r_bloom_filter +!!samps 1 //the bloom filter //filter out any texels which are not to bloom @@ -14,9 +15,8 @@ void main () #endif #ifdef FRAGMENT_SHADER uniform vec3 cvar_r_bloom_filter; -uniform sampler2D s_t0; void main () { gl_FragColor.rgb = (texture2D(s_t0, tc).rgb - cvar_r_bloom_filter)/(1.0-cvar_r_bloom_filter); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/glsl/bloom_final.glsl b/engine/shaders/glsl/bloom_final.glsl index c19092750..fe650c5da 100644 --- a/engine/shaders/glsl/bloom_final.glsl +++ b/engine/shaders/glsl/bloom_final.glsl @@ -1,5 +1,6 @@ !!cvarf r_bloom !!cvarf r_bloom_retain=1.0 +!!samps 4 //add them together //optionally apply tonemapping @@ -14,10 +15,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; -uniform sampler2D s_t1; -uniform sampler2D s_t2; -uniform sampler2D s_t3; uniform float cvar_r_bloom; uniform float cvar_r_bloom_retain; void main () diff --git a/engine/shaders/glsl/colourtint.glsl b/engine/shaders/glsl/colourtint.glsl index b2d070571..e4aea61b0 100644 --- a/engine/shaders/glsl/colourtint.glsl +++ b/engine/shaders/glsl/colourtint.glsl @@ -1,3 +1,4 @@ +!!samps 2 //this glsl shader is useful for cubemapped post processing effects (see csaddon for an example) varying vec4 tf; #ifdef VERTEX_SHADER @@ -7,8 +8,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; -uniform sampler3D s_t1; void main() { vec2 fc; diff --git a/engine/shaders/glsl/crepuscular_rays.glsl b/engine/shaders/glsl/crepuscular_rays.glsl index 07d7d64ff..e82b068ae 100644 --- a/engine/shaders/glsl/crepuscular_rays.glsl +++ b/engine/shaders/glsl/crepuscular_rays.glsl @@ -1,6 +1,7 @@ !!cvarf crep_decay !!cvarf crep_density !!cvarf crep_weight +!!samps 1 //this is a post-processing shader, drawn in 2d //there will be a render target containing sky surfaces drawn with crepuscular_sky, and everything else drawn with crepuscular_opaque (to mask out the sky) @@ -22,7 +23,6 @@ const float crep_density = 0.5; const float crep_weight = 0.2; uniform vec3 l_lightcolour; uniform vec3 l_lightscreen; -uniform sampler2D s_t0; const int NUM_SAMPLES = 100; void main() { diff --git a/engine/shaders/glsl/crepuscular_sky.glsl b/engine/shaders/glsl/crepuscular_sky.glsl index 2fc49d2ca..79b44c146 100644 --- a/engine/shaders/glsl/crepuscular_sky.glsl +++ b/engine/shaders/glsl/crepuscular_sky.glsl @@ -1,3 +1,4 @@ +!!samps 2 //pretty much a regular sky shader //though in reality we should render a sun circle in the middle. //still, its kinda cool to have scrolling clouds masking out parts of the sun. @@ -14,8 +15,6 @@ void main () uniform float e_time; uniform vec3 e_eyepos; varying vec3 pos; -uniform sampler2D s_t0; -uniform sampler2D s_t1; void main () { vec2 tccoord; diff --git a/engine/shaders/glsl/default2d.glsl b/engine/shaders/glsl/default2d.glsl index 98532eabc..ad5afd308 100644 --- a/engine/shaders/glsl/default2d.glsl +++ b/engine/shaders/glsl/default2d.glsl @@ -1,4 +1,5 @@ !!ver 100-450 +!!samps 1 //this shader is present for support for gles/gl3core contexts //it is single-texture-with-vertex-colours, and doesn't do anything special. @@ -19,7 +20,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; void main () { vec4 f = vc; diff --git a/engine/shaders/glsl/defaultadditivesprite.glsl b/engine/shaders/glsl/defaultadditivesprite.glsl index 1ec33074a..51ab562fd 100644 --- a/engine/shaders/glsl/defaultadditivesprite.glsl +++ b/engine/shaders/glsl/defaultadditivesprite.glsl @@ -1,4 +1,5 @@ !!permu FOG +!!samps 1 //meant to be used for additive stuff. presumably particles and sprites. though actually its only flashblend effects that use this at the time of writing. //includes fog, apparently. @@ -17,7 +18,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; varying vec2 tc; varying vec4 vc; uniform vec4 e_colourident; diff --git a/engine/shaders/glsl/defaultgammacb.glsl b/engine/shaders/glsl/defaultgammacb.glsl index 8a6716365..c57ff14f5 100644 --- a/engine/shaders/glsl/defaultgammacb.glsl +++ b/engine/shaders/glsl/defaultgammacb.glsl @@ -1,4 +1,5 @@ !!ver 100-450 +!!samps 1 //this shader is applies gamma/contrast/brightness to the source image, and dumps it out. varying vec2 tc; @@ -15,7 +16,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; void main () { gl_FragColor = pow(texture2D(s_t0, tc) * vc.g, vec4(vc.r)) + vc.b; diff --git a/engine/shaders/glsl/defaultskin.glsl b/engine/shaders/glsl/defaultskin.glsl index 29afcc77b..095dd1819 100644 --- a/engine/shaders/glsl/defaultskin.glsl +++ b/engine/shaders/glsl/defaultskin.glsl @@ -11,7 +11,8 @@ !!cvarf gl_specular !!cvardf gl_affinemodels=0 !!cvardf r_tessellation_level=5 -!!samps diffuse normalmap specular fullbright upper lower paletted reflectmask reflectcube +!!samps !EIGHTBIT diffuse normalmap specular fullbright upper lower reflectmask reflectcube +!!samps =EIGHTBIT paletted 1 #include "sys/defs.h" @@ -208,7 +209,6 @@ uniform float cvar_gl_specular; #ifdef EIGHTBIT #define s_colourmap s_t0 -uniform sampler2D s_colourmap; #endif affine varying vec2 tc; diff --git a/engine/shaders/glsl/defaultsky.glsl b/engine/shaders/glsl/defaultsky.glsl index d10a83766..1f29a081e 100644 --- a/engine/shaders/glsl/defaultsky.glsl +++ b/engine/shaders/glsl/defaultsky.glsl @@ -1,4 +1,5 @@ !!permu FOG +!!samps 2 #include "sys/fog.h" //regular sky shader for scrolling q1 skies @@ -16,8 +17,6 @@ void main () uniform float e_time; uniform vec3 e_eyepos; varying vec3 pos; -uniform sampler2D s_t0; -uniform sampler2D s_t1; void main () { vec2 tccoord; diff --git a/engine/shaders/glsl/defaultsprite.glsl b/engine/shaders/glsl/defaultsprite.glsl index cf3b6b272..3199554ba 100644 --- a/engine/shaders/glsl/defaultsprite.glsl +++ b/engine/shaders/glsl/defaultsprite.glsl @@ -1,4 +1,5 @@ !!permu FOG +!!samps 1 //used by both particles and sprites. //note the fog blending mode is all that differs from defaultadditivesprite @@ -16,7 +17,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; varying vec2 tc; varying vec4 vc; uniform vec4 e_colourident; diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index 55b1b2ea4..c34f9106f 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -9,7 +9,11 @@ !!permu REFLECTCUBEMASK !!cvarf r_glsl_offsetmapping_scale !!cvardf r_tessellation_level=5 -!!samps diffuse lightmap specular normalmap fullbright reflectmask reflectcube paletted lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3 +!!samps !EIGHTBIT diffuse specular normalmap fullbright reflectmask reflectcube +//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse. +!!samps =EIGHTBIT paletted 1 specular diffuse +!!samps lightmap deluxemap +!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3 #include "sys/defs.h" @@ -224,10 +228,7 @@ void main() #ifdef FRAGMENT_SHADER - -//samplers #define s_colourmap s_t0 -uniform sampler2D s_colourmap; #ifdef OFFSETMAPPING #include "sys/offsetmapping.h" diff --git a/engine/shaders/glsl/drawflat_wall.glsl b/engine/shaders/glsl/drawflat_wall.glsl index 22a94d7dd..7353e32e1 100644 --- a/engine/shaders/glsl/drawflat_wall.glsl +++ b/engine/shaders/glsl/drawflat_wall.glsl @@ -1,6 +1,7 @@ !!cvard_srgb_b r_floorcolor !!cvard_srgb_b r_wallcolor !!permu FOG +!!samps lm:0 //this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals. @@ -23,10 +24,9 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; varying vec2 lm; void main () { - gl_FragColor = fog4(col * texture2D(s_t0, lm)); + gl_FragColor = fog4(col * texture2D(s_lm, lm)); } #endif diff --git a/engine/shaders/glsl/fixedemu.glsl b/engine/shaders/glsl/fixedemu.glsl index a3984d4c6..7dcf2be82 100644 --- a/engine/shaders/glsl/fixedemu.glsl +++ b/engine/shaders/glsl/fixedemu.glsl @@ -1,4 +1,5 @@ !!ver 100-450 +!!samps sourcetex:0 //this shader is present for support for gles/gl3core contexts //it is single-texture-with-vertex-colours, and doesn't do anything special. @@ -22,7 +23,6 @@ void main () } #endif #ifdef FRAGMENT_SHADER -uniform sampler2D s_t0; varying vec2 tc; #ifndef UC varying vec4 vc; @@ -33,7 +33,7 @@ uniform vec4 s_colour; float e_time; void main () { - vec4 fc = texture2D(s_t0, tc) * vc; + vec4 fc = texture2D(s_sourcetex, tc) * vc; #ifdef ALPHATEST if (!(fc.a ALPHATEST)) discard; diff --git a/engine/shaders/glsl/menutint.glsl b/engine/shaders/glsl/menutint.glsl index 5fc063067..187853b85 100644 --- a/engine/shaders/glsl/menutint.glsl +++ b/engine/shaders/glsl/menutint.glsl @@ -1,5 +1,6 @@ !!cvari r_menutint_inverse !!cvard_srgb r_menutint +!!samps 1 #ifdef VERTEX_SHADER attribute vec2 v_texcoord; @@ -15,7 +16,6 @@ #ifdef FRAGMENT_SHADER varying vec2 texcoord; - uniform sampler2D s_t0; uniform int cvar_r_menutint_inverse; const vec3 lumfactors = vec3(0.299, 0.587, 0.114); const vec3 invertvec = vec3(1.0, 1.0, 1.0); @@ -28,4 +28,4 @@ texcolor = (cvar_r_menutint_inverse > 0) ? (invertvec - texcolor) : texcolor; gl_FragColor = vec4(texcolor, 1.0); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/glsl/postproc_ascii.glsl b/engine/shaders/glsl/postproc_ascii.glsl index 37bad25a0..26edf6770 100644 --- a/engine/shaders/glsl/postproc_ascii.glsl +++ b/engine/shaders/glsl/postproc_ascii.glsl @@ -1,5 +1,5 @@ !!cvardf r_glsl_ascii_mono=0 -!!samps 1 +!!samps screen=0 //derived from https://www.shadertoy.com/view/lssGDj @@ -30,7 +30,7 @@ float character(float n, vec2 p) void main(void) { vec2 uv = floor(texcoord.xy * e_sourcesize); //in pixels. - vec3 col = texture2D(s_t0, (floor(uv/8.0)*8.0+4.0)/e_sourcesize.xy).rgb; + vec3 col = texture2D(s_screen, (floor(uv/8.0)*8.0+4.0)/e_sourcesize.xy).rgb; float gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b; @@ -56,4 +56,4 @@ void main(void) col = col*character(n, p); //note that this is kinda cheating. gl_FragColor = vec4(col, 1.0); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/glsl/postproc_equirectangular.glsl b/engine/shaders/glsl/postproc_equirectangular.glsl index 14b81cc3a..6b522e347 100644 --- a/engine/shaders/glsl/postproc_equirectangular.glsl +++ b/engine/shaders/glsl/postproc_equirectangular.glsl @@ -1,4 +1,5 @@ !!cvarf ffov +!!samps screen:samplerCube=0 //equirectangular view rendering, commonly used for sphere->2d map projections. @@ -12,7 +13,6 @@ void main() } #endif #ifdef FRAGMENT_SHADER -uniform samplerCube s_t0; varying vec2 texcoord; uniform float cvar_ffov; @@ -26,6 +26,6 @@ void main() tc.z = cos(lng) * sin(lat); tc.x = sin(lng) * sin(lat); tc.y = cos(lat); - gl_FragColor = textureCube(s_t0, tc); + gl_FragColor = textureCube(s_screen, tc); } #endif diff --git a/engine/shaders/glsl/postproc_fisheye.glsl b/engine/shaders/glsl/postproc_fisheye.glsl index a5899a33d..278932d0d 100644 --- a/engine/shaders/glsl/postproc_fisheye.glsl +++ b/engine/shaders/glsl/postproc_fisheye.glsl @@ -1,4 +1,5 @@ !!cvarf ffov +!!samps screen:samplerCube=0 //fisheye view rendering, for silly fovs that are still playable. @@ -12,7 +13,6 @@ void main() } #endif #ifdef FRAGMENT_SHADER -uniform samplerCube s_t0; varying vec2 texcoord; uniform float cvar_ffov; void main() @@ -26,6 +26,6 @@ void main() tc.x = sin(ang.x) * cos(ang.y); tc.y = sin(ang.x) * sin(ang.y); tc.z = cos(ang.x); - gl_FragColor = textureCube(s_t0, tc); + gl_FragColor = textureCube(s_screen, tc); } #endif diff --git a/engine/shaders/glsl/postproc_laea.glsl b/engine/shaders/glsl/postproc_laea.glsl index 6f1f5d204..22f2210d1 100644 --- a/engine/shaders/glsl/postproc_laea.glsl +++ b/engine/shaders/glsl/postproc_laea.glsl @@ -1,4 +1,5 @@ !!cvarf ffov +!!samps screen:samplerCube=0 //my attempt at lambert azimuthal equal-area view rendering, because you'll remember that name easily. @@ -17,7 +18,6 @@ void main() } #endif #ifdef FRAGMENT_SHADER -uniform samplerCube s_t0; varying vec2 texcoord; void main() { @@ -39,7 +39,7 @@ void main() tc.y *= -1.0; tc.z *= -1.0; - gl_FragColor = textureCube(s_t0, tc); + gl_FragColor = textureCube(s_screen, tc); } } #endif diff --git a/engine/shaders/glsl/postproc_panorama.glsl b/engine/shaders/glsl/postproc_panorama.glsl index 57a41fa1b..8c6cc006c 100644 --- a/engine/shaders/glsl/postproc_panorama.glsl +++ b/engine/shaders/glsl/postproc_panorama.glsl @@ -1,4 +1,5 @@ !!cvarf ffov +!!samps screen:samplerCube=0 //panoramic view rendering, for promo map shots or whatever. @@ -12,7 +13,6 @@ void main() } #endif #ifdef FRAGMENT_SHADER -uniform samplerCube s_t0; varying vec2 texcoord; uniform float cvar_ffov; void main() @@ -23,6 +23,6 @@ void main() tc.x = sin(ang); tc.y = -texcoord.y; tc.z = cos(ang); - gl_FragColor = textureCube(s_t0, tc); + gl_FragColor = textureCube(s_screen, tc); } #endif diff --git a/engine/shaders/glsl/postproc_stereographic.glsl b/engine/shaders/glsl/postproc_stereographic.glsl index 46200dc88..da0858850 100644 --- a/engine/shaders/glsl/postproc_stereographic.glsl +++ b/engine/shaders/glsl/postproc_stereographic.glsl @@ -1,4 +1,5 @@ !!cvarf ffov +!!samps screen:samplerCube=0 //stereographic view rendering, for high fovs that are still playable. @@ -17,7 +18,6 @@ void main() } #endif #ifdef FRAGMENT_SHADER -uniform samplerCube s_t0; varying vec2 texcoord; void main() { @@ -32,6 +32,6 @@ void main() tc.y = -2.0*d.y/div; tc.z = -(-1.0 + d.x*d.x + d.y*d.y)/div; - gl_FragColor = textureCube(s_t0, tc); + gl_FragColor = textureCube(s_screen, tc); } #endif diff --git a/engine/shaders/glsl/terrain.glsl b/engine/shaders/glsl/terrain.glsl index 38377c4d4..39c686256 100644 --- a/engine/shaders/glsl/terrain.glsl +++ b/engine/shaders/glsl/terrain.glsl @@ -1,4 +1,11 @@ !!permu FOG +//t0-t3 are the diffusemaps, t4 is the blend factors +!!samps 5 +!!samps =PCF 6 +!!samps =CUBE 7 + +//light levels + #include "sys/fog.h" varying vec2 tc; varying vec2 lm; @@ -72,22 +79,9 @@ void main (void) #ifdef FRAGMENT_SHADER -//four texture passes -uniform sampler2D s_t0; -uniform sampler2D s_t1; -uniform sampler2D s_t2; -uniform sampler2D s_t3; - -//mix values -uniform sampler2D s_t4; - #ifdef PCF - uniform sampler2DShadow s_t5; #include "sys/pcf.h" #endif -#ifdef CUBE - uniform samplerCube s_t6; -#endif //light levels uniform vec4 e_lmscale; @@ -151,4 +145,4 @@ void main (void) gl_FragColor = fog4(r); #endif } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/glsl/underwaterwarp.glsl b/engine/shaders/glsl/underwaterwarp.glsl index 47c9501bd..171404127 100644 --- a/engine/shaders/glsl/underwaterwarp.glsl +++ b/engine/shaders/glsl/underwaterwarp.glsl @@ -1,13 +1,14 @@ !!cvarf r_waterwarp +!!samps screen=0 warp=1 edge=2 //this is a post processing shader that is drawn fullscreen whenever the view is underwater. //its generally expected to warp the view a little. -#ifdef VERTEX_SHADER -attribute vec2 v_texcoord; varying vec2 v_stc; varying vec2 v_warp; varying vec2 v_edge; +#ifdef VERTEX_SHADER +attribute vec2 v_texcoord; uniform float e_time; void main () { @@ -19,19 +20,13 @@ void main () } #endif #ifdef FRAGMENT_SHADER -varying vec2 v_stc; -varying vec2 v_warp; -varying vec2 v_edge; -uniform sampler2D s_t0;/*$currentrender*/ -uniform sampler2D s_t1;/*warp image*/ -uniform sampler2D s_t2;/*edge image*/ uniform vec4 e_rendertexturescale; uniform float cvar_r_waterwarp; void main () { - vec2 amp = (0.010 / 0.625) * cvar_r_waterwarp * texture2D(s_t2, v_edge).rg; - vec3 offset = (texture2D(s_t1, v_warp).rgb - 0.5) * 2.0; + vec2 amp = (0.010 / 0.625) * cvar_r_waterwarp * texture2D(s_edge, v_edge).rg; + vec3 offset = (texture2D(s_warp, v_warp).rgb - 0.5) * 2.0; vec2 temp = v_stc + offset.xy * amp; - gl_FragColor = texture2D(s_t0, temp*e_rendertexturescale.st); + gl_FragColor = texture2D(s_screen, temp*e_rendertexturescale.st); } #endif diff --git a/engine/shaders/hlsl9/defaultskin.hlsl b/engine/shaders/hlsl9/defaultskin.hlsl index a72521cfd..79fe9af64 100644 --- a/engine/shaders/hlsl9/defaultskin.hlsl +++ b/engine/shaders/hlsl9/defaultskin.hlsl @@ -1,5 +1,9 @@ !!permu FRAMEBLEND !!permu UPPERLOWER +//!!permu FULLBRIGHT +!!samps diffuse upper lower +// fullbright + struct a2v { float3 pos: POSITION0; @@ -70,7 +74,7 @@ sampler s_fullbright; /*fullbright*/ col.rgb *= inp.light; #ifdef FULLBRIGHT float4 fb = tex2D(s_fullbright, inp.tc); - col.rgb = mix(col.rgb, fb.rgb, fb.a); + col.rgb = lerp(col.rgb, fb.rgb, fb.a); #endif return col * e_colourident; // return fog4(col * e_colourident); diff --git a/engine/shaders/hlsl9/defaultsky.hlsl b/engine/shaders/hlsl9/defaultsky.hlsl index 6cf8c59df..1524934b8 100644 --- a/engine/shaders/hlsl9/defaultsky.hlsl +++ b/engine/shaders/hlsl9/defaultsky.hlsl @@ -1,3 +1,5 @@ +!!samps 2 + struct a2v { float4 pos: POSITION; @@ -12,11 +14,11 @@ #ifdef VERTEX_SHADER float4x4 m_modelviewprojection; - v2f main (a2v inp) + v2f main (in a2v inp) { v2f outp; outp.pos = mul(m_modelviewprojection, inp.pos); - outp.vpos = inp.pos; + outp.vpos = inp.pos.xyz; return outp; } #endif @@ -41,7 +43,6 @@ tccoord = (dir.xy + e_time*0.0625); float4 clouds = tex2D(s_fullbright, tccoord); - return float4((solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb), 1); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/hlsl9/defaultskybox.hlsl b/engine/shaders/hlsl9/defaultskybox.hlsl index 64bdc11f4..3e3e14bf2 100644 --- a/engine/shaders/hlsl9/defaultskybox.hlsl +++ b/engine/shaders/hlsl9/defaultskybox.hlsl @@ -1,3 +1,5 @@ +!!samps reflectcube + struct a2v { float4 pos: POSITION; @@ -30,4 +32,4 @@ tc.y = -tc.y; return texCUBE(s_reflectcube, tc); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/hlsl9/defaultwarp.hlsl b/engine/shaders/hlsl9/defaultwarp.hlsl index d2b8fcf70..aa521bbcc 100644 --- a/engine/shaders/hlsl9/defaultwarp.hlsl +++ b/engine/shaders/hlsl9/defaultwarp.hlsl @@ -1,4 +1,6 @@ !!cvarf r_wateralpha +!!samps diffuse + struct a2v { float4 pos: POSITION; float2 tc: TEXCOORD0; diff --git a/engine/shaders/hlsl9/drawflat_wall.hlsl b/engine/shaders/hlsl9/drawflat_wall.hlsl index 81f243487..53195dd6d 100644 --- a/engine/shaders/hlsl9/drawflat_wall.hlsl +++ b/engine/shaders/hlsl9/drawflat_wall.hlsl @@ -1,5 +1,6 @@ !!cvard3 r_floorcolour !!cvard3 r_wallcolour +!!samps 1 //FIXME !!permu FOG struct a2v { diff --git a/engine/shaders/hlsl9/rtlight.hlsl b/engine/shaders/hlsl9/rtlight.hlsl index 381da4ce0..e4846608f 100644 --- a/engine/shaders/hlsl9/rtlight.hlsl +++ b/engine/shaders/hlsl9/rtlight.hlsl @@ -3,7 +3,7 @@ !!permu OFFSETMAPPING !!permu SKELETAL !!permu FOG - +!!samps diffuse // texture units: // s0=diffuse, s1=normal, s2=specular, s3=shadowmap @@ -62,4 +62,4 @@ #endif return float4(diff * col, 1); } -#endif \ No newline at end of file +#endif diff --git a/engine/shaders/vulkan/underwaterwarp.glsl b/engine/shaders/vulkan/underwaterwarp.glsl index b3efd3d02..773c56c62 100644 --- a/engine/shaders/vulkan/underwaterwarp.glsl +++ b/engine/shaders/vulkan/underwaterwarp.glsl @@ -14,7 +14,7 @@ layout(location=2) varying vec2 v_edge; void main () { gl_Position = ftetransform(); - v_stc = vec2(v_texcoord.x, 1.0-v_texcoord.y); + v_stc = vec2(v_texcoord.x, /*1.0-*/v_texcoord.y); v_warp.s = e_time * 0.25 + v_texcoord.s; v_warp.t = e_time * 0.25 + v_texcoord.t; v_edge = v_texcoord.xy; diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 61c4e3121..ce9127840 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1028,9 +1028,9 @@ VkShaderModule VK_CreateGLSLModule(program_t *prog, const char *name, int ver, c return mod; } -qboolean VK_LoadGLSL(program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile) +qboolean VK_LoadGLSL(program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile) { - if (permu) //FIXME... + if (permu->permutation) //FIXME... return false; prog->nofixedcompat = false; @@ -1038,10 +1038,10 @@ qboolean VK_LoadGLSL(program_t *prog, const char *name, unsigned int permu, int prog->cvardata = NULL; prog->cvardatasize = 0; prog->pipelines = NULL; - prog->vert = VK_CreateGLSLModule(prog, name, ver, precompilerconstants, vert, false); - prog->frag = VK_CreateGLSLModule(prog, name, ver, precompilerconstants, frag, true); + prog->vert = VK_CreateGLSLModule(prog, prog->name, ver, precompilerconstants, vert, false); + prog->frag = VK_CreateGLSLModule(prog, prog->name, ver, precompilerconstants, frag, true); - VK_FinishProg(prog, name); + VK_FinishProg(prog, prog->name); return true; } diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 5047b4d3f..b1e10ed0a 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -2346,6 +2346,8 @@ static qboolean VK_R_RenderScene_Cubemap(struct vk_rendertarg *fb) if (R2D_Flush) Con_Printf("no flush\n"); + + VKBE_RT_End(&rtc->face[i]); } r_refdef.vrect = vrect; diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 10900ee66..cbdbc3192 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -434,7 +434,8 @@ void VK_R_BloomShutdown(void); qboolean R_CanBloom(void); struct programshared_s; -qboolean VK_LoadGLSL(struct programshared_s *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); +struct programpermu_s; +qboolean VK_LoadGLSL(struct programshared_s *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); VkCommandBuffer VK_AllocFrameCBuf(void); void VK_Submit_Work(VkCommandBuffer cmdbuf, VkSemaphore semwait, VkPipelineStageFlags semwaitstagemask, VkSemaphore semsignal, VkFence fencesignal, struct vkframe *presentframe, struct vk_fencework *fencedwork); diff --git a/plugins/bullet/bulletplug.cpp b/plugins/bullet/bulletplug.cpp index 1e854cebd..2979dcbfb 100644 --- a/plugins/bullet/bulletplug.cpp +++ b/plugins/bullet/bulletplug.cpp @@ -924,6 +924,7 @@ public: VectorNegate(axis[1], axis[1]); VectorAvg(edict->rbe.mins, edict->rbe.maxs, offset); VectorMA(edict->v->origin, offset[0]*1, axis[0], org); + org[3] = 0;//for sse. VectorMA(org, offset[1]*1, axis[1], org); VectorMA(org, offset[2]*1, axis[2], org); @@ -1705,8 +1706,11 @@ static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd) case RBECMD_FORCE: if (body) { + btVector3 relativepos; + const btVector3 ¢er = body->getCenterOfMassPosition(); + VectorSubtract(cmd->v2, center, relativepos); body->setActivationState(1); - body->applyForce(btVector3(cmd->v1[0], cmd->v1[1], cmd->v1[2]), btVector3(cmd->v2[0], cmd->v2[1], cmd->v2[2])); + body->applyImpulse(btVector3(cmd->v1[0], cmd->v1[1], cmd->v1[2]), relativepos); } break; case RBECMD_TORQUE: @@ -1736,26 +1740,48 @@ static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *va ctx->cmdqueuetail = ctx->cmdqueuehead = cmd; } -/* -static void QDECL World_Bullet_TraceEntity(world_t *world, vec3_t start, vec3_t end, wedict_t *ed) +static void QDECL World_Bullet_TraceEntity(world_t *world, wedict_t *ed, vec3_t start, vec3_t end, trace_t *trace) { struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe; btCollisionShape *shape = (btCollisionShape*)ed->rbe.body.geom; +//btCollisionAlgorithm class myConvexResultCallback : public btCollisionWorld::ConvexResultCallback { public: + void *m_impactent; + btVector3 m_impactpos; + btVector3 m_impactnorm; virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) { + if (m_closestHitFraction > convexResult.m_hitFraction) + { + m_closestHitFraction = convexResult.m_hitFraction; + m_impactpos = convexResult.m_hitPointLocal; + m_impactnorm = convexResult.m_hitNormalLocal; + m_impactent = convexResult.m_hitCollisionObject->getUserPointer(); + } return 0; } } result; + result.m_impactent = NULL; + result.m_closestHitFraction = trace->fraction; btTransform from(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(start[0], start[1], start[2])); btTransform to(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(end[0], end[1], end[2])); ctx->dworld->convexSweepTest((btConvexShape*)shape, from, to, result, 1); + + if (result.m_impactent) + { + memset(trace, 0, sizeof(*trace)); + trace->fraction = trace->truefraction = result.m_closestHitFraction; + VectorInterpolate(start, result.m_closestHitFraction, end, trace->endpos); +// VectorCopy(result.m_impactpos, trace->endpos); + VectorCopy(result.m_impactnorm, trace->plane.normal); + trace->ent = result.m_impactent; + trace->startsolid = qfalse; //FIXME: we don't really know + } } -*/ static void QDECL World_Bullet_Start(world_t *world) { @@ -1782,6 +1808,7 @@ static void QDECL World_Bullet_Start(world_t *world) ctx->funcs.RagDestroyJoint = World_Bullet_RagDestroyJoint; ctx->funcs.RunFrame = World_Bullet_Frame; ctx->funcs.PushCommand = World_Bullet_PushCommand; + ctx->funcs.Trace = World_Bullet_TraceEntity; world->rbe = &ctx->funcs;