Index: source/main.cpp =================================================================== --- source/main.cpp +++ source/main.cpp @@ -108,8 +108,8 @@ // Request the high performance GPU on Windows by default if no system override is specified. // See: // - https://github.com/supertuxkart/stk-code/pull/4693/commits/0a99c667ef513b2ce0f5755729a6e05df8aac48a -// - https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm -// - https://gpuopen.com/learn/amdpowerxpressrequesthighperformance/ +// - https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm +// - https://gpuopen.com/learn/amdpowerxpressrequesthighperformance/ extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -496,9 +496,9 @@ // moved into a helper function to ensure args is destroyed before // exit(), which may result in a memory leak. -static void RunGameOrAtlas(int argc, const char* argv[]) +static void RunGameOrAtlas(const PS::span argv) { - CmdLineArgs args(argc, argv); + CmdLineArgs args(argv); g_CmdLineArgs = args; @@ -736,7 +736,8 @@ EarlyInit(); // must come at beginning of main - RunGameOrAtlas(argc, const_cast(argv)); + // static_cast is ok, argc is required to be non-negative. + RunGameOrAtlas({argv, static_cast(argc)}); // Shut down profiler initialised by EarlyInit g_Profiler2.Shutdown(); Index: source/ps/CStr.h =================================================================== --- source/ps/CStr.h +++ source/ps/CStr.h @@ -63,12 +63,10 @@ using StrBase = std::tstring; using Char = typename std::tstring::value_type; - CStr() {} - CStr(const Char* str) : StrBase(str) {} - CStr(const Char* str, size_t len) : StrBase(str, len) {} CStr(const StrBase& str) : StrBase(str) {} - template - CStr (InputIterator first, InputIterator last) : StrBase(first, last) {} + + // Inherit all base class constructors. + using StrBase::StrBase; /** * Repeat: Named constructor, to avoid overload overload. Index: source/ps/GameSetup/CmdLineArgs.h =================================================================== --- source/ps/GameSetup/CmdLineArgs.h +++ source/ps/GameSetup/CmdLineArgs.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,9 +18,11 @@ #ifndef INCLUDED_CMDLINEARGS #define INCLUDED_CMDLINEARGS -#include "ps/CStr.h" #include "lib/os_path.h" +#include "ps/containers/Span.h" +#include "ps/CStr.h" +#include #include class CmdLineArgs @@ -33,10 +35,9 @@ * All arguments are required to be of the form -name or * -name=value - anything else is ignored. * - * @param argc size of argv array - * @param argv array of arguments; argv[0] should be the program's name + * @param argv span of arguments; argv[0] should be the program's name */ - CmdLineArgs(int argc, const char* argv[]); + CmdLineArgs(const PS::span argv); /** * Test whether the given name was specified, as either -name or Index: source/ps/GameSetup/CmdLineArgs.cpp =================================================================== --- source/ps/GameSetup/CmdLineArgs.cpp +++ source/ps/GameSetup/CmdLineArgs.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,10 @@ #include "lib/sysdep/sysdep.h" +#include +#include +#include + CmdLineArgs g_CmdLineArgs; namespace @@ -42,41 +46,38 @@ } // namespace -CmdLineArgs::CmdLineArgs(int argc, const char* argv[]) +CmdLineArgs::CmdLineArgs(const PS::span argv) { - if (argc >= 1) - { - std::string arg0(argv[0]); - // avoid OsPath complaining about mixing both types of separators, - // which happens when running in the VC2010 debugger - std::replace(arg0.begin(), arg0.end(), '/', SYS_DIR_SEP); - m_Arg0 = arg0; - } + if (argv.empty()) + return; + + std::string arg0(argv[0]); + // avoid OsPath complaining about mixing both types of separators, + // which happens when running in the VC2010 debugger + std::replace(arg0.begin(), arg0.end(), '/', SYS_DIR_SEP); + m_Arg0 = arg0; - for (int i = 1; i < argc; ++i) + // Implicit conversion from const char* to std::string_view. + for (const std::string_view argN : argv.subspan(1)) { // Only accept arguments that start with '-' - if (argv[i][0] != '-') + if (argN[0] != '-') { - m_ArgsWithoutName.emplace_back(argv[i]); + m_ArgsWithoutName.emplace_back(argN); continue; } // Allow -arg and --arg - char offset = argv[i][1] == '-' ? 2 : 1; - CStr name, value; + const std::string_view afterDashes = argN.substr(argN[1] == '-' ? 2 : 1); // Check for "-arg=value" - const char* eq = strchr(argv[i], '='); - if (eq) - { - name = CStr(argv[i]+offset, eq-argv[i]-offset); - value = CStr(eq+1); - } - else - name = CStr(argv[i]+offset); + const std::string_view::iterator eq = + std::find(afterDashes.begin(), afterDashes.end(), '='); + + const CStr value = (std::distance(eq, afterDashes.end()) > 1) ? + CStr(eq + 1, afterDashes.end()) : CStr(); - m_Args.emplace_back(std::move(name), std::move(value)); + m_Args.emplace_back(CStr(afterDashes.begin(), eq), value); } } Index: source/ps/GameSetup/tests/test_CmdLineArgs.h =================================================================== --- source/ps/GameSetup/tests/test_CmdLineArgs.h +++ source/ps/GameSetup/tests/test_CmdLineArgs.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,13 +19,15 @@ #include "ps/GameSetup/CmdLineArgs.h" +#include + class TestCmdLineArgs : public CxxTest::TestSuite { public: void test_has() { - const char* argv[] = { "program", "-test2" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + constexpr std::array argv = { "program", "-test2" }; + CmdLineArgs c(argv); TS_ASSERT(!c.Has("test1")); TS_ASSERT(c.Has("test2")); TS_ASSERT(!c.Has("test3")); @@ -34,8 +36,11 @@ void test_get() { - const char* argv[] = { "program", "-test1=", "--test2=x", "-test3=-y=y-", "-=z" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + constexpr std::array argv = + { + "program", "-test1=", "--test2=x", "-test3=-y=y-", "-=z" + }; + CmdLineArgs c(argv); TS_ASSERT(!c.Has("program")); TS_ASSERT_STR_EQUALS(c.Get("test0"), ""); TS_ASSERT_STR_EQUALS(c.Get("test1"), ""); @@ -46,8 +51,11 @@ void test_multiple() { - const char* argv[] = { "program", "-test1=one", "--test1=two", "-test2=none", "-test1=three" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + constexpr std::array argv = + { + "program", "-test1=one", "--test1=two", "-test2=none", "-test1=three" + }; + CmdLineArgs c(argv); TS_ASSERT_STR_EQUALS(c.Get("test1"), "one"); TS_ASSERT_STR_EQUALS(c.Get("test2"), "none"); @@ -66,10 +74,10 @@ void test_get_invalid() { - const char* argv[] = { + constexpr std::array argv = { "-test1", "--test2", "test3-", " -test4", "--", "-==" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + CmdLineArgs c(argv); TS_ASSERT(!c.Has("test1")); TS_ASSERT(c.Has("test2")); @@ -79,26 +87,32 @@ void test_arg0() { - const char* argv[] = { "program" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + constexpr std::array argv = { "program" }; + CmdLineArgs c(argv); TS_ASSERT_WSTR_EQUALS(c.GetArg0().string(), L"program"); - CmdLineArgs c2(0, NULL); + CmdLineArgs c2(PS::span{}); TS_ASSERT_WSTR_EQUALS(c2.GetArg0().string(), L""); - const char* argv3[] = { "ab/cd/ef/gh/../ij" }; - CmdLineArgs c3(ARRAY_SIZE(argv3), argv3); -#if OS_WIN - TS_ASSERT_WSTR_EQUALS(c3.GetArg0().string(), L"ab\\cd\\ef\\gh\\..\\ij"); -#else - TS_ASSERT_WSTR_EQUALS(c3.GetArg0().string(), L"ab/cd/ef/gh/../ij"); -#endif + const std::array argv3 = { "ab/cd/ef/gh/../ij" }; + CmdLineArgs c3(argv3); + if constexpr(OS_WIN) + { + TS_ASSERT_WSTR_EQUALS(c3.GetArg0().string(), L"ab\\cd\\ef\\gh\\..\\ij"); + } + else + { + TS_ASSERT_WSTR_EQUALS(c3.GetArg0().string(), L"ab/cd/ef/gh/../ij"); + } } void test_get_without_names() { - const char* argv[] = { "program", "test0", "-test1", "test2", "test3", "--test4=test5" }; - CmdLineArgs c(ARRAY_SIZE(argv), argv); + constexpr std::array argv = + { + "program", "test0", "-test1", "test2", "test3", "--test4=test5" + }; + CmdLineArgs c(argv); TS_ASSERT(c.Has("test1")); TS_ASSERT_STR_EQUALS(c.Get("test4"), "test5"); CStr expected_args[] = { "test0", "test2", "test3" }; Index: source/ps/containers/Span.h =================================================================== --- source/ps/containers/Span.h +++ source/ps/containers/Span.h @@ -38,7 +38,7 @@ public: using element_type = T; using value_type = std::remove_cv_t; - using size_type = std::size_t; + using size_type = size_t; using pointer = T*; using reference = T&; using iterator = pointer; @@ -52,6 +52,10 @@ constexpr span(iterator first, iterator last) : m_Pointer(first), m_Extent(static_cast(last - first)) {} + template + constexpr span(const std::array& arr) + : m_Pointer(arr.data()), m_Extent(arr.size()) {} + constexpr span(const span& other) = default; constexpr span& operator=(const span& other) = default; @@ -66,11 +70,16 @@ constexpr iterator begin() const { return m_Pointer; } constexpr iterator end() const { return m_Pointer + m_Extent; } + constexpr span subspan(size_type offset) const { return {m_Pointer + offset, m_Extent - offset}; } + private: pointer m_Pointer; size_type m_Extent; }; +template +span(const std::array&) -> span; + } // namespace PS #endif // INCLUDED_PS_SPAN Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -57,10 +57,10 @@ CVector3D m_RetreatPosition; CVector2D m_PerpVect; - u8 m_UV[3]; + std::array m_UV; // pad to a power of two - u8 m_Padding[5]; + std::array m_Padding; }; cassert(sizeof(SWavesVertex) == 64); @@ -398,6 +398,69 @@ ComputeDirection(m_DistanceHeightmap.get(), heightmap, m_WaterHeight, SideSize, maxLevel); } + +static void constructShoreVertex(std::back_insert_iterator> addToVertices, + const CTerrain& terrain, const float waterHeight, const float outmost, const int sign, + const u16 width, const u16 a, const CVector2D perp, const CVector2D pos) +{ + struct ProtoVertex + { + std::array, 4> data; + u8 index; + }; + constexpr std::array protoVertexes = + {{ + {{{{9.7f, 0.0f}, {9.5f, 0.0f}, {9.0f, 0.0f}, {9.0f, 0.0f}}}, 0}, + {{{{6.6f, 0.2f}, {3.6f, 0.2f}, {3.6f, 0.0f}, {0.0f, 3.8f}}}, 1}, + {{{{6.5f, 0.6f}, {3.3f, 0.6f}, {2.2f, 0.0f}, {2.7f, 0.0f}}}, 2}, + {{{{6.4f, 0.85f}, {3.0f, 0.85f}, {1.3f, 0.03f}, {1.9f, 0.0f}}}, 3}, + {{{{6.3f, 0.9f}, {2.4f, 0.9f}, {0.6f, 0.1f}, {1.7f, 0.0f}}}, 4}, + {{{{6.2f, 0.8f}, {2.3f, 0.8f}, {0.0f, 0.1f}, {1.5f, 0.0f}}}, 5}, + {{{{6.1f, 0.5f}, {2.2f, 0.5f}, {-0.2f, 0.0f}, {1.2f, 0.0f}}}, 6}, + {{{{6.05f, 0.2f}, {2.1f, 0.2f}, {0.7f, -0.4f}, {2.1f, 0.0f}}}, 7}, + {{{{6.0f, 0.0f}, {2.0f, 0.0f}, {1.1f, -0.8f}, {2.0f, 0.0f}}}, 8} + }}; + + constexpr float baseHeight = 0.04f; + + const float halfWidth = (width-1.0f)/2.0f; + const float sideNess = sqrtf(Clamp( (halfWidth - fabsf(a - halfWidth)) / 3.0f, 0.0f, 1.0f)); + + for (const ProtoVertex& protoV : protoVertexes) + { + // Coresponding to m_BasePosition, m_ApexPosition, m_SplashPosition and m_RetreatPosition. + const std::array scaledOutmostArr = + { + outmost, outmost, outmost * sideNess, outmost + }; + std::array result; + + // transforming protoV.data and scaledOutmostArr into result + std::transform(protoV.data.begin(), protoV.data.end(), scaledOutmostArr.begin(), + result.begin(), [&](const std::array& protoN, const float scaledOutmost) + { + const float terrHeight = 0.05f + terrain.GetExactGroundLevel( + pos.X + sign * perp.X * (std::get<0>(protoN) + scaledOutmost), + pos.Y + sign * perp.Y * (std::get<0>(protoN) + scaledOutmost)); + return CVector3D( + pos.X + sign * perp.X * (std::get<0>(protoN) + scaledOutmost), + baseHeight + std::get<1>(protoN) * sideNess + + std::max(waterHeight, terrHeight), + pos.Y + sign * perp.Y * (std::get<0>(protoN) + scaledOutmost)); + }); + + addToVertices = SWavesVertex + { + std::get<0>(result), + std::get<1>(result), + std::get<2>(result), + std::get<3>(result), + perp, + {static_cast(a), protoV.index, 0} + }; + } +} + // This requires m_DistanceHeightmap to be defined properly. void WaterManager::CreateWaveMeshes() { @@ -678,85 +741,14 @@ perp /= nb; perp = CVector2D(-perp.Y,perp.X).Normalized(); - SWavesVertex point[9]; - - float baseHeight = 0.04f; - - float halfWidth = (width-1.0f)/2.0f; - float sideNess = sqrtf(Clamp( (halfWidth - fabsf(a - halfWidth)) / 3.0f, 0.0f, 1.0f)); - - point[0].m_UV[0] = a; point[0].m_UV[1] = 8; - point[1].m_UV[0] = a; point[1].m_UV[1] = 7; - point[2].m_UV[0] = a; point[2].m_UV[1] = 6; - point[3].m_UV[0] = a; point[3].m_UV[1] = 5; - point[4].m_UV[0] = a; point[4].m_UV[1] = 4; - point[5].m_UV[0] = a; point[5].m_UV[1] = 3; - point[6].m_UV[0] = a; point[6].m_UV[1] = 2; - point[7].m_UV[0] = a; point[7].m_UV[1] = 1; - point[8].m_UV[0] = a; point[8].m_UV[1] = 0; - - point[0].m_PerpVect = perp; - point[1].m_PerpVect = perp; - point[2].m_PerpVect = perp; - point[3].m_PerpVect = perp; - point[4].m_PerpVect = perp; - point[5].m_PerpVect = perp; - point[6].m_PerpVect = perp; - point[7].m_PerpVect = perp; - point[8].m_PerpVect = perp; - - static const float perpT1[9] = { 6.0f, 6.05f, 6.1f, 6.2f, 6.3f, 6.4f, 6.5f, 6.6f, 9.7f }; - static const float perpT2[9] = { 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 3.0f, 3.3f, 3.6f, 9.5f }; - static const float perpT3[9] = { 1.1f, 0.7f, -0.2f, 0.0f, 0.6f, 1.3f, 2.2f, 3.6f, 9.0f }; - static const float perpT4[9] = { 2.0f, 2.1f, 1.2f, 1.5f, 1.7f, 1.9f, 2.7f, 3.8f, 9.0f }; - - static const float heightT1[9] = { 0.0f, 0.2f, 0.5f, 0.8f, 0.9f, 0.85f, 0.6f, 0.2f, 0.0 }; - static const float heightT2[9] = { -0.8f, -0.4f, 0.0f, 0.1f, 0.1f, 0.03f, 0.0f, 0.0f, 0.0 }; - static const float heightT3[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0 }; - - for (size_t t = 0; t < 9; ++t) - { - float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT1[t]+outmost), - pos.Y+sign*perp.Y*(perpT1[t]+outmost)); - point[t].m_BasePosition = CVector3D(pos.X+sign*perp.X*(perpT1[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), - pos.Y+sign*perp.Y*(perpT1[t]+outmost)); - } - for (size_t t = 0; t < 9; ++t) - { - float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT2[t]+outmost), - pos.Y+sign*perp.Y*(perpT2[t]+outmost)); - point[t].m_ApexPosition = CVector3D(pos.X+sign*perp.X*(perpT2[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight), - pos.Y+sign*perp.Y*(perpT2[t]+outmost)); - } - for (size_t t = 0; t < 9; ++t) - { - float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), - pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); - point[t].m_SplashPosition = CVector3D(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), baseHeight + heightT2[t]*sideNess + std::max(m_WaterHeight,terrHeight), pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess)); - } - for (size_t t = 0; t < 9; ++t) - { - float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT4[t]+outmost), - pos.Y+sign*perp.Y*(perpT4[t]+outmost)); - point[t].m_RetreatPosition = CVector3D(pos.X+sign*perp.X*(perpT4[t]+outmost), baseHeight + heightT3[t]*sideNess + std::max(m_WaterHeight,terrHeight), - pos.Y+sign*perp.Y*(perpT4[t]+outmost)); - } + constructShoreVertex(std::back_inserter(vertices), *terrain, m_WaterHeight, + outmost, sign, width, a, perp, pos); - vertices.push_back(point[8]); - vertices.push_back(point[7]); - vertices.push_back(point[6]); - vertices.push_back(point[5]); - vertices.push_back(point[4]); - vertices.push_back(point[3]); - vertices.push_back(point[2]); - vertices.push_back(point[1]); - vertices.push_back(point[0]); - - shoreWave->m_AABB += point[8].m_SplashPosition; - shoreWave->m_AABB += point[8].m_BasePosition; - shoreWave->m_AABB += point[0].m_SplashPosition; - shoreWave->m_AABB += point[0].m_BasePosition; - shoreWave->m_AABB += point[4].m_ApexPosition; + shoreWave->m_AABB += (vertices.end() - 9)->m_SplashPosition; + shoreWave->m_AABB += (vertices.end() - 9)->m_BasePosition; + shoreWave->m_AABB += (vertices.end() - 1)->m_SplashPosition; + shoreWave->m_AABB += (vertices.end() - 1)->m_BasePosition; + shoreWave->m_AABB += (vertices.end() - 5)->m_ApexPosition; } if (sign == 1)