How do I get the width and height of the texture for TCastleAbstractPrimitive?
While I’m doing it like this.
Tex := TImageTextureNode.Create;
Tex.SetUrl(Self.Texture);
writeln(Tex.TextureImage.Width);
But the texture loading takes place in TCastleAbstractPrimitive.UpdateMaterialNode
It turns out that I load the texture twice. Therefore, my way does not seem right to me.
Is there another way?
There are some “tricks” you could use to access the already loaded texture node:
-
One is to look into primitive children, there’s an internal TCastleScene
, and you could search there for TImageTextureNode
.
-
Another is to use X3DCache.TextureImage_IncReference
to use cache directly,
… but my recommendation would be (for now) to not do these tricks.
Instead follow the approach you show above, create a TImageTextureNode just to read size, this is OK…
…just make sure to keep your TImageTextureNode existing for a longer time (maybe just keep it existing as much as the primitive) to make sure that both your TImageTextureNode and the TCastleAbstractPrimitive use the same texture instance from the cache. I.e. the texture will not be loaded twice if it was already present in the cache So whoever (you or primitive) will load the texture for the 2nd time, in 2nd TImageTextureNode instance, will actually just use the cache, and it will be instant.
I did a quick test, attaching:
In TViewMain.Start
I create a new
TextureNodeOnlyToGetSize := TImageTextureNode.Create
and set URL, only to know the texture size. I let this TextureNodeOnlyToGetSize
to exist (until TViewMain.Stop
) so that it keeps the texture in the cache. When the box (TCastleBox) needs to load the texture, it will just use the existing texture from the cache. This can be confirmed by activating log
LogTextureCache := true
and looking at log:
++: Texture image castle-data:/totoro-powerof2.jpg: 1
Size: 2048 x 1024
++: Texture image castle-data:/totoro-powerof2.jpg: 2
So the reference count of castle-data:/totoro-powerof2.jpg
has increased to 2. The 2nd access to it was lighting fast, it just used existing instance of TEncodedImage
(this one instance of TEncodedImage
is internally used by 2 instances of TImageTextureNode
in effect) from cache.
my-new-project-boxcache-0.1-src.zip (2.4 MB)
1 Like
Thanks very much. CGI stretches the width and height of the texture to the power of two. At what point does this happen? How do I get this width and height?
Indeed. The scaling happens right before texture is actually loaded into the GPU, so you cannot (kind of by design) actually see the scaled sizes now anywhere. But you can just invoke ResizeToTextureSize
to use the same algorithm as CGE. It has an overloaded version that just takes and returns an integer size, i.e. it doesn’t actually resize any image, just answers what the resulting image “would have”: Castle Game Engine: CastleGLImages ,
function ResizeToTextureSize(const Size: Cardinal; const Sizing: TTextureSizing): Cardinal; overload;
So if you have a texture Width and Height, you can do
FinalWidth := ResizeToTextureSize(Width, tsScalablePowerOf2);
FinalHeight := ResizeToTextureSize(Height, tsScalablePowerOf2);
You can go one step further to support TextureProperties.guiTexture
, Texturing component - extensions | Castle Game Engine (I admit I don’t like this name, I should change it to like Mipmaps
with inverted meaning – because it has use-case outside of GUI of course too, sometimes you don’t need mipmaps and then you don’t need power of 2). This would look like:
var
GUITexture: Boolean; // mipmaps not necessary, no need to scale to power-of-2
TextureNode: TImageTextureNode;
Sizing: TTextureSizing;
begin
TextureNode := ...;
if TextureNode.TextureProperties <> nil then
GUITexture := TextureProperties.GUITexture
else
GUITexture := false;
if GUITexture then
Sizing := tsAny
else
Sizing := tsScalablePowerOf2;
FinalWidth := ResizeToTextureSize(TextureNode.TextureImage.Width, Sizing);
FinalHeight := ResizeToTextureSize(TextureNode.TextureImage.Height, Sizing);
end;
I wrote this (untested) code looking at our current logic in src/scene/castleinternalrenderer_texture.inc
.
1 Like