# X3d geometry components, docs outdated?

**URL:** https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595
**Category:** 2D
**Created:** [June 26, 2022, 11:19pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595 "2022-06-26T23:19:29Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [June 26, 2022, 11:19pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/1 "2022-06-26T23:19:29Z")

</div>

Hello again.

I’d like to draw a flat (2D) polygon with an outline (thick and different color) and some added details.  
Then i’d like to move (a la `TransformXY`) and rotate the shape. Maybe also to scale/zoom it.

It seems rather straightforward using `DrawPrimitive2D` with GL TrinaglesFan and GL Lines mode.  
But i’d like to move to “declarative approach” instead.

Obvious starting points seems to be:

- [Geometry2D component | Castle Game Engine](https://castle-engine.io/x3d_implementation_geometry2d.php)
- [Geometry3D component | Castle Game Engine](https://castle-engine.io/x3d_implementation_geometry3d.php)

The source examples there are inspiring, but sadly they do not give conceptual overview, what steps / added info is required to turn array of points/vertexes into a figure. There should be some colours, stencils, etc…

> 1. Supported nodes …
> 
> - `TriangleSet2D` [(API reference)](https://castle-engine.io/apidoc-unstable/html/X3DNodes.TTriangleSet2DNode.html)Triangles.

So far so good. X3D ref seems to say there would be no such thing as “fan” built around some natural “center”, but it would not be hard to copy the initial vertex. Except that…

> `type TTriangleSet2DNode = class(TAbstractGeometryNode)`  
> **Description**  
> Set of triangles in 2D. **Rendering of this node is not implemented yet.**

Ooops… TO me this sounds weird, in which sence that component is “supported” if it is not rendered? Or is it?

`function TTriangleSet2DNode.Proxy` seems implemented and on a cursory look it does not seem much different from `TRectangle2DNode.Proxy`, as for the rest it seems mostly auto-generated.

If it still is NOT rendered, then what do i miss?

But yahoo, the sources teach me about `TTriangleSetNode` and `TTriangleFanSetNode`. The last sounds very good… Yet those are not even mentioned at [Geometry3D component | Castle Game Engine](https://castle-engine.io/x3d_implementation_geometry3d.php)

Are them also non-implemented about rendering? But there is no such warning in docs and sources it seems. [Castle Game Engine: X3DNodes: Class TTriangleFanSetNode](https://castle-engine.io/apidoc-unstable/html/X3DNodes.TTriangleFanSetNode.html)

_Also, i wonder if that is possible to translate all 3D classes to their 2D counterparts. It seems it can be well templates, it seems all one needs is to replace `Vector3` with `Vector2` as coordinates type and add explicit property `Z`. Perhaps it would miss a goal of straightforward mapping of XML nodes, though. Yet maybe some easy conversion of 2D to 3D, like [https://www.makewordart.com](https://www.makewordart.com) could be handy._

```auto
  Transform := TTransformNode.Create;
 
  RectGeometry := TRectangle2DNode.CreateWithShape(RectShape);

```

But why?  
`constructor CreateWithTransform(out Shape: TShapeNode; out Transform: TTransformNode);`

---

<div class="post-metadata">

### Author: ![michalis](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/michalis/32/3_2.png) [@michalis](https://forum.castle-engine.io/u/michalis)
#### Post date: [June 28, 2022, 12:42pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/2 "2022-06-28T12:42:54Z")

</div>

1. Aside from [Geometry3D component | Castle Game Engine](https://castle-engine.io/x3d_implementation_geometry3d.php) , [Geometry2D component | Castle Game Engine](https://castle-engine.io/x3d_implementation_geometry2d.php) , see also “Building a mesh using code” on [Writing code to modify scenes and transformations | Manual | Castle Game Engine](https://castle-engine.io/viewport_and_scenes_from_code#_building_a_mesh_using_code) .

2. As for “Rendering of this node is not implemented yet.” at TTriangleSet2DNode docs – ups, that’s just a mistake 🙂 Removed it.

3. TTriangleSetNode and TTriangleFanSetNode are part of Rendering component, [Rendering component | Castle Game Engine](https://castle-engine.io/x3d_implementation_rendering.php) , not Geometry3D.

4. As for “Also, i wonder if that is possible to translate all 3D classes to their 2D counterparts.” – it is possible, but a bit pointless. I mean, the gain (you can build 2D primitives without specifing Z = 0 everywhere) is less that the additional complication (much more nodes, and their handling introduces additional conversion step). We already have TTriangleSet2DNode that is analogous to TTriangleSetNode… and the usefullness of it is rather low. `TTriangleSetNode` works as nicely.

5. 

> [@](#):
>
> But why?  
> constructor CreateWithTransform(out Shape: TShapeNode; out Transform: TTransformNode);

As for “why” – all geometry nodes have additional constructors “CreateWithShape” and “CreateWithTransform” (which is really “create with both shape and transform”). It’s just a useful shortcut – when creating a geometry node, you almost always want to also create a shape node, and then usually also a transform node.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [June 28, 2022, 7:37pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/3 "2022-06-28T19:37:28Z")

</div>

Thanks for hints. Here is a quick reply, i did not have time to look into “Building a mesh using code” yet but again thanks for the pointer!

> 1. As for “why” – all geometry nodes have additional constructors

Ermmm… you understood me the opposite way. I mean, why you even do that `TTransformNode.Create;` explicitly when you have the seemingly fitting helper constructor?

Either create both Shape and Tranform explicitly and outside - or create both by the helper constructor.

Is it just a dusty old code from times when you had no `CreateWithTransform` yet, or am i missing something and it can not be the substitute?

Also - while it is a bit stupid for a German and Russian guys to reflect upon details of English - i still think `CreateWithXXXX` was a bad name. I dived into the code why? because i noticed that you fail to initialize the Shape, and then you pass that shape as an input-parameter into constructor…

Yet again, not being native speaker, but “Whiskey with cola” d not sound to me as whiskey creating cola, but that pre-made cola was mixed into whiskey.

I see you tried to rename it, but it did not made things much better, not for me at least. It still looked like non-initialized in-param until i dived into the sources.

Frankly, i do not know if there can be concise yet specific and nice way to name those functions. `CreateGivingXXX`, `CreateMeAndCreateXXX`, `CreateProvidingXXXX`, `CreateCreatingXXX` - those all feel ugly to me. I failed to imagine any good naming…

That said, personally i would just not have any different names at all.

```delphi
type PShapeNode = ^TShapeNode; PTransformNode = ^TTransformNode;

{$T+}   
private constructor Create(const SH: PShapeNode; const T: PTransformNode ); overload;

public
   constructor Create(out SH: TShapeNode; out T: TTransformNode ); overload;
   constructor Create(out T: TTransformNode; out SH: TShapeNode ); overload;
   constructor Create(out SH: TShapeNode); overload;
   constructor Create(out T: TTransformNode); overload;
   constructor Create(); overload;

```

with the obvious bridging to the real `(ptr, ptr)` constructor.

```delphi
 {$T+}
 constructor xxxx.Create(out T: TTransformNode); overload;
 begin
    Create( nil, @T );
 end;

```

Since i can’t come out with a decent name - then why bother at all? 😃

* * *

> mean, the gain (you can build 2D primitives without specifing Z = 0 everywhere) is less that the additional complication (much more nodes, and their handling introduces additional conversion step).

Yeah, that is the question, and i am on the fence about it.

But then, maybe the best of both worlds can be done by adding a special method? like you have `TransformXY` augmenting full-featured `Transform`, like the `RotationAngle` i proposed.

Right now you have in your 3D classes the method `OutlineCoords.SetPoint( const Vs: array of Vector3 );`  
Perhaps those very 3D classes could be augmented with method like `OutlineCoords.SetPointXY( const Vs: array of Vector2; const Z = 0.0 );` ?

* * *

> Personally I think they should be part of Geometry3D, the current distinction between Rendering (“stuff that doesn’t need triangulation”) and Geometry3D (“stuff that needs triangulation”) is probably more confusing than helpful.

> see also “Building a mesh using code”

Yeah, this “look from above” on the whole picture seems really missing from the docs. It is in your head, but is not easily accessible to bystanders ☹

That’s why i speculated the doc is shabby and obsolete on that part.

In particular, the Geometry2D demo seems to me as an attempt to ride two horses, to show explicit creation of `TTransformNode` yet at the smame time to ignore it and keep things as simple as possible.

If i get the gist behind embedding the `TTransformNode` then perhps it would be better to have two demos. One would do whole rotation and would not have any explicit `TTransformNode` at all, like it was suggested in the comments.

```delphi
  // Note: in this case, since you just rotate whole Scene,
  // you could also rotate it like this:
  //Scene.Rotation := Vector4(0, 0, 1, LifeTime * 2);
  // There's no need for TTransformNode in this case.

```

See, trying to squeeze opposite intentions into one…

Just make a demo#2 on top of the first, having some segmented shape, like railway semaphore, or a clock with hour and minute arrows/hands, or a torso with limbs. Then you create `TTransformNode` to represent moving joints, right? And so it would be obvious intention and implementation, on top of the basic “create simplistic anything” as demo#1

---

<div class="post-metadata">

### Author: ![michalis](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/michalis/32/3_2.png) [@michalis](https://forum.castle-engine.io/u/michalis)
#### Post date: [June 29, 2022, 12:19am UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/4 "2022-06-29T00:19:17Z")

</div>

> [@Arioch](#):
>
> Is it just a dusty old code from times when you had no `CreateWithTransform` yet, or am i missing something and it can not be the substitute?

I simply didn’t always use the `CreateWithShape` or `CreateWithTransform` shortcut, to show it is possible to work without them.

Nothing dusty or whatever.

As for naming – well these are the best names I came up with. Overloading `Create` would be much more confusing, so no.

> [@Arioch](#):
>
> Perhaps those very 3D classes could be augmented with method like `OutlineCoords.SetPointXY( const Vs: array of Vector2; const Z = 0.0 );` ?

Maybe. The usefulness of this shortcut would still be limited – how hard it is to just pass an array of `TVector3`? So not for now, but I’ll keep it in mind.

> [@Arioch](#):
>
> Just make a demo#2 on top of the first, having some segmented shape, like railway semaphore, or a clock with hour and minute arrows/hands, or a torso with limbs.

This is a good idea. Though note that ideally, I want to get rid of 2 alternative ways to transform stuff in CGE – we have `TTransformNode` and `TCastleTransform` and there are many situations when both are sensible solutions. In the long run, these should be one and the same, [Roadmap | Manual | Castle Game Engine](https://castle-engine.io/roadmap#_make_tcastlescene_tcastletranform_and_friends_to_be_special_x3d_nodes) .

Still, surely more demos showing it would be nice, good point.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [June 29, 2022, 12:02pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/5 "2022-06-29T12:02:34Z")

</div>

> [@michalis](#):
>
> to show it is possible to work without them.

i guess the result is the opposite, you imply there is one hidden differnce there, why one can be used and another can not. The novice reader is left confused (F.U.D.) as what fine reasoning did he missed…

i guess it would be better to use the helper and then add the comments that it is equivalent with this explicit and verbose code.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [June 29, 2022, 12:12pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/6 "2022-06-29T12:12:07Z")

</div>

> [@michalis](#):
>
> `TTransformNode` and `TCastleTransform` and there are many situations when both are sensible solutions. In the long run, these should be one and the same

Not sure.

CGE is not just a thin wrapper over x3d, so it can deviate.

To me `TCastleTransform` is “programming by contract” and `TTransformNode` is “implementation detail”. It might be reasonable to make every CT refer to explicit or implicit TN behind the cover. But still i think making them one and the same would be leaky abstraction and tight coupling

---

<div class="post-metadata">

### Author: ![michalis](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/michalis/32/3_2.png) [@michalis](https://forum.castle-engine.io/u/michalis)
#### Post date: [June 29, 2022, 12:42pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/7 "2022-06-29T12:42:42Z")

</div>

> [@Arioch](#):
>
> To me `TCastleTransform` is “programming by contract” and `TTransformNode` is “implementation detail”. It might be reasonable to make every CT refer to explicit or implicit TN behind the cover. But still i think making them one and the same would be leaky abstraction and tight coupling

That is a good point, and I also view them this way.

I mean, in general, in most CGE API, we try to hide X3D nodes, and give you higher-level things to work with. Like our TCastleBox or TCastlePointLight, that underneath wrap some X3D nodes, but you even cannot deal with these X3D nodes directly. Or TCastleScene, that is really a big wrapper over TX3DRootNode – and you _can_, but in 90% cases you _don’t have to_ deal with X3D nodes inside `MyScene.RootNode`.

This makes better API – X3D is sometimes too low-level, and/or sometimes it has it’s “weirdness” that we prefer to hide.

So I don’t really want to “burden” TCastleTransform API with some additional X3D-specific stuff. Indeed, the link TCastleTransform\<-\>TTransformNode should be “under the covers”.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [July 3, 2022, 1:42pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/8 "2022-07-03T13:42:08Z")

</div>

> [@michalis](#):
>
> how hard it is to just pass an array of `TVector3`?

if the app/game is generally 3D in it’s internal data - then there probably is some ready-made array already, indeed.

if the app is mostly 2D inside - then there would be tedious conversions here and there.

and exactly because they would be simple and boring developer would have his guards down and would start overlooking copy-paste typos. That is why utility functions are made, to write it once and only use later 🙂

Which perhaps means there’d be a global utility  
`function Vector3s( const Vs: array of TVector2; const Z: ... = 0.0 ): TArray<TVector3>; overload;`  
and the said methods perhaps should just call it.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [July 16, 2022, 10:26pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/9 "2022-07-16T22:26:25Z")

</div>

Just some night musing…

> [@michalis](#):
>
> > [@Arioch](#):
> >
> > Perhaps those very 3D classes could be augmented with method like `OutlineCoords.SetPointXY( const Vs: array of Vector2; const Z = 0.0 );` ?
> 
> Maybe. The usefulness of this shortcut would still be limited – how hard it is to just pass an array of `TVector3`? So not for now, but I’ll keep it in mind.

Interesting, that you kind of already have it, albeit reserved in ownership.

I found this `function TVector3List.ToVector4(const W: Single): TVector4List;`

Strangely, there is no similar helpers in `TVector3List`. It was more of ad hoc hack than a consistent design choice. But if so then WHY was it promoted into a class member?..

Yeah, yeah, List is not an array, so this function is dangerous of memory leaks, and classes are not a fastest thing either (some speed-obsessed libs even stuck with objects instead of classes, at least until “advanced records” came). But still, that function is there. Alone.

Also, after wetting my feet in functional programming, i’d more appreciate “pull” than “push”.  
IOW i’d more like - assuming all other things the same - “pure function” way of `constructor ToVector4List.Create(const TVector3List or TArray<TVector3>)` than a pattern like `function TStringList.ToStringArray()`;

And then we hypothetically could have (abuse?) implicit typecasts, which some Scala folk christened a “magnet pattern” and which they used to fight combinatorial explosion in overloaded methods.

_Funny that some years before them coining it i tried to do a similar thing to char and string functions in Jedi Code Library, which names and arguments were kinda erratic. This did not wanted by upstream uch and was not completed, though. Because - jsut a geist and synthetic example - a hypothetical function to subtract a set of char from another could have each of their arguments as a char, an array of, a string of, or a set of, or even a TList\< char \>. “Classic” way could be to provide a function (maybe an overload, otherwise an extra problem of reasonable names comes) for every combination of argument types, which is the ad and fragile explosion. Alternative way would be to make one funciton with some selected final type of arguments, and then to provide the compiler a set of implicit type converting functions, which it would apply at call sites._

_Granted, Delphi and FPC are not very good with “type inference” and thus with implicit typecasts too…_

Now, why you use `procedure SetPoint(const Value: array of TVector3); overload;` instead of `procedure SetPoint(const Value: TArray<TVector3>); overload;` in places like `TCoordinateNode` ?

Just legacy and avoiding boilerplate of creating named dynarray types in pre-generics FPC?

Or do open arrays (TWO parameters with no refcounting) actually work better and faster for this application than a dynamic array (single parameter but might trigger refcounting later in the flow) ?

I mean, the obvious `TCoordinateNode.SetPoint( TVector3List.CreateOutOf( array of Vector2, Z ) )` would leak and thus is non-starter.

However a compiler-managed type, like dynarray, could pursue this way, hypothetically.

Like `TVector3` is not just an array but a `record` containing array.  
So could there be a record `TVector3Array` packing in extra methods, including implicit and explicit type casts. And then a hypothetical `TCoordinateNode.SetPoint( TVector3Array.Create( array of Vector2, Z ) )` could fly.

_Even if that hypothetical `TVector3Array` was an array nor record (like ad hoc `TBytes` and `TStringDynArray` in Delphi 7) then maybe and with some compilers auto-casting could be provided as `record helper`/`type helper`. Those helpers seem to me too overused by Delphi XE3+ RTL - basically abusing the concept to gloss over ocmpiler shortcomings - but that train has already departed whether i like it or not._

Or, returning to the comment start, there could be `function TVector2List.ToVector2(const Z: Single = 0): TVector3Array` and `function TVector2Array.ToVector3(const Z: Single = 0): TVector3Array`, providing for a better readable call site like `TCoordinateNode.SetPoint( my_2d_array.ToVector3(100) )`.

Getting effectively the same without adding an yet-another-name function like `SetPointXY` nor a 3rd overload of `SetPoint`.

Basically, type conversion really feels a generic enough task that should not be embedded inside data consumers, which would result in ugly copy-pasting those helper functions all across the records and classes. All those “pseudo-generic” containers libraries of Delphi 7, be them macros-based or copy-paste-based, were really itchy to see.

---

<div class="post-metadata">

### Author: ![michalis](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/michalis/32/3_2.png) [@michalis](https://forum.castle-engine.io/u/michalis)
#### Post date: [July 18, 2022, 6:54am UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/10 "2022-07-18T06:54:54Z")

</div>

> [@Arioch](#):
>
> Now, why you use `procedure SetPoint(const Value: array of TVector3); overload;` instead of `procedure SetPoint(const Value: TArray<TVector3>); overload;` in places like `TCoordinateNode` ?

In general we encourage to use classes (list `TVector3List`) for containers, instead of (dynamic) arrays, because the classes are more packed with features and can be extended with even more. (This got a bit blurry when type helpers for dynamic arrays became possible, but still I feel classes are just a “complete solution” to containers).

Some API accepts both a class and an array (like above `SetPoint`) because I recognize that sometimes an array is still simpler to use.

The conversion routines like `TVector3List.ToVector4` are indeed just added when they proved useful / necessary. I do not want to commit to expose every possible combination there – it is too easy to make a big API with lots of such “utility” methods that will be almost unused then.

Thinking about 2D coords more, I realized that what we really need, and this would be more comfortable and also more performant in some cases, is a new `TCoordinate2DNode`. This one should keep a list of `TVector2`. It’s better than overloading 3D `TCoordinateNode` with utility functions to load there 2D data, because it means that `TCoordinate2DNode` can be loaded to GPU as 2D, so it will be faster to send to GPU. Following the conventions (from OpenGL, CGE) etc. of course such 2D vector is functionally equivalent to 3D vector with Z = 0. Just like 3D vector is functionally equivalent to 4D vector in homogeneous coordinates with W = 0.

Still, I’m not saying when I’d add it. The argument “this has low usage” remains. Neither glTF (`POSITION` must be `VEC3`, [glTF™ 2.0 Specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) ) nor X3D (the only `X3DCoordinateNode` descendants are 3D, [Extensible 3D (X3D), ISO/IEC 19775-1:2022, 11 Rendering component](https://www.web3d.org/specifications/X3Dv4Draft/ISO-IEC19775-1v4-CD1/Part01/components/rendering.html#Coordinate) ) have added such 2D coords, even though the opportunity is obvious (and it would also imply smaller file size), likely exactly for this reason – sure it can be added, but if the real-world usage is low, then the priority to do this is low.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [July 28, 2022, 6:17pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/11 "2022-07-28T18:17:11Z")

</div>

> [@michalis](#):
>
> hat `TCoordinate2DNode` can be loaded to GPU as 2D, so it will be faster to send to GPU. Following the conventions (from OpenGL, CGE) etc. of course such 2D vector is functionally equivalent to 3D vector with Z = 0

This is one specific OpenGL “implicit type conversion” trick. It won’t work if Z \<\> 0 or if orthogonal rotation applied (i mean, 2D are X and Z or Y and Z, not X and Y).

Not sure if such a narrow special case is required. What if there is 3D rotation transformation applied to that X-Y-zero plane? Would you still have to calculate all 3 coords via rotation matirx, or would you tell OpenGL to do the turn?

Then how would it go with collision detection? I am not sure if rotation offloading to OpenGL is a good thing. I thought i heard “Scene definition” subpart of OpenGL was considered obsolete together with outher fixed-function pipeline related functions. But not sure. Yet even if it is normal, later you would have to re-calculate that again in CPU to check collisions?

- [7. OpenGL Rotation and Translation (Version 2.0) – Swiftless Tutorials - Various older tutorials and newer programming musings](http://www.swiftless.com/tutorials/opengl/rotation.html)
- [General OpenGL: Transformations - OpenGL Wiki](https://www.khronos.org/opengl/wiki/General_OpenGL:_Transformations#I_can.27t_get_transformations_to_work._Where_can_I_learn_more_about_matrices.3F)

These do not claim rotation as obsolete, so perhaps i am wrong. Still not sure if you use them.

---

<div class="post-metadata">

### Author: ![Arioch](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/arioch/32/689_2.png) [@Arioch](https://forum.castle-engine.io/u/Arioch)
#### Post date: [July 28, 2022, 6:20pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/12 "2022-07-28T18:20:41Z")

</div>

> [@michalis](#):
>
> > [@Arioch](#):
> >
> > Now, why you use `procedure SetPoint(const Value: array of TVector3); overload;` instead of `procedure SetPoint(const Value: TArray<TVector3>); overload;` in places like `TCoordinateNode` ?
> 
> Some API accepts both a class and an array (like above `SetPoint`) because I recognize that sometimes an array is still simpler to use.

Also, you kind of miss the point. I was not asking class vs array, i was asking dynamic array vs open array.

You remember that `procedure X( ns: array of integer );` technicalyl has TWO parameters, not one, don’t you?

> [@Arioch](#):
>
> Or do open arrays (TWO parameters with no refcounting) actually work better and faster for this application than a dynamic array (single parameter but might trigger refcounting later in the flow) ?

Yes, this syntax overlapping is a confusing legacy of pre-dynarray Turbo Pascal, and in “Modern Pascal” i’d expect procedures to be changed to use “generic dynamic array” instead of “open array”, unless low-level “this is two parameters not one” is exactly what you aim at (then it better be documented).

* * *

> a bit blurry when type helpers for dynamic arrays became possible

Type helpers were not designed to uniformly extend types, but to hack on 3rd party libraries you have no source for (or wish to keep it vanilla). “Retconning” as they say on TV Tropes 🙂

Delphi XE3 decided to (ab)use type helpers to gloss over lack of type inference in the compiler, or so i think.

To get “best of both worlds” i believe one has to use advanced records, which naturally blend data and funcitons into one local namespace, while type helpers are global and mutually exclusive (try to have two helpers for one type).

I suspect record-boxed dynarray would be somewhat slower than naked dynarray, yet still faster than Delphi-like class instance.

---

<div class="post-metadata">

### Author: ![michalis](https://forum.castle-engine.io/user_avatar/forum.castle-engine.io/michalis/32/3_2.png) [@michalis](https://forum.castle-engine.io/u/michalis)
#### Post date: [July 28, 2022, 8:08pm UTC](https://forum.castle-engine.io/t/x3d-geometry-components-docs-outdated/595/13 "2022-07-28T20:08:25Z")

</div>

As for `TCoordinate2DNode`:

- Indeed it would limit the case to situation where Z = 0.

- But of course you can transform such objects. You can move them (also in Z), rotate them, scale etc. It’s normal and its what regularly happens in 2D games 🙂

- Fixed-function, that offered one way of transforming objects (`glRotatef` and friends) is deprecated. But of course you still can, and everyone does it, transform (rotate, translate, scale…) objects in OpenGL, using shaders (most commonly: using matrix multiplication in vertex shader). Nothing special about it, it’s what happens already in CGE and pretty much all game engines 🙂

- The reason why I wonder (but still only wonder) about `TCoordinate2DNode` is that it not only addresses a common case in 2D (specifying object with constant Z = 0) but also can be more efficient. Sending a million of points in `TCoordinate2DNode` means 2/3 less data transfer to GPU vs million of points in `TCoordinateNode`.
