Main: constant-initialize the Matrix3, Matrix4, Affine3, Quaternion and AxisAlignedBox constants by ybai08 · Pull Request #3761 · OGRECave/ogre · GitHub
Skip to content

Main: constant-initialize the Matrix3, Matrix4, Affine3, Quaternion and AxisAlignedBox constants - #3761

Open
ybai08 wants to merge 1 commit into
OGRECave:masterfrom
ybai08:constexpr-math-constants
Open

ybai08 wants to merge 1 commit into
OGRECave:masterfrom
ybai08:constexpr-math-constants

Conversation

@ybai08

@ybai08 ybai08 commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Part of #3321. This covers the five classes still unticked in its checklist: AxisAlignedBox, Matrix3, Matrix4, Affine3 and Quaternion.

The constructors used to define ZERO, IDENTITY, CLIPSPACE2DTOIMAGESPACE, BOX_NULL and BOX_INFINITE are now constexpr. The definitions in the .cpp files are unchanged, but they now meet the C++14 rule for constant initialization: a static object initialized by a constexpr constructor with constant arguments. They are therefore set before any dynamic initialization runs, so another translation unit (or a static library user) that reads them from its own static initializer no longer depends on initialization order.

This differs from #3313/#3315: the constants stay objects (static const Matrix4 IDENTITY;) instead of becoming references, so the ABI doesn't change. If you'd rather keep the #3315 pattern for consistency, that is a small follow-up on top of the constexpr constructors.

Changes:

  • Matrix3(9 reals), Quaternion(w, x, y, z) and both AxisAlignedBox constructors initialize their members in the member initializer list and are constexpr. The AxisAlignedBox values are the same as before: (-0.5) to (0.5), with the given extent.
  • Matrix4(16 reals) and Affine3(12 reals) are constexpr. C++14 requires a constexpr constructor to initialize every member, and m lives in TransformBase. So this adds a protected constexpr TransformBase/TransformBaseReal constructor that takes all 16 entries, and the two constructors forward to it. Affine3 passes 0, 0, 0, 1 for the last row, as before.
  • Matrix3::EPSILON, msSvdMaxIterations and Quaternion::msEpsilon are scalars with constant initializers, so they were already fine.

Tests (Tests/OgreMain/src/General.cpp):

  • constexpr variables built with each of these constructors at namespace scope. This compiles only if the constructors are usable in constant expressions, which is what the constants rely on.
  • Math.ConstexprConstructors checks the entry order (row-major, Affine3's last row) and the two box extents.
  • Math.StaticConstants checks the values of all eleven constants.

Verification (macOS arm64, Apple clang, Unix Makefiles generator, Debug, OGRE_BUILD_LIBS_AS_FRAMEWORKS=OFF, all render systems off, samples and tests on):

  • Without the header changes, General.cpp fails to compile: constexpr variable cannot have non-literal type for Matrix3, Matrix4, Affine3, Quaternion and both AxisAlignedBox variables (6 errors).
  • Dynamic initializers (___cxx_global_var_init* in nm -m of each object file), before -> after: OgreMatrix3.cpp.o 3 -> 1, OgreMatrix4.cpp.o 6 -> 1, OgreQuaternion.cpp.o 3 -> 1, OgreAxisAlignedBox.cpp.o 3 -> 1. The remaining one is the same std::string initializer that OgreVector.cpp.o (already converted) also has.
  • Test_Ogre --gtest_filter=-UseCustomCapabilitiesTests*:
    • on master: 159 tests, 154 passed, 2 skipped (DotSceneTests.exportImport, QuaternionTests.Precision), 3 failed;
    • with the change: 161 tests, 156 passed, the same 2 skipped and the same 3 failed.
    • The 3 failures are Root.shutdown, MaterialSerializer.Basic and Image.Compressed. All three come from this non-framework build: they can't dlopen Contents/Frameworks/Plugin_ParticleFX.framework.
  • make of all targets (including the tools and SampleBrowser) succeeds with the change.

Not run: GCC, MSVC, Linux/Windows builds, the SWIG bindings, visual tests, and an Xcode-generator build.

…nd AxisAlignedBox constants

Make the constructors used to define ZERO, IDENTITY,
CLIPSPACE2DTOIMAGESPACE, BOX_NULL and BOX_INFINITE constexpr. Their
definitions are then constant-initialized, so they are already set when
another translation unit reads them during its own dynamic
initialization.

Unlike OGRECave#3313 and OGRECave#3315 the constants stay objects, so this keeps the
ABI. Matrix4 and Affine3 initialize their entries through a new
protected constexpr TransformBase constructor.

Part of OGRECave#3321.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant