text: /*****************************************************************************/
  /*                             Spike SourceCode                              */
  /*                                                                           */
  /* File created by: Fahim Fuad                                               */
  /* Other editors: None                                                       */
  /*                                                                           */
  /*   Licensed under the Apache License, Version 2.0 (the "License");         */
  /*   you may not use this file except in compliance with the License.        */
  /*   You may obtain a copy of the License at                                 */
  /*                                                                           */
  /*       http://www.apache.org/licenses/LICENSE-2.0                          */
  /*                                                                           */
  /*   Unless required by applicable law or agreed to in writing, software     */
  /*   distributed under the License is distributed on an "AS IS" BASIS,       */
  /*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/
  /*   See the License for the specific language governing permissions and     */
  /*   limitations under the License.                                          */
  /*****************************************************************************/
  #include "spkpch.h"
  #include "Scene.h"
  #include "Spike/Renderer/Renderer2D.h"
  #include <glm/glm.hpp>
  #include "Spike/Scene/Components.h"
  #include "Entity.h"
  
  namespace Spike
  {
      Scene::Scene()
      {
      }
  
      Scene::~Scene()
      {
      }
  
      Entity Scene::CreateEntity(const std::string& name)
      {
          Entity entity( m_Registry.create(), this );
          entity.AddComponent<TransformComponent>();
          auto& tag = entity.AddComponent<TagComponent>();
  
          tag.Tag = name.empty() ? "Entity" : name;
          return entity;
      }
  
      void Scene::DestroyEntity(Entity entity)
      {
          m_Registry.destroy(entity);
      }
  
      void Scene::OnUpdateRuntime(Timestep ts)
      {
          // Update scripts
          {
              m_Registry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc)
                  {
                      if (!nsc.Instance)
                      {
                          nsc.Instance = nsc.InstantiateScript();
                          nsc.Instance->m_Entity = Entity{ entity, this };
                          nsc.Instance->OnCreate();
                      }
  
                      //TODO: The OnDestroy() function! 
                      nsc.Instance->OnUpdate(ts);
                  });
          }
  
          //Render 2D
          Camera* mainCamera = nullptr;
          glm::mat4 cameraTransform;
  
          {
              auto view = m_Registry.view<TransformComponent, CameraComponent>();
              for (auto entity : view)
              {
                  auto [transform, camera] = view.get<TransformComponent, CameraComponent>(entity);
                  if (camera.Primary)
                  {
                      mainCamera = &camera.Camera;
                      cameraTransform = transform.GetTransform();
                      break;
                  }
              }
          }
          if (mainCamera)
          {
              Renderer2D::BeginScene(*mainCamera, cameraTransform);
  
              auto group = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
              for (auto entity : group)
              {
                  auto [transform, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
                  Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color);
              }
  
              Renderer2D::EndScene();
  
          }
      }
  
      void Scene::OnUpdateEditor(Timestep ts, EditorCamera& camera)
      {
          Renderer2D::BeginScene(camera);
  
          auto group = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
          for (auto entity : group)
          {
              auto [transform, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
  
              Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color);
          }
  
          Renderer2D::EndScene();
      }
  
      void Scene::OnViewportResize(uint32_t width, uint32_t height)
      {
          m_ViewportWidth = width;
          m_ViewportHeight = height;
  
          auto view = m_Registry.view<CameraComponent>();
          for (auto entity : view)
          {
              auto& cameraComponent = view.get<CameraComponent>(entity);
              if (!cameraComponent.FixedAspectRatio)
                  cameraComponent.Camera.SetViewportSize(width, height);
          }
      }
  
      Entity Scene::GetPrimaryCameraEntity()
      {
          auto view = m_Registry.view<CameraComponent>();
          for (auto entity : view)
          {
              const auto& camera = view.get<CameraComponent>(entity);
              if (camera.Primary)
                  return Entity{ entity, this };
          }
          return {};
      }
  
      template<typename T>
      void Scene::OnComponentAdded(Entity entity, T& component)
      {
          static_assert(false);
      }
  
      template<>
      void Scene::OnComponentAdded<TransformComponent>(Entity entity, TransformComponent& component)
      {
      }
  
      template<>
      void Scene::OnComponentAdded<CameraComponent>(Entity entity, CameraComponent& component)
      {
          component.Camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
      }
  
      template<>
      void Scene::OnComponentAdded<SpriteRendererComponent>(Entity entity, SpriteRendererComponent& component)
      {
      }
  
      template<>
      void Scene::OnComponentAdded<TagComponent>(Entity entity, TagComponent& component)
      {
      }
  
      template<>
      void Scene::OnComponentAdded<NativeScriptComponent>(Entity entity, NativeScriptComponent& component)
      {
      }
  }