We have made a significant change to how our vectors are declared. They now have
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):
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.
Wis now the only way to change the vector “in place” that works reliably and is not deprecated.
Vworks but is read-only now. It is equivalent to
Constructions that treat
Dataas an array will no longer work, as it is now an indexed property. So
V1.Data := V2.Datashould change to just
V1 := V2.
Datais no longer a direct field, so
V.Data += 2will no longer work. Change it to
V.X += 2. If you really need by-index access, you can temporarily change it to
V.Data := V.Data + 2or
V.InternalData := V.InternalData + 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).