From de4751c2d3e7cb907fe6c611382817e5a0ae0dbf Mon Sep 17 00:00:00 2001
From: Nomango <569629550@qq.com>
Date: Thu, 24 Jan 2019 12:21:01 +0800
Subject: [PATCH] refactoring
---
 project/vs2013/Easy2D.vcxproj          |  10 +-
 project/vs2013/Easy2D.vcxproj.filters  |  39 ++--
 project/vs2015/Easy2D.vcxproj          |  10 +-
 project/vs2015/Easy2D.vcxproj.filters  |  39 ++--
 project/vs2017/Easy2D.vcxproj          |  10 +-
 project/vs2017/Easy2D.vcxproj.filters  |  39 ++--
 src/core/Action.hpp                    |   8 +-
 src/core/ActionManager.h               |   2 +-
 src/core/{Game.cpp => Application.cpp} | 228 +++++++++++-----------
 src/core/{Game.h => Application.h}     |  27 +--
 src/core/Canvas.cpp                    |   4 +-
 src/core/Canvas.h                      |  11 +-
 src/core/DebugNode.cpp                 |  27 ++-
 src/core/DebugNode.h                   |  11 +-
 src/core/Event.hpp                     | 109 +++++++++--
 src/core/EventDispatcher.cpp           |   6 +-
 src/core/EventDispatcher.h             |   4 +-
 src/core/EventListener.h               |  11 +-
 src/core/Factory.cpp                   |  58 +++---
 src/core/Factory.h                     |  13 +-
 src/core/Frames.h                      |   2 +-
 src/core/Geometry.h                    |   2 +-
 src/core/GeometryNode.cpp              |   6 +-
 src/core/Image.cpp                     |   4 +-
 src/core/Image.h                       |   2 +-
 src/core/Input.cpp                     |  26 +--
 src/core/Input.h                       |  21 +-
 src/core/IntrusiveList.hpp             | 254 ++++++++++++++++++++++++
 src/core/IntrusivePtr.hpp              | 201 +++++++++++++++++++
 src/core/KeyEvent.hpp                  |  47 -----
 src/core/MouseEvent.hpp                |  55 ------
 src/core/Music.h                       |   2 +-
 src/core/Node.cpp                      |  89 +++++----
 src/core/Node.h                        |  64 +++---
 src/core/Scene.cpp                     |   4 +-
 src/core/Singleton.hpp                 |   7 +-
 src/core/Sprite.cpp                    |   2 +-
 src/core/Task.h                        |   8 +-
 src/core/TaskManager.h                 |   2 +-
 src/core/Text.cpp                      |   6 +-
 src/core/Transition.cpp                |  30 +--
 src/core/Transition.h                  |   4 +-
 src/core/audio.cpp                     |  18 +-
 src/core/audio.h                       |  12 +-
 src/core/d2dhelper.hpp                 |   4 +-
 src/core/helper.hpp                    |  13 +-
 src/core/intrusive/List.hpp            | 257 -------------------------
 src/core/intrusive/SmartPtr.hpp        | 204 --------------------
 src/core/keys.hpp                      |  27 ++-
 src/core/logs.cpp                      |  18 +-
 src/core/render.cpp                    |  68 +++----
 src/core/render.h                      |  30 ++-
 src/core/window.cpp                    |  32 +--
 src/core/window.h                      |  12 +-
 src/easy2d.h                           |   8 +-
 src/math/Matrix.hpp                    |   4 +-
 src/math/Rect.hpp                      |   6 +-
 src/math/vector.hpp                    |   4 +-
 src/ui/Button.cpp                      |  14 +-
 src/ui/Button.h                        |   2 +-
 src/utils/ResLoader.cpp                |  18 +-
 src/utils/ResLoader.h                  |   6 +-
 src/utils/Transcoder.cpp               |  18 +-
 63 files changed, 1107 insertions(+), 1172 deletions(-)
 rename src/core/{Game.cpp => Application.cpp} (68%)
 rename src/core/{Game.h => Application.h} (88%)
 create mode 100644 src/core/IntrusiveList.hpp
 create mode 100644 src/core/IntrusivePtr.hpp
 delete mode 100644 src/core/KeyEvent.hpp
 delete mode 100644 src/core/MouseEvent.hpp
 delete mode 100644 src/core/intrusive/List.hpp
 delete mode 100644 src/core/intrusive/SmartPtr.hpp
diff --git a/project/vs2013/Easy2D.vcxproj b/project/vs2013/Easy2D.vcxproj
index b364d231..7656da8a 100644
--- a/project/vs2013/Easy2D.vcxproj
+++ b/project/vs2013/Easy2D.vcxproj
@@ -36,21 +36,19 @@
     
     
     
-    
+    
     
     
     
     
     
     
-    
-    
-    
+    
+    
     
     
     
     
-    
     
     
     
@@ -102,7 +100,7 @@
     
     
     
-    
+    
     
     
     
diff --git a/project/vs2013/Easy2D.vcxproj.filters b/project/vs2013/Easy2D.vcxproj.filters
index a14c5e46..2111540b 100644
--- a/project/vs2013/Easy2D.vcxproj.filters
+++ b/project/vs2013/Easy2D.vcxproj.filters
@@ -17,9 +17,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -125,12 +122,6 @@
     
       core
     
-    
-      core\intrusive
-    
-    
-      core\intrusive
-    
     
       core
     
@@ -167,15 +158,6 @@
     
       core
     
-    
-      core
-    
-    
-      core
-    
-    
-      core
-    
     
       core
     
@@ -203,6 +185,18 @@
     
       utils
     
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
   
   
     
@@ -217,9 +211,6 @@
     
       {07b6d541-4a1b-472a-aae0-daf9d082fe84}
     
-    
-      {0f508149-735a-43da-ab16-36cc1e9ab63a}
-    
   
   
     
@@ -237,9 +228,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -354,5 +342,8 @@
     
       utils
     
+    
+      core
+    
   
 
\ No newline at end of file
diff --git a/project/vs2015/Easy2D.vcxproj b/project/vs2015/Easy2D.vcxproj
index 413b0d2e..ab2c482c 100644
--- a/project/vs2015/Easy2D.vcxproj
+++ b/project/vs2015/Easy2D.vcxproj
@@ -36,21 +36,19 @@
     
     
     
-    
+    
     
     
     
     
     
     
-    
-    
-    
+    
+    
     
     
     
     
-    
     
     
     
@@ -102,7 +100,7 @@
     
     
     
-    
+    
     
     
     
diff --git a/project/vs2015/Easy2D.vcxproj.filters b/project/vs2015/Easy2D.vcxproj.filters
index a14c5e46..2111540b 100644
--- a/project/vs2015/Easy2D.vcxproj.filters
+++ b/project/vs2015/Easy2D.vcxproj.filters
@@ -17,9 +17,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -125,12 +122,6 @@
     
       core
     
-    
-      core\intrusive
-    
-    
-      core\intrusive
-    
     
       core
     
@@ -167,15 +158,6 @@
     
       core
     
-    
-      core
-    
-    
-      core
-    
-    
-      core
-    
     
       core
     
@@ -203,6 +185,18 @@
     
       utils
     
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
   
   
     
@@ -217,9 +211,6 @@
     
       {07b6d541-4a1b-472a-aae0-daf9d082fe84}
     
-    
-      {0f508149-735a-43da-ab16-36cc1e9ab63a}
-    
   
   
     
@@ -237,9 +228,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -354,5 +342,8 @@
     
       utils
     
+    
+      core
+    
   
 
\ No newline at end of file
diff --git a/project/vs2017/Easy2D.vcxproj b/project/vs2017/Easy2D.vcxproj
index 3a9bee02..fd983f57 100644
--- a/project/vs2017/Easy2D.vcxproj
+++ b/project/vs2017/Easy2D.vcxproj
@@ -36,21 +36,19 @@
     
     
     
-    
+    
     
     
     
     
     
     
-    
-    
-    
+    
+    
     
     
     
     
-    
     
     
     
@@ -102,7 +100,7 @@
     
     
     
-    
+    
     
     
     
diff --git a/project/vs2017/Easy2D.vcxproj.filters b/project/vs2017/Easy2D.vcxproj.filters
index a14c5e46..2111540b 100644
--- a/project/vs2017/Easy2D.vcxproj.filters
+++ b/project/vs2017/Easy2D.vcxproj.filters
@@ -17,9 +17,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -125,12 +122,6 @@
     
       core
     
-    
-      core\intrusive
-    
-    
-      core\intrusive
-    
     
       core
     
@@ -167,15 +158,6 @@
     
       core
     
-    
-      core
-    
-    
-      core
-    
-    
-      core
-    
     
       core
     
@@ -203,6 +185,18 @@
     
       utils
     
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
+    
+      core
+    
   
   
     
@@ -217,9 +211,6 @@
     
       {07b6d541-4a1b-472a-aae0-daf9d082fe84}
     
-    
-      {0f508149-735a-43da-ab16-36cc1e9ab63a}
-    
   
   
     
@@ -237,9 +228,6 @@
     
       core
     
-    
-      core
-    
     
       core
     
@@ -354,5 +342,8 @@
     
       utils
     
+    
+      core
+    
   
 
\ No newline at end of file
diff --git a/src/core/Action.hpp b/src/core/Action.hpp
index 81080623..e73d1e5b 100644
--- a/src/core/Action.hpp
+++ b/src/core/Action.hpp
@@ -22,21 +22,21 @@
 #include "include-forwards.h"
 #include "time.h"
 #include "noncopyable.hpp"
-#include "intrusive/List.hpp"
+#include "IntrusiveList.hpp"
 
 namespace easy2d
 {
 	class ActionManager;
 
 	class Action
-		: public Object
-		, protected intrusive::ListItem
+		: public virtual Object
+		, protected IntrusiveListItem
 	{
 		friend class ActionManager;
 		friend class Loop;
 		friend class Sequence;
 		friend class Spawn;
-		friend class intrusive::List;
+		friend class IntrusiveList;
 
 	public:
 		Action() : running_(false), done_(false), initialized_(false) {}
diff --git a/src/core/ActionManager.h b/src/core/ActionManager.h
index ea8ac98c..c46a2a86 100644
--- a/src/core/ActionManager.h
+++ b/src/core/ActionManager.h
@@ -25,7 +25,7 @@ namespace easy2d
 {
 	class ActionManager
 	{
-		using Actions = intrusive::List;
+		using Actions = IntrusiveList;
 
 	public:
 		// 执行动作
diff --git a/src/core/Game.cpp b/src/core/Application.cpp
similarity index 68%
rename from src/core/Game.cpp
rename to src/core/Application.cpp
index 51e4a0b9..f038b211 100644
--- a/src/core/Game.cpp
+++ b/src/core/Application.cpp
@@ -18,15 +18,14 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include "Game.h"
+#include "Application.h"
 #include "logs.h"
 #include "modules.h"
 #include "Factory.h"
+#include "Event.hpp"
 #include "Scene.h"
 #include "DebugNode.h"
 #include "Transition.h"
-#include "KeyEvent.hpp"
-#include "MouseEvent.hpp"
 #include 
 #include 
 
@@ -34,29 +33,24 @@
 
 namespace easy2d
 {
-	Game::Game()
+	Application::Application(String const& app_name)
 		: active_(false)
 		, debug_(false)
 		, curr_scene_(nullptr)
 		, next_scene_(nullptr)
 		, transition_(nullptr)
 		, time_scale_(1.f)
+		, app_name_(app_name)
 	{
 		::CoInitialize(nullptr);
 	}
 
-	Game::Game(Options const & options)
-		: Game()
-	{
-		Init(options);
-	}
-
-	Game::~Game()
+	Application::~Application()
 	{
 		::CoUninitialize();
 	}
 
-	void Game::Init(const Options& options)
+	void Application::Init(const Options& options)
 	{
 		debug_ = options.debug;
 
@@ -70,7 +64,7 @@ namespace easy2d
 				options.width,
 				options.height,
 				options.icon,
-				Game::WndProc,
+				Application::WndProc,
 				debug_
 			)
 		);
@@ -78,7 +72,7 @@ namespace easy2d
 		HWND hwnd = Window::Instance()->GetHandle();
 
 		ThrowIfFailed(
-			Graphics::Instance()->Init(
+			RenderSystem::Instance()->Init(
 				hwnd,
 				options.vsync,
 				debug_
@@ -126,11 +120,13 @@ namespace easy2d
 			::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
 		}
 
-		// use Game instance in message loop
+		// use Application instance in message loop
 		::SetWindowLongW(hwnd, GWLP_USERDATA, PtrToUlong(this));
+
+		Setup();
 	}
 
-	void Game::Run()
+	void Application::Run()
 	{
 		HWND hwnd = Window::Instance()->GetHandle();
 
@@ -148,14 +144,14 @@ namespace easy2d
 		}
 	}
 
-	void Game::Quit()
+	void Application::Quit()
 	{
 		Window::Instance()->Destroy();
 	}
 
-	void Game::EnterScene(ScenePtr const & scene)
+	void Application::EnterScene(ScenePtr const & scene)
 	{
-		E2D_ASSERT(scene && "Game::EnterScene failed, NULL pointer exception");
+		E2D_ASSERT(scene && "Application::EnterScene failed, NULL pointer exception");
 
 		if (curr_scene_ == scene || next_scene_ == scene)
 			return;
@@ -163,7 +159,7 @@ namespace easy2d
 		next_scene_ = scene;
 	}
 
-	void Game::EnterScene(ScenePtr const& scene, TransitionPtr const& transition)
+	void Application::EnterScene(ScenePtr const& scene, TransitionPtr const& transition)
 	{
 		EnterScene(scene);
 		
@@ -178,17 +174,17 @@ namespace easy2d
 		}
 	}
 
-	ScenePtr const& Game::GetCurrentScene()
+	ScenePtr const& Application::GetCurrentScene()
 	{
 		return curr_scene_;
 	}
 
-	void Game::SetTimeScale(float scale)
+	void Application::SetTimeScale(float scale)
 	{
 		time_scale_ = scale;
 	}
 
-	void Game::Update()
+	void Application::Update()
 	{
 		static auto last = time::Now();
 
@@ -229,12 +225,12 @@ namespace easy2d
 			DebugNode::Instance()->Update(dt);
 	}
 
-	void Game::Render(HWND hwnd)
+	void Application::Render(HWND hwnd)
 	{
-		auto graphics = Graphics::Instance();
+		auto rt = RenderSystem::Instance();
 		
 		ThrowIfFailed(
-			graphics->BeginDraw(hwnd)
+			rt->BeginDraw(hwnd)
 		);
 
 		if (transition_)
@@ -250,27 +246,18 @@ namespace easy2d
 			DebugNode::Instance()->Render();
 
 		ThrowIfFailed(
-			graphics->EndDraw()
+			rt->EndDraw()
 		);
 
 		if (active_)
 			::InvalidateRect(hwnd, NULL, FALSE);
 	}
 
-	void Game::Dispatch(Event * event)
+	LRESULT CALLBACK Application::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 	{
-		if (transition_)
-			return;
+		Application * app = reinterpret_cast(::GetWindowLongW(hwnd, GWLP_USERDATA));
 
-		if (curr_scene_)
-			curr_scene_->DispatchEvent(event);
-	}
-
-	LRESULT CALLBACK Game::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
-	{
-		Game * game = reinterpret_cast(::GetWindowLongW(hwnd, GWLP_USERDATA));
-
-		if (!game)
+		if (!app)
 			return ::DefWindowProcW(hwnd, msg, wparam, lparam);
 		
 		switch (msg)
@@ -280,8 +267,8 @@ namespace easy2d
 			PAINTSTRUCT ps;
 			::BeginPaint(hwnd, &ps);
 
-			game->Update();
-			game->Render(hwnd);
+			app->Update();
+			app->Render(hwnd);
 
 			::EndPaint(hwnd, &ps);
 
@@ -289,11 +276,25 @@ namespace easy2d
 		}
 		break;
 
+		case WM_KEYDOWN:
+		case WM_KEYUP:
+		{
+			if (!app->transition_ && app->curr_scene_)
+			{
+				Event evt((msg == WM_KEYDOWN) ? KeyboardEvent::Down : KeyboardEvent::Up);
+				evt.key.code = KeyCode(wparam);
+				evt.key.count = static_cast(lparam & 0xFF);
+
+				app->curr_scene_->Dispatch(evt);
+			}
+		}
+		break;
+
 		case WM_LBUTTONUP:
 		case WM_LBUTTONDOWN:
 		//case WM_LBUTTONDBLCLK:
-		//case WM_MBUTTONUP:
-		//case WM_MBUTTONDOWN:
+		case WM_MBUTTONUP:
+		case WM_MBUTTONDOWN:
 		//case WM_MBUTTONDBLCLK:
 		case WM_RBUTTONUP:
 		case WM_RBUTTONDOWN:
@@ -301,70 +302,36 @@ namespace easy2d
 		case WM_MOUSEMOVE:
 		case WM_MOUSEWHEEL:
 		{
-			float x = GET_X_LPARAM(lparam) * Window::Instance()->GetContentScaleX();
-			float y = GET_Y_LPARAM(lparam) * Window::Instance()->GetContentScaleY();
-			float wheel_delta = 0.f;
-
-			MouseEvent::Type type;
-			if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN)
-				type = MouseEvent::Down;
-			else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP)
-				type = MouseEvent::Up;
-			else if (msg == WM_MOUSEMOVE)
-				type = MouseEvent::Move;
-			else
+			if (!app->transition_ && app->curr_scene_)
 			{
-				type = MouseEvent::Wheel;
-				wheel_delta = GET_WHEEL_DELTA_WPARAM(wparam) / 120.f;
+				Event evt;
+
+				evt.mouse.x = GET_X_LPARAM(lparam) * Window::Instance()->GetContentScaleX();
+				evt.mouse.y = GET_Y_LPARAM(lparam) * Window::Instance()->GetContentScaleY();
+				evt.mouse.left_btn_down = !!(wparam & MK_LBUTTON);
+				evt.mouse.left_btn_down = !!(wparam & MK_RBUTTON);
+
+				if (msg == WM_MOUSEMOVE)
+					evt.type = MouseEvent::Move;
+				else if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN)
+					evt.type = MouseEvent::Down;
+				else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP)
+					evt.type = MouseEvent::Up;
+				else
+				{
+					evt.type = MouseEvent::Wheel;
+					evt.mouse.wheel_delta = GET_WHEEL_DELTA_WPARAM(wparam) / 120.f;
+				}
+
+				if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP)
+					evt.mouse.button = MouseButton::Left;
+				else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP)
+					evt.mouse.button = MouseButton::Right;
+				else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP)
+					evt.mouse.button = MouseButton::Middle;
+
+				app->curr_scene_->Dispatch(evt);
 			}
-
-			MouseEvent event(type, x, y, wheel_delta);
-
-			if (wparam & MK_LBUTTON || wparam & MK_RBUTTON)
-				event.button_down = true;
-
-			game->Dispatch(&event);
-		}
-		break;
-
-		case WM_KEYDOWN:
-		case WM_KEYUP:
-		{
-			KeyEvent event(msg, KeyCode(wparam));
-			game->Dispatch(&event);
-		}
-		break;
-
-		case WM_DISPLAYCHANGE:
-		{
-			E2D_LOG(L"The display resolution has changed");
-
-			::InvalidateRect(hwnd, nullptr, FALSE);
-		}
-		break;
-
-		case WM_CLOSE:
-		{
-			E2D_LOG(L"Received a message to close the window");
-
-			SysEvent event(SysEvent::WindowClose);
-			game->Dispatch(&event);
-
-			if (game->OnClose())
-			{
-				::DestroyWindow(hwnd);
-			}
-			return 0;
-		}
-		break;
-
-		case WM_DESTROY:
-		{
-			E2D_LOG(L"Window was destroyed");
-
-			game->OnExit();
-			::PostQuitMessage(0);
-			return 0;
 		}
 		break;
 
@@ -372,13 +339,13 @@ namespace easy2d
 		{
 			if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
 			{
-				game->active_ = false;
+				app->active_ = false;
 
 				E2D_LOG(L"Window minimized");
 			}
 			else if (SIZE_RESTORED == wparam)
 			{
-				game->active_ = true;
+				app->active_ = true;
 				::InvalidateRect(hwnd, nullptr, FALSE);
 
 				E2D_LOG(L"Window restored");
@@ -390,7 +357,7 @@ namespace easy2d
 			// 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染
 			// 目标的大小。它可能会调用失败,但是这里可以忽略有可能的
 			// 错误,因为这个错误将在下一次调用 EndDraw 时产生
-			Graphics::Instance()->Resize(width, height);
+			RenderSystem::Instance()->Resize(width, height);
 		}
 		break;
 
@@ -401,15 +368,21 @@ namespace easy2d
 			{
 				E2D_LOG(L"Window activated");
 
-				SysEvent event(SysEvent::WindowActivate);
-				game->Dispatch(&event);
+				if (app->curr_scene_)
+				{
+					Event evt(WindowEvent::Activate);
+					app->curr_scene_->Dispatch(evt);
+				}
 			}
 			else
 			{
 				E2D_LOG(L"Window deactivated");
 
-				SysEvent event(SysEvent::WindowDeavtivate);
-				game->Dispatch(&event);
+				if (app->curr_scene_)
+				{
+					Event evt(WindowEvent::Deavtivate);
+					app->curr_scene_->Dispatch(evt);
+				}
 			}
 		}
 		break;
@@ -425,6 +398,37 @@ namespace easy2d
 			E2D_LOG(L"Window icon changed");
 		}
 		break;
+
+		case WM_DISPLAYCHANGE:
+		{
+			E2D_LOG(L"The display resolution has changed");
+
+			::InvalidateRect(hwnd, nullptr, FALSE);
+		}
+		break;
+
+		case WM_CLOSE:
+		{
+			E2D_LOG(L"Received a message to close the window");
+
+			if (app->curr_scene_)
+			{
+				Event evt(WindowEvent::Closing);
+				app->curr_scene_->Dispatch(evt);
+			}
+			::DestroyWindow(hwnd);
+			return 0;
+		}
+		break;
+
+		case WM_DESTROY:
+		{
+			E2D_LOG(L"Window was destroyed");
+
+			::PostQuitMessage(0);
+			return 0;
+		}
+		break;
 		}
 
 		return ::DefWindowProcW(hwnd, msg, wparam, lparam);
diff --git a/src/core/Game.h b/src/core/Application.h
similarity index 88%
rename from src/core/Game.h
rename to src/core/Application.h
index c84187d1..8481941b 100644
--- a/src/core/Game.h
+++ b/src/core/Application.h
@@ -25,7 +25,6 @@
 #include "render.h"
 #include "input.h"
 #include "audio.h"
-#include "Event.hpp"
 
 namespace easy2d
 {
@@ -49,23 +48,18 @@ namespace easy2d
 	};
 
 
-	class Game
+	class Application
 		: protected Noncopyable
 	{
 	public:
-		Game();
-
-		Game(
-			Options const& options
+		Application(
+			String const& app_name = L"Easy2dGame"
 		);
 
-		virtual ~Game();
+		virtual ~Application();
 
-		// 退出游戏
-		virtual void OnExit() {}
-
-		// 窗口关闭
-		virtual bool OnClose() { return true; }
+		// 启动
+		virtual void Setup() {}
 
 		// 初始化
 		void Init(
@@ -100,18 +94,15 @@ namespace easy2d
 
 		void Update();
 
-		void Dispatch(
-			Event* event
-		);
-
 		static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
 	private:
 		bool			debug_;
 		bool			active_;
 		float			time_scale_;
-		ScenePtr			curr_scene_;
-		ScenePtr			next_scene_;
+		String			app_name_;
+		ScenePtr		curr_scene_;
+		ScenePtr		next_scene_;
 		TransitionPtr	transition_;
 	};
 }
diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp
index af192cd0..c8ca5bd1 100644
--- a/src/core/Canvas.cpp
+++ b/src/core/Canvas.cpp
@@ -32,7 +32,7 @@ namespace easy2d
 		, stroke_width_(1.0f)
 	{
 		ThrowIfFailed(
-			Graphics::Instance()->CreateBitmapRenderTarget(render_target_)
+			RenderSystem::Instance()->CreateBitmapRenderTarget(render_target_)
 		);
 
 		auto properties = D2D1::BrushProperties();
@@ -105,7 +105,7 @@ namespace easy2d
 		
 		if (bitmap_cached_)
 		{
-			Graphics::Instance()->DrawBitmap(bitmap_cached_);
+			RenderSystem::Instance()->DrawBitmap(bitmap_cached_);
 		}
 	}
 
diff --git a/src/core/Canvas.h b/src/core/Canvas.h
index 68735c41..d8c7037d 100644
--- a/src/core/Canvas.h
+++ b/src/core/Canvas.h
@@ -224,11 +224,9 @@ namespace easy2d
 		D2DBitmapPtr const& GetBitmap() const;
 
 	protected:
-		mutable bool			cache_expired_;
-		mutable D2DBitmapPtr		bitmap_cached_;
-		float					stroke_width_;
-		Font					text_font_;
-		TextStyle				text_style_;
+		float						stroke_width_;
+		Font						text_font_;
+		TextStyle					text_style_;
 		D2DPathGeometryPtr			current_geometry_;
 		D2DGeometrySinkPtr			current_sink_;
 		D2DStrokeStylePtr			outline_join_style_;
@@ -237,5 +235,8 @@ namespace easy2d
 		D2DSolidColorBrushPtr		text_brush_;
 		D2DTextRendererPtr			text_renderer_;
 		D2DBitmapRenderTargetPtr	render_target_;
+
+		mutable bool				cache_expired_;
+		mutable D2DBitmapPtr		bitmap_cached_;
 	};
 }
\ No newline at end of file
diff --git a/src/core/DebugNode.cpp b/src/core/DebugNode.cpp
index be484c09..d621c250 100644
--- a/src/core/DebugNode.cpp
+++ b/src/core/DebugNode.cpp
@@ -28,8 +28,7 @@
 
 namespace easy2d
 {
-
-	DebugNodeImpl::DebugNodeImpl()
+	DebugNode::DebugNode()
 	{
 		debug_text_ = new Text();
 		debug_text_->SetPosition(15, 15);
@@ -46,11 +45,11 @@ namespace easy2d
 		debug_text_->SetStyle(style);
 	}
 
-	DebugNodeImpl::~DebugNodeImpl()
+	DebugNode::~DebugNode()
 	{
 	}
 
-	void DebugNodeImpl::AddDebugText(String const & text)
+	void DebugNode::AddDebugText(String const & text)
 	{
 		try
 		{
@@ -61,29 +60,29 @@ namespace easy2d
 		}
 	}
 
-	void DebugNodeImpl::ClearDebugText()
+	void DebugNode::ClearDebugText()
 	{
 		texts_.clear();
 	}
 
-	void DebugNodeImpl::OnRender()
+	void DebugNode::OnRender()
 	{
-		auto graphics = Graphics::Instance();
+		auto rt = RenderSystem::Instance();
 
-		graphics->SetTransform(Matrix{});
+		rt->SetTransform(Matrix{});
 
-		graphics->GetSolidBrush()->SetColor(Color(0.0f, 0.0f, 0.0f, 0.5f));
+		rt->GetSolidBrush()->SetColor(Color(0.0f, 0.0f, 0.0f, 0.5f));
 
-		graphics->GetRenderTarget()->FillRoundedRectangle(
+		rt->GetRenderTarget()->FillRoundedRectangle(
 			D2D1::RoundedRect(
 				D2D1_RECT_F{ 10, 10, 200, 120 },
 				6.f,
 				6.f),
-			graphics->GetSolidBrush().Get()
+			rt->GetSolidBrush().Get()
 		);
 	}
 
-	void DebugNodeImpl::OnUpdate(Duration const & dt)
+	void DebugNode::OnUpdate(Duration const & dt)
 	{
 		try
 		{
@@ -106,9 +105,9 @@ namespace easy2d
 		ss << "Objects: " << Object::__GetTracingObjects().size() << std::endl;
 #endif
 
-		ss << "Render: " << Graphics::Instance()->GetStatus().duration.Milliseconds() << "ms" << std::endl;
+		ss << "Render: " << RenderSystem::Instance()->GetStatus().duration.Milliseconds() << "ms" << std::endl;
 
-		ss << "Primitives / sec: " << Graphics::Instance()->GetStatus().primitives * frame_time_.size() << std::endl;
+		ss << "Primitives / sec: " << RenderSystem::Instance()->GetStatus().primitives * frame_time_.size() << std::endl;
 
 		PROCESS_MEMORY_COUNTERS_EX pmc;
 		GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
diff --git a/src/core/DebugNode.h b/src/core/DebugNode.h
index 7c419f65..a868aedb 100644
--- a/src/core/DebugNode.h
+++ b/src/core/DebugNode.h
@@ -25,15 +25,16 @@
 
 namespace easy2d
 {
-	class DebugNodeImpl
+	class DebugNode
 		: public Node
+		, public ISingleton
 	{
-		E2D_DECLARE_SINGLETON(DebugNodeImpl);
+		E2D_DECLARE_SINGLETON(DebugNode);
 
 	public:
-		DebugNodeImpl();
+		DebugNode();
 
-		virtual ~DebugNodeImpl();
+		virtual ~DebugNode();
 
 		void AddDebugText(String const& text);
 
@@ -48,6 +49,4 @@ namespace easy2d
 		Array	frame_time_;
 		Array		texts_;
 	};
-
-	E2D_DECLARE_SINGLETON_TYPE(DebugNodeImpl, DebugNode);
 }
diff --git a/src/core/Event.hpp b/src/core/Event.hpp
index fda759c1..ff2b2638 100644
--- a/src/core/Event.hpp
+++ b/src/core/Event.hpp
@@ -20,39 +20,116 @@
 
 #pragma once
 #include "macros.h"
+#include "keys.hpp"
 
 namespace easy2d
 {
 	typedef UINT EventType;
 
-	class Event
+	// 鼠标事件
+	struct MouseEvent
 	{
-	public:
-		Event(EventType type) : type(type), has_target(false) {}
+		enum Type : EventType
+		{
+			First = WM_MOUSEFIRST,
 
-		virtual ~Event() {}
+			Move,	// 移动
+			Down,	// 按下
+			Up,		// 抬起
+			Wheel,	// 滚轮滚动
 
-		EventType type;
-		bool has_target;
+			Hover,	// 鼠标移入
+			Out,	// 鼠标移出
+			Click,	// 鼠标点击
+
+			Last	// 结束标志
+		};
+
+		float x;
+		float y;
+		bool left_btn_down;		// 左键是否按下
+		bool right_btn_down;	// 右键是否按下
+
+		struct
+		{
+			MouseButton button;	// 仅当消息类型为 Down | Up | Click 时有效
+		};
+
+		struct
+		{
+			float wheel_delta;	// 仅当消息类型为 Wheel 时有效
+		};
+
+		static inline bool Check(EventType type)
+		{
+			return type > Type::First && type < Type::Last;
+		}
 	};
 
-	class SysEvent
-		: public Event
+	// 键盘事件
+	struct KeyboardEvent
 	{
-	public:
-		enum Type
+		enum Type : UINT
 		{
-			First = WM_NULL,
+			First = WM_KEYFIRST,
 
-			WindowActivate,		// 窗口获得焦点
-			WindowDeavtivate,	// 窗口失去焦点
-			WindowClose,		// 关闭窗口
+			Down,	// 键按下
+			Up,		// 键抬起
 
 			Last
 		};
 
-		SysEvent(EventType type) : Event(type) {}
+		KeyCode code;
+		int count;
 
-		static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; }
+		static inline bool Check(UINT type)
+		{
+			return type > Type::First && type < Type::Last;
+		}
+	};
+
+	// 窗口事件
+	struct WindowEvent
+	{
+	public:
+		enum Type : EventType
+		{
+			First = WM_NULL,
+
+			Activate,		// 窗口获得焦点
+			Deavtivate,		// 窗口失去焦点
+			Closing,		// 关闭窗口
+
+			Last
+		};
+
+		static inline bool Check(EventType type)
+		{
+			return type > Type::First && type < Type::Last;
+		}
+	};
+
+	// 事件
+	struct Event
+	{
+		EventType type;
+		bool has_target;
+
+		union
+		{
+			MouseEvent mouse;
+			KeyboardEvent key;
+			WindowEvent win;
+		};
+
+		Event()
+			: type(0)
+			, has_target(false)
+		{}
+
+		Event(EventType type)
+			: type(type)
+			, has_target(false)
+		{}
 	};
 }
diff --git a/src/core/EventDispatcher.cpp b/src/core/EventDispatcher.cpp
index a06e49e1..19150541 100644
--- a/src/core/EventDispatcher.cpp
+++ b/src/core/EventDispatcher.cpp
@@ -23,7 +23,7 @@
 
 namespace easy2d
 {
-	void EventDispatcher::DispatchEvent(Event* e)
+	void EventDispatcher::Dispatch(Event& evt)
 	{
 		if (listeners_.IsEmpty())
 			return;
@@ -33,9 +33,9 @@ namespace easy2d
 		{
 			next = listener->NextItem();
 
-			if (listener->type_ == e->type)
+			if (listener->type_ == evt.type)
 			{
-				listener->callback_(e);
+				listener->callback_(evt);
 			}
 		}
 	}
diff --git a/src/core/EventDispatcher.h b/src/core/EventDispatcher.h
index ecf7615e..90bc7411 100644
--- a/src/core/EventDispatcher.h
+++ b/src/core/EventDispatcher.h
@@ -25,7 +25,7 @@ namespace easy2d
 {
 	class EventDispatcher
 	{
-		using Listeners = intrusive::List;
+		using Listeners = IntrusiveList;
 
 	public:
 		// 添加监听器
@@ -70,7 +70,7 @@ namespace easy2d
 			EventType type
 		);
 
-		virtual void DispatchEvent(Event* e);
+		virtual void Dispatch(Event& evt);
 
 	protected:
 		Listeners listeners_;
diff --git a/src/core/EventListener.h b/src/core/EventListener.h
index c6bafcb6..222f2093 100644
--- a/src/core/EventListener.h
+++ b/src/core/EventListener.h
@@ -20,22 +20,21 @@
 
 #pragma once
 #include "include-forwards.h"
-#include "intrusive/List.hpp"
+#include "IntrusiveList.hpp"
 #include "Event.hpp"
 
 namespace easy2d
 {
-	typedef std::function EventCallback;
-
+	using EventCallback = std::function;
 
 	class EventDispatcher;
 
 	class EventListener
-		: public Object
-		, protected intrusive::ListItem
+		: public virtual Object
+		, protected IntrusiveListItem
 	{
 		friend class EventDispatcher;
-		friend class intrusive::List;
+		friend class IntrusiveList;
 
 	public:
 		EventListener(
diff --git a/src/core/Factory.cpp b/src/core/Factory.cpp
index 9953b011..12b0f899 100644
--- a/src/core/Factory.cpp
+++ b/src/core/Factory.cpp
@@ -25,18 +25,18 @@
 
 namespace easy2d
 {
-	FactoryImpl::FactoryImpl()
+	Factory::Factory()
 	{
 	}
 
-	FactoryImpl::~FactoryImpl()
+	Factory::~Factory()
 	{
-		E2D_LOG(L"Destroying device independent resources");
+		E2D_LOG(L"Destroying device-independent resources");
 	}
 
-	HRESULT FactoryImpl::Init(bool debug)
+	HRESULT Factory::Init(bool debug)
 	{
-		E2D_LOG(L"Creating device independent resources");
+		E2D_LOG(L"Creating device-independent resources");
 
 		D2D1_FACTORY_OPTIONS fact_options;
 		fact_options.debugLevel = debug ? D2D1_DEBUG_LEVEL_INFORMATION : D2D1_DEBUG_LEVEL_NONE;
@@ -111,7 +111,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateHwndRenderTarget(D2DHwndRenderTargetPtr & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const
+	HRESULT Factory::CreateHwndRenderTarget(D2DHwndRenderTargetPtr & hwnd_render_target, D2D1_RENDER_TARGET_PROPERTIES const & properties, D2D1_HWND_RENDER_TARGET_PROPERTIES const & hwnd_rt_properties) const
 	{
 		if (!factory_)
 			return E_UNEXPECTED;
@@ -128,7 +128,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateTextRenderer(
+	HRESULT Factory::CreateTextRenderer(
 		D2DTextRendererPtr& text_renderer,
 		D2DRenderTargetPtr const& render_target,
 		D2DSolidColorBrushPtr const& brush
@@ -150,20 +150,18 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateBitmapFromFile(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, String const & file_path)
+	HRESULT Factory::CreateBitmapFromFile(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, String const & file_path)
 	{
 		if (imaging_factory_ == nullptr)
 		{
 			return E_UNEXPECTED;
 		}
 
-		using namespace intrusive;
-
-		SmartPtr		decoder;
-		SmartPtr	source;
-		SmartPtr			stream;
-		SmartPtr	converter;
-		SmartPtr			bitmap_tmp;
+		IntrusivePtr		decoder;
+		IntrusivePtr	source;
+		IntrusivePtr			stream;
+		IntrusivePtr	converter;
+		IntrusivePtr			bitmap_tmp;
 
 		HRESULT hr = imaging_factory_->CreateDecoderFromFilename(
 			file_path.c_str(),
@@ -211,20 +209,18 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateBitmapFromResource(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, Resource const & res)
+	HRESULT Factory::CreateBitmapFromResource(D2DBitmapPtr & bitmap, D2DRenderTargetPtr const & rt, Resource const & res)
 	{
 		if (imaging_factory_ == nullptr)
 		{
 			return E_UNEXPECTED;
 		}
 
-		using namespace intrusive;
-
-		SmartPtr		decoder;
-		SmartPtr	source;
-		SmartPtr			stream;
-		SmartPtr	converter;
-		SmartPtr			bitmap_tmp;
+		IntrusivePtr		decoder;
+		IntrusivePtr	source;
+		IntrusivePtr			stream;
+		IntrusivePtr	converter;
+		IntrusivePtr			bitmap_tmp;
 		
 		// 加载资源
 		LPVOID buffer;
@@ -294,7 +290,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateRectangleGeometry(D2DRectangleGeometryPtr & geo, Rect const& rect) const
+	HRESULT Factory::CreateRectangleGeometry(D2DRectangleGeometryPtr & geo, Rect const& rect) const
 	{
 		if (!factory_)
 			return E_UNEXPECTED;
@@ -310,7 +306,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateRoundedRectangleGeometry(D2DRoundedRectangleGeometryPtr & geo, Rect const & rect, float radius_x, float radius_y) const
+	HRESULT Factory::CreateRoundedRectangleGeometry(D2DRoundedRectangleGeometryPtr & geo, Rect const & rect, float radius_x, float radius_y) const
 	{
 		if (!factory_)
 			return E_UNEXPECTED;
@@ -330,7 +326,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateEllipseGeometry(D2DEllipseGeometryPtr & geo, Point const & center, float radius_x, float radius_y) const
+	HRESULT Factory::CreateEllipseGeometry(D2DEllipseGeometryPtr & geo, Point const & center, float radius_x, float radius_y) const
 	{
 		if (!factory_)
 			return E_UNEXPECTED;
@@ -350,7 +346,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateTransformedGeometry(
+	HRESULT Factory::CreateTransformedGeometry(
 		D2DTransformedGeometryPtr& transformed,
 		Matrix const& matrix,
 		D2DGeometryPtr const& geo
@@ -373,7 +369,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreatePathGeometry(D2DPathGeometryPtr & geometry) const
+	HRESULT Factory::CreatePathGeometry(D2DPathGeometryPtr & geometry) const
 	{
 		if (!factory_)
 			return E_UNEXPECTED;
@@ -381,7 +377,7 @@ namespace easy2d
 		return factory_->CreatePathGeometry(&geometry);
 	}
 
-	HRESULT FactoryImpl::CreateTextFormat(D2DTextFormatPtr & text_format, Font const & font, TextStyle const & text_style) const
+	HRESULT Factory::CreateTextFormat(D2DTextFormatPtr & text_format, Font const & font, TextStyle const & text_style) const
 	{
 		if (!write_factory_)
 			return E_UNEXPECTED;
@@ -419,7 +415,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT FactoryImpl::CreateTextLayout(D2DTextLayoutPtr & text_layout, Size& layout_size, String const & text, D2DTextFormatPtr const& text_format, TextStyle const & text_style) const
+	HRESULT Factory::CreateTextLayout(D2DTextLayoutPtr & text_layout, Size& layout_size, String const & text, D2DTextFormatPtr const& text_format, TextStyle const & text_style) const
 	{
 		if (!write_factory_)
 			return E_UNEXPECTED;
@@ -497,7 +493,7 @@ namespace easy2d
 		return hr;
 	}
 
-	D2DStrokeStylePtr const& FactoryImpl::GetStrokeStyle(StrokeStyle stroke) const
+	D2DStrokeStylePtr const& Factory::GetStrokeStyle(StrokeStyle stroke) const
 	{
 		switch (stroke)
 		{
diff --git a/src/core/Factory.h b/src/core/Factory.h
index 922c3d4b..e0c17eec 100644
--- a/src/core/Factory.h
+++ b/src/core/Factory.h
@@ -25,14 +25,13 @@
 #include "Resource.h"
 #include "TextRenderer.h"
 #include "TextStyle.hpp"
-#include "../math/Matrix.hpp"
 
 namespace easy2d
 {
-	class FactoryImpl
-		: protected Noncopyable
+	class Factory
+		: public ISingleton
 	{
-		E2D_DECLARE_SINGLETON(FactoryImpl);
+		E2D_DECLARE_SINGLETON(Factory);
 
 	public:
 		HRESULT Init(bool debug);
@@ -109,9 +108,9 @@ namespace easy2d
 		) const;
 
 	protected:
-		FactoryImpl();
+		Factory();
 
-		~FactoryImpl();
+		~Factory();
 
 	protected:
 		D2DFactoryPtr			factory_;
@@ -121,6 +120,4 @@ namespace easy2d
 		D2DStrokeStylePtr		bevel_stroke_style_;
 		D2DStrokeStylePtr		round_stroke_style_;
 	};
-
-	E2D_DECLARE_SINGLETON_TYPE(FactoryImpl, Factory);
 }
diff --git a/src/core/Frames.h b/src/core/Frames.h
index 128a4faa..7e27ec16 100644
--- a/src/core/Frames.h
+++ b/src/core/Frames.h
@@ -26,7 +26,7 @@ namespace easy2d
 {
 	// 帧集合
 	class Frames
-		: public Object
+		: public virtual Object
 	{
 	public:
 		Frames();
diff --git a/src/core/Geometry.h b/src/core/Geometry.h
index a37e89c4..8da2be52 100644
--- a/src/core/Geometry.h
+++ b/src/core/Geometry.h
@@ -25,7 +25,7 @@ namespace easy2d
 {
 	// 几何抽象
 	class Geometry
-		: public RefCounter
+		: public virtual Object
 	{
 		friend class Canvas;
 		friend class GeometryNode;
diff --git a/src/core/GeometryNode.cpp b/src/core/GeometryNode.cpp
index 9d77fc35..5ba5cbc0 100644
--- a/src/core/GeometryNode.cpp
+++ b/src/core/GeometryNode.cpp
@@ -70,14 +70,14 @@ namespace easy2d
 	{
 		if (geometry_ && geometry_->geo_)
 		{
-			auto graphics = Graphics::Instance();
+			auto rt = RenderSystem::Instance();
 
-			graphics->FillGeometry(
+			rt->FillGeometry(
 				geometry_->geo_,
 				fill_color_
 			);
 
-			graphics->DrawGeometry(
+			rt->DrawGeometry(
 				geometry_->geo_,
 				stroke_color_,
 				stroke_width_,
diff --git a/src/core/Image.cpp b/src/core/Image.cpp
index 42441a18..5e51c0f0 100644
--- a/src/core/Image.cpp
+++ b/src/core/Image.cpp
@@ -67,11 +67,11 @@ namespace easy2d
 				logs::Warningln(L"Image file '%s' not found!", res.GetFileName());
 				return false;
 			}
-			hr = Graphics::Instance()->CreateBitmapFromFile(bitmap, res.GetFileName());
+			hr = RenderSystem::Instance()->CreateBitmapFromFile(bitmap, res.GetFileName());
 		}
 		else
 		{
-			hr = Graphics::Instance()->CreateBitmapFromResource(bitmap, res);
+			hr = RenderSystem::Instance()->CreateBitmapFromResource(bitmap, res);
 		}
 
 		if (FAILED(hr))
diff --git a/src/core/Image.h b/src/core/Image.h
index cc97592c..eea23ae6 100644
--- a/src/core/Image.h
+++ b/src/core/Image.h
@@ -26,7 +26,7 @@ namespace easy2d
 {
 	// 图片
 	class Image
-		: public Object
+		: public virtual Object
 	{
 	public:
 		Image();
diff --git a/src/core/Input.cpp b/src/core/Input.cpp
index 7d5de0a8..b2370427 100644
--- a/src/core/Input.cpp
+++ b/src/core/Input.cpp
@@ -24,7 +24,7 @@
 
 namespace easy2d
 {
-	InputDevice::InputDevice()
+	Input::Input()
 		: hwnd_(nullptr)
 		, scale_x_(1.f)
 		, scale_y_(1.f)
@@ -33,12 +33,12 @@ namespace easy2d
 		ZeroMemory(keys_cache_, sizeof(keys_cache_));
 	}
 
-	InputDevice::~InputDevice()
+	Input::~Input()
 	{
 		E2D_LOG(L"Destroying input device");
 	}
 
-	HRESULT InputDevice::Init(HWND hwnd, float scale_x, float scale_y, bool debug)
+	HRESULT Input::Init(HWND hwnd, float scale_x, float scale_y, bool debug)
 	{
 		E2D_LOG(L"Initing input device");
 
@@ -49,47 +49,47 @@ namespace easy2d
 		return S_OK;
 	}
 
-	void InputDevice::Update()
+	void Input::Update()
 	{
 		memcpy(keys_cache_, keys_, sizeof(keys_cache_));
 		GetKeyboardState(keys_);
 	}
 
-	bool InputDevice::IsDown(KeyCode code)
+	bool Input::IsDown(KeyCode code)
 	{
 		return !!(keys_[static_cast(code)] & 0x80);
 	}
 
-	bool InputDevice::IsDown(MouseButton btn)
+	bool Input::IsDown(MouseButton btn)
 	{
 		return !!(keys_[static_cast(btn)] & 0x80);
 	}
 
-	bool InputDevice::WasPressed(KeyCode code)
+	bool Input::WasPressed(KeyCode code)
 	{
 		return !(keys_cache_[static_cast(code)] & 0x80)
 			&& (keys_[static_cast(code)] & 0x80);
 	}
 
-	bool InputDevice::WasPressed(MouseButton btn)
+	bool Input::WasPressed(MouseButton btn)
 	{
 		return !(keys_cache_[static_cast(btn)] & 0x80)
 			&& (keys_[static_cast(btn)] & 0x80);
 	}
 
-	bool InputDevice::WasReleased(KeyCode code)
+	bool Input::WasReleased(KeyCode code)
 	{
 		return (keys_cache_[static_cast(code)] & 0x80)
 			&& !(keys_[static_cast(code)] & 0x80);
 	}
 
-	bool InputDevice::WasReleased(MouseButton btn)
+	bool Input::WasReleased(MouseButton btn)
 	{
 		return (keys_cache_[static_cast(btn)] & 0x80)
 			&& !(keys_[static_cast(btn)] & 0x80);
 	}
 
-	float InputDevice::GetMouseX()
+	float Input::GetMouseX()
 	{
 		POINT pos;
 		::GetCursorPos(&pos);
@@ -97,7 +97,7 @@ namespace easy2d
 		return pos.x * scale_x_;
 	}
 
-	float InputDevice::GetMouseY()
+	float Input::GetMouseY()
 	{
 		POINT pos;
 		::GetCursorPos(&pos);
@@ -105,7 +105,7 @@ namespace easy2d
 		return pos.y * scale_y_;
 	}
 
-	Point InputDevice::GetMousePos()
+	Point Input::GetMousePos()
 	{
 		POINT pos;
 		::GetCursorPos(&pos);
diff --git a/src/core/Input.h b/src/core/Input.h
index cc21cc87..95a25db5 100644
--- a/src/core/Input.h
+++ b/src/core/Input.h
@@ -25,19 +25,10 @@
 
 namespace easy2d
 {
-	// 鼠标键值
-	enum class MouseButton : int
+	class Input
+		: public ISingleton
 	{
-		Left = VK_LBUTTON,	// 鼠标左键
-		Right = VK_RBUTTON,	// 鼠标右键
-		Middle = VK_MBUTTON	// 鼠标中键
-	};
-
-
-	class InputDevice
-		: protected Noncopyable
-	{
-		E2D_DECLARE_SINGLETON(InputDevice);
+		E2D_DECLARE_SINGLETON(Input);
 
 	public:
 		HRESULT Init(HWND hwnd, float scale_x, float scale_y, bool debug);
@@ -84,9 +75,9 @@ namespace easy2d
 		void Update();
 
 	protected:
-		InputDevice();
+		Input();
 
-		~InputDevice();
+		~Input();
 
 	protected:
 		HWND	hwnd_;
@@ -95,6 +86,4 @@ namespace easy2d
 		BYTE	keys_[256];
 		BYTE	keys_cache_[256];
 	};
-
-	E2D_DECLARE_SINGLETON_TYPE(InputDevice, Input);
 }
diff --git a/src/core/IntrusiveList.hpp b/src/core/IntrusiveList.hpp
new file mode 100644
index 00000000..9a9e0a1f
--- /dev/null
+++ b/src/core/IntrusiveList.hpp
@@ -0,0 +1,254 @@
+// Copyright (c) 2016-2018 Easy2D - Nomango
+// 
+// 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:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// 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.
+
+#pragma once
+#include "macros.h"
+#include 
+
+#undef DEBUG_CHECK_LIST
+#ifdef E2D_DEBUG
+#	define DEBUG_CHECK_LIST(list_ptr) list_ptr->Check()
+#else
+#	define DEBUG_CHECK_LIST __noop
+#endif
+
+namespace easy2d
+{
+	template  class IntrusiveList;
+
+	template 
+	class IntrusiveListItem
+	{
+		T prev_;
+		T next_;
+
+		template 
+		friend class IntrusiveList;
+
+	public:
+		using ItemType = T;
+
+		IntrusiveListItem() : prev_(), next_() {}
+
+		T const& PrevItem() const { return prev_; }
+
+		T& PrevItem() { return prev_; }
+
+		T const& NextItem() const { return next_; }
+
+		T& NextItem() { return next_; }
+	};
+
+
+	template 
+	class IntrusiveList
+	{
+		T first_;
+		T last_;
+
+	public:
+		using ItemType = T;
+
+		IntrusiveList() : first_(), last_() {}
+
+		~IntrusiveList() { Clear(); }
+
+		T const& First() const { return first_; }
+
+		T& First() { return first_; }
+
+		T const& Last() const { return last_; }
+
+		T& Last() { return last_; }
+
+		bool IsEmpty() const { return !first_; }
+
+		void PushBack(T const& child)
+		{
+			if (child->prev_)
+				child->prev_->next_ = child->next_;
+			if (child->next_)
+				child->next_->prev_ = child->prev_;
+
+			child->prev_ = last_;
+			child->next_ = nullptr;
+
+			if (first_)
+			{
+				last_->next_ = child;
+			}
+			else
+			{
+				first_ = child;
+			}
+
+			last_ = child;
+
+			DEBUG_CHECK_LIST(this);
+		}
+
+		void PushFront(T const& child)
+		{
+			if (child->prev_)
+				child->prev_->next_ = child->next_;
+			if (child->next_)
+				child->next_->prev_ = child->prev_;
+
+			child->prev_ = nullptr;
+			child->next_ = first_;
+
+			if (first_)
+			{
+				first_->prev_ = child;
+			}
+			else
+			{
+				last_ = child;
+			}
+
+			first_ = child;
+
+			DEBUG_CHECK_LIST(this);
+		}
+
+		void InsertBefore(T const& child, T const& before)
+		{
+			if (child->prev_)
+				child->prev_->next_ = child->next_;
+			if (child->next_)
+				child->next_->prev_ = child->prev_;
+
+			if (before->prev_)
+				before->prev_->next_ = child;
+			else
+				first_ = child;
+
+			child->prev_ = before->prev_;
+			child->next_ = before;
+			before->prev_ = child;
+
+			DEBUG_CHECK_LIST(this);
+		}
+
+		void InsertAfter(T const& child, T const& after)
+		{
+			if (child->prev_)
+				child->prev_->next_ = child->next_;
+			if (child->next_)
+				child->next_->prev_ = child->prev_;
+
+			if (after->next_)
+				after->next_->prev_ = child;
+			else
+				last_ = child;
+
+			child->next_ = after->next_;
+			child->prev_ = after;
+			after->next_ = child;
+
+			DEBUG_CHECK_LIST(this);
+		}
+
+		void Remove(T const& child)
+		{
+#ifdef E2D_DEBUG
+			T tmp = first_;
+			while (tmp != child)
+			{
+				if (tmp == last_)
+					E2D_ASSERT(false && "The node to be removed is not in this list");
+				tmp = tmp->next_;
+			}
+#endif
+
+			if (child->next_)
+			{
+				child->next_->prev_ = child->prev_;
+			}
+			else
+			{
+				last_ = child->prev_;
+			}
+
+			if (child->prev_)
+			{
+				child->prev_->next_ = child->next_;
+			}
+			else
+			{
+				first_ = child->next_;
+			}
+
+			child->prev_ = nullptr;
+			child->next_ = nullptr;
+
+			DEBUG_CHECK_LIST(this);
+		}
+
+		void Clear()
+		{
+			T p = first_;
+			while (p)
+			{
+				T tmp = p;
+				p = p->next_;
+				if (tmp)
+				{
+					tmp->next_ = nullptr;
+					tmp->prev_ = nullptr;
+				}
+			}
+			first_ = nullptr;
+			last_ = nullptr;
+		}
+
+#ifdef E2D_DEBUG
+
+	private:
+		void Check()
+		{
+			if (!first_)
+				return;
+
+			int pos = 0;
+			T p = first_;
+			T tmp = p;
+			do
+			{
+				tmp = p;
+				p = p->next_;
+				++pos;
+
+				if (p)
+				{
+					E2D_ASSERT(p->prev_ == tmp && "Check list failed");
+				}
+				else
+				{
+					E2D_ASSERT(tmp == last_ && "Check list failed");
+				}
+			} while (p);
+		}
+
+#endif
+	};
+}
+
+#undef DEBUG_CHECK_LIST
diff --git a/src/core/IntrusivePtr.hpp b/src/core/IntrusivePtr.hpp
new file mode 100644
index 00000000..11b78b1c
--- /dev/null
+++ b/src/core/IntrusivePtr.hpp
@@ -0,0 +1,201 @@
+// Copyright (c) 2016-2018 Easy2D - Nomango
+// 
+// Permission is hereby granted, free of charge, to any person obtaining lhs 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:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// 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.
+
+#pragma once
+#include "macros.h"
+#include 
+
+namespace easy2d
+{
+	template 
+	class IntrusivePtr
+	{
+		T* ptr_{ nullptr };
+
+	public:
+		using Type = T;
+
+		IntrusivePtr() E2D_NOEXCEPT {}
+
+		IntrusivePtr(nullptr_t) E2D_NOEXCEPT {}
+
+		IntrusivePtr(Type* p) E2D_NOEXCEPT : ptr_(p)
+		{
+			IntrusivePtrAddRef(ptr_);
+		}
+
+		IntrusivePtr(const IntrusivePtr& other) E2D_NOEXCEPT
+			: ptr_(other.ptr_)
+		{
+			IntrusivePtrAddRef(ptr_);
+		}
+
+		template 
+		IntrusivePtr(const IntrusivePtr& other) E2D_NOEXCEPT
+			: ptr_(other.Get())
+		{
+			IntrusivePtrAddRef(ptr_);
+		}
+
+		IntrusivePtr(IntrusivePtr&& other) E2D_NOEXCEPT
+		{
+			ptr_ = other.ptr_;
+			other.ptr_ = nullptr;
+		}
+
+		~IntrusivePtr() E2D_NOEXCEPT
+		{
+			IntrusivePtrRelease(ptr_);
+		}
+
+		inline Type* Get() const E2D_NOEXCEPT { return ptr_; }
+
+		inline void Swap(IntrusivePtr& other) E2D_NOEXCEPT
+		{
+			std::swap(ptr_, other.ptr_);
+		}
+
+		inline Type* operator ->() const
+		{
+			E2D_ASSERT(ptr_ != nullptr && "Invalid pointer");
+			return ptr_;
+		}
+
+		inline Type& operator *() const
+		{
+			E2D_ASSERT(ptr_ != nullptr && "Invalid pointer");
+			return *ptr_;
+		}
+
+		inline Type** operator &()
+		{
+			E2D_ASSERT(ptr_ == nullptr && "Memory leak");
+			return &ptr_;
+		}
+
+		inline operator bool() const E2D_NOEXCEPT { return ptr_ != nullptr; }
+
+		inline bool operator !() const E2D_NOEXCEPT { return ptr_ == 0; }
+
+		inline IntrusivePtr& operator =(const IntrusivePtr& other) E2D_NOEXCEPT
+		{
+			if (other.ptr_ != ptr_)
+				IntrusivePtr(other).Swap(*this);
+			return *this;
+		}
+
+		inline IntrusivePtr& operator =(IntrusivePtr&& other) E2D_NOEXCEPT
+		{
+			IntrusivePtrRelease(ptr_);
+			ptr_ = other.ptr_;
+			other.ptr_ = nullptr;
+			return *this;
+		}
+
+		inline IntrusivePtr& operator =(Type* p) E2D_NOEXCEPT
+		{
+			if (p != ptr_)
+				IntrusivePtr(p).Swap(*this);
+			return *this;
+		}
+
+		inline IntrusivePtr& operator =(nullptr_t) E2D_NOEXCEPT
+		{
+			if (nullptr != ptr_)
+				IntrusivePtr{}.Swap(*this);
+			return *this;
+		}
+	};
+
+	template
+	inline bool operator==(IntrusivePtr const& lhs, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return lhs.Get() == rhs.Get();
+	}
+
+	template
+	inline bool operator!=(IntrusivePtr const& lhs, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return lhs.Get() != rhs.Get();
+	}
+
+	template
+	inline bool operator<(IntrusivePtr const& lhs, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return lhs.Get() < rhs.Get();
+	}
+
+	template
+	inline bool operator==(IntrusivePtr const& lhs, T* rhs) E2D_NOEXCEPT
+	{
+		return lhs.Get() == rhs;
+	}
+
+	template
+	inline bool operator!=(IntrusivePtr const& lhs, T* rhs) E2D_NOEXCEPT
+	{
+		return lhs.Get() != rhs;
+	}
+
+	template
+	inline bool operator==(T* lhs, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return lhs == rhs.Get();
+	}
+
+	template
+	inline bool operator!=(T* lhs, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return lhs != rhs.Get();
+	}
+
+	template
+	inline bool operator==(IntrusivePtr const& lhs, nullptr_t) E2D_NOEXCEPT
+	{
+		return !static_cast(lhs);
+	}
+
+	template
+	inline bool operator!=(IntrusivePtr const& lhs, nullptr_t) E2D_NOEXCEPT
+	{
+		return static_cast(lhs);
+	}
+
+	template
+	inline bool operator==(nullptr_t, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return !static_cast(rhs);
+	}
+
+	template
+	inline bool operator!=(nullptr_t, IntrusivePtr const& rhs) E2D_NOEXCEPT
+	{
+		return static_cast(rhs);
+	}
+
+	// template class cannot specialize std::swap,
+	// so implement a swap function in easy2d namespace
+	template
+	inline void swap(IntrusivePtr& lhs, IntrusivePtr& rhs) E2D_NOEXCEPT
+	{
+		lhs.Swap(rhs);
+	}
+
+}
diff --git a/src/core/KeyEvent.hpp b/src/core/KeyEvent.hpp
deleted file mode 100644
index 4bc00188..00000000
--- a/src/core/KeyEvent.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2016-2018 Easy2D - Nomango
-// 
-// 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:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// 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.
-
-#pragma once
-#include "Event.hpp"
-#include "keys.hpp"
-
-namespace easy2d
-{
-	class KeyEvent
-		: public Event
-	{
-	public:
-		enum Type
-		{
-			First = WM_KEYFIRST,
-
-			Down,	// 键按下
-			Up,		// 键抬起
-
-			Last	// 结束标志
-		};
-
-		KeyEvent(EventType type, KeyCode key) : Event(type), key(key) {}
-
-		static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; }
-
-		KeyCode key;
-	};
-}
diff --git a/src/core/MouseEvent.hpp b/src/core/MouseEvent.hpp
deleted file mode 100644
index 50aa7035..00000000
--- a/src/core/MouseEvent.hpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2016-2018 Easy2D - Nomango
-// 
-// 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:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// 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.
-
-#pragma once
-#include "Event.hpp"
-#include "helper.hpp"
-
-namespace easy2d
-{
-	class MouseEvent
-		: public Event
-	{
-	public:
-		enum Type
-		{
-			First = WM_MOUSEFIRST,
-
-			Move,	// 移动
-			Down,	// 按下
-			Up,		// 抬起
-			Wheel,	// 滚轮滚动
-
-			Hover,	// 鼠标移入
-			Out,	// 鼠标移出
-			Click,	// 鼠标点击
-
-			Last	// 结束标志
-		};
-
-		MouseEvent(EventType type, float x, float y, float wheel_delta) : Event(type), position(x, y), wheel_delta(wheel_delta), button_down(false) {}
-
-		static bool Check(Event* e) { return e->type > Type::First && e->type < Type::Last; }
-
-		Point position;
-		float wheel_delta;
-		bool button_down;
-	};
-}
diff --git a/src/core/Music.h b/src/core/Music.h
index 73d34b22..1fcaedef 100644
--- a/src/core/Music.h
+++ b/src/core/Music.h
@@ -27,7 +27,7 @@ namespace easy2d
 {
 	// 音乐
 	class Music
-		: public Object
+		: public virtual Object
 	{
 	public:
 		Music();
diff --git a/src/core/Node.cpp b/src/core/Node.cpp
index 3d2f5d18..435a1dcb 100644
--- a/src/core/Node.cpp
+++ b/src/core/Node.cpp
@@ -23,7 +23,6 @@
 #include "Factory.h"
 #include "Scene.h"
 #include "Task.h"
-#include "MouseEvent.hpp"
 #include "render.h"
 #include "logs.h"
 
@@ -31,18 +30,19 @@ namespace easy2d
 {
 	namespace
 	{
-		float default_pivot_x = 0.f;
-		float default_pivot_y = 0.f;
+		float default_anchor_x = 0.f;
+		float default_anchor_y = 0.f;
 	}
 
-	void Node::SetDefaultPivot(float pivot_x, float pivot_y)
+	void Node::SetDefaultAnchor(float anchor_x, float anchor_y)
 	{
-		default_pivot_x = pivot_x;
-		default_pivot_y = pivot_y;
+		default_anchor_x = anchor_x;
+		default_anchor_y = anchor_y;
 	}
 
 	Node::Node()
 		: visible_(true)
+		, pause_(false)
 		, dirty_transform_(false)
 		, dirty_transform_inverse_(false)
 		, parent_(nullptr)
@@ -50,12 +50,15 @@ namespace easy2d
 		, z_order_(0)
 		, opacity_(1.f)
 		, display_opacity_(1.f)
-		, pivot_(default_pivot_x, default_pivot_y)
+		, anchor_(default_anchor_x, default_anchor_y)
 	{
 	}
 
 	void Node::Update(Duration const & dt)
 	{
+		if (pause_)
+			return;
+
 		OnUpdate(dt);
 		UpdateActions(this, dt);
 		UpdateTasks(dt);
@@ -78,12 +81,12 @@ namespace easy2d
 
 		UpdateTransform();
 
-		auto graphics = Graphics::Instance();
+		auto rt = RenderSystem::Instance();
 
 		if (children_.IsEmpty())
 		{
-			graphics->SetTransform(transform_matrix_);
-			graphics->SetOpacity(display_opacity_);
+			rt->SetTransform(transform_matrix_);
+			rt->SetOpacity(display_opacity_);
 
 			OnRender();
 		}
@@ -100,8 +103,8 @@ namespace easy2d
 				child = child->NextItem().Get();
 			}
 
-			graphics->SetTransform(transform_matrix_);
-			graphics->SetOpacity(display_opacity_);
+			rt->SetTransform(transform_matrix_);
+			rt->SetOpacity(display_opacity_);
 
 			OnRender();
 
@@ -113,7 +116,7 @@ namespace easy2d
 		}
 	}
 
-	void Node::DispatchEvent(Event * e)
+	void Node::Dispatch(Event& evt)
 	{
 		if (!visible_)
 			return;
@@ -122,26 +125,24 @@ namespace easy2d
 		for (auto child = children_.Last(); child; child = prev)
 		{
 			prev = child->PrevItem();
-			child->DispatchEvent(e);
+			child->Dispatch(evt);
 		}
 
-		if (MouseEvent::Check(e))
+		if (MouseEvent::Check(evt.type))
 		{
-			MouseEvent* me = static_cast(e);
-
-			if (me->type == MouseEvent::Move)
+			if (evt.type == MouseEvent::Move)
 			{
-				if (!me->has_target && ContainsPoint(me->position))
+				if (!evt.has_target && ContainsPoint(Point{ evt.mouse.x, evt.mouse.y }))
 				{
-					me->has_target = true;
+					evt.has_target = true;
 
 					if (!hover_)
 					{
 						hover_ = true;
 
-						MouseEvent hover = *me;
+						Event hover = evt;
 						hover.type = MouseEvent::Hover;
-						DispatchEvent(&hover);
+						Dispatch(hover);
 					}
 				}
 				else if (hover_)
@@ -149,28 +150,38 @@ namespace easy2d
 					hover_ = false;
 					pressed_ = false;
 
-					MouseEvent hover = *me;
-					hover.type = MouseEvent::Out;
-					DispatchEvent(&hover);
+					Event out = evt;
+					out.type = MouseEvent::Out;
+					Dispatch(out);
 				}
 			}
 
-			if (me->type == MouseEvent::Down && hover_)
+			if (evt.type == MouseEvent::Down && hover_)
 			{
 				pressed_ = true;
 			}
 
-			if (me->type == MouseEvent::Up && pressed_)
+			if (evt.type == MouseEvent::Up && pressed_)
 			{
 				pressed_ = false;
 
-				MouseEvent click = *me;
+				Event click = evt;
 				click.type = MouseEvent::Click;
-				DispatchEvent(&click);
+				Dispatch(click);
 			}
 		}
 
-		EventDispatcher::DispatchEvent(e);
+		EventDispatcher::Dispatch(evt);
+	}
+
+	void Node::PauseUpdating()
+	{
+		pause_ = true;
+	}
+
+	void Node::ResumeUpdating()
+	{
+		pause_ = false;
 	}
 
 	Matrix const & Node::GetTransformMatrix()  const
@@ -214,7 +225,7 @@ namespace easy2d
 			* Matrix::Rotation(transform_.rotation)
 			* Matrix::Translation(transform_.position);
 
-		Point offset{ -size_.x * pivot_.x, -size_.y * pivot_.y };
+		Point offset{ -size_.x * anchor_.x, -size_.y * anchor_.y };
 		transform_matrix_.Translate(offset);
 
 		if (parent_)
@@ -290,23 +301,23 @@ namespace easy2d
 		UpdateOpacity();
 	}
 
-	void Node::SetPivotX(float pivot_x)
+	void Node::SetAnchorX(float anchor_x)
 	{
-		this->SetPivot(pivot_x, pivot_.y);
+		this->SetAnchor(anchor_x, anchor_.y);
 	}
 
-	void Node::SetPivotY(float pivot_y)
+	void Node::SetAnchorY(float anchor_y)
 	{
-		this->SetPivot(pivot_.x, pivot_y);
+		this->SetAnchor(anchor_.x, anchor_y);
 	}
 
-	void Node::SetPivot(float pivot_x, float pivot_y)
+	void Node::SetAnchor(float anchor_x, float anchor_y)
 	{
-		if (pivot_.x == pivot_x && pivot_.y == pivot_y)
+		if (anchor_.x == anchor_x && anchor_.y == anchor_y)
 			return;
 
-		pivot_.x = pivot_x;
-		pivot_.y = pivot_y;
+		anchor_.x = anchor_x;
+		anchor_.y = anchor_y;
 		dirty_transform_ = true;
 	}
 
diff --git a/src/core/Node.h b/src/core/Node.h
index e29270f9..c38395f7 100644
--- a/src/core/Node.h
+++ b/src/core/Node.h
@@ -25,26 +25,26 @@
 #include "TaskManager.h"
 #include "ActionManager.h"
 #include "EventDispatcher.h"
-#include "intrusive/List.hpp"
+#include "IntrusiveList.hpp"
 
 namespace easy2d
 {
-	class Game;
+	class Application;
 
 	// 节点
 	class Node
-		: public Object
+		: public virtual Object
 		, public TaskManager
 		, public ActionManager
 		, public EventDispatcher
-		, protected intrusive::ListItem
+		, protected IntrusiveListItem
 	{
-		friend class Game;
+		friend class Application;
 		friend class Scene;
 		friend class Transition;
-		friend class intrusive::List;
+		friend class IntrusiveList;
 
-		using Children = intrusive::List;
+		using Children = IntrusiveList;
 
 	public:
 		Node();
@@ -55,11 +55,14 @@ namespace easy2d
 		// 渲染节点
 		virtual void OnRender() {}
 
+		// 事件分发
+		virtual void Dispatch(Event& evt) override;
+
 		// 获取显示状态
 		bool IsVisible()				const	{ return visible_; }
 
 		// 获取名称
-		String const& GetName()	const	{ return name_; }
+		String const& GetName()			const	{ return name_; }
 
 		// 获取名称的 Hash 值
 		size_t GetHashName()			const	{ return hash_name_; }
@@ -109,11 +112,11 @@ namespace easy2d
 		// 获取缩放后的大小
 		Size GetScaledSize()			const	{ return Size{ GetScaledWidth(), GetScaledHeight() }; }
 
-		// 获取 x 方向支点
-		float GetPivotX()				const	{ return pivot_.x; }
+		// 获取 x 方向锚点
+		float GetAnchorX()				const	{ return anchor_.x; }
 
-		// 获取 y 方向支点
-		float GetPivotY()				const	{ return pivot_.y; }
+		// 获取 y 方向锚点
+		float GetAnchorY()				const	{ return anchor_.y; }
 
 		// 获取透明度
 		float GetOpacity()				const	{ return opacity_; }
@@ -228,23 +231,23 @@ namespace easy2d
 			float rotation
 		);
 
-		// 设置支点的横向位置
+		// 设置锚点的横向位置
 		// 默认为 0, 范围 [0, 1]
-		void SetPivotX(
-			float pivot_x
+		void SetAnchorX(
+			float anchor_x
 		);
 
-		// 设置支点的纵向位置
+		// 设置锚点的纵向位置
 		// 默认为 0, 范围 [0, 1]
-		void SetPivotY(
-			float pivot_y
+		void SetAnchorY(
+			float anchor_y
 		);
 
-		// 设置支点位置
+		// 设置锚点位置
 		// 默认为 (0, 0), 范围 [0, 1]
-		void SetPivot(
-			float pivot_x,
-			float pivot_y
+		void SetAnchor(
+			float anchor_x,
+			float anchor_y
 		);
 
 		// 修改宽度
@@ -333,12 +336,16 @@ namespace easy2d
 		// 从父节点移除
 		void RemoveFromParent();
 
-		virtual void DispatchEvent(Event* e) override;
+		// 暂停节点更新
+		void PauseUpdating();
 
-		// 设置默认支点
-		static void SetDefaultPivot(
-			float pivot_x,
-			float pivot_y
+		// 继续节点更新
+		void ResumeUpdating();
+
+		// 设置默认锚点
+		static void SetDefaultAnchor(
+			float anchor_x,
+			float anchor_y
 		);
 
 	protected:
@@ -356,13 +363,14 @@ namespace easy2d
 		bool		visible_;
 		bool		hover_;
 		bool		pressed_;
+		bool		pause_;
 		int			z_order_;
 		float		opacity_;
 		float		display_opacity_;
 		String		name_;
 		size_t		hash_name_;
 		Transform	transform_;
-		Point		pivot_;
+		Point		anchor_;
 		Size		size_;
 		Node*		parent_;
 		Scene*		scene_;
diff --git a/src/core/Scene.cpp b/src/core/Scene.cpp
index b6e28d34..81c7153f 100644
--- a/src/core/Scene.cpp
+++ b/src/core/Scene.cpp
@@ -26,8 +26,8 @@ namespace easy2d
 {
 	Scene::Scene()
 	{
-		AddListener(SysEvent::WindowActivate, std::bind(&Scene::OnActivate, this));
-		AddListener(SysEvent::WindowDeavtivate, std::bind(&Scene::OnDeactivate, this));
+		AddListener(WindowEvent::Activate, std::bind(&Scene::OnActivate, this));
+		AddListener(WindowEvent::Deavtivate, std::bind(&Scene::OnDeactivate, this));
 
 		scene_ = this;
 	}
diff --git a/src/core/Singleton.hpp b/src/core/Singleton.hpp
index 18d03bcb..ba34f3c1 100644
--- a/src/core/Singleton.hpp
+++ b/src/core/Singleton.hpp
@@ -37,7 +37,7 @@ namespace easy2d
 			return instance_.get();
 		}
 
-	private:
+	protected:
 		ISingleton() = default;
 
 		~ISingleton() {}
@@ -53,8 +53,3 @@ namespace easy2d
 	friend struct ::std::default_delete< type >;\
 	friend class ::easy2d::ISingleton< type >
 #endif
-
-#ifndef E2D_DECLARE_SINGLETON_TYPE
-#define E2D_DECLARE_SINGLETON_TYPE( type, singleton_type ) \
-	using singleton_type = ::easy2d::ISingleton< type >
-#endif
diff --git a/src/core/Sprite.cpp b/src/core/Sprite.cpp
index 7e942e8c..898b838f 100644
--- a/src/core/Sprite.cpp
+++ b/src/core/Sprite.cpp
@@ -99,7 +99,7 @@ namespace easy2d
 	{
 		if (image_)
 		{
-			Graphics::Instance()->DrawImage(image_);
+			RenderSystem::Instance()->DrawImage(image_);
 		}
 	}
 }
\ No newline at end of file
diff --git a/src/core/Task.h b/src/core/Task.h
index 3bc8319e..1640ec43 100644
--- a/src/core/Task.h
+++ b/src/core/Task.h
@@ -21,7 +21,7 @@
 #pragma once
 #include "include-forwards.h"
 #include "time.h"
-#include "intrusive/List.hpp"
+#include "IntrusiveList.hpp"
 #include 
 
 namespace easy2d
@@ -30,11 +30,11 @@ namespace easy2d
 
     // 定时任务
 	class Task
-		: public Object
-		, protected intrusive::ListItem
+		: public virtual Object
+		, protected IntrusiveListItem
 	{
 		friend class TaskManager;
-		friend class intrusive::List;
+		friend class IntrusiveList;
 
 		using Callback = std::function;
 
diff --git a/src/core/TaskManager.h b/src/core/TaskManager.h
index 5b36891b..0896dcc5 100644
--- a/src/core/TaskManager.h
+++ b/src/core/TaskManager.h
@@ -25,7 +25,7 @@ namespace easy2d
 {
 	class TaskManager
 	{
-		using Tasks = intrusive::List;
+		using Tasks = IntrusiveList;
 
 	public:
 		// 添加任务
diff --git a/src/core/Text.cpp b/src/core/Text.cpp
index 7524d491..43671a01 100644
--- a/src/core/Text.cpp
+++ b/src/core/Text.cpp
@@ -295,15 +295,15 @@ namespace easy2d
 	{
 		if (text_layout_)
 		{
-			auto graphics = Graphics::Instance();
-			graphics->SetTextStyle(
+			auto rt = RenderSystem::Instance();
+			rt->SetTextStyle(
 				style_.color,
 				style_.outline,
 				style_.outline_color,
 				style_.outline_width,
 				style_.outline_stroke
 			);
-			graphics->DrawTextLayout(text_layout_);
+			rt->DrawTextLayout(text_layout_);
 		}
 	}
 
diff --git a/src/core/Transition.cpp b/src/core/Transition.cpp
index 72159694..e6ac5930 100644
--- a/src/core/Transition.cpp
+++ b/src/core/Transition.cpp
@@ -66,14 +66,14 @@ namespace easy2d
 		if (in_scene_)
 		{
 			ThrowIfFailed(
-				Graphics::Instance()->CreateLayer(in_layer_)
+				RenderSystem::Instance()->CreateLayer(in_layer_)
 			);
 		}
 
 		if (out_scene_)
 		{
 			ThrowIfFailed(
-				Graphics::Instance()->CreateLayer(out_layer_)
+				RenderSystem::Instance()->CreateLayer(out_layer_)
 			);
 		}
 
@@ -101,34 +101,34 @@ namespace easy2d
 
 	void Transition::Render()
 	{
-		auto graphics = Graphics::Instance();
+		auto rt = RenderSystem::Instance();
 
 		if (out_scene_)
 		{
-			graphics->PushClip(
+			rt->PushClip(
 				out_scene_->GetTransformMatrix(),
 				window_size_
 			);
-			graphics->PushLayer(out_layer_, out_layer_prop_);
+			rt->PushLayer(out_layer_, out_layer_prop_);
 
 			out_scene_->Render();
 
-			graphics->PopLayer();
-			graphics->PopClip();
+			rt->PopLayer();
+			rt->PopClip();
 		}
 
 		if (in_scene_)
 		{
-			graphics->PushClip(
+			rt->PushClip(
 				in_scene_->GetTransformMatrix(),
 				window_size_
 			);
-			graphics->PushLayer(in_layer_, in_layer_prop_);
+			rt->PushLayer(in_layer_, in_layer_prop_);
 
 			in_scene_->Render();
 
-			graphics->PopLayer();
-			graphics->PopClip();
+			rt->PopLayer();
+			rt->PopClip();
 		}
 	}
 
@@ -337,13 +337,13 @@ namespace easy2d
 		if (out_scene_)
 		{
 			out_scene_->SetTransform(transform);
-			out_scene_->SetPivot(0.5f, 0.5f);
+			out_scene_->SetAnchor(0.5f, 0.5f);
 		}
 
 		if (in_scene_)
 		{
 			in_scene_->SetTransform(transform);
-			in_scene_->SetPivot(0.5f, 0.5f);
+			in_scene_->SetAnchor(0.5f, 0.5f);
 		}
 
 		in_layer_prop_.opacity = 0;
@@ -384,13 +384,13 @@ namespace easy2d
 		if (out_scene_)
 		{
 			out_scene_->SetTransform(Transform{});
-			out_scene_->SetPivot(0.f, 0.f);
+			out_scene_->SetAnchor(0.f, 0.f);
 		}
 
 		if (in_scene_)
 		{
 			in_scene_->SetTransform(Transform{});
-			in_scene_->SetPivot(0.f, 0.f);
+			in_scene_->SetAnchor(0.f, 0.f);
 		}
 	}
 }
diff --git a/src/core/Transition.h b/src/core/Transition.h
index b6c57a38..5f04f3b5 100644
--- a/src/core/Transition.h
+++ b/src/core/Transition.h
@@ -28,9 +28,9 @@ namespace easy2d
 
 	// 场景过渡
 	class Transition
-		: public Object
+		: public virtual Object
 	{
-		friend class Game;
+		friend class Application;
 
 	public:
 		explicit Transition(
diff --git a/src/core/audio.cpp b/src/core/audio.cpp
index 8318de84..23357ad7 100644
--- a/src/core/audio.cpp
+++ b/src/core/audio.cpp
@@ -156,16 +156,16 @@ namespace easy2d
 
 
 	//-------------------------------------------------------
-	// AudioDevice
+	// Audio
 	//-------------------------------------------------------
 
-	AudioDevice::AudioDevice()
+	Audio::Audio()
 		: x_audio2_(nullptr)
 		, mastering_voice_(nullptr)
 	{
 	}
 
-	AudioDevice::~AudioDevice()
+	Audio::~Audio()
 	{
 		E2D_LOG(L"Destroying audio device");
 
@@ -182,7 +182,7 @@ namespace easy2d
 		modules::MediaFoundation::Get().MFShutdown();
 	}
 
-	HRESULT AudioDevice::Init(bool debug)
+	HRESULT Audio::Init(bool debug)
 	{
 		E2D_LOG(L"Initing audio device");
 
@@ -201,7 +201,7 @@ namespace easy2d
 		return hr;
 	}
 
-	HRESULT AudioDevice::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx)
+	HRESULT Audio::CreateVoice(Voice& voice, const WAVEFORMATEX* wfx)
 	{
 		HRESULT hr;
 		IXAudio2SourceVoice* source_voice;
@@ -215,12 +215,12 @@ namespace easy2d
 		return hr;
 	}
 
-	void AudioDevice::DeleteVoice(Voice* voice)
+	void Audio::DeleteVoice(Voice* voice)
 	{
 		voice_cache_.erase(voice);
 	}
 
-	void AudioDevice::ClearVoiceCache()
+	void Audio::ClearVoiceCache()
 	{
 		for (auto voice : voice_cache_)
 		{
@@ -229,12 +229,12 @@ namespace easy2d
 		voice_cache_.clear();
 	}
 
-	void AudioDevice::Open()
+	void Audio::Open()
 	{
 		x_audio2_->StartEngine();
 	}
 
-	void AudioDevice::Close()
+	void Audio::Close()
 	{
 		x_audio2_->StopEngine();
 	}
diff --git a/src/core/audio.h b/src/core/audio.h
index ee1ceb8a..6b6651f3 100644
--- a/src/core/audio.h
+++ b/src/core/audio.h
@@ -74,10 +74,10 @@ namespace easy2d
 	};
 
 
-	class AudioDevice
-		: protected Noncopyable
+	class Audio
+		: public ISingleton