diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e4f1825f0..bbe9286d94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -689,6 +689,7 @@ if (BUILD_CLIENT OR WIN32) endif() find_package(SDL3 REQUIRED CONFIG) + message("Found SDL3 ${SDL3_VERSION}: ${SDL3_DIR}") if (WIN32) set(LIBS_ENGINE_BASE ${LIBS_ENGINE_BASE} SDL3::SDL3) diff --git a/cmake/DaemonArchitecture.cmake b/cmake/DaemonArchitecture.cmake index cbf0033b0b..73962ac408 100644 --- a/cmake/DaemonArchitecture.cmake +++ b/cmake/DaemonArchitecture.cmake @@ -81,6 +81,17 @@ if (LINUX OR FREEBSD) # The nexe is system agnostic so there should be no difference with armel. set(NACL_ARCH "armhf") endif() + + set(BOX64_USAGE ppc64el riscv64) + if (ARCH IN_LIST BOX64_USAGE) + option(DAEMON_NACL_BOX64_EMULATION "Use Box64 to emulate x86_64 NaCl loader on unsupported platforms" ON) + if (DAEMON_NACL_BOX64_EMULATION) + # Use Box64 to run x86_64 NaCl loader and amd64 nexe. + # Box64 must be installed and available in PATH at runtime. + set(NACL_ARCH "amd64") + add_definitions(-DDAEMON_NACL_BOX64_EMULATION) + endif() + endif() elseif(APPLE) if ("${ARCH}" STREQUAL arm64) # You can get emulated NaCl going like this: @@ -91,6 +102,12 @@ endif() daemon_add_buildinfo("char*" "DAEMON_NACL_ARCH_STRING" "\"${NACL_ARCH}\"") +# NaCl runtime is only available on architectures that have a NaCl loader. +set(NACL_RUNTIME_ARCH amd64 i686 armhf) +if (NACL_ARCH IN_LIST NACL_RUNTIME_ARCH) + add_definitions(-DDAEMON_NACL_RUNTIME_ENABLED) +endif() + option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON) mark_as_advanced(USE_ARCH_INTRINSICS) @@ -111,6 +128,7 @@ set_arch_intrinsics(${ARCH}) set(amd64_PARENT "i686") set(arm64_PARENT "armhf") +set(ppc64el_PARENT "ppc64") if (${ARCH}_PARENT) set_arch_intrinsics(${${ARCH}_PARENT}) diff --git a/cmake/DaemonCBSE.cmake b/cmake/DaemonCBSE.cmake index 6cfdbbbc8c..66b50564a1 100644 --- a/cmake/DaemonCBSE.cmake +++ b/cmake/DaemonCBSE.cmake @@ -45,7 +45,7 @@ function(CBSE target definition output) COMMAND ${DAEMON_CBSE_PYTHON_PATH} -c "import jinja2, yaml, collections, argparse, sys, os.path, re" RESULT_VARIABLE RET) if (NOT RET EQUAL 0) - message(FATAL_ERROR "Missing dependences for CBSE generation. Please ensure you have python ≥ 2, python-yaml, and python-jinja installed. + message(FATAL_ERROR "Missing dependences for CBSE generation. Please ensure you have python with python-yaml and python-jinja installed. Use pip install -r src/utils/cbse/requirements.txt to install") endif() set(GENERATED_CBSE ${output}/backend/CBSEBackend.cpp diff --git a/cmake/DaemonFlags.cmake b/cmake/DaemonFlags.cmake index 0170401998..53c733b555 100644 --- a/cmake/DaemonFlags.cmake +++ b/cmake/DaemonFlags.cmake @@ -659,6 +659,18 @@ elseif (NOT NACL) set(GCC_GENERIC_ARCH "armv6") # There is no generic tuning option for armv6. unset(GCC_GENERIC_TUNE) + elseif (ARCH STREQUAL "ppc64el") + # POWER8 minimum (first little-endian POWER). + # GCC uses -mcpu instead of -march/-mtune for POWER. + unset(GCC_GENERIC_ARCH) + unset(GCC_GENERIC_TUNE) + set(GCC_GENERIC_CPU "power8") + elseif (ARCH STREQUAL "ppc64") + # POWER5 minimum (first 64-bit POWER in wide use). + # GCC uses -mcpu instead of -march/-mtune for POWER. + unset(GCC_GENERIC_ARCH) + unset(GCC_GENERIC_TUNE) + set(GCC_GENERIC_CPU "power5") else() message(WARNING "Unknown architecture ${ARCH}") endif() @@ -676,6 +688,11 @@ elseif (NOT NACL) if (GCC_GENERIC_TUNE) try_c_cxx_flag_werror(MTUNE "-mtune=${GCC_GENERIC_TUNE}") endif() + + # POWER architectures use -mcpu instead of -march/-mtune. + if (GCC_GENERIC_CPU) + try_c_cxx_flag_werror(MCPU "-mcpu=${GCC_GENERIC_CPU}") + endif() endif() if (USE_CPU_RECOMMENDED_FEATURES) diff --git a/cmake/DaemonNacl.cmake b/cmake/DaemonNacl.cmake index f3310514ee..a763cddb82 100644 --- a/cmake/DaemonNacl.cmake +++ b/cmake/DaemonNacl.cmake @@ -72,7 +72,11 @@ else() elseif( NACL_ARCH STREQUAL "armhf" ) add_definitions( -DNACL_BUILD_ARCH=arm ) else() - message(WARNING "Unknown architecture ${NACL_ARCH}") + # NaCl does not support this architecture natively, but these defines must + # be set because nacl_config.h is included unconditionally. Use dummy x86 + # values as PNaCl does for architecture-independent builds. + add_definitions( -DNACL_BUILD_ARCH=x86 ) + add_definitions( -DNACL_BUILD_SUBARCH=64 ) endif() endif() diff --git a/src/common/Defs.h b/src/common/Defs.h index 1c2fd6f0d3..b672b20b42 100644 --- a/src/common/Defs.h +++ b/src/common/Defs.h @@ -64,7 +64,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define TEAMCONFIG_NAME "teamconfig.cfg" #define UNNAMED_PLAYER "UnnamedPlayer" -#define UNNAMED_SERVER PRODUCT_NAME " " PRODUCT_VERSION " Server" +#define UNNAMED_SERVER "Unnamed " PRODUCT_NAME " Server" /** file containing our RSA public and private keys */ #define RSAKEY_FILE "pubkey" diff --git a/src/common/FileSystem.cpp b/src/common/FileSystem.cpp index 45bd66b8b0..abed38d07f 100644 --- a/src/common/FileSystem.cpp +++ b/src/common/FileSystem.cpp @@ -477,6 +477,27 @@ std::string Build(Str::StringRef base, Str::StringRef path) return out; } +std::string NormalizeSlashes(Str::StringRef path) +{ + std::string out; + out.reserve(path.size()); + bool lastSlash = true; + + for (char c : path) { + if (c == '/' || c == '\\') { + if (!lastSlash) { + lastSlash = true; + out.push_back('/'); + } + } else { + out.push_back( c ); + lastSlash = false; + } + } + + return out; +} + std::string DirName(Str::StringRef path) { if (path.empty()) diff --git a/src/common/FileSystem.h b/src/common/FileSystem.h index 725afa66d8..787e95bb43 100644 --- a/src/common/FileSystem.h +++ b/src/common/FileSystem.h @@ -177,6 +177,11 @@ namespace Path { // Build a path from components std::string Build(Str::StringRef base, Str::StringRef path); + // Replace \ with / + // Remove multiple consecutive slashes + // Remove initial slashes + std::string NormalizeSlashes(Str::StringRef path); + // Get the directory portion of a path: // a/b/c => a/b // a/b/ => a diff --git a/src/common/cm/cm_local.h b/src/common/cm/cm_local.h index 09ff99311d..4f0d21902e 100644 --- a/src/common/cm/cm_local.h +++ b/src/common/cm/cm_local.h @@ -32,6 +32,9 @@ Maryland 20850 USA. =========================================================================== */ +#ifndef COMMON_CM_CM_LOCAL_H_ +#define COMMON_CM_CM_LOCAL_H_ + #include "cm_public.h" #include "cm_polylib.h" @@ -313,3 +316,5 @@ bool CM_BoundsIntersect( const vec3_t mins, const vec3_t m bool CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point ); // XreaL END + +#endif // COMMON_CM_CM_LOCAL_H_ diff --git a/src/common/cm/cm_patch.h b/src/common/cm/cm_patch.h index 09f4237912..5bc9fd50fd 100644 --- a/src/common/cm/cm_patch.h +++ b/src/common/cm/cm_patch.h @@ -32,6 +32,9 @@ Maryland 20850 USA. =========================================================================== */ +#ifndef COMMON_CM_CM_PATCH_H_ +#define COMMON_CM_CM_PATCH_H_ + //#define CULL_BBOX /* @@ -86,3 +89,5 @@ void CM_SetGridWrapWidth( cGrid_t *grid ); void CM_SubdivideGridColumns( cGrid_t *grid ); void CM_RemoveDegenerateColumns( cGrid_t *grid ); void CM_TransposeGrid( cGrid_t *grid ); + +#endif // COMMON_CM_CM_PATCH_H_ diff --git a/src/common/cm/cm_public.h b/src/common/cm/cm_public.h index 1747445cca..5b26323407 100644 --- a/src/common/cm/cm_public.h +++ b/src/common/cm/cm_public.h @@ -32,6 +32,9 @@ Maryland 20850 USA. =========================================================================== */ +#ifndef COMMON_CM_CM_PUBLIC_H_ +#define COMMON_CM_CM_PUBLIC_H_ + #include "engine/qcommon/q_shared.h" void CM_LoadMap(Str::StringRef name); @@ -79,3 +82,5 @@ int CM_WriteAreaBits( byte *buffer, int area ); // cm_marks.c int CM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); + +#endif // COMMON_CM_CM_PUBLIC_H_ diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 2fa99c8a98..9774509d65 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -24,7 +24,7 @@ along with this program. If not, see . #define CG_MSGDEF_H #include "cg_api.h" -#include "engine/RefAPI.h" +#include "engine/renderer/tr_types.h" #include "common/IPC/CommonSyscalls.h" #include "common/KeyIdentification.h" diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index d716c90b0b..51875f0ba4 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -137,7 +137,8 @@ void CL_ConfigstringModified( Cmd::Args& csCmd ) /* =================== CL_HandleServerCommand -CL_GetServerCommand + +Returns true if the command should be passed to the cgame =================== */ bool CL_HandleServerCommand(Str::StringRef text, std::string& newText) { @@ -255,13 +256,6 @@ void CL_FillServerCommands(std::vector& commands, int start, int en // if we have irretrievably lost a reliable command, drop the connection if ( start <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { - // when a demo record was started after the client got a whole bunch of - // reliable commands then the client never got those first reliable commands - if ( clc.demoplaying ) - { - return; - } - Sys::Drop( "CL_FillServerCommand: a reliable command was cycled out" ); } diff --git a/src/engine/client/cl_parse.cpp b/src/engine/client/cl_parse.cpp index cf91714f19..45e8bfad66 100644 --- a/src/engine/client/cl_parse.cpp +++ b/src/engine/client/cl_parse.cpp @@ -408,7 +408,17 @@ void CL_ParseGamestate( msg_t *msg ) CL_ClearState(); // a gamestate always marks a server command sequence - clc.serverCommandSequence = MSG_ReadLong( msg ); + int commandNum = MSG_ReadLong( msg ); + + if ( commandNum < clc.serverCommandSequence ) + { + Sys::Drop( "Gamestate moved serverCommandSequence backward" ); + } + + clc.serverCommandSequence = commandNum; + + // trash any commands from previous game + clc.lastExecutedServerCommand = clc.serverCommandSequence; } // parse all the configstrings and baselines @@ -496,6 +506,13 @@ void CL_ParseCommandString( msg_t *msg ) return; } + if ( clc.serverCommandSequence + 1 != seq ) + { + Sys::Drop( "Out-of-sequence server command: expected %d, got %d", + clc.serverCommandSequence + 1, seq ); + return; + } + clc.serverCommandSequence = seq; index = seq & ( MAX_RELIABLE_COMMANDS - 1 ); diff --git a/src/engine/framework/VirtualMachine.cpp b/src/engine/framework/VirtualMachine.cpp index 482c6336d5..bc37adae72 100644 --- a/src/engine/framework/VirtualMachine.cpp +++ b/src/engine/framework/VirtualMachine.cpp @@ -42,6 +42,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +// POSIX: environ is the process environment, not always declared in headers. +extern char **environ; #ifdef __linux__ #include #if defined(DAEMON_ARCH_armhf) @@ -73,6 +75,54 @@ static Cvar::Cvar workaround_naclSystem_freebsd_disableQualification( "Disable platform qualification when running Linux NaCl loader on FreeBSD through Linuxulator", Cvar::NONE, true); +#if defined(DAEMON_NACL_BOX64_EMULATION) +static Cvar::Cvar workaround_box64_disableQualification( + "workaround.box64.disableQualification", + "Disable platform qualification when running amd64 NaCl loader under Box64 emulation", + Cvar::NONE, true); + +static Cvar::Cvar workaround_box64_disableBootstrap( + "workaround.box64.disableBootstrap", + "Disable NaCl bootstrap helper when using Box64 emulation", + Cvar::NONE, true); + +static Cvar::Cvar vm_box64_path( + "vm.box64.path", + "Path to the box64 binary for NaCl emulation (empty = search PATH)", + Cvar::NONE, ""); + +// Resolve box64 binary path by searching PATH if not explicitly set. +static std::string ResolveBox64Path() { + std::string path = vm_box64_path.Get(); + if (!path.empty()) { + return path; + } + + const char* envPath = getenv("PATH"); + if (!envPath) { + Sys::Error("Box64 emulation is enabled but PATH is not set and vm.box64.path is empty."); + } + + std::string pathStr(envPath); + size_t start = 0; + while (start < pathStr.size()) { + size_t end = pathStr.find(':', start); + if (end == std::string::npos) { + end = pathStr.size(); + } + std::string candidate = pathStr.substr(start, end - start) + "/box64"; + if (access(candidate.c_str(), X_OK) == 0) { + return candidate; + } + start = end + 1; + } + + Sys::Error("Box64 emulation is enabled but 'box64' was not found in PATH. " + "Install Box64 or set vm.box64.path to the full path of the box64 binary."); + return ""; // unreachable +} +#endif + static Cvar::Cvar vm_nacl_qualification( "vm.nacl.qualification", "Enable NaCl loader platform qualification", @@ -88,6 +138,18 @@ static Cvar::Cvar vm_timeout( "Receive timeout in seconds", Cvar::NONE, 2); +#if defined(DAEMON_NACL_RUNTIME_ENABLED) +static Cvar::Cvar vm_nacl_available( + "vm.nacl.available", + "Whether NaCl runtime is available on this platform", + Cvar::ROM, true); +#else +static Cvar::Cvar vm_nacl_available( + "vm.nacl.available", + "Whether NaCl runtime is available on this platform", + Cvar::ROM, false); +#endif + namespace VM { // https://github.com/Unvanquished/Unvanquished/issues/944#issuecomment-744454772 @@ -116,7 +178,7 @@ static void CheckMinAddressSysctlTooLarge() } // Platform-specific code to load a module -static std::pair InternalLoadModule(std::pair pair, const char* const* args, bool reserve_mem, FS::File stderrRedirect = FS::File()) +static std::pair InternalLoadModule(std::pair pair, const char* const* args, bool reserve_mem, FS::File stderrRedirect = FS::File(), bool inheritEnvironment = false) { #ifdef _WIN32 // Inherit the socket in the child process @@ -201,6 +263,7 @@ static std::pair InternalLoadModule(std::pair InternalLoadModule(std::pair(args), nullptr); + // By default, the child process gets an empty environment for sandboxing. + // When Box64 emulation is used, the child needs to inherit the parent's + // environment so Box64 can find its configuration (e.g. ~/.box64rc, HOME) + // and honor settings like BOX64_DYNAREC_PERFMAP. + char* emptyEnv[] = {nullptr}; + char** envp = inheritEnvironment ? environ : emptyEnv; + int err = posix_spawn(&pid, args[0], &fileActions, nullptr, const_cast(args), envp); posix_spawn_file_actions_destroy(&fileActions); if (err != 0) { Sys::Drop("VM: Failed to spawn process: %s", strerror(err)); @@ -243,6 +312,10 @@ static std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair CreateNativeVM(std::pair pair, Str::StringRef name, bool debug) { @@ -497,6 +614,13 @@ void VMBase::Create() std::pair pair = IPC::Socket::CreatePair(); IPC::Socket rootSocket; +#if !defined(DAEMON_NACL_RUNTIME_ENABLED) + if (type == TYPE_NACL || type == TYPE_NACL_LIBPATH) { + Sys::Error("NaCl VM is not supported on this platform. " + "Set vm.cgame.type and vm.sgame.type to 3 (native DLL) " + "and use devmap instead of map."); + } +#endif if (type == TYPE_NACL || type == TYPE_NACL_LIBPATH) { std::tie(processHandle, rootSocket) = CreateNaClVM(std::move(pair), name, params.debug.Get(), type == TYPE_NACL, params.debugLoader.Get()); } else if (type == TYPE_NATIVE_EXE) { diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 5f84d35477..7ee62efc29 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -80,8 +80,8 @@ void RE_EndRegistration() { } void RE_ClearScene() { } void RE_AddRefEntityToScene( const refEntity_t * ) { } void RE_SyncRefEntities( const std::vector& ) {} -std::vector RE_SyncLerpTags( const std::vector& ) { - return {}; +std::vector RE_SyncLerpTags( const std::vector& in ) { + return std::vector(in.size()); } void RE_AddPolyToScene( qhandle_t, int, const polyVert_t* ) { } void RE_AddPolysToScene( qhandle_t, int, const polyVert_t*, int ) { } diff --git a/src/engine/qcommon/SurfaceFlags.h b/src/engine/qcommon/SurfaceFlags.h index e227c0bbca..4aa8316436 100644 --- a/src/engine/qcommon/SurfaceFlags.h +++ b/src/engine/qcommon/SurfaceFlags.h @@ -28,6 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =========================================================================== */ +#ifndef ENGINE_QCOMMON_SURFACEFLAGS_H_ +#define ENGINE_QCOMMON_SURFACEFLAGS_H_ + // this file is used by both engine and game code // see engine/qcommon/q_shared.h @@ -114,3 +117,5 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Jedi Knights games (see OpenJK) also define a third bitfield for flags with MATERIAL prefix to tell surface is water, snow, sand, glass, short grasss, long grass, etc. // Jedi Knights games also redefine a lot of CONTENTS flags (introducing things like CONTENTS_LADDER) and SURF FLAGS (moving SURF_SKY to BIT(13) for example) // Smokin'Guns uses a special .tex sidecar files to tweak surfaces flags + +#endif // ENGINE_QCOMMON_SURFACEFLAGS_H_ diff --git a/src/engine/renderer/EntityCache.cpp b/src/engine/renderer/EntityCache.cpp index 9d69487098..06f130e801 100644 --- a/src/engine/renderer/EntityCache.cpp +++ b/src/engine/renderer/EntityCache.cpp @@ -264,7 +264,7 @@ void ClearEntityCache() { } } -std::vector SyncEntityCacheToCGame( const std::vector& lerpTags ) { +std::vector RE_SyncLerpTags( const std::vector& lerpTags ) { std::vector entityOrientations; entityOrientations.reserve( lerpTags.size() ); @@ -284,7 +284,7 @@ std::vector SyncEntityCacheToCGame( const std::vector& ents ) { +void RE_SyncRefEntities( const std::vector& ents ) { for ( const EntityUpdate& ent : ents ) { bool flip = entities[ent.id].e.active != ent.ent.active; diff --git a/src/engine/renderer/EntityCache.h b/src/engine/renderer/EntityCache.h index 9540d8ca2e..135e09b5e7 100644 --- a/src/engine/renderer/EntityCache.h +++ b/src/engine/renderer/EntityCache.h @@ -53,7 +53,7 @@ void TransformEntity( trRefEntity_t* ent ); void ClearEntityCache(); -std::vector SyncEntityCacheToCGame( const std::vector& lerpTags ); -void SyncEntityCacheFromCGame( const std::vector& ents ); +std::vector RE_SyncLerpTags( const std::vector& lerpTags ); +void RE_SyncRefEntities( const std::vector& ents ); #endif // ENTITY_CACHE_H diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index da4cac0fcd..0eca1b1c10 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -32,6 +32,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =========================================================================== */ +#ifndef ENGINE_RENDERER_SHADECOMMON_H_ +#define ENGINE_RENDERER_SHADECOMMON_H_ + inline size_t GetLightMapNum( const shaderCommands_t* tess ) { return tess->lightmapNum; @@ -276,3 +279,5 @@ inline uint GetShaderProfilerRenderSubGroupsMode( const uint32_t stateBits ) { return 0; } + +#endif // ENGINE_RENDERER_SHADECOMMON_H_ diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 64b942fae8..22ee8d605b 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -490,10 +490,14 @@ static void AddConst( std::string& str, const std::string& name, float v1, float static std::string GenVersionDeclaration( const std::vector &addedExtensions ) { // Declare version. - std::string str = Str::Format( "#version %d %s\n\n", + std::string str = Str::Format( "#version %d %s\n", glConfig.shadingLanguageVersion, glConfig.shadingLanguageVersion >= 150 ? ( glConfig.glCoreProfile ? "core" : "compatibility" ) : "" ); + str += "#line 1000000000\n"; + + str += "\n"; + // Add supported GLSL extensions. for ( const auto& addedExtension : addedExtensions ) { addExtension( str, addedExtension.available, addedExtension.minGlslVersion, addedExtension.name ); @@ -859,7 +863,10 @@ std::string GLShaderManager::GetDeformShaderName( const int index ) { std::string GLShaderManager::BuildDeformShaderText( const std::string& steps ) { std::string shaderText; - shaderText = steps + "\n"; + shaderText = "\n" + steps + "\n"; + + shaderText += "#line 2000000000\n"; + shaderText += GetShaderText( "deformVertexes_vp.glsl" ); return shaderText; @@ -1223,6 +1230,13 @@ std::string GLShaderManager::ProcessInserts( const std::string& shaderText ) con while ( std::getline( shaderTextStream, line, '\n' ) ) { ++lineCount; + + /* The deform vertex header is prepended to the mainText and is part + of the shaderText, so we should reset line numbering after it. */ + if ( line == "#line 0" ) { + lineCount = 0; + } + const std::string::size_type position = line.find( "#insert" ); if ( position == std::string::npos || line.find_first_not_of( " \t" ) != position ) { out += line + "\n"; @@ -1353,7 +1367,9 @@ void GLShaderManager::InitShader( GLShader* shader ) { if ( shaderType.enabled ) { Com_sprintf( filename, sizeof( filename ), "%s%s.glsl", shaderType.path.c_str(), shaderType.postfix ); - shaderType.mainText = GetShaderText( filename ); + /* The deform vertex header is prepended to the mainText, + so we should reset line numbering after it. */ + shaderType.mainText = "#line 0\n" + GetShaderText( filename ); } } diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 3d87ecf326..9330290c7c 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -76,11 +76,6 @@ unsigned int GenerateImageHashValue( const char *fname ) { letter = Str::ctolower( fname[ i ] ); - if ( letter == '\\' ) - { - letter = '/'; // damn path names - } - hash += ( unsigned )( letter ) * ( i + 119 ); i++; } @@ -1823,19 +1818,21 @@ Finds or loads the given image. Returns nullptr if it fails, not a default image. ============== */ -image_t *R_FindImageFile( const char *imageName, imageParams_t &imageParams ) +image_t *R_FindImageFile( const char *imageName0, imageParams_t &imageParams ) { - if ( !imageName ) + if ( !imageName0 ) { return nullptr; } - unsigned hash = GenerateImageHashValue( imageName ); + std::string imageName = FS::Path::NormalizeSlashes( imageName0 ); + + unsigned hash = GenerateImageHashValue( imageName.c_str() ); // See if the image is already loaded. for ( image_t *image = r_imageHashTable[ hash ]; image; image = image->next ) { - if ( !Q_strnicmp( imageName, image->name, sizeof( image->name ) ) ) + if ( Str::IsIEqual( imageName, image->name ) ) { if ( imageParams == image->initialParams || r_allowImageParamMismatch.Get() ) { @@ -1894,7 +1891,7 @@ image_t *R_FindImageFile( const char *imageName, imageParams_t &imageParams ) byte *pic[ MAX_TEXTURE_MIPS * MAX_TEXTURE_LAYERS ]; pic[ 0 ] = nullptr; - R_LoadImage( imageName, pic, &width, &height, &numLayers, &numMips, &imageParams.bits ); + R_LoadImage( imageName.c_str(), pic, &width, &height, &numLayers, &numMips, &imageParams.bits); if ( *pic ) { @@ -1914,7 +1911,7 @@ image_t *R_FindImageFile( const char *imageName, imageParams_t &imageParams ) R_ProcessLightmap( *pic, width, height, imageParams.bits ); } - image_t *image = R_CreateImage( imageName, (const byte **)pic, width, height, numMips, imageParams ); + image_t *image = R_CreateImage( imageName.c_str(), (const byte**)pic, width, height, numMips, imageParams); image->initialParams = initialParams; Z_Free( *pic ); diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index b6174545d7..2777aa8a26 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1693,8 +1693,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.SyncRefEntities = SyncEntityCacheFromCGame; - re.SyncLerpTags = SyncEntityCacheToCGame; + re.SyncRefEntities = RE_SyncRefEntities; + re.SyncLerpTags = RE_SyncLerpTags; re.AddPolyToScene = RE_AddPolyToSceneET; re.AddPolysToScene = RE_AddPolysToScene; diff --git a/src/engine/renderer/tr_model.cpp b/src/engine/renderer/tr_model.cpp index 43d10b437c..9df6a84346 100644 --- a/src/engine/renderer/tr_model.cpp +++ b/src/engine/renderer/tr_model.cpp @@ -442,6 +442,9 @@ int RE_LerpTagET( orientation_t* tag, const trRefEntity_t* ent, const char* tagN float frontLerp = frac; float backLerp = 1.0f - frac; + AxisClear( tag->axis ); + VectorClear( tag->origin ); + if ( model->type == modtype_t::MOD_MD5 || model->type == modtype_t::MOD_IQM ) { vec3_t tmp; @@ -476,8 +479,6 @@ int RE_LerpTagET( orientation_t* tag, const trRefEntity_t* ent, const char* tagN if ( !start || !end ) { - AxisClear( tag->axis ); - VectorClear( tag->origin ); return -1; } diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index bffc8d2f72..13f9ea981d 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -123,17 +123,7 @@ static unsigned int generateHashValue( const char *fname, const int size ) if ( letter == '.' ) { - break; // don't include extension - } - - if ( letter == '\\' ) - { - letter = '/'; // damn path names - } - - if ( letter == PATH_SEP ) - { - letter = '/'; // damn path names + break; // don't include extension. FIXME: could have multiple dots } hash += ( unsigned )( letter ) * ( i + 119 ); @@ -6247,7 +6237,8 @@ shader_t *R_FindShader( const char *name, int flags ) return tr.defaultShader; } - COM_StripExtension3( name, strippedName, sizeof( strippedName ) ); + COM_StripExtension3( FS::Path::NormalizeSlashes( name ).c_str(), + strippedName, sizeof( strippedName ) ); hash = generateHashValue( strippedName, FILE_HASH_SIZE ); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 778a7a64f4..2c90e9bb47 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -58,11 +58,11 @@ using bool8_t = uint8_t; // renderfx flags enum RenderFx : uint8_t { - RF_THIRD_PERSON = 0x000001, // don't draw through eyes, only mirrors (player bodies, chat sprites) - RF_FIRST_PERSON = 0x000002, // only draw through eyes (view weapon, damage blood blob) - RF_DEPTHHACK = 0x000004, // for view weapon Z crunching - RF_NOSHADOW = 0x000008, // don't add stencil shadows - RF_SWAPCULL = 0x000010 // swap CT_FRONT_SIDED and CT_BACK_SIDED + RF_THIRD_PERSON = 0x01, // don't draw through eyes, only mirrors (player bodies, chat sprites) + RF_FIRST_PERSON = 0x02, // only draw through eyes (view weapon, damage blood blob) + RF_DEPTHHACK = 0x04, // for view weapon Z crunching + RF_NOSHADOW = 0x08, // don't add stencil shadows + RF_SWAPCULL = 0x10 // swap CT_FRONT_SIDED and CT_BACK_SIDED }; // refdef flags @@ -230,14 +230,14 @@ struct refEntity_t EntityTag positionOnTag; - int8_t clearOrigin; - int8_t clearOrigin2; + bool8_t clearOrigin; + bool8_t clearOrigin2; - int8_t boundsAdd; + bool8_t boundsAdd; - int8_t nonNormalizedAxes; // axis are not normalized, i.e. they have scale + bool8_t nonNormalizedAxes; // axis are not normalized, i.e. they have scale - int8_t active; + bool8_t active; uint16_t attachmentEntity; diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index 5ace84f369..70a9881474 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -20,6 +20,9 @@ along with this program. If not, see . =========================================================================== */ +#ifndef ENGINE_SERVER_SG_MSGDEF_H_ +#define ENGINE_SERVER_SG_MSGDEF_H_ + #include "common/IPC/CommonSyscalls.h" // game-module-to-engine calls @@ -196,3 +199,5 @@ using GameClientThinkMsg = IPC::SyncMessage< using GameRunFrameMsg = IPC::SyncMessage< IPC::Message, int> >; + +#endif // ENGINE_SERVER_SG_MSGDEF_H_ diff --git a/src/engine/server/sv_client.cpp b/src/engine/server/sv_client.cpp index 3b6f336754..469c99f96a 100644 --- a/src/engine/server/sv_client.cpp +++ b/src/engine/server/sv_client.cpp @@ -354,6 +354,7 @@ void SV_SendClientGameState( client_t *client ) // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side + // TODO(0.57): remove. The client will just throw away old commands on getting a gamestate SV_UpdateServerCommandsToClient( client, &msg ); // send the gamestate diff --git a/src/engine/sys/con_common.h b/src/engine/sys/con_common.h index 1682171f2e..ba0123ed44 100644 --- a/src/engine/sys/con_common.h +++ b/src/engine/sys/con_common.h @@ -31,6 +31,9 @@ Maryland 20850 USA. =========================================================================== */ +#ifndef ENGINE_SYS_CON_COMMON_H_ +#define ENGINE_SYS_CON_COMMON_H_ + #include "common/Color.h" #include "qcommon/q_shared.h" #include "qcommon/qcommon.h" @@ -48,3 +51,5 @@ namespace Color { int To4bit( const Color& color ) NOEXCEPT; } // namespace Color + +#endif // ENGINE_SYS_CON_COMMON_H_ diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index da4c679f54..c530c58dd6 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -295,14 +295,9 @@ void trap_R_ClearScene() cmdBuffer.SendMsg(); } -/* HACK: We need the entityNum to get the correct positions for entities that need to be attached to another entity's bone -This must be equal to the r_numEntities in engine at the time of adding the entity */ -static int entityNum; -int trap_R_AddRefEntityToScene( const refEntity_t *re ) +void trap_R_AddRefEntityToScene( const refEntity_t *re ) { cmdBuffer.SendMsg(*re); - entityNum++; - return entityNum - 1; } void trap_R_SyncRefEntities( const std::vector& ents ) { @@ -380,7 +375,6 @@ void trap_R_AddLightToScene( const vec3_t origin, float radius, float intensity, void trap_R_RenderScene( const refdef_t *fd ) { - entityNum = 0; cmdBuffer.SendMsg(*fd); } diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 69a2087035..069344358c 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -33,8 +33,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define SHARED_CLIENT_API_H_ #include "engine/qcommon/q_shared.h" -#include "engine/RefAPI.h" #include "engine/client/cg_api.h" +#include "engine/renderer/tr_types.h" #include "common/KeyIdentification.h" #include "shared/CommonProxies.h" #include @@ -65,7 +65,7 @@ qhandle_t trap_R_RegisterModel( const char *name ); qhandle_t trap_R_RegisterSkin( const char *name ); qhandle_t trap_R_RegisterShader( const char *name, int flags ); void trap_R_ClearScene(); -int trap_R_AddRefEntityToScene( const refEntity_t *re ); +void trap_R_AddRefEntityToScene( const refEntity_t *re ); void trap_R_SyncRefEntities( const std::vector& ents ); std::vector trap_R_SyncLerpTags( const std::vector& lerpTags ); void trap_R_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts ); @@ -82,7 +82,6 @@ void trap_R_ResetClipRegion(); void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); void trap_R_DrawRotatedPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader, float angle ); void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); -int trap_R_LerpTag( orientation_t *tag, const refEntity_t* refent, const char *tagName, int startIndex ); void trap_R_GetTextureSize( qhandle_t handle, int *x, int *y ); qhandle_t trap_R_GenerateTexture( const byte *data, int x, int y ); void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime );