My application has multiple views which utilize their own SDL_Window
and SDL_Renderer
, using the renderer to draw all of my tile layers into the main view (the main view contains a composited result of rendering several layers of tiles, and the other views are meant to show each individual layer in a photoshop-style 'layer panel'). The problem here is trying to take a texture (or surface, renderer, etc) and rendering it to another self-contained view. If I use SetRenderTarget
and SDL_RenderCopy
, it fails because the target texture belongs to a different renderer...
I've also tried locking the pixels of each view's texture, in an attempt to manually copy over the pixels, but locking the pixels fails unless the texture was created as a streaming texture... Also, the views are of different sizes, so the target texture would need to be stretched down to fit, causing more work than should be necessary.
This led me to the use of SDL_SoftStretch
... Which works, but of course is painfully slow since it can't be used with hardware accelerated textures.
Is there any plausible, reasonably efficient way of taking the rendered output of one SDL_Window
, and rendering a scaled-down version version of it into another?
EDIT:
Besides the cramped use of SDL_SoftStretch
, this is the closest I came to getting things to work out...
It fails because I hit another brick wall when looking for a way to grab the pixel data from the renderer:
SDLView.cpp
//...
BOOL SDLView::Init()
{
m_sdlWindow = SDL_CreateWindowFrom( (PVOID)m_hWndParent );
if(m_sdlWindow == NULL)
return false;
m_sdlRenderer = SDL_CreateRenderer(m_sdlWindow, -1, SDL_RendererFlags::SDL_RENDERER_ACCELERATED);
if(m_sdlRenderer == NULL)
return false;
memset(&m_rect, 0, sizeof(SDL_Rect));
SDL_GetRendererOutputSize(m_sdlRenderer, &m_rect.w, &m_rect.h);
m_pixelFormat = SDL_GetWindowPixelFormat(m_sdlWindow);
m_sdlTexture = SDL_CreateTexture(m_sdlRenderer, m_pixelFormat, SDL_TEXTUREACCESS_STREAMING, m_rect.w, m_rect.h);
SDL_SetRenderDrawColor(m_sdlRenderer, 0x64, 0x95, 0xED, 0xFF);
return true;
}
BOOL SDLView::Clear()
{
memset(&m_rect, 0, sizeof(SDL_Rect));
SDL_GetRendererOutputSize(m_sdlRenderer, &m_rect.w, &m_rect.h);
return SDL_RenderClear(m_sdlRenderer) == 0;
}
VOID SDLView::Present()
{
// Doesn't work because we still have no way of grabbing the rendered output!!
SDL_RenderPresent(m_sdlRenderer);
int result = SDL_RenderCopy(m_sdlRenderer, m_sdlTexture, NULL, NULL);
if(result != 0) {
std::string err(SDL_GetError());
DebugBreak();
}
}
LayerListItem.cpp
void CLayerListItem::OnPaint()
{
CWnd::OnPaint();
CRect rc;
GetClientRect(&rc);
if(m_destView != nullptr)
{
m_destView->Clear();
if(m_srcView != nullptr)
{
int srcPitch = 0, destPitch = 0;
void *srcPixels = nullptr, *destPixels = nullptr;
// Lock the source pixels
int ret = SDL_LockTexture(m_srcView->GetTexture(), &m_srcView->GetRect(), &srcPixels, &srcPitch);
if(ret != 0) {
std::string err(SDL_GetError());
DebugBreak();
}
// Lock the destination pixels
ret = SDL_LockTexture(m_destView->GetTexture(), &m_destView->GetRect(), &destPixels, &destPitch);
if(ret != 0) {
std::string err(SDL_GetError());
DebugBreak();
}
// Unlock all pixels
SDL_UnlockTexture(m_destView->GetTexture());
SDL_UnlockTexture(m_srcView->GetTexture());
// Update our destinaition texture
// (I have tried every possible combination for this line, still no dice!)
int result = SDL_UpdateTexture(
m_destView->GetTexture(),
&m_destView->GetRect(),
srcPixels, srcPitch
);
if(ret != 0) {
std::string err(SDL_GetError());
DebugBreak();
}
SDL_RenderCopy(m_destView->GetRenderer(), m_destView->GetTexture(), NULL, NULL);
OutputDebugStringA("[RENDERED!]...\n");
}
m_destView->Present();
}
}
An OnPaint event is sent to fire off every few seconds, which in turn attempts to grab the rendered output and store it in m_destView
(which, like m_srcView
, is an SDLView). At best, this appears to result in a properly rendered main view (the 'source view'), but a pitch black destination view. I feel like I've tried everything at this point, unless there's something beyond what I've already attempted... any ideas?