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 );