Motive Animation System
An open source project by FPL.
 All Classes Functions Variables Typedefs Friends Pages
Using Your Own Vector Types

Overview

Internally, Motive uses mathfu types. For example, all the data in a MotiveProcessor is transmitted using mathfu::vec3, mathfu::mat4, etc.

The external API can be wrapped in a conversion layer. You can supply your own vector types, together with conversion functions to and from mathfu types.

Example

For example, suppose you have these vector types in your code base:

struct MyMatrix4 {
float m[4][4];
};
template <int kDimension>
struct MyVecTemplate {
float v[kDimension];
explicit MyVecTemplate(const float* pointer) {
memcpy(v, pointer, sizeof(v));
}
};
typedef MyVecTemplate<2> MyVec2;
typedef MyVecTemplate<3> MyVec3;
typedef MyVecTemplate<4> MyVec4;

Then, in your own header file, you can define a conversion class like this:

class MyVectorConverter {
public:
// Define our vector types in the public section.
typedef MyVec2 Vector2;
typedef MyVec3 Vector3;
typedef MyVec4 Vector4;
typedef MyMatrix4 Matrix4;
// Convert the data types to pointers. Note that we currently assume that
// external matrices are in column-major format, the same as mathfu's.
// A future change will store the matrices as row-major AffineTransforms
// instead of 4x4 matrices.
static float* ToPtr(float& f) { return &f; }
static float* ToPtr(Vector2& v) { return &v.v[0]; }
static float* ToPtr(Vector3& v) { return &v.v[0]; }
static float* ToPtr(Vector4& v) { return &v.v[0]; }
static float* ToPtr(Matrix4& m) { return &m.m[0][0]; }
// This call results in a read of 'f' and then a write to the stack of
// the return value. The optimizer will almost certainly eliminate this extra
// read-write, since it does nothing.
static float FromPtr(const float* f, float) { return *f; }
static Vector2 FromPtr(const float* f, Vector2) { return Vector2(f); }
static Vector3 FromPtr(const float* f, Vector3) { return Vector3(f); }
static Vector4 FromPtr(const float* f, Vector4) { return Vector4(f); }
};

And then define a MatrixMotivator that uses your types in its external API:

typedef MatrixMotivator4fTemplate<MyVectorConverter> MyMatrixMotivator4f;

Strict Aliasing

Strict aliasing is not a worry in this situation.

Strict aliasing bugs can occur when you cast between types. The C++ compiler is allowed to rearrange pointer operations (reads and writes) of different types. Therefore, writing a value, casting a pointer to the value to a different type, then reading from at pointer can get you into trouble: the read can be put before the write.

In Motive, for all conversions, the read and write are separated by a virtual function call. The compiler cannot reorder across a virtual function call boundary (because they cannot be inlined). Therefore, strict aliasing is probably not a worry.

So casting a mathfu::mat4 reference to a reference of your matrix type shouldn't result in aliasing bugs. You do need to ensure that the alignment restrictions are the same, however (see below).

Of course, this is only true for the specific situation described here in Motive. If you reuse your conversion class elsewhere in your code, you may be setting yourself up for trouble. If you do use casts, be aware that it is a maintanence hazard.

Alignment Restrictions

Note that mathfu types will be 16-byte aligned, if you're using the SIMD option of mathfu. The SIMD option will make Motive run faster on most platforms, so it's a good idea to enable it when you can.

If your types are only 4-byte aligned, then you will need to create copies of them in your converter's From calls. These copies cannot be optimized away, and are therefore pure excess call overhead.

For maximal efficiency, you may want to consider aligning your vector types to match mathfu alignment.