I'm using SDL2 with SDL_TEXTUREACCESS_STREAMING
without OpenGL and I want to transfer/combine some Textures from my function to my main loop. So, I decided to change my Access type from STREAMING
to TARGET
, use SDL_SetRenderTarget
with SDL_RenderCopy
and again put the Access type to STREAMING
, but when I preview it with the SDL_RenderPresent
not is showing the sended texture.
Here is my function to Open the textures:
TUserFunc(
void, OpenTTF, Reference font, int32_t align, int32_t x, int32_t y, Reference txt, int32_t scl)
{
int tgt_w = g_w;
int tgt_h = g_h;
TTF_Font * ttfFont = TTF_OpenFont(pu->refToAstr(CP_THREAD_ACP, font).c_str(), scl);
if(ttfFont == nullptr) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error cargando la direccion de las fuentes", NULL);
quitGame();
}
SDL_Surface * surfaceText = TTF_RenderText_Blended(ttfFont, (pu->refToAstr(CP_THREAD_ACP, txt).c_str()), color);
if(surfaceText == nullptr){
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error creando Superficie", NULL);
quitGame();
}
textureText = SDL_CreateTextureFromSurface(g_renderer,surfaceText);
if(textureText == nullptr){
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SDL ERROR", "Error creando Texturas", NULL);
quitGame();
}
SDL_Rect rectangle;
rectangle.x = x;
rectangle.y = y;
rectangle.w = surfaceText->w;
rectangle.h = surfaceText->h;
//The Problem Start from here
unlockTarget();
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, tgt_w, tgt_h);
SDL_SetRenderTarget(g_renderer, g_target);
SDL_RenderCopy(g_renderer, textureText, NULL, &rectangle);
SDL_SetRenderTarget(g_renderer, NULL);
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);
lockTarget();
}
lockTarget()
and unlockTarget()
it's for a simple way to lock and unlock the texture, and how you can see, I use the CreateTexture
to change to TARGET
, put my SetRenderTarget
and RenderCopy
and again use the CreateTexture
to change back to STREAMING
And this is my main loop to show the graphics:
TUserFunc(void, Flip)
{
if(g_target){
unlockTarget();
SDL_RenderCopy(g_renderer, g_target, nullptr, nullptr);
lockTarget();
}
SDL_RenderPresent(g_renderer);
}
but if I add this, the texture is showed, but not same texture, I mean, not is combined with g_target
TUserFunc(void, Flip)
{
if(g_target){
unlockTarget();
SDL_RenderCopy(g_renderer, g_target, nullptr, nullptr);
lockTarget();
}
if(textureText){
unlockTarget();
SDL_RenderCopy(g_renderer, textureText, nullptr, nullptr);
lockTarget();
}
SDL_RenderPresent(g_renderer);
}
Here you can see the other functions to have a better view about the problem:
TUserFunc(bool, Init...)
{
...
// This is the main and unique call to g_target
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, w, h);
SDL_SetTextureBlendMode(g_target, SDL_BLENDMODE_NONE);
...
}
void lockTarget()
{
if(g_target) SDL_LockTexture(g_target, nullptr, (void**)&g_pix, &g_pitch);
if(textureText) SDL_LockTexture(textureText, nullptr, (void**)&g_pix, &g_pitch);
}
void unlockTarget()
{
if(g_target) SDL_UnlockTexture(g_target);
if(textureText) SDL_UnlockTexture(textureText);
}
This can't work:
unlockTarget();
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, tgt_w, tgt_h);
SDL_SetRenderTarget(g_renderer, g_target);
SDL_RenderCopy(g_renderer, textureText, NULL, &rectangle);
SDL_SetRenderTarget(g_renderer, NULL);
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);
lockTarget();
You create a texture, render another one onto it, and then proceed to get rid of its pointer and create a new one.
SDL_CreateTexture
, as its name implies, creates a texture.
With this line:
g_target = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tgt_w, tgt_h);
You are essentially throwing away whatever g_target
held and replaces it with a new, empty texture with STREAMING
access.
I use the
CreateTexture
to change toTARGET
, put mySetRenderTarget
andRenderCopy
and again use theCreateTexture
to change back toSTREAMING
This simply not how it works. You can't change a texture's access mode once it has been created. All that SDL_CreateTexture
does is creating yet another texture.
As a result, all you do is leaking memory and get non-working code.
An SDL_Texture
, according to the documentation (archive), is:
A structure that contains an efficient, driver-specific representation of pixel data.
You aren't supposed to do anything with SDL_Texture
s besides rendering them or rendering other textures onto it.
Changing their access mode in real time is not possible.
If you really need to render textures on top of others and then access their pixel data, then use SDL_Surface
s (archive):
A structure that contains a collection of pixels used in software blitting.
You can blit those on top of others as well, using SDL_BlitSurface
. Plus, you can access SDL_Surface
s' pixel data for further editing.
And only THEN, where you are DONE touching to pixel data, convert it into a texture using SDL_CreateTextureFromSurface
and render it.
It might be slower than trying to mess directly with textures, but at least it works and is meant to be done.
Sure, STREAMING
mode exists on textures for a reason, but all you can do with it is hacky trickery to get things poorly done where using surfaces would have been much better.
And besides, you can't change a texture's access mode from TARGET
to STREAMING
as I have already said, so you don't really have a choice here. You need to use surfaces.