SDL2 Рендеринг в текстуру

Мое приложение имеет несколько представлений, которые используют свои собственные SDL_Window и SDL_Renderer, используя рендерер для отрисовки всех моих слоев плитки в основной вид (основной вид содержит составной результат рендеринга нескольких слоев плиток, а другие представления предназначены для отображения каждый отдельный слой на «панели слоев» в стиле Photoshop). Проблема здесь заключается в попытке взять текстуру (или поверхность, средство визуализации и т. д.) и отобразить ее в другом автономном представлении. Если я использую SetRenderTarget и SDL_RenderCopy, произойдет сбой, потому что целевая текстура принадлежит другому рендереру...

Я также пытался заблокировать пиксели текстуры каждого представления, пытаясь вручную скопировать пиксели, но блокировка пикселей не удалась, если текстура не была создана как потоковая текстура... Кроме того, представления имеют разные размеры, поэтому целевая текстура должна быть растянута, чтобы соответствовать, что требует больше работы, чем необходимо.

Это привело меня к использованию SDL_SoftStretch... Который работает, но, конечно, мучительно медленный, поскольку его нельзя использовать с текстурами с аппаратным ускорением.

Есть ли какой-нибудь правдоподобный и достаточно эффективный способ взять отрендеренный вывод одного SDL_Window и преобразовать его уменьшенную версию в другой?


РЕДАКТИРОВАТЬ:
Помимо ограниченного использования SDL_SoftStretch, это самое близкое, что я подошел к тому, чтобы все получилось... Это терпит неудачу, потому что я наткнулся на еще одну кирпичную стену, когда искал способ схватить пиксельные данные из средства визуализации:

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();
    }
}



Каждые несколько секунд отправляется событие OnPaint, которое, в свою очередь, пытается получить визуализированный вывод и сохранить его в m_destView (который, как и m_srcView, является SDLView). В лучшем случае это приводит к правильно отображаемому основному виду («исходному виду»), но к абсолютно черному виду назначения. Я чувствую, что перепробовал все на данный момент, если только нет чего-то сверх того, что я уже пробовал... есть идеи?


person RectangleEquals    schedule 24.06.2014    source источник


Ответы (1)


Я вроде решил эту проблему, используя несколько медленную -- (но все же лучше, чем SDL_SoftRect) -- функцию SDL_RenderReadPixels:

VOID SDLView::CopyTo(SDLView *targetView)
{
    int result = SDL_RenderReadPixels(m_sdlRenderer, nullptr, m_pixelFormat, m_sdlSurface->pixels, m_sdlSurface->pitch);
    if(result != 0) {
        std::string err(SDL_GetError());
        OutputDebugStringA(err.c_str());
        return;
    }

    SDL_Texture *destTexture = targetView->GetTexture();
    result = SDL_UpdateTexture(destTexture, nullptr, m_sdlSurface->pixels, m_sdlSurface->pitch);
    if(result != 0) {
        std::string err(SDL_GetError());
        OutputDebugStringA(err.c_str());
        return;
    }
}


Хорошо работает в паре с m_sdlSurface = SDL_GetWindowSurface(m_sdlWindow), а также m_pixelFormat = SDL_GetWindowPixelFormat(m_sdlWindow)...

Однако обратите внимание, что это НЕ помогает уменьшить масштаб изображения, что, вероятно, означает, что мне все равно нужно будет использовать RenderCopyEx или его эквивалент в какой-то момент, прежде чем предоставить окончательное изображение получателю. Но пока я отмечу это как ответ, пока кто-нибудь не предложит лучшее решение.

person RectangleEquals    schedule 24.06.2014