Vectors changes, to avoid a trap with modifying a temporary value

Cthulhu high-poly model (4.5 million triangles) in glTF by TooManyDemons

We have made a significant change to how our vectors are declared. They now have X, Y, Z, W as fields (not properties), and the compiler will prevent you from falling into a trap of writing

Scene.Translation.X := Scene.Translation.X + 10;

Like in the below testcase:

uses SysUtils, CastleScene, CastleVectors;
var
  S: TCastleScene;
begin
  S := TCastleScene.Create(nil);
  S.Translation.X := S.Translation.X + 10;
  FreeAndNil(S);
end.

This has always been invalid code, as it potentially modifies a temporary value, not the actual Scene.Translation value. And even if it modifies the actual Scene.Translation value (under some optimization/compiler version), it bypasses the Scene.Translation property setter. This is documented in-depth in coding traps documentation page.

I recognized this was a significant trap when using CGE vectors, and changed the way vector is declared to make it impossible. From now on, this code will no longer compile. FPC prevents us from making this mistake.

This affects all our vectors and colors:

The change is mostly backward compatible (if your code was safe).

  • Some properties and methods remain as deprecated (so they will compile, for now, albeit with clear warning from a compiler): Data, Items properties,methods Init and NormalizeMe. We will completely remove them at some point in the future (we don’t like traps in API 🙂 ) so please follow the compiler warnings and adjust your code to not use them.

  • Setting fields X, Y, Z, W is now the only way to change the vector “in place” that works reliably and is not deprecated.

  • V[0] works but is read-only now. It is equivalent to V.X or V.AsArray[0].

  • Constructions that treat Data as an array will no longer work, as it is now an indexed property. So V1.Data := V2.Data should change to just V1 := V2.

  • Data is no longer a direct field, so V.Data[0] += 2 will no longer work. Change it to V.X += 2. If you really need by-index access, you can temporarily change it to V.Data[0] := V.Data[0] + 2 or V.InternalData[0] := V.InternalData[0] + 2 — these provide a quick upgrade path, although we recommend avoiding such constructions altogether in new code.

  • Constant declarations will need to change. Foo: TVector3 = (Data: (1, 2, 3)) should now be Foo: TVector3 = (X: 1; Y: 2; Z: 3).

The other records in CGE will soon follow with a similar redesign. The only way to change the record “in place” is by direct field access, not by some method or property setter. This means that compiler will prevent invalid operations. This applies to:

P.S. As usual with such posts, I had trouble selecting a screenshot. How do you visualize “vector API cleanup”? 🙂 So here’s a screenshot of view3dscene rendering glTF model of Cthulhu (model by TooManyDemons, distributed on SketchFab). The model is quite high-poly, done in ZBrush (4.5 million triangles, but it’s just s single mesh and it renders with 60 FPS).