Exemple #1
0
void frts::Drawer::updatePosition(const SharedManagerPtr& shared, PointPtr pos, Point::value zLevel,
                                  const RegionManagerPtr& regionManager, const ModelFactoryPtr& modelFactory,
                                  const GraphicDataPtr& graphicData, const ModelDataPtr& modelData)
{
    // Pos is not a reference because we may override it.

    assert(shared != nullptr);
    assert(pos != nullptr);
    assert(initialized);

    // We only render on the same z-level or levels below.
    if (pos->getZ() > zLevel)
    {
        return;
    }

    // Change pos if it is below because we render always relative to the current zLevel.
    // Also we check if it is necessary to render (this may change later depending on transparency).
    bool renderPos = (pos->getZ() == zLevel);
    if (pos->getZ() < zLevel)
    {
        pos = modelFactory->makePoint(pos->getX(), pos->getY(), zLevel);
    }

    // The rectangle on the screen which should be rendered.
    auto mapArea = graphicData->getMapArea();
    auto renderX = mapArea.x + regionToScreenX(pos->getX(), shared);
    auto renderY = mapArea.y + regionToScreenY(pos->getY(), shared);
    auto renderWidth = std::min(static_cast<GraphicData::pixel>(graphicData->getZoom() * graphicData->getTileWidth()),
                                mapArea.x + mapArea.width - renderX);
    auto renderHeight = std::min(static_cast<GraphicData::pixel>(graphicData->getZoom() * graphicData->getTileHeight()),
                                 mapArea.y + mapArea.height - renderY);
    SDL_Rect rectToRender = {
        static_cast<int>(renderX),
        static_cast<int>(renderY),
        static_cast<int>(renderWidth),
        static_cast<int>(renderHeight)
    };
    SDL_SetRenderDrawColor(renderer.get(), tileBackgroundR, tileBackgroundG, tileBackgroundB, 0);

    // Check if the position is in the map rectangle.
    if (!mapArea.isPixelInRect(renderX, renderY))
    {
        return;
    }

    // Because of zoom it might be outside the region, so let's just render the background.
    if (pos->getX() >= modelData->getMapSizeX() || pos->getY() >= modelData->getMapSizeY())
    {
        SDL_RenderFillRect(renderer.get(), &rectToRender);
        return;
    }

    // Get block.
    auto renderableId = shared->makeId(Sdl2Ids::renderable());
    auto block = regionManager->getBlock(pos, shared);
    auto entities = block->getByComponent(renderableId);

    // Stacking support.
    IdUnorderedSet stacked;

    // Check for transparency. Currently we only render blocks below if the first entity (the assumed background) has it.
    auto filledBackground = false;
    if (entities.size() > 0)
    {
        auto transparency = getTransparency(entities, renderableId);

        if (transparency > 0)
        {
            SDL_RenderFillRect(renderer.get(), &rectToRender);
            filledBackground = true;

            // Even if the position on the current z-level doesn't need rendering we can look through
            // so it's still necessary to do that.
            renderPos = true;
        }

        // Check descending if the entities are transparent.
        std::vector<EntityVector> allEntitiesBelow;
        for (Point::value i = 1; i <= transparency; ++i)
        {
            auto posBelow = modelFactory->makePoint(pos->getX(),
                                                    pos->getY(),
                                                    pos->getZ() - i);
            auto blockBelow = regionManager->getBlock(posBelow, shared);
            auto entitiesBelow = blockBelow->getByComponent(renderableId);
            allEntitiesBelow.push_back(entitiesBelow);

            // Initialize with a value greater 0 to keep going if there are no entities.
            frts::Point::value transparencyBelow = 1;
            if (entitiesBelow.size() > 0)
            {
                transparencyBelow = getTransparency(entitiesBelow, renderableId);
            }
            if (transparencyBelow == 0)
            {
                // Doesn't make sense to go deeper if not transparent.
                break;
            }
        }

        // Render beginning from the lowest one.
        for (auto it = allEntitiesBelow.rbegin(); it != allEntitiesBelow.rend(); ++it)
        {
            renderEntities(*it, renderableId, rectToRender, stacked, shared, graphicData->getZoom());
        }
    }

    if (renderPos)
    {
        if (!filledBackground)
        {
            SDL_RenderFillRect(renderer.get(), &rectToRender);
        }

        renderEntities(entities, renderableId, rectToRender, stacked, shared, graphicData->getZoom());
    }
}