loader.loadTexture(), Texture.makeCopy()

I just realised that loader.loadTexture() doesn’t just return a texture object wrapped around some source image that is never loaded twice, it returns -the same- texture object whenever the source image is the same.

This is not ideal as the same image could be useful multiple times with different settings, i.e. different wrapping settings. I tried to do a shallow copy of the returned object but I receive this error message:

Eventually I found the method Texture.makeCopy(), but for some strange reason the resulting object, when applied in the same fashion as a non-copy, is not displayed, and the card on which the texture should be mapped is simply white.

Any idea what might be going on?

Manu

loader.loadTexture loads the texture through the TexturePool, which does exactly what you don’t want.
Either release the texture from the pool or you need to use Texture.read directly. Like:

newtex = Texture()
newtex.setup2dTexture()
newtex.read("yourfile.png")

Hmmm… ok, let me get this straight. If I do this:

newtex1 = Texture()
newtex1.setup2dTexture()
newtex1.read("yourfile.png")

newtex2 = Texture()
newtex2.setup2dTexture()
newtex2.read("yourfile.png")

am I correct to say that the same file is loaded twice in memory? If so, would I be correct to say that one way to have two texture objects share the same image data would be to do something such as:

newtex2 = Texture()
newtex2.setup2dTexture()
newtex2.setRamImage(newtex1.getRamImage())

=?

Manu

EDIT: in the meantime I’ve tried this but I get this error:

AssertionError: compression != CM_off || image.size() == do_get_expected_ram_image_size() at line 787 of c:\p\p3d\panda3d-1.6.1\panda\src\gobj\texture.cxx

Not sure, but that’s the way I do it myself.

As for your error, when setup2dTexture is used together with set_ram_image you must specify the size, compression type, etc. parameters to setup2dTexture. Otherwise it won’t know how to interpret the raw data.

newtex2.setup2dTexture(512, 512, Texture.CMOff, Texture.FRgba)

This is not needed when you use load() or read() instead of filling in the raw data.
Be careful with setting the compression type and format - they have to match exactly. Usually, when loading it from another texture, you would get the data from the old texture.

newtex.setup2dTexture(texture.getXSize(), texture.getYSize(), texture.getComponentType(), texture.getFormat())
newtex.setRamImage(texture.getRamImage())

tex.makeCopy() should certainly work, and return a new copy of the texture that you can apply normally. If it doesn’t, something’s wrong–can you tell me more?

Note that all of these strategies–including tex.makeCopy(), or reloading from disk, or setting the same ram image on multiple textures–all of them involve replicating the texture multiple times in texture memory. That’s the only way to set different wrap mode settings–you have to replicate it if you really want to do this. The wrap mode settings are bound to the OpenGL texture object, same as the image.

So, if not wasting texture memory is important to you, I recommend finding a way to share the same wrap settings on all copies of a particular texture.

David

Yep, have a look at this code:

from direct.directbase.DirectStart import *
from direct.gui.DirectGui import *
from pandac.PandaModules import *

cardMaker = CardMaker("Frame")
aCard = render.attachNewNode(cardMaker.generate())
aCard.setTransparency(TransparencyAttrib.MAlpha)

aTexture = loader.loadTexture("aPngWithAnAlpha.png")
aTextureCopy = aTexture.makeCopy()

aCard.setTexture(aTexture)
#aCard.setTexture(aTextureCopy)

DirectFrame(geom=aCard)

run()

Notice the two texture-setting lines. If “aTexture” is used the card shows the image and the transparency as expected. If “aTextureCopy” is used the card doesn’t show anything: it’s just 100% white, but I’d expect the exact same result as when using “aTexture”. Shouldn’t I?

Ah! Thank you for that. It answers my original question and it means that not even makeCopy() would allow me to share the image data across two texture objects. I had a look at the OpenGL reference and I understand what you are saying about the wrap settings being bound to the OpenGL texture object. I’m wondering if this is due to the array storing the image data itself being permanently rearranged when the wrap setting is chosen, for performance reason. No big deal though, I’m fine sharing texture objects rather than raw image data. It will do.

Ah, you’re right; and this is indeed a bug in Panda. I just checked in the fix; it should become part of 1.6.2.

I kind of doubt this sort of thing happens. It’s just the way the API is designed, and it might not relate to any detail of implementation. In fact, I think it’s the nature of texturing that it would be rare that you’d want to switch the wrap mode for any one particular texture image, since normally a texture is either designed to be clamped, or designed to be repeated; and this is probably when the OpenGL designers had in mind when they came up with the interface.

I guess it would be possible to write OpenGL code that did actually switch the wrap mode for a particular texture object dynamically during the frame. This might or might not have performance implications, depending on the driver implementation. And I doubt many people make the attempt to do this; Panda doesn’t. :slight_smile:

David

Yippieee!!! I found a bug! If I find another 999 do I get a bug-hunter achievement digital badge to proudly display with my avatar here in the forum? I think there could be five tiers: [color=orange]bronze badge after 10 bugs, [color=grey]silver badge after 25, [color=yellow]gold badge after 50, [color=white]platinum badge after 100 and [color=blue]p[color=indigo]os[color=red]it[color=orange]ro[color=yellow]ni[color=green]um badge after 1000 bugs!

:smiley:

Manu

No, you’ll get those when you actually fix them. :wink:

Nah, if that was true, drwr’s badge would explode. :slight_smile:

Naww, you don’t get points for fixing your own bugs. :slight_smile:

David