├── .gitattributes
├── .gitignore
├── .gitmodules
├── Demo.Desktop
├── CMakeLists.txt
├── DeclareDPIAware.manifest
├── Demo.Desktop.vcxproj
├── Demo.Desktop.vcxproj.filters
└── main.c
├── LICENSE.txt
├── README.md
├── WTFDanmaku.sln
├── include
├── WTFDanmaku.h
├── WTFEngine.hpp
├── WTFWindow.hpp
└── WTF_API.h
├── libwtfdanmaku.Desktop
├── libwtfdanmaku.Desktop.vcxproj
└── libwtfdanmaku.Desktop.vcxproj.filters
├── libwtfdanmaku.Universal
├── libwtfdanmaku.Universal.vcxproj
└── libwtfdanmaku.Universal.vcxproj.filters
├── libwtfdanmaku.Windows
├── libwtfdanmaku.Windows.vcxproj
└── libwtfdanmaku.Windows.vcxproj.filters
├── libwtfdanmaku.Windows7
├── libwtfdanmaku.Windows7.vcxproj
└── libwtfdanmaku.Windows7.vcxproj.filters
├── libwtfdanmaku.WindowsPhone
├── libwtfdanmaku.WindowsPhone.vcxproj
└── libwtfdanmaku.WindowsPhone.vcxproj.filters
└── src
├── BaseDanmaku.cpp
├── BaseDanmaku.hpp
├── BilibiliParser.cpp
├── BilibiliParser.hpp
├── BottomDanmaku.cpp
├── BottomDanmaku.hpp
├── Controller.cpp
├── Controller.hpp
├── DanmakuConfig.hpp
├── DanmakuFactory.cpp
├── DanmakuFactory.hpp
├── DanmakusManager.cpp
├── DanmakusManager.hpp
├── DanmakusRetainer.cpp
├── DanmakusRetainer.hpp
├── Displayer.cpp
├── Displayer.hpp
├── DisplayerImpl.cpp
├── DisplayerImpl.hpp
├── IParser.hpp
├── ITimer.hpp
├── Noncopyable.hpp
├── OutlineTextRenderer.cpp
├── OutlineTextRenderer.hpp
├── PerformanceTimer.cpp
├── PerformanceTimer.hpp
├── R2LDanmaku.cpp
├── R2LDanmaku.hpp
├── Rect.hpp
├── Renderable.cpp
├── Renderable.hpp
├── StringUtils.cpp
├── StringUtils.hpp
├── TopDanmaku.cpp
├── TopDanmaku.hpp
├── WTFDanmaku.cpp
├── WTFEngine.cpp
├── WTFWindow.cpp
├── Win32Mutex.hpp
├── WinmmTimer.cpp
├── WinmmTimer.hpp
├── dllmain.cpp
├── libwtfdanmaku.Shared.vcxitems
└── libwtfdanmaku.Shared.vcxitems.filters
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # Build results
11 | [Dd]ebug/
12 | [Dd]ebugPublic/
13 | [Rr]elease/
14 | [Rr]eleases/
15 | x64/
16 | x86/
17 | build/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Roslyn cache directories
23 | *.ide/
24 |
25 | # MSTest test Results
26 | [Tt]est[Rr]esult*/
27 | [Bb]uild[Ll]og.*
28 |
29 | #NUNIT
30 | *.VisualState.xml
31 | TestResult.xml
32 |
33 | # Build Results of an ATL Project
34 | [Dd]ebugPS/
35 | [Rr]eleasePS/
36 | dlldata.c
37 |
38 | *_i.c
39 | *_p.c
40 | *_i.h
41 | *.ilk
42 | *.meta
43 | *.obj
44 | *.pch
45 | *.pdb
46 | *.pgc
47 | *.pgd
48 | *.rsp
49 | *.sbr
50 | *.tlb
51 | *.tli
52 | *.tlh
53 | *.tmp
54 | *.tmp_proj
55 | *.log
56 | *.vspscc
57 | *.vssscc
58 | .builds
59 | *.pidb
60 | *.svclog
61 | *.scc
62 |
63 | # Chutzpah Test files
64 | _Chutzpah*
65 |
66 | # Visual C++ cache files
67 | ipch/
68 | *.aps
69 | *.ncb
70 | *.opensdf
71 | *.sdf
72 | *.cachefile
73 |
74 | # Visual Studio profiler
75 | *.psess
76 | *.vsp
77 | *.vspx
78 |
79 | # TFS 2012 Local Workspace
80 | $tf/
81 |
82 | # Guidance Automation Toolkit
83 | *.gpState
84 |
85 | # ReSharper is a .NET coding add-in
86 | _ReSharper*/
87 | *.[Rr]e[Ss]harper
88 | *.DotSettings.user
89 |
90 | # JustCode is a .NET coding addin-in
91 | .JustCode
92 |
93 | # TeamCity is a build add-in
94 | _TeamCity*
95 |
96 | # DotCover is a Code Coverage Tool
97 | *.dotCover
98 |
99 | # NCrunch
100 | _NCrunch_*
101 | .*crunch*.local.xml
102 |
103 | # MightyMoose
104 | *.mm.*
105 | AutoTest.Net/
106 |
107 | # Web workbench (sass)
108 | .sass-cache/
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.[Pp]ublish.xml
128 | *.azurePubxml
129 | # TODO: Comment the next line if you want to checkin your web deploy settings
130 | # but database connection strings (with potential passwords) will be unencrypted
131 | *.pubxml
132 | *.publishproj
133 |
134 | # NuGet Packages
135 | *.nupkg
136 | # The packages folder can be ignored because of Package Restore
137 | **/packages/*
138 | # except build/, which is used as an MSBuild target.
139 | !**/packages/build/
140 | # If using the old MSBuild-Integrated Package Restore, uncomment this:
141 | #!**/packages/repositories.config
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # =========================
187 | # Operating System Files
188 | # =========================
189 |
190 | # OSX
191 | # =========================
192 |
193 | .DS_Store
194 | .AppleDouble
195 | .LSOverride
196 |
197 | # Thumbnails
198 | ._*
199 |
200 | # Files that might appear on external disk
201 | .Spotlight-V100
202 | .Trashes
203 |
204 | # Directories potentially created on remote AFP share
205 | .AppleDB
206 | .AppleDesktop
207 | Network Trash Folder
208 | Temporary Items
209 | .apdisk
210 |
211 | # Windows
212 | # =========================
213 |
214 | # Windows image file caches
215 | Thumbs.db
216 | ehthumbs.db
217 |
218 | # Folder config file
219 | Desktop.ini
220 |
221 | # Recycle Bin used on file shares
222 | $RECYCLE.BIN/
223 |
224 | # Windows Installer files
225 | *.cab
226 | *.msi
227 | *.msm
228 | *.msp
229 |
230 | # Windows shortcuts
231 | *.lnk
232 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "3rdparty/rapidxml"]
2 | path = 3rdparty/rapidxml
3 | url = https://github.com/xqq/rapidxml.git
4 | [submodule "src/base"]
5 | path = src/base
6 | url = https://github.com/xqq/SmartRef.git
7 |
--------------------------------------------------------------------------------
/Demo.Desktop/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 | project(demo)
3 |
4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
5 |
6 | include_directories(demo ../include)
7 | link_directories(demo ../Release/libwtfdanmaku.Desktop)
8 |
9 | set(SOURCE_FILES main.c)
10 |
11 | add_executable(demo ${SOURCE_FILES})
12 |
13 | target_link_libraries(demo libwtfdanmaku)
--------------------------------------------------------------------------------
/Demo.Desktop/DeclareDPIAware.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True/PM
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Demo.Desktop/Demo.Desktop.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}
23 | Demo
24 |
25 |
26 |
27 | Application
28 | true
29 | v120
30 | Unicode
31 |
32 |
33 | Application
34 | true
35 | v120
36 | Unicode
37 |
38 |
39 | Application
40 | false
41 | v120
42 | true
43 | Unicode
44 |
45 |
46 | Application
47 | false
48 | v120
49 | true
50 | Unicode
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | $(SolutionDir)$(Configuration)\libwtfdanmaku.Desktop\
70 | $(Configuration)\
71 | $(RootNamespace)
72 |
73 |
74 | $(SolutionDir)$(Platform)\$(Configuration)\libwtfdanmaku.Desktop\
75 | $(Platform)\$(Configuration)\
76 | $(RootNamespace)
77 |
78 |
79 | $(SolutionDir)$(Platform)\$(Configuration)\libwtfdanmaku.Desktop\
80 | $(Platform)\$(Configuration)\
81 | $(RootNamespace)
82 |
83 |
84 | $(SolutionDir)$(Configuration)\libwtfdanmaku.Desktop\
85 | $(Configuration)\
86 | $(RootNamespace)
87 |
88 |
89 |
90 | Level3
91 | Disabled
92 | true
93 | $(SolutionDir)include\;%(AdditionalIncludeDirectories)
94 |
95 |
96 | true
97 | %(AdditionalDependencies)
98 |
99 |
100 |
101 |
102 | Level3
103 | Disabled
104 | true
105 | $(SolutionDir)include\;%(AdditionalIncludeDirectories)
106 |
107 |
108 | true
109 | %(AdditionalDependencies)
110 |
111 |
112 |
113 |
114 | Level3
115 | MaxSpeed
116 | true
117 | true
118 | true
119 | $(SolutionDir)include\;%(AdditionalIncludeDirectories)
120 |
121 |
122 | true
123 | true
124 | true
125 | %(AdditionalDependencies)
126 |
127 |
128 |
129 |
130 | Level3
131 | MaxSpeed
132 | true
133 | true
134 | true
135 | $(SolutionDir)include\;%(AdditionalIncludeDirectories)
136 |
137 |
138 | true
139 | true
140 | true
141 | %(AdditionalDependencies)
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | {817ebe08-2be4-4251-92d0-117822d8f16a}
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/Demo.Desktop/Demo.Desktop.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 |
23 |
24 | Resource Files
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo.Desktop/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "WTFDanmaku.h"
6 |
7 | #ifndef WS_EX_NOREDIRECTIONBITMAP
8 | #define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
9 | #endif
10 |
11 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
12 |
13 | bool hasArgFile = false;
14 | char optFileName[MAX_PATH] = { 0 };
15 | bool wtfInited = false;
16 | WTF_Window* window = NULL;
17 | WTF_Instance* wtf = NULL;
18 |
19 | int main(int argc, char** argv) {
20 | if (argv[1]) {
21 | if (strlen(argv[1]) > 0) {
22 | strcpy_s(optFileName, sizeof(optFileName), argv[1]);
23 | hasArgFile = true;
24 | }
25 | }
26 | window = WTFWindow_Create(GetModuleHandle(NULL), SW_SHOWNORMAL);
27 | WTFWindow_SetCustomWndProc(window, WndProc);
28 | WTFWindow_Initialize(window, WS_EX_NOREDIRECTIONBITMAP, 1280, 720, L"WTFDanmaku Demo");
29 | WTFWindow_SetHitTestOverEnabled(window, 0);
30 | int ret = WTFWindow_RunMessageLoop(window);
31 | WTFWindow_Release(window);
32 | return ret;
33 | }
34 |
35 | void InitializeWTF(HWND hwnd) {
36 | if (!wtfInited) {
37 | wtf = WTF_CreateInstance();
38 | WTF_InitializeWithHwnd(wtf, (void*)hwnd);
39 | WTF_SetFontName(wtf, L"SimHei");
40 | WTF_SetFontWeight(wtf, 700);
41 | WTF_SetFontScaleFactor(wtf, 1.0f);
42 | WTF_SetDanmakuStyle(wtf, WTF_DANMAKU_STYLE_OUTLINE);
43 | WTF_SetCompositionOpacity(wtf, 0.9f);
44 | WTF_SetDanmakuTypeVisibility(wtf, WTF_DANMAKU_TYPE_SCROLLING_VISIBLE |
45 | WTF_DANMAKU_TYPE_TOP_VISIBLE |
46 | WTF_DANMAKU_TYPE_BOTTOM_VISIBLE);
47 |
48 | if (hasArgFile) {
49 | WTF_LoadBilibiliFile(wtf, optFileName);
50 | } else {
51 | WTF_LoadBilibiliFile(wtf, "E:\\Downloads\\Downloads\\1055660.xml");
52 | }
53 | wtfInited = true;
54 | }
55 | WTF_Start(wtf);
56 | }
57 |
58 | void ResizeWTF(uint32_t width, uint32_t height) {
59 | if (wtf) {
60 | WTF_Resize(wtf, width, height);
61 | }
62 | }
63 |
64 | void RButtonWTF() {
65 | if (wtf) {
66 | WTF_Pause(wtf);
67 | }
68 | }
69 |
70 | void ReleaseWTF() {
71 | if (wtf) {
72 | if (WTF_IsRunning(wtf)) {
73 | WTF_Stop(wtf);
74 | }
75 | WTF_ReleaseInstance(wtf);
76 | wtf = NULL;
77 | wtfInited = false;
78 | }
79 | }
80 |
81 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
82 | switch (message) {
83 | case WM_SIZE:
84 | if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) {
85 | ResizeWTF(LOWORD(lParam), HIWORD(lParam));
86 | }
87 | break;
88 | case WM_LBUTTONDOWN:
89 | InitializeWTF(hwnd);
90 | break;
91 | case WM_RBUTTONDOWN:
92 | RButtonWTF();
93 | break;
94 | case WM_DESTROY:
95 | ReleaseWTF();
96 | break;
97 | case WM_DPICHANGED: {
98 | uint32_t dpi = LOWORD(wParam);
99 | if (wtf != NULL && WTF_IsRunning(wtf)) {
100 | WTF_SetDpi(wtf, dpi, dpi);
101 | }
102 | break;
103 | }
104 | }
105 | return WTFWindow_DefaultWindowProc(window, (void*)hwnd, message, (WPARAM)wParam, (LPARAM)lParam);
106 | }
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | libwtfdanmaku
2 | =============
3 | High-performance danmaku engine for Windows, based on Direct2D and DirectComposition API.
4 |
5 | This project is still under developing.
6 |
7 | ### Features
8 | - Hardware accelerated by Direct2D, DirectWrite, Direct3D 11.0 and DXGI 1.2
9 | - Supports Windows 8 or later, Windows 8.1 Store App, and Windows 7 with [Platform Update](https://msdn.microsoft.com/en-us/library/windows/desktop/jj863687(v=vs.85).aspx)
10 | - Few cpu usage (<= 5%) with smooth animation
11 | - Accurate danmaku layout
12 |
13 | ### TODO
14 | - ~~Renderable's bitmap invalid issue~~
15 | - ~~Multiple instance~~
16 | - ~~x64 compatible~~
17 | - Optimize danmaku style effect
18 | - Rendering Statistics
19 | - ~~Hi-DPI support, and Pre-monitor DPI Aware~~
20 | - Further performance optimization
21 | - ~~Resize support (need rebuild device-dependent resources)~~
22 | - ~~BottomDanmaku~~, L2RDanmaku, Mode7 support, etc.
23 | - Refined error handling
24 | - User-friendly ~~C & C++ API~~
25 | - C++/CLI wrapper for .NET
26 | - Interoperate with Media Player
27 | - ~~Optimize Renderable building~~
28 | - ~~Windows Phone / UWP compatible~~
29 | - ~~Windows 7 compatible (maybe LayeredWindow?)~~
30 | - ~~Move to Direct3D 11~~
31 | - R2LDanmaku lines limitation
32 | - Keywords filter by regular expression
33 | - C++/CX wrapper for C#/WinRT invoking
34 | - More smooth animation (percision problem when calculating coordinates?)
35 | - ~~Refactor project files to vcxitems (Shared/Windows/WindowsPhone)~~
36 |
37 | ### Build
38 | My environment: Visual Studio Community 2013. Also tested under VS2015.
39 |
40 | Don't forget to checkout submodule (git submodule update --init)
41 |
42 | - Win32 Desktop
43 | - Import project `libwtfdanmaku.Desktop`
44 | - Win32 Desktop (for Windows7 compatibility)
45 | - Import project `libwtfdanmaku.Windows7`
46 | - Windows 10 Universal Platform
47 | - Import project `libwtfdanmaku.Universal`
48 | - Windows 8.1 WinRT/Universal
49 | - Import project `libwtfdanmaku.Windows`
50 | - Windows Phone 8.1
51 | - Import project `libwtfdanmaku.WindowsPhone`
52 |
53 | libwtfdanmaku is permitted to work under shared library (DLL) according to the license.
54 |
55 | ### Screenshot
56 |
57 | 
58 |
59 | ### License
60 | Copyright (C) 2015 xqq
61 |
62 | Licensed under LGPL v2.1
--------------------------------------------------------------------------------
/WTFDanmaku.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libwtfdanmaku", "libwtfdanmaku", "{E11B4418-B776-440A-93EB-E8C781728135}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.Windows", "libwtfdanmaku.Windows\libwtfdanmaku.Windows.vcxproj", "{BD09F5C8-43DC-4034-AD9C-5C8F7097073E}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.Shared", "src\libwtfdanmaku.Shared.vcxitems", "{6B39FFA8-CD29-4E39-8BB2-8C6B1F6EF2F9}"
11 | EndProject
12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.WindowsPhone", "libwtfdanmaku.WindowsPhone\libwtfdanmaku.WindowsPhone.vcxproj", "{4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}"
13 | EndProject
14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.Universal", "libwtfdanmaku.Universal\libwtfdanmaku.Universal.vcxproj", "{51D09FCD-92E8-4200-9138-4B06A1FF63A7}"
15 | EndProject
16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.Desktop", "libwtfdanmaku.Desktop\libwtfdanmaku.Desktop.vcxproj", "{817EBE08-2BE4-4251-92D0-117822D8F16A}"
17 | EndProject
18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwtfdanmaku.Windows7", "libwtfdanmaku.Windows7\libwtfdanmaku.Windows7.vcxproj", "{EB79010D-CCFC-4A09-93D9-E3DBFC61092F}"
19 | EndProject
20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo.Desktop", "Demo.Desktop\Demo.Desktop.vcxproj", "{6C6C2A8C-E868-4343-BD6E-6D164BF25134}"
21 | EndProject
22 | Global
23 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
24 | src\libwtfdanmaku.Shared.vcxitems*{51d09fcd-92e8-4200-9138-4b06a1ff63a7}*SharedItemsImports = 4
25 | src\libwtfdanmaku.Shared.vcxitems*{bd09f5c8-43dc-4034-ad9c-5c8f7097073e}*SharedItemsImports = 4
26 | src\libwtfdanmaku.Shared.vcxitems*{817ebe08-2be4-4251-92d0-117822d8f16a}*SharedItemsImports = 4
27 | src\libwtfdanmaku.Shared.vcxitems*{eb79010d-ccfc-4a09-93d9-e3dbfc61092f}*SharedItemsImports = 4
28 | src\libwtfdanmaku.Shared.vcxitems*{6b39ffa8-cd29-4e39-8bb2-8c6b1f6ef2f9}*SharedItemsImports = 9
29 | src\libwtfdanmaku.Shared.vcxitems*{4f9b663c-244b-4dd6-9f1c-32be2bcbd045}*SharedItemsImports = 4
30 | EndGlobalSection
31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
32 | Debug|ARM = Debug|ARM
33 | Debug|Win32 = Debug|Win32
34 | Debug|x64 = Debug|x64
35 | Release|ARM = Release|ARM
36 | Release|Win32 = Release|Win32
37 | Release|x64 = Release|x64
38 | EndGlobalSection
39 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
40 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|ARM.ActiveCfg = Debug|ARM
41 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|ARM.Build.0 = Debug|ARM
42 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|Win32.ActiveCfg = Debug|Win32
43 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|Win32.Build.0 = Debug|Win32
44 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|x64.ActiveCfg = Debug|x64
45 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Debug|x64.Build.0 = Debug|x64
46 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|ARM.ActiveCfg = Release|ARM
47 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|ARM.Build.0 = Release|ARM
48 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|Win32.ActiveCfg = Release|Win32
49 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|Win32.Build.0 = Release|Win32
50 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|x64.ActiveCfg = Release|x64
51 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E}.Release|x64.Build.0 = Release|x64
52 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Debug|ARM.ActiveCfg = Debug|ARM
53 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Debug|ARM.Build.0 = Debug|ARM
54 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Debug|Win32.ActiveCfg = Debug|Win32
55 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Debug|Win32.Build.0 = Debug|Win32
56 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Debug|x64.ActiveCfg = Debug|Win32
57 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Release|ARM.ActiveCfg = Release|ARM
58 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Release|ARM.Build.0 = Release|ARM
59 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Release|Win32.ActiveCfg = Release|Win32
60 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Release|Win32.Build.0 = Release|Win32
61 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045}.Release|x64.ActiveCfg = Release|Win32
62 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|ARM.ActiveCfg = Debug|ARM
63 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|ARM.Build.0 = Debug|ARM
64 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|Win32.ActiveCfg = Debug|Win32
65 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|Win32.Build.0 = Debug|Win32
66 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|x64.ActiveCfg = Debug|x64
67 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Debug|x64.Build.0 = Debug|x64
68 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|ARM.ActiveCfg = Release|ARM
69 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|ARM.Build.0 = Release|ARM
70 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|Win32.ActiveCfg = Release|Win32
71 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|Win32.Build.0 = Release|Win32
72 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|x64.ActiveCfg = Release|x64
73 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7}.Release|x64.Build.0 = Release|x64
74 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Debug|ARM.ActiveCfg = Debug|Win32
75 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Debug|Win32.ActiveCfg = Debug|Win32
76 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Debug|Win32.Build.0 = Debug|Win32
77 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Debug|x64.ActiveCfg = Debug|x64
78 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Debug|x64.Build.0 = Debug|x64
79 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Release|ARM.ActiveCfg = Release|Win32
80 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Release|Win32.ActiveCfg = Release|Win32
81 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Release|Win32.Build.0 = Release|Win32
82 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Release|x64.ActiveCfg = Release|x64
83 | {817EBE08-2BE4-4251-92D0-117822D8F16A}.Release|x64.Build.0 = Release|x64
84 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Debug|ARM.ActiveCfg = Debug|Win32
85 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Debug|Win32.ActiveCfg = Debug|Win32
86 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Debug|Win32.Build.0 = Debug|Win32
87 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Debug|x64.ActiveCfg = Debug|x64
88 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Debug|x64.Build.0 = Debug|x64
89 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Release|ARM.ActiveCfg = Release|Win32
90 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Release|Win32.ActiveCfg = Release|Win32
91 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Release|Win32.Build.0 = Release|Win32
92 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Release|x64.ActiveCfg = Release|x64
93 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}.Release|x64.Build.0 = Release|x64
94 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Debug|ARM.ActiveCfg = Debug|Win32
95 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Debug|Win32.ActiveCfg = Debug|Win32
96 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Debug|Win32.Build.0 = Debug|Win32
97 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Debug|x64.ActiveCfg = Debug|x64
98 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Debug|x64.Build.0 = Debug|x64
99 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Release|ARM.ActiveCfg = Release|Win32
100 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Release|Win32.ActiveCfg = Release|Win32
101 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Release|Win32.Build.0 = Release|Win32
102 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Release|x64.ActiveCfg = Release|x64
103 | {6C6C2A8C-E868-4343-BD6E-6D164BF25134}.Release|x64.Build.0 = Release|x64
104 | EndGlobalSection
105 | GlobalSection(SolutionProperties) = preSolution
106 | HideSolutionNode = FALSE
107 | EndGlobalSection
108 | GlobalSection(NestedProjects) = preSolution
109 | {BD09F5C8-43DC-4034-AD9C-5C8F7097073E} = {E11B4418-B776-440A-93EB-E8C781728135}
110 | {6B39FFA8-CD29-4E39-8BB2-8C6B1F6EF2F9} = {E11B4418-B776-440A-93EB-E8C781728135}
111 | {4F9B663C-244B-4DD6-9F1C-32BE2BCBD045} = {E11B4418-B776-440A-93EB-E8C781728135}
112 | {51D09FCD-92E8-4200-9138-4B06A1FF63A7} = {E11B4418-B776-440A-93EB-E8C781728135}
113 | {817EBE08-2BE4-4251-92D0-117822D8F16A} = {E11B4418-B776-440A-93EB-E8C781728135}
114 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F} = {E11B4418-B776-440A-93EB-E8C781728135}
115 | EndGlobalSection
116 | EndGlobal
117 |
--------------------------------------------------------------------------------
/include/WTFDanmaku.h:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_DANMAKU_C_WRAPPER_H
2 | #define _WTF_DANMAKU_C_WRAPPER_H
3 |
4 | #include
5 | #include
6 | #include "WTF_API.h"
7 |
8 | WTF_C_API typedef struct WTF_Instance {
9 | void* controller;
10 | } WTF_Instance;
11 |
12 | #define WTF_DANMAKU_TYPE_SCROLLING 1
13 | #define WTF_DANMAKU_TYPE_BOTTOM 4
14 | #define WTF_DANMAKU_TYPE_TOP 5
15 | #define WTF_DANMAKU_TYPE_RESERVE 6
16 | #define WTF_DANMAKU_TYPE_POSITION 7
17 | #define WTF_DANMAKU_TYPE_ADVANCED 8
18 |
19 | #define WTF_DANMAKU_STYLE_OUTLINE 1
20 | #define WTF_DANMAKU_STYLE_PROJECTION 2
21 |
22 | #define WTF_DANMAKU_TYPE_SCROLLING_VISIBLE (1)
23 | #define WTF_DANMAKU_TYPE_BOTTOM_VISIBLE (2)
24 | #define WTF_DANMAKU_TYPE_TOP_VISIBLE (4)
25 | #define WTF_DANMAKU_TYPE_RESERVE_VISIBLE (8)
26 | #define WTF_DANMAKU_TYPE_POSITION_VISIBLE (16)
27 | #define WTF_DANMAKU_TYPE_ADVANCED_VISIBLE (32)
28 |
29 | WTF_C_API WTF_Instance* __stdcall WTF_CreateInstance();
30 | WTF_C_API void __stdcall WTF_ReleaseInstance(WTF_Instance* instance);
31 | WTF_C_API int __stdcall WTF_InitializeWithHwnd(WTF_Instance* instance, void* hwnd);
32 | WTF_C_API int __stdcall WTF_InitializeOffscreen(WTF_Instance* instance, uint32_t initialWidth, uint32_t initialHeight);
33 | WTF_C_API void __stdcall WTF_Terminate(WTF_Instance* instance);
34 | WTF_C_API int __stdcall WTF_QuerySwapChain(WTF_Instance* instance, const void* pGuid, void** ppObject);
35 | WTF_C_API void __stdcall WTF_LoadBilibiliFile(WTF_Instance* instance, const char* filePath);
36 | WTF_C_API void __stdcall WTF_LoadBilibiliFileW(WTF_Instance* instance, const wchar_t* filePath);
37 | WTF_C_API void __stdcall WTF_LoadBilibiliXml(WTF_Instance* instance, const char* str);
38 | WTF_C_API void __stdcall WTF_AddDanmaku(WTF_Instance* instance, int type, int64_t time, const wchar_t* comment, int fontSize, int fontColor, int64_t timestamp, int danmakuId);
39 | WTF_C_API void __stdcall WTF_AddLiveDanmaku(WTF_Instance* instance, int type, int64_t time, const wchar_t* comment, int fontSize, int fontColor, int64_t timestamp, int danmakuId);
40 | WTF_C_API void __stdcall WTF_Start(WTF_Instance* instance);
41 | WTF_C_API void __stdcall WTF_Pause(WTF_Instance* instance);
42 | WTF_C_API void __stdcall WTF_Resume(WTF_Instance* instance);
43 | WTF_C_API void __stdcall WTF_Stop(WTF_Instance* instance);
44 | WTF_C_API void __stdcall WTF_SeekTo(WTF_Instance* instance, int64_t milliseconds);
45 | WTF_C_API void __stdcall WTF_Resize(WTF_Instance* instance, uint32_t width, uint32_t height);
46 | WTF_C_API void __stdcall WTF_SetDpi(WTF_Instance* instance, uint32_t dpiX, uint32_t dpiY);
47 | WTF_C_API int64_t __stdcall WTF_GetCurrentPosition(WTF_Instance* instance);
48 | WTF_C_API int __stdcall WTF_IsRunning(WTF_Instance* instance);
49 | WTF_C_API float __stdcall WTF_GetFontScaleFactor(WTF_Instance* instance);
50 | WTF_C_API void __stdcall WTF_SetFontScaleFactor(WTF_Instance* instance, float factor);
51 | WTF_C_API void __stdcall WTF_SetFontName(WTF_Instance* instance, const wchar_t* fontName);
52 | WTF_C_API void __stdcall WTF_SetFontWeight(WTF_Instance* instance, int dwriteFontWeight);
53 | WTF_C_API void __stdcall WTF_SetFontStyle(WTF_Instance* instance, int dwriteFontStyle);
54 | WTF_C_API void __stdcall WTF_SetFontStretch(WTF_Instance* instance, int dwriteFontStretch);
55 | WTF_C_API void __stdcall WTF_SetDanmakuStyle(WTF_Instance* instance, int style);
56 | WTF_C_API void __stdcall WTF_SetCompositionOpacity(WTF_Instance* instance, float opacity);
57 | WTF_C_API void __stdcall WTF_SetDanmakuTypeVisibility(WTF_Instance* instance, int params);
58 |
59 | #ifndef _WTF_BUILD_UWP
60 |
61 | WTF_C_API typedef struct WTF_Window WTF_Window;
62 |
63 | WTF_C_API WTF_Window* __stdcall WTFWindow_Create(void* hInstance, int nCmdShow);
64 | WTF_C_API void __stdcall WTFWindow_Release(WTF_Window* window);
65 | WTF_C_API void __stdcall WTFWindow_Initialize(WTF_Window* window, uint32_t dwExStyle, int width, int height, const wchar_t* title);
66 | WTF_C_API void* __stdcall WTFWindow_GetHwnd(WTF_Window* window);
67 | WTF_C_API void __stdcall WTFWindow_SetCustomWndProc(WTF_Window* window, void* proc);
68 | WTF_C_API LRESULT __stdcall WTFWindow_DefaultWindowProc(WTF_Window* window, void* hwnd, uint32_t message, WPARAM wParam, LPARAM lParam);
69 | WTF_C_API void __stdcall WTFWindow_SetHitTestOverEnabled(WTF_Window* window, int enabled);
70 | WTF_C_API int __stdcall WTFWindow_RunMessageLoop(WTF_Window* window);
71 |
72 | #endif // !_WTF_BUILD_UWP
73 |
74 |
75 | #endif // _WTF_DANMAKU_C_WRAPPER_H
--------------------------------------------------------------------------------
/include/WTFEngine.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_ENGINE_HPP
2 | #define _WTF_ENGINE_HPP
3 |
4 | #include
5 | #include "WTF_API.h"
6 |
7 | namespace WTFDanmaku {
8 |
9 | class Controller;
10 |
11 | enum Type : int {
12 | Scrolling = 1,
13 | Bottom = 4,
14 | Top = 5,
15 | Reverse = 6,
16 | Position = 7,
17 | Advanced = 8
18 | };
19 |
20 | enum TypeVisible : int {
21 | ScrollingVisible = 1,
22 | BottomVisible = 2,
23 | TopVisible = 4,
24 | ReserveVisible = 8,
25 | PositionVisible = 16,
26 | AdvancedVisible = 32
27 | };
28 |
29 | enum Style : int {
30 | Outline = 1,
31 | Projection = 2
32 | };
33 |
34 | class WTF_API WTFEngine {
35 | public:
36 | explicit WTFEngine();
37 | ~WTFEngine();
38 | int Initialize(void* hwnd);
39 | int InitializeOffscreen(uint32_t initialWidth, uint32_t initialHeight);
40 | void Terminate();
41 | int QuerySwapChain(const void* pGuid, void** ppObject);
42 | void LoadBilibiliFile(const char* filePath);
43 | void LoadBilibiliFile(const wchar_t* filePath);
44 | void LoadBilibiliXml(const char* str);
45 | void AddDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
46 | void AddLiveDanmaku(Type type, time_t time, const wchar_t* comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
47 | void Start();
48 | void Pause();
49 | void Resume();
50 | void Stop();
51 | void SeekTo(time_t milliseconds);
52 | void Resize(uint32_t width, uint32_t height);
53 | void SetDpi(uint32_t dpiX, uint32_t dpiY);
54 | time_t GetCurrentPosition();
55 | bool IsRunning();
56 | float GetFontScaleFactor();
57 | void SetFontScaleFactor(float factor);
58 | void SetFontName(const wchar_t* fontName);
59 | void SetFontWeight(int dwriteFontWeight);
60 | void SetFontStyle(int dwriteFontStyle);
61 | void SetFontStretch(int dwriteFontStretch);
62 | void SetDanmakuStyle(Style style);
63 | void SetCompositionOpacity(float opacity);
64 | void SetDanmakuTypeVisibility(int params);
65 | private:
66 | WTFEngine(const WTFEngine&) = delete;
67 | WTFEngine& operator=(const WTFEngine&) = delete;
68 | private:
69 | Controller* mController;
70 | };
71 |
72 | }
73 |
74 |
75 | #endif // _WTF_ENGINE_HPP
--------------------------------------------------------------------------------
/include/WTFWindow.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_WINDOW_HPP
2 | #define _WTF_WINDOW_HPP
3 |
4 | #include
5 | #include
6 | #include "WTF_API.h"
7 |
8 | #ifndef _WTF_BUILD_UWP
9 |
10 | namespace WTFDanmaku {
11 |
12 | class WTF_API WTFWindow {
13 | public:
14 | explicit WTFWindow(HINSTANCE hInst, int nCmdShow);
15 | ~WTFWindow();
16 | int Initialize(DWORD dwExStyle = NULL, int width = 1280, int height = 720, const wchar_t* title = nullptr);
17 | void SetCustomWindowProc(WNDPROC proc);
18 | void SetHitTestOverEnabled(bool enabled);
19 | int Run();
20 | HWND GetHwnd();
21 | LRESULT DefaultWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
22 | private:
23 | ATOM RegisterWindowClass();
24 | static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
25 | private:
26 | WTFWindow(const WTFWindow&) = delete;
27 | WTFWindow& operator=(const WTFWindow&) = delete;
28 | private:
29 | int m_nCmdShow = 0;
30 | HINSTANCE m_hInstance = NULL;
31 | WNDPROC m_CustomWndProc = NULL;
32 | HWND m_hWindow = NULL;
33 | PWSTR m_WindowClassName = L"WTFDanmaku";
34 |
35 | uint32_t m_ClientWidth = 0;
36 | uint32_t m_ClientHeight = 0;
37 | };
38 |
39 | }
40 |
41 | #endif // !_WTF_BUILD_UWP
42 |
43 | #endif // _WTF_SAMPLE_WINDOW_HPP
--------------------------------------------------------------------------------
/include/WTF_API.h:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_API_H
2 | #define _WTF_API_H
3 |
4 | #ifdef _MSC_VER
5 | #ifdef LIBWTFDANMAKU_EXPORTS
6 | #define WTF_API __declspec(dllexport)
7 | #else
8 | #define WTF_API __declspec(dllimport)
9 | #endif
10 | #else
11 | #define WTF_API
12 | #endif
13 |
14 | #ifdef __cplusplus
15 | #define WTF_C_API extern "C" WTF_API
16 | #else
17 | #define WTF_C_API WTF_API
18 | #endif
19 |
20 | #endif // _WTF_API_H
--------------------------------------------------------------------------------
/libwtfdanmaku.Desktop/libwtfdanmaku.Desktop.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {817EBE08-2BE4-4251-92D0-117822D8F16A}
23 | Win32Proj
24 | libwtfdanmaku
25 | libwtfdanmaku.Desktop
26 |
27 |
28 |
29 | DynamicLibrary
30 | true
31 | v120
32 | Unicode
33 |
34 |
35 | DynamicLibrary
36 | true
37 | v120
38 | Unicode
39 |
40 |
41 | DynamicLibrary
42 | false
43 | v120
44 | true
45 | Unicode
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v120
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 | $(ItemsRootNamespace)
76 | $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\
77 |
78 |
79 | true
80 | $(ItemsRootNamespace)
81 | $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
82 |
83 |
84 | false
85 | $(ItemsRootNamespace)
86 | $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\
87 |
88 |
89 | false
90 | $(ItemsRootNamespace)
91 | $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
92 |
93 |
94 |
95 | Level3
96 | Disabled
97 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;%(PreprocessorDefinitions)
98 | true
99 | true
100 | false
101 |
102 |
103 | Windows
104 | true
105 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
106 |
107 |
108 |
109 |
110 | Level3
111 | Disabled
112 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;%(PreprocessorDefinitions)
113 | true
114 | true
115 | false
116 |
117 |
118 | Windows
119 | true
120 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
121 |
122 |
123 |
124 |
125 | Level3
126 | MaxSpeed
127 | true
128 | true
129 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;%(PreprocessorDefinitions)
130 | true
131 | true
132 |
133 |
134 | Windows
135 | true
136 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
137 | true
138 | true
139 |
140 |
141 |
142 |
143 | Level3
144 | MaxSpeed
145 | true
146 | true
147 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;%(PreprocessorDefinitions)
148 | true
149 | true
150 |
151 |
152 | Windows
153 | true
154 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
155 | true
156 | true
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Desktop/libwtfdanmaku.Desktop.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Universal/libwtfdanmaku.Universal.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM
7 |
8 |
9 | Debug
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | ARM
19 |
20 |
21 | Release
22 | Win32
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 | {51d09fcd-92e8-4200-9138-4b06a1ff63a7}
31 | DynamicLibrary
32 | libwtfdanmaku.Universal
33 | libwtfdanmaku
34 | zh-CN
35 | 14.0
36 | true
37 | Windows Store
38 | 10.0.10586.0
39 | 10.0.10240.0
40 | 10.0
41 |
42 |
43 |
44 | DynamicLibrary
45 | true
46 | v140
47 |
48 |
49 | DynamicLibrary
50 | true
51 | v140
52 |
53 |
54 | DynamicLibrary
55 | true
56 | v140
57 |
58 |
59 | DynamicLibrary
60 | false
61 | true
62 | v140
63 |
64 |
65 | DynamicLibrary
66 | false
67 | true
68 | v140
69 |
70 |
71 | DynamicLibrary
72 | false
73 | true
74 | v140
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | false
104 | false
105 | $(ItemsRootNamespace)
106 |
107 |
108 | false
109 | false
110 | $(ItemsRootNamespace)
111 |
112 |
113 | false
114 | false
115 | $(ItemsRootNamespace)
116 |
117 |
118 | false
119 | false
120 | $(ItemsRootNamespace)
121 |
122 |
123 | false
124 | false
125 | $(ItemsRootNamespace)
126 |
127 |
128 | false
129 | false
130 | $(ItemsRootNamespace)
131 |
132 |
133 |
134 | NotUsing
135 | false
136 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
137 |
138 |
139 | Console
140 | false
141 | false
142 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
143 |
144 |
145 |
146 |
147 | NotUsing
148 | false
149 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
150 |
151 |
152 | Console
153 | false
154 | false
155 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
156 |
157 |
158 |
159 |
160 | NotUsing
161 | false
162 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
163 |
164 |
165 | Console
166 | false
167 | false
168 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
169 |
170 |
171 |
172 |
173 | NotUsing
174 | false
175 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
176 |
177 |
178 | Console
179 | false
180 | false
181 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
182 |
183 |
184 |
185 |
186 | NotUsing
187 | false
188 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
189 |
190 |
191 | Console
192 | false
193 | false
194 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
195 |
196 |
197 |
198 |
199 | NotUsing
200 | false
201 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
202 |
203 |
204 | Console
205 | false
206 | false
207 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Universal/libwtfdanmaku.Universal.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
7 |
8 |
9 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Windows/libwtfdanmaku.Windows.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM
7 |
8 |
9 | Debug
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | ARM
19 |
20 |
21 | Release
22 | Win32
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 |
30 | {bd09f5c8-43dc-4034-ad9c-5c8f7097073e}
31 | DynamicLibrary
32 | libwtfdanmaku
33 | zh-CN
34 | 12.0
35 | true
36 | Windows Store
37 | 8.1
38 | CodeSharingDll
39 |
40 |
41 |
42 | DynamicLibrary
43 | true
44 | v120
45 |
46 |
47 | DynamicLibrary
48 | true
49 | v120
50 |
51 |
52 | DynamicLibrary
53 | true
54 | v120
55 |
56 |
57 | DynamicLibrary
58 | false
59 | true
60 | v120
61 |
62 |
63 | DynamicLibrary
64 | false
65 | true
66 | v120
67 |
68 |
69 | DynamicLibrary
70 | false
71 | true
72 | v120
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | false
101 | false
102 | $(ItemsRootNamespace)
103 |
104 |
105 | false
106 | false
107 | $(ItemsRootNamespace)
108 |
109 |
110 | false
111 | false
112 | $(ItemsRootNamespace)
113 |
114 |
115 | false
116 | false
117 | $(ItemsRootNamespace)
118 |
119 |
120 | false
121 | false
122 | $(ItemsRootNamespace)
123 |
124 |
125 | false
126 | false
127 | $(ItemsRootNamespace)
128 |
129 |
130 |
131 | NotUsing
132 | false
133 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
134 |
135 |
136 | Console
137 | false
138 | false
139 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
140 |
141 |
142 |
143 |
144 | NotUsing
145 | false
146 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
147 |
148 |
149 | Console
150 | false
151 | false
152 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
153 |
154 |
155 |
156 |
157 | NotUsing
158 | false
159 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
160 |
161 |
162 | Console
163 | false
164 | false
165 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
166 |
167 |
168 |
169 |
170 | NotUsing
171 | false
172 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
173 |
174 |
175 | Console
176 | false
177 | false
178 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
179 |
180 |
181 |
182 |
183 | NotUsing
184 | false
185 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
186 |
187 |
188 | Console
189 | false
190 | false
191 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
192 |
193 |
194 |
195 |
196 | NotUsing
197 | false
198 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
199 |
200 |
201 | Console
202 | false
203 | false
204 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Windows/libwtfdanmaku.Windows.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Windows7/libwtfdanmaku.Windows7.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {EB79010D-CCFC-4A09-93D9-E3DBFC61092F}
23 | Win32Proj
24 | libwtfdanmaku
25 | libwtfdanmaku.Windows7
26 |
27 |
28 |
29 | DynamicLibrary
30 | true
31 | v120
32 | Unicode
33 |
34 |
35 | DynamicLibrary
36 | true
37 | v120
38 | Unicode
39 |
40 |
41 | DynamicLibrary
42 | false
43 | v120
44 | true
45 | Unicode
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v120
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 | $(ItemsRootNamespace)
76 | $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\
77 |
78 |
79 | true
80 | $(ItemsRootNamespace)
81 | $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
82 |
83 |
84 | false
85 | $(ItemsRootNamespace)
86 | $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\
87 |
88 |
89 | false
90 | $(ItemsRootNamespace)
91 | $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
92 |
93 |
94 |
95 | Level3
96 | Disabled
97 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_WIN7;%(PreprocessorDefinitions)
98 | true
99 | true
100 | false
101 |
102 |
103 | Windows
104 | true
105 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
106 |
107 |
108 |
109 |
110 | Level3
111 | Disabled
112 | WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_WIN7;%(PreprocessorDefinitions)
113 | true
114 | true
115 | false
116 |
117 |
118 | Windows
119 | true
120 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
121 |
122 |
123 |
124 |
125 | Level3
126 | MaxSpeed
127 | true
128 | true
129 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_WIN7;%(PreprocessorDefinitions)
130 | true
131 | true
132 |
133 |
134 | Windows
135 | true
136 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
137 | true
138 | true
139 |
140 |
141 |
142 |
143 | Level3
144 | MaxSpeed
145 | true
146 | true
147 | WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_WIN7;%(PreprocessorDefinitions)
148 | true
149 | true
150 |
151 |
152 | Windows
153 | true
154 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
155 | true
156 | true
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/libwtfdanmaku.Windows7/libwtfdanmaku.Windows7.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/libwtfdanmaku.WindowsPhone/libwtfdanmaku.WindowsPhone.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM
7 |
8 |
9 | Debug
10 | Win32
11 |
12 |
13 | Release
14 | ARM
15 |
16 |
17 | Release
18 | Win32
19 |
20 |
21 |
22 | {4f9b663c-244b-4dd6-9f1c-32be2bcbd045}
23 | DynamicLibrary
24 | libwtfdanmaku
25 | zh-CN
26 | 12.0
27 | true
28 | Windows Phone
29 | 8.1
30 | CodeSharingDll
31 |
32 |
33 |
34 | DynamicLibrary
35 | true
36 | v120_wp81
37 |
38 |
39 | DynamicLibrary
40 | true
41 | v120_wp81
42 |
43 |
44 | DynamicLibrary
45 | false
46 | true
47 | v120_wp81
48 |
49 |
50 | DynamicLibrary
51 | false
52 | true
53 | v120_wp81
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | false
76 | false
77 | $(ItemsRootNamespace)
78 |
79 |
80 | false
81 | false
82 | $(ItemsRootNamespace)
83 |
84 |
85 | false
86 | false
87 | $(ItemsRootNamespace)
88 |
89 |
90 | false
91 | false
92 | $(ItemsRootNamespace)
93 |
94 |
95 |
96 | NotUsing
97 | false
98 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
99 |
100 |
101 | Console
102 | false
103 | false
104 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
105 |
106 |
107 |
108 |
109 | NotUsing
110 | false
111 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
112 |
113 |
114 | Console
115 | false
116 | false
117 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
118 |
119 |
120 |
121 |
122 | NotUsing
123 | false
124 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
125 |
126 |
127 | Console
128 | false
129 | false
130 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
131 |
132 |
133 |
134 |
135 | NotUsing
136 | false
137 | WIN32;_WINDOWS;_USRDLL;LIBWTFDANMAKU_EXPORTS;_WTF_BUILD_UWP;%(PreprocessorDefinitions)
138 |
139 |
140 | Console
141 | false
142 | false
143 | dxgi.lib;d3d11.lib;d2d1.lib;dwrite.lib;%(AdditionalDependencies)
144 |
145 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/libwtfdanmaku.WindowsPhone/libwtfdanmaku.WindowsPhone.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/BaseDanmaku.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "DanmakuConfig.hpp"
3 | #include "Renderable.hpp"
4 | #include "BaseDanmaku.hpp"
5 |
6 | namespace WTFDanmaku {
7 |
8 | BaseDanmaku::BaseDanmaku() {
9 |
10 | }
11 |
12 | BaseDanmaku::~BaseDanmaku() {
13 |
14 | }
15 |
16 | DanmakuType BaseDanmaku::GetType() {
17 | return kNull;
18 | }
19 |
20 | bool BaseDanmaku::HasMeasured(DanmakuConfig* config) {
21 | return nullptr != mRenderable
22 | && mRenderable->HasTextLayout()
23 | && mMeasureFlag == config->MeasureFlag;
24 | }
25 |
26 | bool BaseDanmaku::HasLayout(DanmakuConfig* config) {
27 | return mLayoutFlag == config->LayoutFlag;
28 | }
29 |
30 | void BaseDanmaku::Measure(Displayer* displayer, DanmakuConfig* config) {
31 | if (nullptr == mRenderable) {
32 | mRenderable = std::make_shared(this);
33 | }
34 |
35 | mRenderable->BuildTextLayout(displayer, config);
36 |
37 | mDuration = config->DanmakuDuration;
38 | mMeasureFlag = config->MeasureFlag;
39 | }
40 |
41 | void BaseDanmaku::ReleaseResources() {
42 | this->ReleaseRenderable();
43 | }
44 |
45 | bool BaseDanmaku::IsAlive(time_t time) {
46 | time_t elapsed = time - this->mStartTime;
47 | return elapsed > 0 && elapsed <= mDuration;
48 | }
49 |
50 | weak_ptr BaseDanmaku::BuildRenderable(Displayer* displayer, DanmakuConfig* config) {
51 | if (nullptr == mRenderable || !mRenderable->HasTextLayout())
52 | this->Measure(displayer, config);
53 |
54 | if (!mRenderable->HasBitmap(config)) {
55 | mRenderable->BuildBitmap(displayer, config);
56 | }
57 |
58 | return mRenderable;
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/src/BaseDanmaku.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_BASE_DANMAKU_HPP
2 | #define _WTF_BASE_DANMAKU_HPP
3 |
4 | #include
5 | #include
6 | #include
7 | #include "base/RefBase.hpp"
8 | #include "base/RefPtr.hpp"
9 | #include "Noncopyable.hpp"
10 | #include "Rect.hpp"
11 |
12 | using std::shared_ptr;
13 | using std::weak_ptr;
14 |
15 | namespace WTFDanmaku {
16 |
17 | enum DanmakuType : int {
18 | kNull = 0,
19 | kScrolling = 1,
20 | kBottom = 4,
21 | kTop = 5,
22 | kReverse = 6,
23 | kPosition = 7,
24 | kAdvanced = 8
25 | };
26 |
27 | class Displayer;
28 | class Renderable;
29 | struct DanmakuConfig;
30 |
31 | class BaseDanmaku : public xl::RefBase {
32 | friend class DanmakuFactory;
33 | friend class Renderable;
34 | public:
35 | explicit BaseDanmaku();
36 |
37 | virtual ~BaseDanmaku();
38 |
39 | inline float GetWidth() {
40 | return mTextWidth;
41 | }
42 |
43 | inline float GetHeight() {
44 | return mTextHeight;
45 | }
46 |
47 | bool HasMeasured(DanmakuConfig* config);
48 |
49 | bool HasLayout(DanmakuConfig* config);
50 |
51 | inline bool HasRenderable() {
52 | return mRenderable != nullptr;
53 | }
54 |
55 | weak_ptr BuildRenderable(Displayer* displayer, DanmakuConfig* config);
56 |
57 | inline weak_ptr GetRenderable() {
58 | return weak_ptr(mRenderable);
59 | }
60 |
61 | inline void ReleaseRenderable() {
62 | mRenderable.reset();
63 | }
64 |
65 | virtual void ReleaseResources();
66 |
67 | virtual void Measure(Displayer* displayer, DanmakuConfig* config);
68 |
69 | virtual void Layout(Displayer* displayer, DanmakuConfig* config, float x, float y) = 0;
70 |
71 | virtual DanmakuType GetType() = 0;
72 |
73 | virtual bool IsAlive(time_t time);
74 |
75 | virtual float GetSpeed() = 0;
76 |
77 | virtual float GetLeftAtTime(Displayer* displayer, time_t time) = 0;
78 |
79 | virtual Rect GetRectAtTime(Displayer* displayer, time_t time) = 0;
80 |
81 | inline time_t GetStartTime() {
82 | return mStartTime;
83 | }
84 |
85 | inline void SetStartTime(time_t time) {
86 | mStartTime = time;
87 | }
88 |
89 | inline Rect GetRect() {
90 | return mRect;
91 | }
92 |
93 | inline time_t GetSendTimestamp() {
94 | return mTimestamp;
95 | }
96 |
97 | inline uint32_t GetDanmakuId() {
98 | return mDanmakuId;
99 | }
100 |
101 | inline bool IsSkipped() {
102 | return mSkipped;
103 | }
104 |
105 | inline void SetSkipped(bool skipped) {
106 | mSkipped = skipped;
107 | }
108 | protected:
109 | time_t mStartTime = 0;
110 | time_t mDuration = 0;
111 | Rect mRect;
112 | float mTextWidth = -1.0f;
113 | float mTextHeight = -1.0f;
114 | int mLayoutFlag = -1;
115 | private:
116 | std::wstring mComment;
117 | float mTextSize = 0.0f;
118 | uint32_t mTextColor = 0;
119 | uint32_t mTextShadowColor = 0;
120 | uint32_t mFilterParams = 0;
121 | time_t mTimestamp = 0;
122 | uint32_t mDanmakuId = 0;
123 | int mMeasureFlag = 0;
124 | shared_ptr mRenderable;
125 | bool mSkipped = false;
126 | };
127 |
128 | typedef xl::RefPtr DanmakuRef;
129 |
130 | }
131 |
132 | #endif // _WTF_BASE_DANMAKU_HPP
--------------------------------------------------------------------------------
/src/BilibiliParser.cpp:
--------------------------------------------------------------------------------
1 | #include "BilibiliParser.hpp"
2 | #include
3 | #include
4 | #include "../3rdparty/rapidxml/rapidxml.hpp"
5 | #include "../3rdparty/rapidxml/rapidxml_utils.hpp"
6 | #include "DanmakuFactory.hpp"
7 | #include "StringUtils.hpp"
8 |
9 | using namespace rapidxml;
10 |
11 | namespace WTFDanmaku {
12 |
13 | BilibiliParser::BilibiliParser() {
14 | mDanmakus = std::move(std::unique_ptr>(new std::vector));
15 | }
16 |
17 | bool BilibiliParser::ParseStringSource(const char* str) {
18 | return ParseXml(str);
19 | }
20 |
21 | bool BilibiliParser::ParseFileSource(const char* filePath) {
22 | file<> xmlFile(filePath);
23 | return ParseXml(xmlFile.data(), true);
24 | }
25 |
26 | bool BilibiliParser::ParseFileSource(const wchar_t* filePath) {
27 | std::ifstream file;
28 | file.open(filePath, std::ios::in || std::ios::binary || std::ios::ate);
29 | if (file.fail())
30 | return false;
31 |
32 | file.seekg(0, std::ios::end);
33 | size_t length = static_cast(file.tellg());
34 |
35 | std::string buffer;
36 | buffer.reserve(length + 1);
37 | buffer.resize(length);
38 |
39 | file.seekg(0, std::ios::beg);
40 | file.read(&buffer[0], length);
41 | file.close();
42 |
43 | return ParseXml(buffer.c_str(), true);
44 | }
45 |
46 | bool BilibiliParser::ParseXml(const char* data, bool inplace) {
47 | if (mDanmakus.get() == nullptr)
48 | return false;
49 |
50 | char* buffer = nullptr;
51 | std::unique_ptr raii_buffer;
52 |
53 | if (inplace) {
54 | buffer = const_cast(data);
55 | } else {
56 | size_t buffer_size = strlen(data) + 1;
57 | buffer = new char[buffer_size];
58 | raii_buffer = std::move(std::unique_ptr(buffer));
59 | memset(buffer, 0, buffer_size);
60 | strcpy_s(buffer, buffer_size, data);
61 | }
62 |
63 | xml_document<> doc;
64 | doc.parse<0>(buffer);
65 |
66 | xml_node* root = doc.first_node("i");
67 | if (root == nullptr)
68 | return false;
69 |
70 | for (auto node = root->first_node("d"); node != nullptr; node = node->next_sibling()) {
71 | const char* attr = node->first_attribute("p")->value();
72 | std::vector attributes;
73 | attributes.reserve(8);
74 | SplitString(attr, ',', attributes);
75 |
76 | if (attributes.size() >= 8) {
77 | time_t time = static_cast(std::stod(attributes[0]) * 1000);
78 | DanmakuType type = static_cast(std::stoi(attributes[1]));
79 | int textSize = static_cast(std::stof(attributes[2]));
80 | int textColor = std::stoi(attributes[3]) | 0xFF000000;
81 | time_t timestamp = std::stoull(attributes[4]);
82 | int danmakuId = std::stoi(attributes[7]);
83 | std::wstring comment = UTF8ToWideString(node->value());
84 |
85 | DanmakuRef danmaku = DanmakuFactory::CreateDanmaku(type, time, comment, textSize, textColor, timestamp, danmakuId);
86 | if (danmaku != nullptr) {
87 | mDanmakus->push_back(danmaku);
88 | }
89 | }
90 | }
91 | return true;
92 | }
93 |
94 | std::unique_ptr> BilibiliParser::GetDanmakus() {
95 | return std::move(mDanmakus);
96 | }
97 |
98 | }
--------------------------------------------------------------------------------
/src/BilibiliParser.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_BILIBILI_PARSER_HPP
2 | #define _WTF_BILIBILI_PARSER_HPP
3 |
4 | #include "IParser.hpp"
5 |
6 | namespace WTFDanmaku {
7 |
8 | class BilibiliParser : public IParser {
9 | public:
10 | static inline ParserRef Create() {
11 | return std::make_shared();
12 | }
13 | public:
14 | explicit BilibiliParser();
15 | virtual ~BilibiliParser() = default;
16 | virtual bool ParseStringSource(const char* str) override;
17 | virtual bool ParseFileSource(const char* filePath) override;
18 | virtual bool ParseFileSource(const wchar_t* filePath) override;
19 | virtual std::unique_ptr> GetDanmakus() override;
20 | private:
21 | bool ParseXml(const char* data, bool inplace = false);
22 | private:
23 | std::unique_ptr> mDanmakus;
24 | };
25 |
26 | }
27 |
28 | #endif // _WTF_BILIBILI_PARSER_HPP
--------------------------------------------------------------------------------
/src/BottomDanmaku.cpp:
--------------------------------------------------------------------------------
1 | #include "Displayer.hpp"
2 | #include "BottomDanmaku.hpp"
3 | #include "DanmakusRetainer.hpp"
4 |
5 | namespace WTFDanmaku {
6 |
7 | BottomDanmaku::~BottomDanmaku() {
8 |
9 | }
10 |
11 | DanmakuType BottomDanmaku::GetType() {
12 | return kBottom;
13 | }
14 |
15 | class BottomDanmaku::BottomRetainer : public IDanmakusRetainer {
16 | public:
17 | virtual ~BottomRetainer() override = default;
18 |
19 | virtual void Add(DanmakuRef danmaku, Displayer* displayer, DanmakuConfig* config, time_t currentMillis) override {
20 | if (nullptr == mDanmakus) {
21 | mDanmakus = std::make_unique();
22 | }
23 |
24 | RemoveTimeoutDanmakus(currentMillis);
25 |
26 | if (!danmaku->IsAlive(currentMillis)) {
27 | return;
28 | }
29 |
30 | float screenBottom = static_cast(displayer->GetHeight() - 1);
31 | float bottom = screenBottom;
32 |
33 | for (auto iter = mDanmakus->begin(); iter != mDanmakus->end(); ++iter) {
34 | DanmakuRef item = iter->second;
35 | Rect itemRect = item->GetRect();
36 |
37 | if (item.Get() == danmaku.Get()) {
38 | return;
39 | }
40 |
41 | if (itemRect.bottom < bottom) {
42 | if (danmaku->GetHeight() <= bottom - itemRect.bottom) {
43 | break;
44 | }
45 | }
46 |
47 | bottom = itemRect.top - 1.0f;
48 | if (bottom - danmaku->GetHeight() < 0.0f) {
49 | bottom = screenBottom;
50 | break;
51 | }
52 | }
53 | float top = bottom - danmaku->GetHeight();
54 | danmaku->Layout(displayer, config, 0.0f, top);
55 |
56 | int bottomInt = static_cast(bottom);
57 | auto iter = mDanmakus->find(bottomInt);
58 | if (iter != mDanmakus->end()) {
59 | iter->second = danmaku;
60 | } else {
61 | mDanmakus->insert(std::make_pair(bottomInt, danmaku));
62 | }
63 |
64 | }
65 |
66 | void RemoveTimeoutDanmakus(time_t time) {
67 | auto iter = mDanmakus->begin();
68 | while (iter != mDanmakus->end()) {
69 | if (iter->second->IsAlive(time) == false) {
70 | iter = mDanmakus->erase(iter);
71 | } else {
72 | ++iter;
73 | }
74 | }
75 | }
76 |
77 | virtual void Clear() override {
78 | mDanmakus->clear();
79 | }
80 |
81 | virtual void Release() override {
82 | mDanmakus.reset();
83 | }
84 | private:
85 | unique_ptr mDanmakus;
86 | };
87 |
88 | std::unique_ptr BottomDanmaku::CreateRetainer() {
89 | return std::unique_ptr(new BottomRetainer);
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/src/BottomDanmaku.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_BOTTOM_DANMAKU_HPP
2 | #define _WTF_BOTTOM_DANMAKU_HPP
3 |
4 | #include "TopDanmaku.hpp"
5 |
6 | namespace WTFDanmaku {
7 |
8 | class BottomDanmaku : public TopDanmaku {
9 | public:
10 | static inline DanmakuRef Create() {
11 | return xl::RefPtr(new BottomDanmaku);
12 | }
13 | static std::unique_ptr CreateRetainer();
14 | public:
15 | explicit BottomDanmaku() = default;
16 | virtual ~BottomDanmaku() override;
17 | virtual DanmakuType GetType() override;
18 | private:
19 | class BottomRetainer;
20 | };
21 |
22 | }
23 |
24 |
25 | #endif // _WTF_BOTTOM_DANMAKU_HPP
--------------------------------------------------------------------------------
/src/Controller.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "Displayer.hpp"
3 | #include "DanmakusManager.hpp"
4 | #include "WinmmTimer.hpp"
5 | #include "PerformanceTimer.hpp"
6 | #include "Controller.hpp"
7 |
8 | namespace WTFDanmaku {
9 |
10 | Controller::Controller() {
11 |
12 | }
13 |
14 | Controller::~Controller() {
15 | Stop();
16 | Terminate();
17 | }
18 |
19 | int Controller::Initialize(void* hwnd, uint32_t initialWidth, uint32_t initialHeight) {
20 | if (hwnd == NULL && (initialWidth == 0 || initialHeight == 0))
21 | return -1;
22 |
23 | mHwnd = hwnd;
24 | #ifdef _WTF_BUILD_UWP
25 | mTimer = PerformanceTimer::Create();
26 | #else
27 | mTimer = WinmmTimer::Create();
28 | #endif
29 | mManager = std::make_unique();
30 | mManager->SetTimer(mTimer);
31 |
32 | mDisplayer = std::make_unique();
33 | mDisplayer->SetTarget(mHwnd, initialWidth, initialHeight);
34 |
35 | bool succeed = mDisplayer->SetupBackend();
36 | if (!succeed) {
37 | mHasBackend = false;
38 | return -1;
39 | }
40 | mHasBackend = true;
41 | return 0;
42 | }
43 |
44 | void Controller::Terminate() {
45 | if (mHasBackend) {
46 | mDisplayer->TeardownBackend();
47 | mHasBackend = false;
48 | }
49 | }
50 |
51 | int Controller::QuerySwapChain(const void* pGuid, void** ppObject) {
52 | if (mDisplayer == nullptr)
53 | return -1;
54 |
55 | return mDisplayer->QuerySwapChain(pGuid, ppObject);
56 | }
57 |
58 | bool Controller::HasCommands() {
59 | std::lock_guard locker(mCommandQueueMutex);
60 | bool result = !mCommandQueue.empty();
61 | return result;
62 | }
63 |
64 | void Controller::PushCommand(const Command& cmd) {
65 | std::lock_guard locker(mCommandQueueMutex);
66 | mCommandQueue.push(cmd);
67 | }
68 |
69 | Controller::Command Controller::PopCommand() {
70 | std::lock_guard locker(mCommandQueueMutex);
71 | Command cmd = mCommandQueue.front();
72 | mCommandQueue.pop();
73 | return cmd;
74 | }
75 |
76 | DanmakusManager* Controller::GetManager() {
77 | return mManager.get();
78 | }
79 |
80 | bool Controller::IsRunning() {
81 | return mStatus == State::kRunning;
82 | }
83 |
84 | Controller::State Controller::GetState() {
85 | return mStatus;
86 | }
87 |
88 | void Controller::Start() {
89 | if (mStatus == State::kRunning) {
90 | // ignore
91 | } else if (mStatus == State::kPaused) {
92 | Resume();
93 | } else {
94 | if (mWorker.joinable()) {
95 | mWorker.detach();
96 | }
97 | mWorker = std::thread(&Controller::Working, this);
98 | }
99 | }
100 |
101 | void Controller::Pause() {
102 | if (mStatus == State::kRunning) {
103 | PushCommand(Cmd::kPause);
104 | }
105 | }
106 |
107 | void Controller::Resume() {
108 | if (mStatus == State::kPaused) {
109 | std::unique_lock locker(mConditionMutex);
110 | mStatus = State::kRunning;
111 | PushCommand(Cmd::kResume);
112 | mCondition.notify_all();
113 | }
114 | }
115 |
116 | void Controller::Stop() {
117 | if (mStatus == State::kRunning || mStatus == State::kPaused) {
118 | if (mStatus == State::kPaused) {
119 | Resume();
120 | }
121 |
122 | PushCommand(Cmd::kStop);
123 | if (mWorker.joinable()) {
124 | mWorker.join();
125 | }
126 | }
127 | }
128 |
129 | void Controller::SeekTo(time_t milliseconds) {
130 | if (mStatus == State::kRunning || mStatus == State::kPaused) {
131 | Command cmd(Cmd::kSeek);
132 | cmd.arg1 = *reinterpret_cast(&milliseconds);
133 | cmd.arg2 = *(reinterpret_cast(&milliseconds) + 1);
134 | PushCommand(cmd);
135 | }
136 | }
137 |
138 | void Controller::Resize(uint32_t width, uint32_t height) {
139 | if (mStatus == State::kRunning || mStatus == State::kPaused) {
140 | Command cmd(Cmd::kResize);
141 | cmd.arg1 = width;
142 | cmd.arg2 = height;
143 | PushCommand(cmd);
144 | }
145 | }
146 |
147 | void Controller::SetDpi(uint32_t dpiX, uint32_t dpiY) {
148 | if (mStatus == State::kRunning || mStatus == State::kPaused) {
149 | Command cmd(Cmd::kSetDpi);
150 | cmd.arg1 = dpiX;
151 | cmd.arg2 = dpiY;
152 | PushCommand(cmd);
153 | } else {
154 | mDisplayer->SetDpi(dpiX, dpiY);
155 | }
156 | }
157 |
158 | void Controller::ReLayout() {
159 | if (mStatus == State::kRunning || mStatus == State::kPaused) {
160 | PushCommand(Cmd::kReLayout);
161 | }
162 | }
163 |
164 | time_t Controller::GetCurrentPosition() {
165 | return mTimer->GetMilliseconds();
166 | }
167 |
168 | void Controller::HandleCommand() {
169 | if (!HasCommands())
170 | return;
171 |
172 | while (HasCommands()) {
173 | Command cmd = PopCommand();
174 |
175 | switch (cmd.what) {
176 | case Cmd::kResume:
177 | mTimer->Resume();
178 | mStatus = State::kRunning;
179 | break;
180 | case Cmd::kPause:
181 | if (mStatus == State::kRunning) {
182 | mTimer->Pause();
183 | std::unique_lock locker(mConditionMutex);
184 | mStatus = State::kPaused;
185 | while (mStatus == State::kPaused) {
186 | mCondition.wait(locker);
187 | }
188 | }
189 | break;
190 | case Cmd::kSeek:
191 | if (mStatus == State::kRunning) {
192 | time_t timepoint = 0;
193 | *reinterpret_cast(&timepoint) = cmd.arg1;
194 | *(reinterpret_cast(&timepoint) + 1) = cmd.arg2;
195 | mManager->SeekTo(timepoint);
196 | }
197 | break;
198 | case Cmd::kResize:
199 | mDisplayer->Resize(cmd.arg1, cmd.arg2);
200 | mManager->GetConfig()->MeasureFlag++;
201 | break;
202 | case Cmd::kReLayout:
203 | mManager->ReLayout();
204 | break;
205 | case Cmd::kSetDpi: {
206 | float nowDpiX = mDisplayer->GetDpiX();
207 | float nowDpiY = mDisplayer->GetDpiY();
208 | if (cmd.arg1 != static_cast(nowDpiX) || cmd.arg2 != static_cast(nowDpiY)) {
209 | mDisplayer->SetDpi(cmd.arg1, cmd.arg2);
210 | mManager->GetConfig()->MeasureFlag++;
211 | mManager->GetConfig()->BitmapValidFlag++;
212 | mManager->ReLayout();
213 | }
214 | }
215 | break;
216 | case Cmd::kStop:
217 | mStatus = State::kStopped;
218 | break;
219 | }
220 | }
221 | }
222 |
223 | void Controller::Working() {
224 | if (!mHasBackend) {
225 | #ifdef _WTF_BUILD_UWP
226 | #ifndef NDEBUG // Debug
227 | assert(false && "No backend for rendering, please Initialize first!");
228 | #else // Release
229 | OutputDebugStringW(L"No backend for rendering, please Initialize first!");
230 | throw 0;
231 | #endif
232 | #else
233 | DebugBreak();
234 | #endif
235 | }
236 |
237 | mStatus = State::kRunning;
238 | mTimer->Start();
239 |
240 | RenderingStatistics statistics;
241 |
242 | while (mStatus == State::kRunning || mStatus == State::kPaused) {
243 | HandleCommand();
244 | if (mStatus == State::kStopped) {
245 | break;
246 | }
247 |
248 | statistics = mManager->DrawDanmakus(mDisplayer.get());
249 | if (FAILED(statistics.lastHr)) {
250 | std::wstring message(L"Received HRESULT Error from DrawDanmakus, hr = ");
251 | message.append(std::to_wstring(statistics.lastHr));
252 | message.append(L"\n");
253 | OutputDebugStringW(message.c_str());
254 | }
255 | }
256 |
257 | mTimer->Stop();
258 | mManager->ReleaseActiveResources();
259 | }
260 |
261 | }
--------------------------------------------------------------------------------
/src/Controller.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_CONTROLLER_HPP
2 | #define _WTF_CONTROLLER_HPP
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "BaseDanmaku.hpp"
11 | #include "Win32Mutex.hpp"
12 | #include "Noncopyable.hpp"
13 | #include "ITimer.hpp"
14 |
15 | namespace WTFDanmaku {
16 |
17 | class Displayer;
18 | class DanmakusManager;
19 |
20 | class Controller : public Noncopyable {
21 | public:
22 | enum class State : int {
23 | kIdle = 0,
24 | kRunning = 1,
25 | kPaused = 2,
26 | kStopped = 3
27 | };
28 | private:
29 | enum class Cmd : int {
30 | kNull = 0,
31 | kBase = 0x12450,
32 | kStart = kBase + 1,
33 | kPause = kBase + 2,
34 | kResume = kBase + 3,
35 | kSeek = kBase + 4,
36 | kStop = kBase + 5,
37 | kResize = kBase + 6,
38 | kReLayout = kBase + 7,
39 | kSetDpi = kBase + 8
40 | };
41 |
42 | struct Command {
43 | public:
44 | Cmd what = Cmd::kNull;
45 | int arg1 = 0;
46 | int arg2 = 0;
47 | Command() = default;
48 | Command(Cmd _what) : what(_what) {}
49 | };
50 | public:
51 | explicit Controller();
52 | ~Controller();
53 | int Initialize(void* hwnd, uint32_t initialWidth = 0, uint32_t initialHeight = 0);
54 | void Terminate();
55 | int QuerySwapChain(const void* pGuid, void** ppObject);
56 | DanmakusManager* GetManager();
57 | void Start();
58 | void Pause();
59 | void Resume();
60 | void Stop();
61 | void SeekTo(time_t milliseconds);
62 | void Resize(uint32_t width, uint32_t height);
63 | void SetDpi(uint32_t dpiX, uint32_t dpiY);
64 | void ReLayout();
65 | time_t GetCurrentPosition();
66 | bool IsRunning();
67 | State GetState();
68 | private:
69 | void Working();
70 | bool HasCommands();
71 | void PushCommand(const Command& cmd);
72 | Command PopCommand();
73 | void HandleCommand();
74 | private:
75 | State mStatus = State::kIdle;
76 | std::thread mWorker;
77 | std::mutex mConditionMutex;
78 | std::condition_variable mCondition;
79 | void* mHwnd = nullptr;
80 | bool mHasBackend = false;
81 | TimerRef mTimer;
82 | Win32Mutex mCommandQueueMutex;
83 | std::queue mCommandQueue;
84 | std::unique_ptr mDisplayer;
85 | std::unique_ptr mManager;
86 | };
87 |
88 | }
89 |
90 | #endif // _WTF_CONTROLLER_HPP
--------------------------------------------------------------------------------
/src/DanmakuConfig.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_DANMAKU_CONFIG_HPP
2 | #define _WTF_DANMAKU_CONFIG_HPP
3 |
4 | #include
5 | #include
6 |
7 | namespace WTFDanmaku {
8 |
9 | enum DanmakuStyle : int {
10 | kOutline = 1,
11 | kProjection = 2
12 | };
13 |
14 | struct DanmakuConfig {
15 | bool R2LVisible = true;
16 | bool TopVisible = true;
17 | bool BottomVisible = true;
18 |
19 | int DanmakuDuration = 3800;
20 |
21 | int LogicalScreenWidth = 539;
22 | int LogicalScreenHeight = 385;
23 |
24 | int MeasureFlag = 0;
25 | int LayoutFlag = 0;
26 | int BitmapValidFlag = 0;
27 |
28 | float FontScaleFactor = 1.0f;
29 | float CompositionOpacity = 1.0f;
30 |
31 | DanmakuStyle DanmakuStyle = kOutline;
32 |
33 | std::wstring FontName = L"SimHei";
34 | DWRITE_FONT_WEIGHT FontWeight = DWRITE_FONT_WEIGHT_BOLD;
35 | DWRITE_FONT_STYLE FontStyle = DWRITE_FONT_STYLE_NORMAL;
36 | DWRITE_FONT_STRETCH FontStretch = DWRITE_FONT_STRETCH_NORMAL;
37 | };
38 |
39 | }
40 |
41 | #endif // _WTF_DANMAKU_CONFIG_HPP
--------------------------------------------------------------------------------
/src/DanmakuFactory.cpp:
--------------------------------------------------------------------------------
1 | #include "DanmakuFactory.hpp"
2 | #include "WinmmTimer.hpp"
3 | #include "PerformanceTimer.hpp"
4 | #include "R2LDanmaku.hpp"
5 | #include "TopDanmaku.hpp"
6 | #include "BottomDanmaku.hpp"
7 | #include "StringUtils.hpp"
8 |
9 | namespace WTFDanmaku {
10 |
11 | DanmakuRef DanmakuFactory::CreateDanmaku(DanmakuType type, time_t time, std::wstring& comment, int fontSize, int fontColor, time_t timestamp, int danmakuId) {
12 | DanmakuRef danmaku = nullptr;
13 |
14 | switch (type) {
15 | case kScrolling:
16 | danmaku = R2LDanmaku::Create();
17 | break;
18 | case kTop:
19 | danmaku = TopDanmaku::Create();
20 | break;
21 | case kBottom:
22 | danmaku = BottomDanmaku::Create();
23 | break;
24 | case kNull:
25 | default:
26 | return nullptr;
27 | }
28 |
29 | if (timestamp == 0) {
30 | #ifdef _WTF_BUILD_UWP
31 | timestamp = PerformanceTimer::GetGlobalCurrent();
32 | #else
33 | timestamp = WinmmTimer::GetGlobalCurrent();
34 | #endif
35 | }
36 |
37 | danmaku->mStartTime = time;
38 | danmaku->mTimestamp = timestamp;
39 | danmaku->mDanmakuId = danmakuId;
40 | danmaku->mComment = comment;
41 | ReplaceStringInplace(danmaku->mComment, L"/n", L"\r\n");
42 | danmaku->mTextSize = static_cast(fontSize);
43 | danmaku->mTextColor = fontColor | 0xFF000000;
44 | danmaku->mTextShadowColor = (danmaku->mTextColor <= 0xFF000000) ? 0xFFFFFFFF : 0xFF000000;
45 |
46 | return danmaku;
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/src/DanmakuFactory.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_DANMAKU_FACTORY_HPP
2 | #define _WTF_DANMAKU_FACTORY_HPP
3 |
4 | #include
5 | #include
6 | #include
7 | #include "Noncopyable.hpp"
8 | #include "BaseDanmaku.hpp"
9 |
10 | using std::shared_ptr;
11 |
12 | namespace WTFDanmaku {
13 |
14 | class DanmakuFactory : public Noncopyable {
15 | public:
16 | static DanmakuRef CreateDanmaku(DanmakuType type, time_t time, std::wstring& comment, int fontSize, int fontColor, time_t timestamp = 0, int danmakuId = 0);
17 | };
18 |
19 | }
20 |
21 | #endif // _WTF_DANMAKU_FACTORY_HPP
--------------------------------------------------------------------------------
/src/DanmakusManager.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "Displayer.hpp"
3 | #include "DanmakusRetainer.hpp"
4 | #include "DanmakusManager.hpp"
5 | #include "Renderable.hpp"
6 |
7 | namespace WTFDanmaku {
8 |
9 | bool DanmakusManager::TimeComparator::operator() (const DanmakuRef& a, const DanmakuRef& b) {
10 | int64_t diff = 0;
11 |
12 | diff = a->GetStartTime() - b->GetStartTime();
13 | if (diff < 0)
14 | return true;
15 | else if (diff > 0)
16 | return false;
17 |
18 | diff = a->GetSendTimestamp() - b->GetSendTimestamp();
19 | if (diff < 0)
20 | return true;
21 | else if (diff > 0)
22 | return false;
23 |
24 | diff = a->GetDanmakuId() - b->GetDanmakuId();
25 | if (diff < 0)
26 | return true;
27 | else if (diff > 0)
28 | return false;
29 |
30 | return true;
31 | }
32 |
33 | DanmakusManager::DanmakusManager() {
34 | mNextFetchIter = mAllDanmakus.begin();
35 | mNextPrebuildIter = mAllDanmakus.begin();
36 | mPrebuildBitmapValidFlag = mConfig.BitmapValidFlag;
37 | }
38 |
39 | DanmakusManager::~DanmakusManager() {
40 | ReleaseActiveResources();
41 | mRetainer.Release();
42 | mActiveDanmakus.clear();
43 | mAllDanmakus.clear();
44 | }
45 |
46 | void DanmakusManager::SetDanmakuList(unique_ptr> danmakuArray) {
47 | std::lock_guard locker(mAllDanmakusMutex);
48 | if (!mAllDanmakus.empty()) {
49 | mAllDanmakus.clear();
50 | }
51 | for (auto iter = danmakuArray->begin(); iter != danmakuArray->end(); ++iter) {
52 | mAllDanmakus.insert(*iter);
53 | }
54 | mNextFetchIter = mAllDanmakus.begin();
55 | mNextPrebuildIter = mAllDanmakus.begin();
56 | }
57 |
58 | void DanmakusManager::SetTimer(TimerRef timer) {
59 | mTimer = timer;
60 | }
61 |
62 | void DanmakusManager::SeekTo(time_t timepoint) {
63 | std::lock_guard locker(mActiveDanmakusMutex);
64 |
65 | time_t current = mTimer->GetMilliseconds();
66 | int64_t diff = timepoint - current;
67 |
68 | if (diff != 0) {
69 | mTimer->AddOffset(diff);
70 | if (diff < 0) { // seek back, reset cached iterator
71 | mActiveDanmakus.clear();
72 | mNextFetchIter = mAllDanmakus.begin();
73 | mNextPrebuildIter = mAllDanmakus.begin();
74 | mForceFetch = true;
75 | }
76 | }
77 | }
78 |
79 | void DanmakusManager::AddDanmaku(DanmakuRef danmaku) {
80 | std::lock_guard locker(mAllDanmakusMutex);
81 | mAllDanmakus.insert(danmaku);
82 | }
83 |
84 | void DanmakusManager::AddLiveDanmaku(DanmakuRef danmaku) {
85 | std::lock_guard locker(mActiveDanmakusMutex);
86 | if (danmaku->GetStartTime() == 0) {
87 | danmaku->SetStartTime(mTimer->GetMilliseconds() + 50);
88 | }
89 | mActiveDanmakus.insert(danmaku);
90 | }
91 |
92 | void DanmakusManager::FetchNewDanmakus(Displayer* displayer) {
93 | std::lock_guard locker1(mAllDanmakusMutex);
94 | std::lock_guard locker2(mActiveDanmakusMutex);
95 |
96 | time_t current = mTimer->GetMilliseconds();
97 |
98 | for (auto iter = mNextFetchIter; iter != mAllDanmakus.end(); /* ignore */) {
99 | if ((*iter)->GetStartTime() < current) {
100 | if (!(*iter)->HasMeasured(&mConfig)) {
101 | (*iter)->Measure(displayer, &mConfig);
102 | }
103 | if ((*iter)->IsAlive(current)) {
104 | mActiveDanmakus.insert(*iter);
105 | }
106 | } else {
107 | mNextFetchIter = iter;
108 | break;
109 | }
110 |
111 | if (++iter == mAllDanmakus.end()) {
112 | mNextFetchIter = mAllDanmakus.end();
113 | break;
114 | }
115 | }
116 |
117 | mLastFetchTime = current;
118 | }
119 |
120 | void DanmakusManager::RemoveTimeoutDanmakus() {
121 | std::lock_guard locker(mActiveDanmakusMutex);
122 |
123 | time_t current = mTimer->GetMilliseconds();
124 |
125 | for (auto iter = mActiveDanmakus.begin(); iter != mActiveDanmakus.end(); /* ignore */) {
126 | if ((*iter)->GetStartTime() < current && !(*iter)->IsAlive(current)) {
127 | (*iter)->SetSkipped(false);
128 | (*iter)->ReleaseResources();
129 | iter = mActiveDanmakus.erase(iter);
130 | } else {
131 | ++iter;
132 | }
133 | }
134 | }
135 |
136 | void DanmakusManager::ReleaseActiveResources() {
137 | std::lock_guard locker(mActiveDanmakusMutex);
138 |
139 | mRetainer.Clear();
140 |
141 | for (auto iter = mActiveDanmakus.begin(); iter != mActiveDanmakus.end(); /* ignore*/) {
142 | (*iter)->ReleaseResources();
143 | iter = mActiveDanmakus.erase(iter);
144 | }
145 | }
146 |
147 | void DanmakusManager::ReLayout() {
148 | std::lock_guard locker(mActiveDanmakusMutex);
149 |
150 | mConfig.LayoutFlag++;
151 | mRetainer.Clear();
152 | }
153 |
154 | void DanmakusManager::PrebuildRenderableTask(Displayer* displayer, time_t thisFrameTime, time_t remainTime) {
155 | if (mAllDanmakus.empty() || mNextPrebuildIter == mAllDanmakus.end()) {
156 | return;
157 | }
158 |
159 | if (mPrebuildBitmapValidFlag != mConfig.BitmapValidFlag) {
160 | mNextPrebuildIter = mAllDanmakus.begin();
161 | mInPrebuildProgress = true;
162 | mPrebuildBitmapValidFlag = mConfig.BitmapValidFlag;
163 | }
164 |
165 | int64_t timepoint = thisFrameTime % 10000; // clamp time to [0ms, 9999ms], that is 0s ~ 10s
166 | time_t frameTimeBase = thisFrameTime - timepoint;
167 | if (mInPrebuildProgress == false) {
168 | if ((thisFrameTime >= 0 && thisFrameTime < 2000) || (timepoint >= 7000 && timepoint < 9000)) {
169 | mInPrebuildProgress = true;
170 | } else {
171 | return;
172 | }
173 | }
174 |
175 | std::lock_guard locker(mAllDanmakusMutex);
176 |
177 | const int kCurrentSection = 0;
178 | const int kNextSection = 1;
179 | int section = 0;
180 |
181 | if (timepoint < 7000) { // Task: Build cache for current time section
182 | section = kCurrentSection;
183 | time_t itemStartTime = (*mNextPrebuildIter)->GetStartTime();
184 | if (itemStartTime >= frameTimeBase + 10000) { // Is it in next section?
185 | mInPrebuildProgress = false; // Current task has been completed. Just go back.
186 | return;
187 | }
188 | } else if (timepoint >= 7000 && timepoint < 9999) { // Task: Build cache for next 10-seconds time section
189 | section = kNextSection;
190 | time_t itemStartTime = (*mNextPrebuildIter)->GetStartTime();
191 | if (itemStartTime >= frameTimeBase + 10000 + 10000) {
192 | mInPrebuildProgress = false;
193 | return;
194 | }
195 | }
196 |
197 | time_t beginTime = mTimer->GetMilliseconds();
198 |
199 | for (auto iter = mNextPrebuildIter; iter != mAllDanmakus.end(); /* ignore */) {
200 | time_t itemStartTime = (*iter)->GetStartTime();
201 |
202 | if (itemStartTime >= thisFrameTime) {
203 | if (section == kCurrentSection) {
204 | if (itemStartTime >= frameTimeBase + 10000) {
205 | mNextPrebuildIter = iter;
206 | mInPrebuildProgress = false;
207 | break;
208 | }
209 | } else if (section == kNextSection) {
210 | if (itemStartTime >= frameTimeBase + 10000 + 10000) {
211 | mNextPrebuildIter = iter;
212 | mInPrebuildProgress = false;
213 | break;
214 | }
215 | }
216 |
217 | if (!(*iter)->HasMeasured(&mConfig))
218 | (*iter)->Measure(displayer, &mConfig);
219 | auto renderable = (*iter)->GetRenderable().lock();
220 | if (!renderable->HasBitmap(&mConfig)) {
221 | renderable->BuildBitmap(displayer, &mConfig);
222 | } else {
223 | ++iter; continue;
224 | }
225 | } else if (itemStartTime < thisFrameTime) { // seeked iterator?
226 | if (!(*iter)->HasMeasured(&mConfig)) {
227 | (*iter)->Measure(displayer, &mConfig);
228 | }
229 | if ((*iter)->IsAlive(thisFrameTime)) {
230 | auto renderable = (*iter)->GetRenderable().lock();
231 | if (!renderable->HasBitmap(&mConfig)) {
232 | renderable->BuildBitmap(displayer, &mConfig);
233 | } else {
234 | ++iter; continue;
235 | }
236 | } else {
237 | ++iter; continue; // fast-forward to thisFrameTime
238 | }
239 | }
240 |
241 | time_t now = mTimer->Update()->GetMilliseconds();
242 | if (now - beginTime >= remainTime - 1) {
243 | mNextPrebuildIter = ++iter; // remain time excceed, save iterator and exit.
244 | break;
245 | }
246 |
247 | if (++iter == mAllDanmakus.end()) {
248 | mNextPrebuildIter = mAllDanmakus.end();
249 | break;
250 | }
251 | }
252 | }
253 |
254 | bool DanmakusManager::IsVisibleDanmakuType(DanmakuRef danmaku, DanmakuConfig* config) {
255 | if (danmaku->IsSkipped()) {
256 | return false;
257 | }
258 |
259 | DanmakuType type = danmaku->GetType();
260 |
261 | if (type == DanmakuType::kScrolling) {
262 | return config->R2LVisible;
263 | } else if (type == DanmakuType::kTop) {
264 | return config->TopVisible;
265 | } else if (type == DanmakuType::kBottom) {
266 | return config->BottomVisible;
267 | }
268 |
269 | return true;
270 | }
271 |
272 | RenderingStatistics DanmakusManager::DrawDanmakus(Displayer* displayer) {
273 | mTimer->Update();
274 | time_t current = mTimer->GetMilliseconds();
275 |
276 | if (mForceFetch || current - mLastFetchTime >= 100) {
277 | RemoveTimeoutDanmakus();
278 | FetchNewDanmakus(displayer);
279 | mForceFetch = false;
280 | }
281 |
282 | int count = 0;
283 | HRESULT hr = S_OK;
284 |
285 | /* synchronized */
286 | {
287 | std::lock_guard locker(mActiveDanmakusMutex);
288 |
289 | displayer->BeginDraw();
290 |
291 | for (auto iter = mActiveDanmakus.begin(); iter != mActiveDanmakus.end(); ++iter, ++count) {
292 | if (!(*iter)->HasMeasured(&mConfig)) {
293 | (*iter)->Measure(displayer, &mConfig);
294 | }
295 | if (!(*iter)->HasLayout(&mConfig)) {
296 | mRetainer.Add(*iter, displayer, &mConfig, current);
297 | }
298 | if (IsVisibleDanmakuType(*iter, &mConfig)) {
299 | displayer->DrawDanmakuItem(*iter, current, &mConfig);
300 | }
301 | }
302 |
303 | hr = displayer->EndDraw();
304 |
305 | time_t now = mTimer->Update()->GetMilliseconds();
306 | int64_t elapsed = now - current;
307 | if (elapsed < 14) {
308 | time_t remain = 14 - elapsed;
309 | PrebuildRenderableTask(displayer, current, remain);
310 | }
311 | }
312 |
313 | hr = displayer->Present();
314 |
315 | mStatistics.lastHr = hr;
316 | mStatistics.lastFrameDanmakuCount = count;
317 | mStatistics.lastFrameTime = current;
318 |
319 | return mStatistics;
320 | }
321 |
322 | RenderingStatistics DanmakusManager::GetRenderingStatistics() {
323 | return mStatistics;
324 | }
325 |
326 | DanmakuConfig* DanmakusManager::GetConfig() {
327 | return &mConfig;
328 | }
329 |
330 | }
--------------------------------------------------------------------------------
/src/DanmakusManager.hpp:
--------------------------------------------------------------------------------
1 | #ifndef _WTF_DANMAKUS_MANAGER_HPP
2 | #define _WTF_DANMAKUS_MANAGER_HPP
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "BaseDanmaku.hpp"
9 | #include "Noncopyable.hpp"
10 | #include "DanmakusRetainer.hpp"
11 | #include "DanmakuConfig.hpp"
12 | #include "Win32Mutex.hpp"
13 | #include "ITimer.hpp"
14 |
15 | using std::unique_ptr;
16 |
17 | namespace WTFDanmaku {
18 |
19 | class Displayer;
20 | class DanmakusRetainer;
21 |
22 | struct RenderingStatistics {
23 | public:
24 | float fps = 0.0f;
25 | time_t lastFrameTime = 0;
26 | int lastFrameDanmakuCount = 0;
27 | HRESULT lastHr = NULL;
28 | };
29 |
30 | class DanmakusManager : public Noncopyable {
31 | public:
32 | explicit DanmakusManager();
33 | ~DanmakusManager();
34 | void SetDanmakuList(unique_ptr> danmakuArray);
35 | void SetTimer(TimerRef timer);
36 | void SeekTo(time_t timepoint);
37 | void AddDanmaku(DanmakuRef danmaku);
38 | void AddLiveDanmaku(DanmakuRef danmaku);
39 | void ReleaseActiveResources();
40 | void ReLayout();
41 | DanmakuConfig* GetConfig();
42 | RenderingStatistics DrawDanmakus(Displayer* displayer);
43 | RenderingStatistics GetRenderingStatistics();
44 | private:
45 | void FetchNewDanmakus(Displayer* displayer);
46 | void RemoveTimeoutDanmakus();
47 | void PrebuildRenderableTask(Displayer* displayer, time_t thisFrameTime, time_t remainTime);
48 | bool IsVisibleDanmakuType(DanmakuRef danmaku, DanmakuConfig* config);
49 | private:
50 | struct TimeComparator {
51 | bool operator() (const DanmakuRef& a, const DanmakuRef& b);
52 | };
53 | typedef std::set TimeSortedDanmakus;
54 | private:
55 | TimerRef mTimer;
56 | bool mForceFetch = false;
57 | bool mInPrebuildProgress = false;
58 | time_t mLastFetchTime = 0;
59 | int mPrebuildBitmapValidFlag = -1;
60 | TimeSortedDanmakus::iterator mNextFetchIter;
61 | TimeSortedDanmakus::iterator mNextPrebuildIter;
62 | Win32Mutex mAllDanmakusMutex;
63 | Win32Mutex mActiveDanmakusMutex;
64 | TimeSortedDanmakus mAllDanmakus;
65 | TimeSortedDanmakus mActiveDanmakus;
66 | DanmakusRetainer mRetainer;
67 | DanmakuConfig mConfig;
68 | RenderingStatistics mStatistics;
69 | };
70 |
71 | }
72 |
73 | #endif // _WTF_DANMAKUS_MANAGER_HPP
--------------------------------------------------------------------------------
/src/DanmakusRetainer.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include