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