| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | // Copyright (c) 2016-2018 Kiwano - Nomango
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					
						
							|  |  |  | // of this software and associated documentation files (the "Software"), to deal
 | 
					
						
							|  |  |  | // in the Software without restriction, including without limitation the rights
 | 
					
						
							|  |  |  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					
						
							|  |  |  | // copies of the Software, and to permit persons to whom the Software is
 | 
					
						
							|  |  |  | // furnished to do so, subject to the following conditions:
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | // The above copyright notice and this permission notice shall be included in
 | 
					
						
							|  |  |  | // all copies or substantial portions of the Software.
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					
						
							|  |  |  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					
						
							|  |  |  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					
						
							|  |  |  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					
						
							|  |  |  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					
						
							|  |  |  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					
						
							|  |  |  | // THE SOFTWARE.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | #include <kiwano/platform/Application.h>
 | 
					
						
							|  |  |  | #include <kiwano/platform/Input.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  | #include <kiwano/core/Director.h>
 | 
					
						
							|  |  |  | #include <kiwano/core/Logger.h>
 | 
					
						
							| 
									
										
										
										
											2020-01-17 16:55:47 +08:00
										 |  |  | #include <kiwano/render/TextureCache.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-11 21:55:29 +08:00
										 |  |  | #include <kiwano/utils/ResourceCache.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-10 15:09:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-24 13:33:19 +08:00
										 |  |  | namespace kiwano | 
					
						
							| 
									
										
										
										
											2019-03-31 13:08:59 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Application::Application() | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |     : quiting_(false) | 
					
						
							|  |  |  |     , time_scale_(1.f) | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-08 09:59:17 +08:00
										 |  |  |     Use(&Renderer::GetInstance()); | 
					
						
							|  |  |  |     Use(&Input::GetInstance()); | 
					
						
							|  |  |  |     Use(&Director::GetInstance()); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  | Application::~Application() {} | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  | void Application::Run(Runner& runner, bool debug) | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     // Setup all components
 | 
					
						
							|  |  |  |     for (auto c : comps_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         c->SetupComponent(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (debug) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-08 09:59:17 +08:00
										 |  |  |         Director::GetInstance().ShowDebugInfo(true); | 
					
						
							|  |  |  |         Renderer::GetInstance().GetContext().SetCollectingStatus(true); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Everything is ready
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |     runner.OnReady(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |     // Initialize variables
 | 
					
						
							|  |  |  |     quiting_          = false; | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     last_update_time_ = Time::Now(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 09:59:17 +08:00
										 |  |  |     Window& window = Window::GetInstance(); | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |     while (!quiting_) | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |         if (window.ShouldClose()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (runner.OnClosing()) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 window.SetShouldClose(false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |         while (EventPtr evt = window.PollEvent()) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |             this->DispatchEvent(evt.get()); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |         this->Update(); | 
					
						
							|  |  |  |         this->Render(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Destroy all resources
 | 
					
						
							|  |  |  |     runner.OnDestroy(); | 
					
						
							|  |  |  |     this->Destroy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Destroy window
 | 
					
						
							|  |  |  |     window.Destroy(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::Quit() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-14 17:12:13 +08:00
										 |  |  |     quiting_ = true; | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::Destroy() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Clear all resources
 | 
					
						
							| 
									
										
										
										
											2020-02-08 09:59:17 +08:00
										 |  |  |     Director::GetInstance().ClearStages(); | 
					
						
							|  |  |  |     ResourceCache::GetInstance().Clear(); | 
					
						
							|  |  |  |     TextureCache::GetInstance().Clear(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         (*iter)->DestroyComponent(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::Use(ComponentBase* component) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (component) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | #if defined(KGE_DEBUG)
 | 
					
						
							| 
									
										
										
										
											2020-02-10 13:47:00 +08:00
										 |  |  |         if (std::find(comps_.begin(), comps_.end(), component) != comps_.end()) | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |         { | 
					
						
							|  |  |  |             KGE_ASSERT(false && "Component already exists!"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |         comps_.push_back(component); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (component->Check(RenderComponent::flag)) | 
					
						
							|  |  |  |             render_comps_.push_back(dynamic_cast<RenderComponent*>(component)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (component->Check(UpdateComponent::flag)) | 
					
						
							|  |  |  |             update_comps_.push_back(dynamic_cast<UpdateComponent*>(component)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (component->Check(EventComponent::flag)) | 
					
						
							|  |  |  |             event_comps_.push_back(dynamic_cast<EventComponent*>(component)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::SetTimeScale(float scale_factor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     time_scale_ = scale_factor; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | void Application::Update() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Before update
 | 
					
						
							|  |  |  |     for (auto c : update_comps_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         c->BeforeUpdate(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // perform functions
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!functions_to_perform_.empty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             perform_mutex_.lock(); | 
					
						
							|  |  |  |             auto functions = std::move(functions_to_perform_); | 
					
						
							|  |  |  |             perform_mutex_.unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             while (!functions.empty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 auto& func = functions.front(); | 
					
						
							|  |  |  |                 if (func) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     func(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 functions.pop(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Updating
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         const Time     now = Time::Now(); | 
					
						
							|  |  |  |         const Duration dt  = (now - last_update_time_) * time_scale_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         last_update_time_ = now; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (auto c : update_comps_) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             c->OnUpdate(dt); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // After update
 | 
					
						
							|  |  |  |     for (auto rit = update_comps_.rbegin(); rit != update_comps_.rend(); ++rit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         (*rit)->AfterUpdate(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::Render() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-08 09:59:17 +08:00
										 |  |  |     Renderer& renderer = Renderer::GetInstance(); | 
					
						
							| 
									
										
										
										
											2020-02-03 14:15:30 +08:00
										 |  |  |     renderer.Clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     // Before render
 | 
					
						
							|  |  |  |     for (auto c : render_comps_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         c->BeforeRender(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Rendering
 | 
					
						
							| 
									
										
										
										
											2020-02-03 14:15:30 +08:00
										 |  |  |     renderer.BeginDraw(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     for (auto c : render_comps_) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-02-03 14:15:30 +08:00
										 |  |  |         c->OnRender(renderer.GetContext()); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-03 14:15:30 +08:00
										 |  |  |     renderer.EndDraw(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // After render
 | 
					
						
							|  |  |  |     for (auto rit = render_comps_.rbegin(); rit != render_comps_.rend(); ++rit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         (*rit)->AfterRender(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-03 14:15:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     renderer.Present(); | 
					
						
							| 
									
										
										
										
											2020-01-21 10:09:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::DispatchEvent(Event* evt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (auto c : event_comps_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         c->HandleEvent(evt); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Application::PreformInMainThread(Function<void()> func) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::lock_guard<std::mutex> lock(perform_mutex_); | 
					
						
							|  |  |  |     functions_to_perform_.push(func); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace kiwano
 |