#include "renderer/scene_renderer.hpp" #include #include #include #include #include namespace sophia { SceneRenderer::SceneRenderer(const SceneRegistry& sceneRegistry, ResourceRegistry& resources, Device& device, vk::Format colorFormat) : sceneRegistry{sceneRegistry}, resources{resources}, spriteRenderSystem{device, colorFormat, resources} {} void SceneRenderer::beginFrame(u32 frameIndex) { ZoneScoped; this->spriteRenderSystem.beginFrame(frameIndex); } void SceneRenderer::render(vk::CommandBuffer commandBuffer, const SceneView& sceneView, Entity camera) { ZoneScoped; SOPHIA_ASSERT(camera.hasComponent(), "camera does not have camera component!"); vk::Extent2D extent = this->resources.renderTargetPool.get(sceneView.target).getExtent(); float aspect = static_cast(extent.width) / static_cast(extent.height); glm::mat4 viewProjection = camera.getComponent().getViewProjection( camera.getComponent(), aspect); renderSprites(commandBuffer, this->sceneRegistry.get(sceneView.scene), viewProjection); // TODO: meshes. Group MeshComponent entities by mesh and draw each group // (instanced), as sprites are grouped by texture. } void SceneRenderer::renderSprites(vk::CommandBuffer commandBuffer, const Scene& scene, const glm::mat4& viewProjection) { this->spriteDrawItems.clear(); auto view = scene.registry.view(); for (auto [entity, transform, sprite] : view.each()) { TextureHandle texture = this->resources.texturePool.isAlive(sprite.texture) ? sprite.texture : this->resources.whiteTexture; this->spriteDrawItems.push_back( {sprite.sortOrder, transform.position.z, texture, {sprite.getModel(transform), sprite.color, sprite.uvRect}}); } // Texture is the last key so that sprites whose order doesn't matter // relative to each other still end up in as few batches as possible. std::ranges::sort(this->spriteDrawItems, {}, [](const SpriteDrawItem& item) { return std::tuple{item.sortOrder, item.depth, item.texture}; }); this->spriteInstances.clear(); this->spriteBatches.clear(); for (const SpriteDrawItem& item : this->spriteDrawItems) { auto index = static_cast(this->spriteInstances.size()); this->spriteInstances.push_back(item.instance); if (this->spriteBatches.empty() || this->spriteBatches.back().texture != item.texture) { this->spriteBatches.push_back({item.texture, index, 0}); } this->spriteBatches.back().instanceCount++; } this->spriteRenderSystem.render(commandBuffer, viewProjection, this->spriteInstances, this->spriteBatches); } } // namespace sophia