Returning to Quaternions and Rotations

Continued from the previous entry.

After a long hiatus, I’m working on completing the rotation and quaternion changes that arose as a part of fixing attaching and dettaching actors. To begin, I needed to rebase my old changes so that they applied to the current git master. With all of the progress that has been made since the start of GSoC, the patchset was out of date and doesn’t address all of the current uses of Quaternions and Rotation3d.

In order to make this patchset easier to accept into ResidualVM, I’m splitting the work up into three distinct parts:

  1. Rework of Rotation3d to support the various Euler Angle orders
  2. The final expanded Quaternion implementation
  3. The completed attaching and detaching code

The reasoning behind this approach is that a large portion of the current Quaternion usage is simply to convert from Euler Angles to a Matrix. By removing this extra step, the resulting code will be easier to read and more straightforward. After applying my previous changes to the Rotation3d class, I created tests to check that the code was capable of converting from Euler Angles to a Rotation Matrix, and back again. In this implmentation, the user can specify the Euler Angle order by using the enum EulerOrder values, and building the Rotation Matrix with the member function buildFromXYZ or using the constructor that takes three angles and the EulerOrder.

Let’s take a brief detour here for a moment to explain how to add tests to ResidualVM’s test suite. ResidualVM uses CxxTest as the framework to build unit tests. All of the tests can be found in the directory test, with a directory inside that for each of the ResidualVM components tested. Currently, there are tests for the audio subsystem and the common functionality. In this changeset, I’ve created a new directory, math and added a new file, rotation3d.h which contains the unit tests for the Rotation3d class.

Unit tests are implemented by writing classes that contain the tests and CxxTest automatically generates the rest of the code to run the tests. So, to add a new test, we first include a header from CxxTest that defines the TestSuite class. We then define a class that inherits from this base class and then implement our tests with each unit test as a public member of our class. Each of these unit test functions return no value and have no parameters. To actually test a value, CxxTest provides assertions which should be used to report the test result.

Since math isn’t already a part of the testing structure, we’ll need to add a new directory to the unit test build system. To do this, you must add the test header files to the build by adding them to the module.mk file in the test root. So, to add our new math tests to the unit tests to be built, I modified the TEST variable with the text in red:

  • TESTS := $(srcdir)/test/common/*.h $(srcdir)/test/audio/*.h $(srcdir)/test/math/*.h

I also needed to link the actual math library implementation to the unit test build, so I added the following to the TEST_LIBS variable:

  • TEST_LIBS := audio/libaudio.a math/libmath.a common/libcommon.a

And that’s it! To build and run our tests, from your build directory, simply run:

  • make test

The output will look like this (assuming I didn’t break anything!):

Everything tested out okay!

And failures will look like this when something does break, depending on the assertion type used:

Oops, the test failed!

And that’s it for testing! It’s very straightforward to add additional tests, so I’ll try to add code that performs testing in the future for applicable changes.

Back to Rotation3d! In this incarnation of the updated Rotation3d code, I decided to return the rotation direction to the “left handed” DirectX direction of rotation that was previously in Rotation3d. This will remove the necessity for all of the transpose() calls that I had previously needed to insert to produce the same result as before.

In addition to the basic assertions, I had previously created a test that compared the original implementation of Rotation3d to my new version for each of the uses in ResidualVM. I adapted these tests for the new implementation, but won’t submit them for inclusion because they duplicate a lot of code. The branch containing these tests can be found here, while the Rotation3d changes can be found in PR #936.

In the next post, we’ll look at the Quaternion implementation and finish working on attaching and dettaching.