├── .gitignore
├── C_Environment_Startup.lnk
├── LICENSE
├── MPlay3Data.lnk
├── README.md
├── build.bat
├── build
├── ImageToCArray_TD.exe
├── ImageToCArray_TD.sln
├── MPlay3.exe
├── MPlay3.sln
└── generated
│ ├── FontsForEachBlock.font
│ └── UnicodeGroupList.font
├── buildOptimized.bat
├── code
├── Allocator_TD.c
├── Allocator_TD.h
├── Definitions_TD.h
├── ErrorHandling_TD.c
├── ErrorHandling_TD.h
├── FileUtilities_TD.c
├── FileUtilities_TD.h
├── Font_TD.c
├── Font_TD.h
├── GL_TD.c
├── GL_TD.h
├── GameBasics_TD.c
├── GameBasics_TD.h
├── ImageToCArray_TD.cpp
├── Input_TD.c
├── Input_TD.h
├── Libraries
│ ├── MiniMP3.h
│ ├── MiniMp3_Ext.h
│ ├── STB_Image.h
│ ├── STB_Rect_Pack.h
│ └── STB_Truetype.h
├── Main.cpp
├── Math_TD.c
├── Math_TD.h
├── Renderer_TD.c
├── Renderer_TD.h
├── Sound_Backend_TD.c
├── Sound_Backend_TD.h
├── Sound_Dragging.c
├── Sound_Dragging.h
├── Sound_General_TD.c
├── Sound_General_TD.h
├── Sound_Icons.c
├── Sound_Jobs.c
├── Sound_Jobs.h
├── Sound_Serialization.c
├── Sound_Serialization.h
├── Sound_Settings.c
├── Sound_Thread_TD.c
├── Sound_Thread_TD.h
├── Sound_UI_TD.c
├── Sound_UI_TD.h
├── Sound_settings.h
├── StandardUtilities_TD.c
├── StandardUtilities_TD.h
├── String_TD.h
├── Threading_TD.c
├── Threading_TD.h
├── UI_TD.c
├── UI_TD.h
└── UnicodeGroups_TD.h
├── data
├── Buttons
│ ├── Add_Icon.png
│ ├── Cancel_Icon.png
│ ├── ColorPicker_Icon.png
│ ├── Confirm_Icon.png
│ ├── FastForward_Icon.png
│ ├── Help_Icon.png
│ ├── Help_Pressed_Icon.png
│ ├── Loop_Icon.png
│ ├── Loop_Pressed_Icon.png
│ ├── Minus_Icon.png
│ ├── MusicPath_Icon.png
│ ├── Next_Icon.png
│ ├── PaletteSwap_Icon.png
│ ├── PaletteSwap_Icon2.png
│ ├── Pause_Icon.png
│ ├── PlayPause.png
│ ├── PlayPauseDown.png
│ ├── PlayPauseHover.png
│ ├── PlayPause_Icon.png
│ ├── Play_Icon.png
│ ├── Previous_Icon.png
│ ├── Randomize_Icon.png
│ ├── Randomize_Pressed_Icon.png
│ ├── Rescan_Icon.png
│ ├── Save_Icon.png
│ ├── Search_Icon.png
│ ├── Shuffle_Icon.png
│ ├── Shuffle_Pressed_Icon.png
│ └── Stop_Icon.png
├── ButtonsExactSize
│ ├── Add_Large_Icon.png
│ ├── Add_Medium_Icon.png
│ ├── Add_Small_Icon.png
│ ├── Add_Tiny_Icon.png
│ ├── Background_Icon.png
│ ├── Cancel_Icon.png
│ ├── ColorPicker_Icon.png
│ ├── Confirm_Icon.png
│ ├── Help_Icon.png
│ ├── Help_Pressed_Icon.png
│ ├── Icons.svg
│ ├── Loop_Icon.png
│ ├── Loop_Pressed_Icon.png
│ ├── Minus_Icon.png
│ ├── MusicPath_Icon.png
│ ├── Next_Icon.png
│ ├── Old
│ │ ├── Minus_Icon_old.png
│ │ ├── Plus_Icon_old.png
│ │ └── Save_Icon_old.png
│ ├── PaletteSwap_Icon.png
│ ├── Pause_Icon.png
│ ├── PlayPause_Large_Icon.png
│ ├── PlayPause_Medium_Icon.png
│ ├── PlayPause_Small_Icon.png
│ ├── PlayPause_Tiny_Icon.png
│ ├── Play_Icon.png
│ ├── Playlist_AddSelection_Icon.png
│ ├── Playlist_Remove_Icon.png
│ ├── Playlist_Rename_Icon.png
│ ├── Plus_Icon.png
│ ├── Previous_Icon.png
│ ├── Randomize_Icon.png
│ ├── Randomize_Pressed_Icon.png
│ ├── Rescan_Icon.png
│ ├── Save_Icon.png
│ ├── Search_Icon.png
│ ├── Stop_Icon.png
│ └── Style_Settings_Icon.png
├── Fonts
│ ├── CarminaBoldBT.ttf
│ ├── CarminaBoldItalicBT.ttf
│ ├── CarminaMdBTBold.ttf
│ ├── CarminaMdBTBoldItalic.ttf
│ ├── CarminaMdBTMedium.ttf
│ ├── CarminaMdBTMediumItalic.ttf
│ ├── CarminaMediumBT.ttf
│ ├── CarminaMediumItalicBT.ttf
│ ├── carmini.ttf
│ └── sharefonts.net.txt
├── Logo.svg
├── Logo_V0.1.ico
├── Logo_V0.1.png
├── Logo_V0.1_Large.png
├── ProgressInfo.txt
├── Screenshots
│ ├── MPlay3_ColorPalette_AquaticBlue.png
│ ├── MPlay3_ColorPalette_Custom_Marshmallow.png
│ ├── MPlay3_ColorPalette_DeepNightGrey.png
│ ├── MPlay3_ColorPalette_LushGreen.png
│ ├── MPlay3_ColorPalette_MonochromeGrey.png
│ ├── MPlay3_ColorPalette_SmolderingRed.png
│ ├── MPlay3_ColorPalette_SummerSunrise.png
│ ├── MPlay3_GatherMetadataMusicPath.png
│ ├── MPlay3_Goodbye_Curtain.png
│ ├── MPlay3_MiniVersion.png
│ ├── Pre_01.6
│ │ ├── MPlay3_BluePalette.png
│ │ ├── MPlay3_ColorPicker.png
│ │ ├── MPlay3_CustomColorPalette_Pink.png
│ │ ├── MPlay3_GreenPalette.png
│ │ ├── MPlay3_GreyscaleInvertedPalette.png
│ │ ├── MPlay3_GreyscalePalette.png
│ │ ├── MPlay3_LargeFiles.png
│ │ ├── MPlay3_MiniVersion.png
│ │ ├── MPlay3_QuitAnimation.png
│ │ ├── MPlay3_RedPalette.png
│ │ ├── MPlay3_ScanMusicFolder.png
│ │ └── MPlay3_Searching.png
│ ├── Thumbnail.png
│ └── Thumbnail2.png
└── resources
│ ├── EmbeddedResourcesExactSize_huf.h
│ ├── EmbeddedResourcesExactSize_huf_old.h
│ ├── EmbeddedResourcesExactSize_png.h
│ ├── EmbeddedResourcesSTUB.h
│ ├── Resource.rc
│ ├── ResourceListing.txt
│ ├── ResourceListingExactSize.txt
│ ├── Resources.res
│ └── resource.h
├── editor.bat
├── project.4coder
├── search.bat
└── shell.bat
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
352 | # compilation profiling files
353 | *.etl
354 |
355 | *.mp3
--------------------------------------------------------------------------------
/C_Environment_Startup.lnk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/C_Environment_Startup.lnk
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 CaptainTimberTim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MPlay3Data.lnk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/MPlay3Data.lnk
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MPlay3
2 |
3 | MPlay3 is a music player that lists and plays all .mp3 files in a given folder (more info: https://handmade.network/p/mplay3/).
4 | It lists all Genres, Artists, Albums and Songs in four different columns. If one or multiple entries in a column are selected all subsequent columns will be adjusted to only display the entries corresponding to the selected ones.
5 | For example: if the genre _rock_ is selected, then only artists that are in the category _rock_ are shown in the artist column. Based on that, only albums created by the artists that are still visible are in the album column and only the songs on those albums are then shown in the song column.
6 | This enables you to very quickly assemble a list of songs. Additional features are basic stuff like music shuffle, looping, a search for each column and mulitple color-palettes.
7 |
8 |
9 | The base principle for this project is to do almost everything myself. The only libraries included are the stb_image.h and stb_truetype.h for image and font loading and MiniMp3.h for the .mp3 decoding part. Everything else is written by me. With the rare code snippets here and there taken from somewhere else. The end-goal of this project is to replace all external library code at some point.
10 | A small video of MPlay3 is on youtube: https://www.youtube.com/watch?v=pW9DGD-zUSw&ab_channel=TimDierks
11 |
12 |
13 | ### Only works on Windows!
14 |
15 |
16 | ## Building the repository
17 |
18 | To build this project, the only thing required is the Visual Studio compiler and maybe an editor.
19 | I have a "build.bat" in the code directory, which I use for building.
20 | In the "build" directory is a Visual Studio project file, which is only used for debugging.
21 |
22 | In the base folder is a C_Environment_Startup.lnk which starts a command prompt, Visual Studio (2019) and the editor 4Coder (http://4coder.net/) through *.bat files.
23 | If one or more of the paths to the other applications are different they can be changed in the corresponding *.bat files. You can find Visual Studio's vcvarsall.bat path in the shell.bat and the path to 4coder in the editor.bat.
24 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | IF NOT EXIST "build" mkdir "build"
4 | pushd "build"
5 |
6 | REM -showIncludes
7 | set flags= -nologo -GR- -EHa- -Z7 -FeMPlay3.exe -F4000000 -DUNICODE -DRESOURCE_FILE=2
8 | REM set optimizeFlags= -O2 -MT -Oi -DDEBUG_TD=1
9 | set debugFlags= -Od -MTd -FC -DDEBUG_TD=1
10 |
11 | set compilerWarnings= -WX -W4 -wd4201 -wd4100 -wd4189 -wd4456 -wd4505 -wd4005 -wd4239 -wd4706 -wd4127 -wd4390
12 |
13 | REM subsystem for x86 need 5.1 || 'console' for main(), 'windows' for WinMain
14 | set linkerFlags= /link -incremental:no -opt:ref
15 |
16 | REM -subsystem:windows,5.2
17 | set libIncludes= User32.lib Gdi32.lib winmm.lib Shell32.lib Ole32.lib
18 | REM opengl32.lib // Lives now in the GL_TD.h, a bit cleaner?
19 |
20 | set resources= "..\\data\\resources\\Resources.res"
21 | REM rc -x -nologo -fo %resources% "..\\data\\resources\\Resource.rc"
22 |
23 | cl %flags% %debugFlags% %compilerWarnings% "..\\code\\Main.cpp" %linkerFlags% %libIncludes% %resources%
24 | REM cl %flags% %optimizeFlags% %compilerWarnings% "..\\code\\Main.cpp" %linkerFlags% %libIncludes% %resources%
25 |
26 |
27 |
28 | REM cl -nologo -GR- -EHa- -Z7 %debugFlags% %compilerWarnings% "..\\code\\ImageToCArray_TD.cpp" %linkerFlags% %libIncludes%
29 |
30 | popd
--------------------------------------------------------------------------------
/build/ImageToCArray_TD.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/build/ImageToCArray_TD.exe
--------------------------------------------------------------------------------
/build/ImageToCArray_TD.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30128.74
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "ImageToCArray_TD", "ImageToCArray_TD.exe", "{233B4BD5-1712-4EDB-886F-6611CAE324E5}"
7 | ProjectSection(DebuggerProjectSystem) = preProject
8 | PortSupplier = 00000000-0000-0000-0000-000000000000
9 | Executable = C:\Workspace\Programming\CPP_Projects\MPlay3\build\ImageToCArray_TD.exe
10 | RemoteMachine = DESKTOP-PR7GBHP
11 | StartingDirectory = C:\Workspace\Programming\CPP_Projects\MPlay3\build
12 | Arguments = "../data/resources/ResourceListing2.txt" "Outfile.h" DoDecode
13 | Environment = Default
14 | LaunchingEngine = 00000000-0000-0000-0000-000000000000
15 | UseLegacyDebugEngines = No
16 | LaunchSQLEngine = No
17 | AttachLaunchAction = No
18 | EndProjectSection
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Release|x64 = Release|x64
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {233B4BD5-1712-4EDB-886F-6611CAE324E5}.Release|x64.ActiveCfg = Release|x64
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | GlobalSection(ExtensibilityGlobals) = postSolution
31 | SolutionGuid = {E0A2801C-8814-4548-A75A-EC91CBCCBB11}
32 | EndGlobalSection
33 | EndGlobal
34 |
--------------------------------------------------------------------------------
/build/MPlay3.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/build/MPlay3.exe
--------------------------------------------------------------------------------
/build/MPlay3.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30128.74
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "MPlay3", "MPlay3.exe", "{7CF5D527-0E7F-48FB-A9C6-65749AD8C887}"
7 | ProjectSection(DebuggerProjectSystem) = preProject
8 | PortSupplier = 00000000-0000-0000-0000-000000000000
9 | Executable = C:\Workspace\Programming\CPP_Projects\MPlay3\build\MPlay3.exe
10 | RemoteMachine = DESKTOP-PR7GBHP
11 | StartingDirectory = C:\Workspace\Programming\CPP_Projects\MPlay3\build
12 | Environment = Default
13 | LaunchingEngine = 00000000-0000-0000-0000-000000000000
14 | UseLegacyDebugEngines = No
15 | LaunchSQLEngine = No
16 | AttachLaunchAction = No
17 | EndProjectSection
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Release|x64 = Release|x64
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {7CF5D527-0E7F-48FB-A9C6-65749AD8C887}.Release|x64.ActiveCfg = Release|x64
25 | EndGlobalSection
26 | GlobalSection(SolutionProperties) = preSolution
27 | HideSolutionNode = FALSE
28 | EndGlobalSection
29 | GlobalSection(ExtensibilityGlobals) = postSolution
30 | SolutionGuid = {E77F24CA-01D9-4AC1-A7FF-3031E9EEB2E0}
31 | EndGlobalSection
32 | EndGlobal
33 |
--------------------------------------------------------------------------------
/buildOptimized.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | IF NOT EXIST "build" mkdir "build"
4 | pushd "build"
5 |
6 | REM -showIncludes
7 | set flags= -nologo -GR- -EHa- -Z7 -FeMPlay3.exe -F4000000 -DUNICODE -DRESOURCE_FILE=2
8 | set optimizeFlags= -O2 -MT -Oi -DDEBUG_TD=0
9 |
10 | set compilerWarnings= -WX -W4 -wd4201 -wd4100 -wd4189 -wd4456 -wd4505 -wd4005 -wd4239 -wd4706 -wd4127 -wd4390
11 |
12 | REM subsystem for x86 need 5.1 || 'console' for main(), 'windows' for WinMain
13 | set linkerFlags= /link -incremental:no -opt:ref
14 |
15 | REM -subsystem:windows,5.2
16 | set libIncludes= User32.lib Gdi32.lib winmm.lib Shell32.lib Ole32.lib
17 |
18 | set resources= "..\\data\\resources\\Resources.res"
19 | cl %flags% %optimizeFlags% %compilerWarnings% "..\\code\\Main.cpp" %linkerFlags% %libIncludes% %resources%
20 |
21 |
22 |
23 | popd
--------------------------------------------------------------------------------
/code/Allocator_TD.c:
--------------------------------------------------------------------------------
1 | #include "Allocator_TD.h"
2 |
3 | #include "Math_TD.h"
4 | #include "String_TD.h"
5 |
6 | inline arena *
7 | CreateNewArena(u64 Size)
8 | {
9 | u64 AdjustedSize = Size;
10 |
11 | AdjustedSize += sizeof(arena);
12 | u8 *Memory = (u8 *)VirtualAlloc(0, AdjustedSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
13 | Assert(Memory);
14 |
15 | arena *Arena = (arena *)Memory;
16 | Arena->Memory = Memory + sizeof(arena);
17 | Arena->Size = AdjustedSize - sizeof(arena);
18 |
19 | return Arena;
20 | }
21 |
22 | inline HANDLE
23 | NewMutex()
24 | {
25 | return CreateMutexEx(0, 0, 0, MUTEX_ALL_ACCESS);
26 | }
27 |
28 | inline void
29 | Lock(HANDLE Mutex)
30 | {
31 | WaitForSingleObjectEx(Mutex, INFINITE, false);
32 | }
33 |
34 | inline void
35 | Unlock(HANDLE Mutex)
36 | {
37 | ReleaseMutex(Mutex);
38 | }
39 |
40 | inline void
41 | FreeMemory(arena_allocator *Allocator, void *Memory)
42 | {
43 | if(!Memory) return;
44 | if(Allocator->Flags & arenaFlags_IsThreaded) Lock(Allocator->Mutex);
45 | arena *Arena = Allocator->Base;
46 |
47 | Assert(Allocator->ArenaCount != 0);
48 | For(Allocator->ArenaCount)
49 | {
50 | if(Memory >= Arena->Memory && Memory < (Arena->Memory+Arena->Size))
51 | {
52 | Arena->Count--;
53 | Assert(Arena->Count >= 0);
54 | if(Arena->Count == 0) // If we completely emptied the arena, we can reset it!
55 | {
56 | Arena->Position = 0;
57 | Assert(Allocator->EmptyArenaCount >= 0);
58 | // If we have more than the given limit or the arena size is small, delete it.
59 | if(Allocator->EmptyArenaCount == Allocator->MaxEmptyArenaCount || Arena->Size < ARENA_BASE_SIZE/2)
60 | {
61 | if(Arena->Prev && Arena->Next) // Arena is in the middle.
62 | {
63 | Arena->Prev->Next = Arena->Next;
64 | Arena->Next->Prev = Arena->Prev;
65 | }
66 | else if(Arena->Next) // Arena is the first one.
67 | {
68 | Arena->Next->Prev = 0;
69 | Allocator->Base = Arena->Next;
70 | }
71 | else if(Arena->Prev) Arena->Prev->Next = 0; // Arena is the last one.
72 |
73 | Allocator->ArenaCount--;
74 | Assert(Allocator->ArenaCount >= 0);
75 | if(Allocator->ArenaCount == 0) Allocator->Base = 0;
76 |
77 | VirtualFree(Arena->Memory, 0, MEM_RELEASE);
78 | Allocator->LastUsed = 0;
79 | #if DEBUG_TD
80 | Allocator->DebugData.ArenaFreeCount++;
81 | #endif
82 | }
83 | else Allocator->EmptyArenaCount++;
84 |
85 |
86 | #if DEBUG_TD
87 | Allocator->DebugData.FreeCount++;
88 | arena *DebugArena = Allocator->Base;
89 | Assert(Allocator->ArenaCount <= MAX_DEBUG_ARENA_COUNT);
90 | For(Allocator->ArenaCount)
91 | {
92 | r32 FillP = DebugArena->Position/(r32)DebugArena->Size;
93 | Allocator->DebugData.CurrentFillP[It] = FillP;
94 | DebugArena = DebugArena->Next;
95 | }
96 | #endif
97 |
98 | }
99 | break;
100 | }
101 | Arena = Arena->Next;
102 | }
103 | Assert(Allocator->ArenaCount == 0 || Arena); // Given memory was not created with given allocator!
104 | if(Allocator->Flags & arenaFlags_IsThreaded) Unlock(Allocator->Mutex);
105 | }
106 |
107 | inline void
108 | AppendArena(arena **AppendTo, arena *Arena)
109 | {
110 | arena *LastArena = *AppendTo;
111 | if(LastArena)
112 | {
113 | while(LastArena->Next) LastArena = LastArena->Next;
114 | LastArena->Next = Arena;
115 | Arena->Prev = LastArena;
116 | }
117 | else *AppendTo = Arena;
118 | }
119 |
120 | inline void *
121 | RetrieveMemoryFromArena(arena *Arena, u64 Size)
122 | {
123 | Assert(Arena);
124 | Assert(Arena->Memory != 0);
125 | Assert(Arena->Position+Size <= Arena->Size);
126 |
127 | void *Result = Arena->Memory+Arena->Position;
128 | Arena->Position += Size;
129 | Arena->Count++;
130 |
131 | return Result;
132 | }
133 |
134 | internal void *
135 | AllocateMemory_(arena_allocator *Allocator, u64 Size)
136 | {
137 | void *Result = 0;
138 |
139 | if(Allocator->Flags & arenaFlags_IsThreaded)
140 | {
141 | if(!Allocator->Mutex) Allocator->Mutex = NewMutex();
142 | Lock(Allocator->Mutex);
143 | }
144 |
145 | // For performance we save the last used arena as most of the time the new
146 | // allocation will fit in it.
147 | if(Allocator->LastUsed && (Allocator->LastUsed->Position+Size) < Allocator->LastUsed->Size)
148 | {
149 | if(Allocator->LastUsed->Position == 0) Allocator->EmptyArenaCount--;
150 | Result = RetrieveMemoryFromArena(Allocator->LastUsed, Size);
151 | }
152 | else
153 | {
154 | arena *Arena = Allocator->Base;
155 |
156 | Assert(Allocator->ArenaCount == 0 || Arena);
157 | For(Allocator->ArenaCount)
158 | {
159 | if((Arena->Position+Size) < Arena->Size)
160 | {
161 | if(Arena->Position == 0) Allocator->EmptyArenaCount--;
162 | Result = RetrieveMemoryFromArena(Arena, Size);
163 | break;
164 | }
165 | Arena = Arena->Next;
166 | }
167 |
168 | if(!Result) // If we didn't find any open arenas, we make a new one.
169 | {
170 | u64 ArenaSize = Max(Size, Allocator->ArenaBaseSize ? Allocator->ArenaBaseSize : ARENA_BASE_SIZE);
171 | Arena = CreateNewArena(ArenaSize);
172 | AppendArena(&Allocator->Base, Arena);
173 | Allocator->ArenaCount++;
174 |
175 | Assert(Arena->Position == 0);
176 |
177 | Result = RetrieveMemoryFromArena(Arena, Size);
178 |
179 | #if DEBUG_TD
180 | Allocator->DebugData.ArenaCreationCount++;
181 | #endif
182 | }
183 | Allocator->LastUsed = Arena;
184 | }
185 |
186 | ClearMemory(Result, Size); // TODO:: Think about to, at least, ask to _not_ clear memory.
187 | Assert(Allocator->EmptyArenaCount >= 0);
188 |
189 | #if DEBUG_TD
190 | Allocator->DebugData.AllocationCount++;
191 | Allocator->DebugData.MaxAllocationSize = Max(Allocator->DebugData.MaxAllocationSize, Size);
192 | Allocator->DebugData.MaxArenaCount = Max(Allocator->DebugData.MaxArenaCount, Allocator->ArenaCount);
193 | arena *DebugArena = Allocator->Base;
194 | Assert(Allocator->ArenaCount < MAX_DEBUG_ARENA_COUNT);
195 | For(Allocator->ArenaCount)
196 | {
197 | r32 FillP = DebugArena->Position/(r32)DebugArena->Size;
198 | Allocator->DebugData.MaxFillPercentage[It] = Max(Allocator->DebugData.MaxFillPercentage[It], FillP);
199 | Allocator->DebugData.CurrentFillP[It] = FillP;
200 | DebugArena = DebugArena->Next;
201 | }
202 | #endif
203 |
204 | if(Allocator->Flags & arenaFlags_IsThreaded) Unlock(Allocator->Mutex);
205 | return Result;
206 | }
207 |
208 | internal void *
209 | ReallocateMemory_(arena_allocator *Allocator, void *Memory, u64 OldSize, u64 NewSize)
210 | {
211 | void *Result = 0;
212 |
213 | Result = AllocateMemory_(Allocator, NewSize);
214 | MemoryCopy(Result, Memory, Min(OldSize, NewSize));
215 | FreeMemory(Allocator, Memory);
216 |
217 | return Result;
218 | }
219 |
220 | internal void
221 | ResetMemoryArena(arena_allocator *Allocator)
222 | {
223 | if(Allocator->Flags & arenaFlags_IsThreaded) Lock(Allocator->Mutex);
224 |
225 | Assert(Allocator->Flags & arenaFlags_IsTransient);
226 | arena *Arena = Allocator->Base;
227 | if(Arena)
228 | {
229 | while(Arena->Next) Arena = Arena->Next;
230 | while(Arena)
231 | {
232 | arena *Prev = Arena->Prev;
233 |
234 | if(Prev) VirtualFree(Arena->Memory, 0, MEM_RELEASE);
235 | else
236 | {
237 | Arena->Position = 0;
238 | Arena->Count = 0;
239 | Arena->Next = 0;
240 | }
241 | Arena = Prev;
242 | }
243 | Allocator->ArenaCount = 1;
244 | Allocator->EmptyArenaCount = 1;
245 | Allocator->LastUsed = Allocator->Base;
246 | }
247 |
248 | if(Allocator->Flags & arenaFlags_IsThreaded) Unlock(Allocator->Mutex);
249 | }
250 |
251 | internal void *
252 | AllocateMemory_Private(arena_allocator *Allocator, u64 Size)
253 | {
254 | void *Result = 0;
255 |
256 | if(Allocator->Flags & arenaFlags_IsThreaded) Lock(Allocator->Mutex);
257 |
258 | arena *Arena = CreateNewArena(Size);
259 | AppendArena(&Allocator->Base, Arena);
260 | Allocator->ArenaCount++;
261 |
262 | Assert(Arena->Position == 0);
263 | Result = RetrieveMemoryFromArena(Arena, Size);
264 |
265 | if(Allocator->Flags & arenaFlags_IsThreaded) Unlock(Allocator->Mutex);
266 |
267 | #if DEBUG_TD
268 | Allocator->DebugData.AllocationCount++;
269 | Allocator->DebugData.PrivateAllocationCount++;
270 | Allocator->DebugData.MaxAllocationSize = Max(Allocator->DebugData.MaxAllocationSize, Size);
271 | Allocator->DebugData.MaxArenaCount = Max(Allocator->DebugData.MaxArenaCount, Allocator->ArenaCount);
272 | Allocator->DebugData.ArenaCreationCount++;
273 | #endif
274 |
275 | return Result;
276 | }
277 |
278 | internal void *
279 | ReallocateMemory_Private(arena_allocator *Allocator, void *Memory, u64 OldSize, u64 NewSize)
280 | {
281 | void *Result = 0;
282 |
283 | Result = AllocateMemory_Private(Allocator, NewSize);
284 | MemoryCopy(Result, Memory, Min(OldSize, NewSize));
285 | FreeMemory(Allocator, Memory);
286 |
287 | return Result;
288 | }
289 |
290 |
291 | inline void
292 | Clear_(void *Memory, u64 Size)
293 | {
294 | memset(Memory, 0, Size);
295 | }
296 |
297 |
298 |
299 |
300 | #if DEBUG_TD
301 |
302 | internal void // Call only once per frame for each arena!
303 | CollectArenaDebugFrameData(arena_debug_data *Data)
304 | {
305 | Data->FrameCount++;
306 |
307 | u64 AllocationDiff = Data->AllocationCount - Data->PrevAllocationCount;
308 | Data->PrevAllocationCount = Data->AllocationCount;
309 |
310 | Data->HighestAllocationCountInFrame = Max(Data->HighestAllocationCountInFrame, AllocationDiff);
311 | Data->LowestAllocationCountInFrame = Max(Data->LowestAllocationCountInFrame, AllocationDiff);
312 | }
313 |
314 |
315 | #endif
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
--------------------------------------------------------------------------------
/code/Allocator_TD.h:
--------------------------------------------------------------------------------
1 | /* date = October 13th 2020 9:33 am */
2 | #ifndef _ALLOCATOR__T_D_H
3 | #define _ALLOCATOR__T_D_H
4 |
5 | #if DEBUG_TD // INFO:: Debug data for arenas
6 | #define MAX_DEBUG_ARENA_COUNT 80
7 | struct arena_debug_data
8 | {
9 | struct arena_allocator *Parent;
10 |
11 | u32 FrameCount;
12 |
13 | u32 AllocationCount;
14 | u32 PrevAllocationCount; // Last frame
15 | u32 FreeCount;
16 |
17 | u32 PrivateAllocationCount;
18 |
19 | u64 MaxAllocationSize;
20 |
21 | u64 HighestAllocationCountInFrame;
22 | u64 LowestAllocationCountInFrame;
23 |
24 | u32 MaxArenaCount;
25 | r32 MaxFillPercentage[MAX_DEBUG_ARENA_COUNT];
26 | r32 CurrentFillP[MAX_DEBUG_ARENA_COUNT];
27 |
28 | u32 ArenaCreationCount;
29 | u32 ArenaFreeCount;
30 | };
31 |
32 | #endif
33 |
34 | #define ARENA_BASE_SIZE Megabytes(64)
35 | struct arena
36 | {
37 | struct arena *Prev;
38 | struct arena *Next;
39 |
40 | u32 Count;
41 | u64 Position;
42 | u64 Size;
43 | u8 *Memory;
44 | };
45 |
46 | enum arena_flags
47 | {
48 | arenaFlags_IsTransient = 1<<0,
49 | arenaFlags_IsThreaded = 1<<1,
50 | };
51 |
52 | // ZII: Zero is initialization!
53 | // Means that creating this struct with everything zero
54 | // and just starting to use it is the intended way.
55 | // No addidional initialization is needed.
56 | struct arena_allocator
57 | {
58 | i32 Flags;
59 | u32 ArenaBaseSize;
60 | u32 MaxEmptyArenaCount;
61 |
62 | u32 EmptyArenaCount;
63 |
64 | u32 ArenaCount;
65 | arena *Base;
66 | arena *LastUsed;
67 |
68 | HANDLE Mutex; // Only used when Flag IsThreaded is set.
69 |
70 | #if DEBUG_TD
71 | struct arena_debug_data DebugData;
72 | #endif
73 | };
74 | #define CreateArenaAllocator() {}
75 |
76 | inline void FreeMemory(arena_allocator *Allocator, void *Memory);
77 |
78 | // TODO:: Switch to i64 to catch uninitialized stuff?!
79 |
80 | // This can be called:
81 | // 1. Without VA_ARGS argument, then it is normal memory allocation
82 | // 2. With the keyword Private, then it becomes private allocation
83 | // Each procdeure is briefly described below.
84 | #define AllocateMemory(Allocator, Size, ...) (u8 *) AllocateMemory_##__VA_ARGS__(Allocator, Size)
85 | #define AllocateArray(Allocator, Count, Type, ...) (Type *)AllocateMemory_##__VA_ARGS__(Allocator, (Count)*sizeof(Type))
86 | #define AllocateStruct(Allocator, Type, ...) (Type *)AllocateMemory_##__VA_ARGS__(Allocator, sizeof(Type))
87 |
88 | #define ReallocateMemory(Allocator, Memory, OldSize, NewSize, ...) \
89 | (u8 *)ReallocateMemory_##__VA_ARGS__(Allocator, Memory, OldSize, NewSize)
90 | #define ReallocateArray(Allocator, Memory, OldCount, NewCount, Type, ...) \
91 | (Type *)ReallocateMemory_##__VA_ARGS__(Allocator, Memory, (OldCount)*sizeof(Type), (NewCount)*sizeof(Type))
92 |
93 | // Normal arena allocations. When created is persistent until DeleteMemory is called.
94 | internal void *AllocateMemory_(arena_allocator *Allocator, u64 Size);
95 | internal void *ReallocateMemory_(arena_allocator *Allocator, void *Memory, u64 OldSize, u64 NewSize);
96 |
97 | // Allocates a new arena that is exactly the given size. This is mainly useful for
98 | // allocating big memory blocks that _might_ get deleted at some point and
99 | // having the whole arena empty again and not locking a big chunk of memory,
100 | // because of some small persistent allocation.
101 | internal void *AllocateMemory_Private(arena_allocator *Allocator, u64 Size);
102 | internal void *ReallocateMemory_Private(arena_allocator *Allocator, void *Memory, u64 OldSize, u64 NewSize);
103 |
104 | internal void ResetMemoryArena(arena_allocator *Allocator);
105 |
106 | #define ClearMemory(Memory, Size) Clear_(Memory, Size)
107 | #define ClearArray(Memory, Count, Type) Clear_(Memory, (Count)*sizeof(Type))
108 | inline void Clear_(void *Memory, u64 Size);
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | #endif //_ALLOCATOR__T_D_H
117 |
--------------------------------------------------------------------------------
/code/Definitions_TD.h:
--------------------------------------------------------------------------------
1 | /* date = March 10th 2021 7:07 pm */
2 | #ifndef _DEFINITIONS__T_D_H
3 | #define _DEFINITIONS__T_D_H
4 | #include
5 |
6 |
7 | // NOTE:: internal is for procedures, to let the compiler know that it is only for this compilation unit
8 | #define internal static
9 | #define local_persist static
10 | #define global_variable static
11 |
12 | typedef int8_t i8;
13 | typedef int16_t i16;
14 | typedef int32_t i32;
15 | typedef int64_t i64;
16 | typedef i32 b32;
17 |
18 | typedef uint8_t u8;
19 | typedef uint16_t u16;
20 | typedef uint32_t u32;
21 | typedef uint64_t u64;
22 |
23 | typedef float r32;
24 | typedef double r64;
25 |
26 | #define Kilobytes(Value) ((Value)*1024LL)
27 | #define Megabytes(Value) (Kilobytes(Value)*1024LL)
28 | #define Gigabytes(Value) (Megabytes(Value)*1024LL)
29 | #define Terabytes(Value) (Gigabytes(Value)*1024LL)
30 |
31 | // NOTE:: For loop simplification macro. first param: Count until, second param(optional): Iterater name prefix ...It
32 | #define For(until, ...) for(u32 (__VA_ARGS__##It) = 0; (__VA_ARGS__##It) < (until); ++(__VA_ARGS__##It))
33 |
34 | // NOTE:: Counts the size of a fixed array.
35 | #define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))
36 |
37 | // NOTE:: Meta-Macro, converts a macro back to a 'one-line' statement, which requires a semicolon at the end.
38 | #define ToStatement(E) do{E}while(0)
39 |
40 | #ifndef _Combine // Combine both params to a single name
41 | #define __CD2(X, Y) X##Y
42 | #define _Combine(X, Y) __CD2(X, Y)
43 | #endif
44 |
45 | // NOTE:: General macro for removing an entry/item from an arbitrary array. Moving all following items one up.
46 | #define RemoveItem(Array, ArrayCount, RemovePos, ArrayType) \
47 | ToStatement( \
48 | u32 MoveSize = (ArrayCount-RemovePos)*sizeof(ArrayType); \
49 | u8 *Goal = ((u8 *)Array) + (RemovePos*sizeof(ArrayType)); \
50 | u8 *Start = Goal + sizeof(ArrayType); \
51 | memmove_s(Goal, MoveSize, Start, MoveSize); \
52 | )
53 |
54 | // NOTE:: Cuts off the path from the file
55 | inline i32 LastOccurrenceOfCharacterInString(u8 CharToFind, u8 *String, u8 Delimiter);
56 | #define __FILENAME__ ((LastOccurrenceOfCharacterInString('\\', (u8 *)__FILE__, '\0') > 0) ? (__FILE__ + LastOccurrenceOfCharacterInString('\\', (u8 *)__FILE__, '\0')+1) : (__FILE__))
57 |
58 | // NOTE:: Simple DebugLog that simplifies just printing stuff to the debug output.
59 | // If DEBUG_LOG_INFO is defined, it prints out file and line number.
60 | #define DEBUG_LOG_INFO
61 | #ifdef DEBUG_LOG_INFO
62 | #define DebugLog(Count, Text, ...) { \
63 | char _LogMemory1[Count]; \
64 | sprintf_s(_LogMemory1, Text, __VA_ARGS__);\
65 | char _LogMemory2[Count+260]; \
66 | sprintf_s(_LogMemory2, "%s(%i): %s", __FILENAME__, __LINE__, _LogMemory1);\
67 | OutputDebugStringA(_LogMemory2); \
68 | }
69 | #else
70 | #define DebugLog(Count, Text, ...) { \
71 | char B[Count]; \
72 | sprintf_s(B, Text, __VA_ARGS__);\
73 | OutputDebugStringA(B); \
74 | }
75 | #endif
76 |
77 | // NOTE:: Simple DebugLog that simplifies just printing stuff to the debug output.
78 | #define DebugPrint(Count, Text, ...) { \
79 | char B[Count]; \
80 | sprintf_s(B, Text, __VA_ARGS__);\
81 | printf(B); \
82 | }
83 |
84 | #define MemoryCopy(dest, source, sizeInBytes) memcpy(dest, source, sizeInBytes)
85 | #define MemorySet(memory, setTo, sizeInBytes) memset(memory, setTo, sizeInBytes)
86 |
87 | #if DEBUG_TD
88 | #define MAX_ASSERT_SIZE 512 + MAX_PATH
89 | #define Assert(Expression, ...) \
90 | ToStatement(if(!(Expression)) { \
91 | NewEmptyLocalString(AssertText, MAX_ASSERT_SIZE); \
92 | Append(&AssertText, (u8 *)"Info: \n\n"##__VA_ARGS__##"\n\n"); \
93 | /* 10 is the size of the first Append when nothing is in __VA_ARGS__. */ \
94 | if(AssertText.Pos == 10) ResetStringCompound(AssertText); \
95 | Append(&AssertText, (u8 *)"Assert fired at:\nFile: "##__FILE__##"\nLine: "); \
96 | I32ToString(&AssertText, __LINE__); \
97 | MessageBoxA(0, (char *)AssertText.S, "Assert", MB_OK); \
98 | *(int *)0 = 0; })
99 | #else
100 | #define Assert(Expression)
101 | #endif
102 |
103 | #define InvalidCodePath Assert(!"InvalidCodePath");
104 | #define NotImplemented Assert(!"NotImplementedYet");
105 | #define InvalidDefaultCase default: {Assert(!"InvalidDefaultCase");}
106 |
107 | #endif //_DEFINITIONS__T_D_H
108 |
--------------------------------------------------------------------------------
/code/ErrorHandling_TD.c:
--------------------------------------------------------------------------------
1 | #include "ErrorHandling_TD.h"
2 | internal void UpdatePlayingSong(music_info *MusicInfo);
3 | internal void ResetAllDecodedIDs(game_state *GS);
4 |
5 | internal void
6 | _PushUserErrorMessage(struct game_state *GS, string_c *String, v2 MessagePosition = {MIN_REAL32, MIN_REAL32})
7 | {
8 | renderer *Renderer = &GS->Renderer;
9 | user_error_text *ErrorInfo = &GS->UserErrorText;
10 |
11 | // For each output character we extend the visibility time of the message.
12 | ErrorInfo->AnimTime = 1.0f + String->Pos*0.1f;
13 |
14 | font_size_id FontSize = font_Medium;
15 | if(String->Pos > 60 || Find(*String, '\n') >= 0) FontSize = font_Small;
16 |
17 | ErrorInfo->dAnim = 0;
18 | ErrorInfo->IsAnimating = true;
19 | if(MessagePosition.x == MIN_REAL32)
20 | {
21 | r32 FontAscent = GetFontAscent(GS, FontSize, *String);
22 | MessagePosition.x = GS->Layout.ErrorMessageX;
23 | MessagePosition.y = -GS->Layout.ErrorMessageYOffset - FontAscent;
24 | }
25 |
26 | RenderText(GS, FontSize, String, &GS->MusicInfo.DisplayInfo.ColorPalette.ErrorText, &ErrorInfo->Message, -0.8f, 0, MessagePosition + V2(0, (r32)Renderer->Window.FixedDim.Height));
27 | TranslateWithScreen(&Renderer->TransformList, ErrorInfo->Message.Base, fixedTo_TopLeft);
28 |
29 | // This needs to happen, because TranslateWithScreen already takes currentDim change into accuont,
30 | // thats why we put the absolute position for the text. But that places us in the wrong position,
31 | // when the screen dim has changed, thats why we set the actual position right here with currentDim.
32 | SetPosition(&ErrorInfo->Message, MessagePosition + V2(0, (r32)Renderer->Window.CurrentDim.Height));
33 | SetTransparency(&ErrorInfo->Message, 0);
34 | }
35 |
36 | inline void
37 | AnimateErrorMessage(renderer *Renderer, user_error_text *ErrorInfo, r32 dTime)
38 | {
39 | if(ErrorInfo->IsAnimating)
40 | {
41 | if(ErrorInfo->dAnim >= 1.0f)
42 | {
43 | SetActive(&ErrorInfo->Message, false);
44 | RemoveFromTransformList(&Renderer->TransformList, ErrorInfo->Message.Base);
45 | RemoveRenderText(Renderer, &ErrorInfo->Message);
46 | ErrorInfo->IsAnimating = false;
47 | }
48 | else
49 | {
50 | r32 Alpha = 1-Pow(ErrorInfo->dAnim, 10.0f);
51 | SetTransparency(&ErrorInfo->Message, Alpha);
52 |
53 | ErrorInfo->dAnim += dTime/ErrorInfo->AnimTime;
54 | }
55 | }
56 | }
57 |
58 | // ***************************************
59 | // Job error messaging *******************
60 | // ***************************************
61 |
62 | internal void
63 | PushErrorMessage(struct game_state *GS, error_item Error)
64 | {
65 | WaitForSingleObjectEx(GS->ThreadErrorList.Mutex, INFINITE, false);
66 | if(GS->ThreadErrorList.Count < MAX_THREAD_ERRORS)
67 | {
68 | GS->ThreadErrorList.Errors[GS->ThreadErrorList.Count++] = Error;
69 | GS->ThreadErrorList.RemoveDecode = true;
70 | }
71 | ReleaseMutex(GS->ThreadErrorList.Mutex);
72 | }
73 |
74 | internal void
75 | PushErrorMessage(struct game_state *GS, string_c ErrorText)
76 | {
77 | WaitForSingleObjectEx(GS->ThreadErrorList.Mutex, INFINITE, false);
78 | if(GS->ThreadErrorList.Count < MAX_THREAD_ERRORS)
79 | {
80 | error_item Error = {errorCode_Text, -1, };
81 | Error.ErrorText = NewStringCompound(&GS->JobThreadsArena, ErrorText.Pos);
82 | CopyIntoCompound(&Error.ErrorText, &ErrorText);
83 | GS->ThreadErrorList.Errors[GS->ThreadErrorList.Count++] = Error;
84 | }
85 | ReleaseMutex(GS->ThreadErrorList.Mutex);
86 | }
87 |
88 |
89 | internal error_item
90 | PopErrorMessageFromThread(struct game_state *GS)
91 | {
92 | error_item Result = {errorCode_NoError, {-1}};
93 | WaitForSingleObjectEx(GS->ThreadErrorList.Mutex, INFINITE, false);
94 | if(GS->ThreadErrorList.Count > 0)
95 | {
96 | Result = GS->ThreadErrorList.Errors[--GS->ThreadErrorList.Count];
97 | }
98 | ReleaseMutex(GS->ThreadErrorList.Mutex);
99 | return Result;
100 | }
101 |
102 | inline void
103 | RemoveDecodeFails(struct game_state *GS)
104 | {
105 | WaitForSingleObjectEx(GS->ThreadErrorList.Mutex, INFINITE, false);
106 |
107 | u32 DecodeID = 0;
108 | For(GS->ThreadErrorList.Count)
109 | {
110 | if(GS->ThreadErrorList.Errors[It].Code == errorCode_Text) continue;
111 | if(Find(&GS->MP3Info->DecodeInfo.FileIDs.A, GS->ThreadErrorList.Errors[It].ID, &DecodeID))
112 | {
113 | Put(&GS->MP3Info->DecodeInfo.FileIDs.A, DecodeID, MAX_UINT32);
114 | Put(&GS->MP3Info->DecodeInfo.LastTouched, DecodeID, 0);
115 | if(GS->MusicInfo.PlayingSong.DecodeID == (i32)DecodeID)
116 | {
117 | GS->MusicInfo.PlayingSong.DisplayableID.ID = -1;
118 | GS->MusicInfo.PlayingSong.PlaylistID.ID = -1;
119 | GS->MusicInfo.PlayingSong.DecodeID = -1;
120 | }
121 | }
122 | }
123 |
124 | GS->ThreadErrorList.RemoveDecode = false;
125 | ReleaseMutex(GS->ThreadErrorList.Mutex);
126 | }
127 |
128 | internal void
129 | ProcessThreadErrors(struct game_state *GS)
130 | {
131 | if(GS->ThreadErrorList.Count)
132 | {
133 | // To remove decode fails savely from the main thread (which this is only called from),
134 | // we set RemoveDecode on the errorList when a new one occurs. RemoveDecodeFails then
135 | // goes through the _whole list_ and removes all which need to be decode-removed.
136 | if(GS->ThreadErrorList.RemoveDecode) RemoveDecodeFails(GS);
137 |
138 | if(!GS->UserErrorText.IsAnimating)
139 | {
140 | error_item NextError = PopErrorMessageFromThread(GS);
141 |
142 | switch(NextError.Code)
143 | {
144 | case errorCode_Text:
145 | {
146 | _PushUserErrorMessage(GS, &NextError.ErrorText);
147 | DeleteStringCompound(&GS->JobThreadsArena, &NextError.ErrorText);
148 | } break;
149 |
150 | case errorCode_DecodingFailed:
151 | {
152 | string_c ErrorMsg = NewStringCompound(&GS->ScratchArena, 555);
153 | AppendStringToCompound(&ErrorMsg, (u8 *)"ERROR:: Could not decode song. Is file corrupted? (");
154 | AppendStringCompoundToCompound(&ErrorMsg, GS->MP3Info->FileInfo.FileNames_ + NextError.ID);
155 | AppendStringToCompound(&ErrorMsg, (u8 *)")");
156 | _PushUserErrorMessage(GS, &ErrorMsg);
157 | DeleteStringCompound(&GS->ScratchArena, &ErrorMsg);
158 |
159 | UpdatePlayingSong(&GS->MusicInfo);
160 | ResetAllDecodedIDs(GS);
161 | ChangeSong(GS, &GS->MusicInfo.PlayingSong);
162 | } break;
163 |
164 | case errorCode_FileLoadFailed:
165 | {
166 | string_c ErrorMsg = NewStringCompound(&GS->ScratchArena, 555);
167 | AppendStringToCompound(&ErrorMsg, (u8 *)"ERROR:: Could not load song from disk (");
168 | AppendStringCompoundToCompound(&ErrorMsg, GS->MP3Info->FileInfo.FileNames_ + NextError.ID);
169 | AppendStringToCompound(&ErrorMsg, (u8 *)").\nFiles were moved, doing a retrace.");
170 | _PushUserErrorMessage(GS, &ErrorMsg);
171 | DeleteStringCompound(&GS->ScratchArena, &ErrorMsg);
172 |
173 | UpdatePlayingSong(&GS->MusicInfo);
174 | ResetAllDecodedIDs(GS);
175 | ChangeSong(GS, &GS->MusicInfo.PlayingSong);
176 |
177 | AddJob_CheckMusicPathChanged(&GS->CheckMusicPath);
178 | } break;
179 |
180 | case errorCode_EmptyFile:
181 | {
182 | string_c ErrorMsg = NewStringCompound(&GS->ScratchArena, 555);
183 | AppendStringToCompound(&ErrorMsg, (u8 *)"ERROR:: Could not load song. File was empty. (");
184 | AppendStringCompoundToCompound(&ErrorMsg, GS->MP3Info->FileInfo.FileNames_ + NextError.ID);
185 | AppendStringToCompound(&ErrorMsg, (u8 *)")");
186 | _PushUserErrorMessage(GS, &ErrorMsg);
187 | DeleteStringCompound(&GS->ScratchArena, &ErrorMsg);
188 |
189 | UpdatePlayingSong(&GS->MusicInfo);
190 | ResetAllDecodedIDs(GS);
191 | ChangeSong(GS, &GS->MusicInfo.PlayingSong);
192 | } break;
193 | }
194 |
195 | }
196 | }
197 | }
198 |
199 |
200 | // *************************************************************************
201 | // Crash handling **********************************************************
202 | // *************************************************************************
203 |
204 | #if 0
205 | #include
206 |
207 | internal void
208 | PrintStack()
209 | {
210 | BOOL Result;
211 | HANDLE Process;
212 | HANDLE Thread;
213 | CONTEXT Context;
214 | STACKFRAME64 Stack = {};
215 | ULONG Frame;
216 | IMAGEHLP_SYMBOL64 Symbol;
217 | DWORD64 Displacement;
218 | NewEmptyLocalString(Name, MAX_PATH);
219 |
220 | RtlCaptureContext(&Context);
221 | //MemorySet(&Stack, 0, sizeof(STACKFRAME64));
222 |
223 | Process = GetCurrentProcess();
224 | Thread = GetCurrentThread();
225 | Displacement = 0;
226 | Stack.AddrPC.Offset = Context.Eip;
227 | Stack.AddrPC.Mode = AddrModeFlat;
228 | Stack.AddrStack.Offset = Context.Esp;
229 | Stack.AddrStack.Mode = AddrModeFlat;
230 | Stack.AddrFrame.Offset = Context.Ebp;
231 | Stack.AddrFrame.Mode = AddrModeFlat;
232 |
233 | for(FrameIt = 0; ; ++FrameIt)
234 | {
235 | Result = StackWalk64
236 | (
237 | IMAGE_FILE_MACHINE_I386,
238 | process,
239 | thread,
240 | &stack,
241 | &context,
242 | NULL,
243 | SymFunctionTableAccess64,
244 | SymGetModuleBase64,
245 | NULL
246 | );
247 |
248 | symbol.SizeOfStruct = sizeof( IMAGEHLP_SYMBOL64 );
249 | symbol.MaxNameLength = 255;
250 |
251 | SymGetSymFromAddr64( process, ( ULONG64 )stack.AddrPC.Offset, &displacement, &symbol );
252 | UnDecorateSymbolName( symbol.Name, ( PSTR )name, 256, UNDNAME_COMPLETE );
253 |
254 | printf
255 | (
256 | "Frame %lu:\n"
257 | " Symbol name: %s\n"
258 | " PC address: 0x%08LX\n"
259 | " Stack address: 0x%08LX\n"
260 | " Frame address: 0x%08LX\n"
261 | "\n",
262 | frame,
263 | symbol.Name,
264 | ( ULONG64 )stack.AddrPC.Offset,
265 | ( ULONG64 )stack.AddrStack.Offset,
266 | ( ULONG64 )stack.AddrFrame.Offset
267 | );
268 |
269 | if( !result )
270 | {
271 | break;
272 | }
273 | }
274 | }
275 |
276 | #endif
--------------------------------------------------------------------------------
/code/ErrorHandling_TD.h:
--------------------------------------------------------------------------------
1 | /* date = June 3rd 2021 7:59 am */
2 | #ifndef _ERROR_HANDLING__T_D_H
3 | #define _ERROR_HANDLING__T_D_H
4 |
5 | #include "Renderer_TD.h"
6 |
7 | enum error_codes
8 | {
9 | errorCode_DecodingCanceled = 1,
10 | errorCode_NoError = 0,
11 | errorCode_FileLoadFailed = -1,
12 | errorCode_DecodingFailed = -2,
13 | errorCode_EmptyFile = -3,
14 | errorCode_Text = -4,
15 | };
16 |
17 | struct user_error_text
18 | {
19 | render_text Message;
20 | b32 IsAnimating;
21 | r32 dAnim;
22 | r32 AnimTime;
23 | };
24 |
25 | #define MAX_THREAD_ERRORS 20
26 | struct error_item
27 | {
28 | error_codes Code;
29 | i32 ID;
30 | string_c ErrorText;
31 | };
32 |
33 | struct thread_error_list
34 | {
35 | error_item Errors[MAX_THREAD_ERRORS];
36 | u32 Count;
37 |
38 | b32 RemoveDecode;
39 | HANDLE Mutex;
40 | };
41 |
42 | internal void PushErrorMessage(struct game_state *GS, string_c ErrorText);
43 | internal void PushErrorMessage(struct game_state *GS, error_item Error);
44 |
45 | inline void AnimateErrorMessage(renderer *Renderer, user_error_text *ErrorInfo, r32 dTime);
46 |
47 |
48 |
49 |
50 |
51 |
52 | #endif //_ERROR_HANDLING__T_D_H
53 |
--------------------------------------------------------------------------------
/code/FileUtilities_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "String_TD.h"
4 |
5 |
6 | struct read_file_result
7 | {
8 | u32 Size;
9 | u8 *Data;
10 | };
11 |
12 | // General file methods
13 | internal b32 WriteEntireFile(arena_allocator *Arena, u8 *Filename, u32 MemorySize, void *Memory);
14 | internal b32 WriteEntireFile(string_w *Filename, u32 MemorySize, void *Memory);
15 |
16 | internal b32 WriteToFile(arena_allocator *Arena, u8 *Filename, u32 MemorySize, void *Memory, u32 WriteOffsetFromStart);
17 | internal b32 WriteToFile(string_w *Filename, u32 MemoryWriteSize, void *Memory, u32 WriteOffsetFromStart);
18 |
19 | internal void FreeFileMemory(arena_allocator *Arena, read_file_result File);
20 |
21 | internal b32 DeleteFile(string_w Filename);
22 | internal b32 DeleteFile(arena_allocator *Arena, string_c Filename);
23 |
24 | internal b32 ReadEntireFile(arena_allocator *Arena, read_file_result *FileData, u8 *Filename);
25 | internal b32 ReadEntireFile(arena_allocator *Arena, read_file_result *FileData, string_w *Filename);
26 |
27 | internal b32 ReadBeginningOfFile(arena_allocator *Arena, read_file_result *FileData, u8 *Filename, u32 ReadAmount);
28 | internal b32 ReadBeginningOfFile(arena_allocator *Arena, read_file_result *FileData, string_w *Filename, u32 ReadAmount);
29 |
30 | internal b32 ReadEndOfFile(arena_allocator *Arena, read_file_result *FileData, u8 *Filename, u32 ReadAmount);
31 | internal b32 ReadEndOfFile(arena_allocator *Arena, read_file_result *FileData, string_w *Filename, u32 ReadAmount);
32 |
33 | internal b32 AppendToFile(arena_allocator *Arena, char *FileName, u32 MemorySize, void *Memory);
34 |
35 | internal b32 CheckPathValidity(arena_allocator *ScratchArena, string_c Path);
36 | internal b32 CheckPathValidity(arena_allocator *ScratchArena, string_c Path, i32 *FirstWrongCharPos);
37 | internal b32 CheckFileExists(arena_allocator *ScratchArena, string_c FilePath);
38 |
39 | // .obj loader methods
40 |
41 |
42 | struct bit_scan_result
43 | {
44 | b32 Found;
45 | u32 Index;
46 | };
47 |
48 | enum face_type
49 | {
50 | NO_VALUE,
51 | VERTEX,
52 | VERTEX_TEXCOORD,
53 | VERTEX_NORMAL,
54 | VERTEX_TEXCOORD_NORMAL,
55 | };
56 |
57 | struct mtl_data
58 | {
59 | hash_table NameIndex; // Get index for mtl data via the name string
60 | i32 Count;
61 |
62 | v3 *Ka; // Ambient
63 | v3 *Kd; // Diffuse
64 | v3 *Ks; // Specular
65 | v3 *Tf; // Transmission filter
66 | r32 *Ns; // Spec exponent
67 | r32 *Ni; // Refraction index
68 | r32 *Tr; // Transparency
69 | u32 *Illum; // Illumination model: lookup in list
70 | u8 *Map_Ka; // Ambient texture map
71 | u8 *Map_Kd; // Diffuse texture map
72 | u8 *Map_bump; // Bumpmap
73 | };
74 |
75 | struct obj_material_group
76 | {
77 | //char Name[MAX_PATH];
78 | u8 MatName[50];
79 |
80 | u32 *Indices;
81 | u32 IndiceCount;
82 | };
83 |
84 | struct model_information
85 | {
86 | v3 MinBound;
87 | v3 MaxBound;
88 | };
89 |
90 | struct obj_data
91 | {
92 | char Name[MAX_PATH];
93 |
94 | v3 *Vertice;
95 | v2 *TexCoords;
96 | v3 *Normals;
97 | u8 *SmoothingValue;
98 | u32 Count;
99 | face_type FaceType;
100 |
101 | // Gives information if faces have normals, texcoords, both or nothing
102 | obj_material_group *SurfaceGroups;
103 | u32 GroupCount;
104 |
105 | mtl_data Materials;
106 | model_information Infos;
107 | };
108 |
109 | internal b32 LoadOBJFile(obj_data *Object, u8 *Filename, arena_allocator *ArenaAlloc);
110 | inline u32 ProcessVectorLine(r32 *Results, u32 VectorDim, u8 *LineChar);
111 | inline face_type IdentifyFaceType(u8 *Character);
112 | internal u8 *EvaluateNextFaceIndexGroup(hash_table *FaceTable, obj_data *Object, obj_material_group *CurrentGroup, u8 *Character, v3 *Vertice, v2 *TexCoords, v3 *Normals);
113 | internal obj_material_group CollectAllGroupsInOne(obj_data *Object, arena_allocator *ArenaAlloc);
114 | internal b32 LoadMtlFile(mtl_data *Materials, arena_allocator *ArenaAlloc, u8 *Path, u8 *CutPath);
115 |
116 | // .bmp loader methods
117 | enum bitmap_color_format
118 | {
119 | colorFormat_RGBA,
120 | colorFormat_RGB,
121 | colorFormat_BGR,
122 | colorFormat_Alpha,
123 | };
124 |
125 | struct loaded_bitmap
126 | {
127 | b32 WasLoaded;
128 | u32 Width;
129 | u32 Height;
130 | u32 *Pixels;
131 | bitmap_color_format ColorFormat;
132 | u32 Pitch; // Width*sizeof(One color (e.g. u32));
133 | };
134 |
135 | inline bit_scan_result FindLeastSignificantSetBit(u32 Value);
136 | internal loaded_bitmap LoadBMPImage(arena_allocator *Arena, u8 *FileName);
137 |
138 | #pragma pack(push, 1)
139 | struct bitmap_header
140 | {
141 | u16 FileType;
142 | u32 FileSize;
143 | u16 Reserved1;
144 | u16 Reserved2;
145 | u32 BitmapOffset;
146 | u32 Size;
147 | i32 Width;
148 | i32 Height;
149 | u16 Planes;
150 | u16 BitsPerPixel;
151 | u32 Compression;
152 | u32 SizeOfBitmap;
153 | i32 HorzResolution;
154 | i32 VertResolution;
155 | u32 ColorsUsed;
156 | u32 ColorsImportant;
157 |
158 | u32 RedMask;
159 | u32 GreenMask;
160 | u32 BlueMask;
161 | };
162 | #pragma pack(pop)
163 |
--------------------------------------------------------------------------------
/code/Font_TD.h:
--------------------------------------------------------------------------------
1 | /* date = March 20th 2021 7:44 am */
2 | #ifndef _FONT__T_D_H
3 | #define _FONT__T_D_H
4 |
5 | enum font_size_id // #Helper
6 | {
7 | font_Small = 0,
8 | font_Medium = 1,
9 | font_Big = 2,
10 | font_size_id_Size // Needs to be last _always_!
11 | };
12 | struct font_size
13 | {
14 | font_size_id ID;
15 | r32 Size;
16 | };
17 | struct font_sizes
18 | {
19 | font_size Sizes[font_size_id_Size]; // font_size_id should be able to access the font_size with its own ID!
20 | u32 Count;
21 | };
22 |
23 | struct font_name_list
24 | {
25 | u32 MaxCount;
26 | u32 Count;
27 | string_c *Names;
28 | };
29 |
30 | struct font_data
31 | {
32 | r32 Size;
33 | stbtt_packedchar *CharData;
34 | };
35 |
36 | struct font_metrics
37 | {
38 | // Everything in unscaled pixels.
39 | // Multiply by font scale factor = (FontHeight/(Ascent + Descent*-1).
40 | r32 Ascent; // From baseline.
41 | r32 Descent; // From baseline. Negative.
42 | r32 LineGap; // Spacing between lines (from descent to ascent).
43 | r32 RowGap; // Spacing between lines (from baseline to baseline.
44 | };
45 |
46 | struct codepoint_range
47 | {
48 | u32 First;
49 | u32 Last;
50 | u32 Count;
51 | };
52 |
53 | #define MAX_CODEPOINT_BLOCK 500
54 | // The amount of codepoints loaded, when the containing
55 | // Unicode Group it is bigger than MAX_CODEPOINT_BLOCK.
56 | #define USED_CODEPOINT_RANGE 1
57 |
58 | // TODO:: Maybe cache the fonts, which where found in the
59 | // Settings file. This will reduce the large overhead of
60 | // searching _all_ font, every time.
61 | #define SEARCH_FOR_MISSING_FONT
62 | struct font_group
63 | {
64 | u32 GLID;
65 | u32 BitmapWidth;
66 | u32 BitmapHeight;
67 | struct unicode_group *UnicodeGroup;
68 | codepoint_range CodepointRange;
69 | font_metrics FontMetrics;
70 |
71 | font_data FontDataForEachSize[font_size_id_Size];
72 | };
73 |
74 | struct font_atlas
75 | {
76 | font_sizes FontSizes;
77 |
78 | u32 MaxCount;
79 | u32 Count;
80 | font_group *FontGroups; // Sparse array of required codepoints
81 |
82 | // These are the fonts, which are not in the unicode-group-list.
83 | font_name_list *CachedFontNames; // Points to Settings->CachedFontNames.
84 | };
85 |
86 | inline font_atlas NewFontAtlas(struct serialization_settings *Settings, font_sizes FontSizes);
87 | internal void LoadFonts(arena_allocator *FixArena, arena_allocator *ScratchArena, font_atlas *Atlas,
88 | u8 *RawFontData, /*string_c FontPath, */u32 *CodepointsFromGroup, u32 CodepointCount);
89 | internal void RenderText(struct game_state *GS, font_size_id FontSizeID, string_c *Text,
90 | v3 *Color, render_text *ResultText, r32 ZValue, entry_id *Parent = 0, v2 StartP = {});
91 | internal u8 GetUTF8Decimal(u8 *S, u32 *Utf8Value);
92 | internal font_group *GetFontGroup(game_state *GS, font_atlas *Atlas, u32 Codepoint);
93 | inline font_size GetFontSize(struct renderer *Renderer, font_size_id ID);
94 |
95 | // These are pre-scaled for the given size.
96 | inline font_metrics GetFontMetrics(game_state *GS, font_size_id ID, string_c Text);
97 | inline r32 GetFontDescent(game_state *GS, font_size_id ID, string_c Text);
98 | inline r32 GetFontAscent (game_state *GS, font_size_id ID, string_c Text);
99 |
100 | struct raw_font
101 | {
102 | // In
103 | u32 Codepoint;
104 | string_c *FolderPath;
105 |
106 | // Out
107 | string_c Name;
108 | read_file_result Data; // In Scratch Memory!
109 | };
110 | internal b32 FindAndLoadFontWithUnicodeCodepoint(arena_allocator *ScratchArena, raw_font *SearchFont, string_c *FoundFontPath_out);
111 |
112 |
113 | #include "UnicodeGroups_TD.h"
114 |
115 | #endif //_FONT__T_D_H
116 |
--------------------------------------------------------------------------------
/code/GL_TD.c:
--------------------------------------------------------------------------------
1 | #include "GL_TD.h"
2 | #include "Renderer_TD.h"
3 | #include "GameBasics_TD.h"
4 | // NOTE:: The windows guy is called: Raymond Chen
5 | // See his blog post on fullscreen stuff!
6 | #define glMultMatrixf(m) Assert(false);
7 |
8 | internal void
9 | InitOpenGL(HWND Window, b32 DoBackfaceCulling = true)
10 | {
11 | HDC WindowDC = GetDC(Window);
12 |
13 | // Describing what pixel format we wanna use
14 | PIXELFORMATDESCRIPTOR DesiredPixelFormat = {};
15 | DesiredPixelFormat.nSize = sizeof(DesiredPixelFormat);
16 | DesiredPixelFormat.nVersion = 1;
17 | DesiredPixelFormat.dwFlags = PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER;
18 | DesiredPixelFormat.cColorBits = 32;
19 | DesiredPixelFormat.cAlphaBits = 8;
20 | DesiredPixelFormat.iLayerType = PFD_MAIN_PLANE;
21 |
22 | // Ask for the best fitting pixel format
23 | i32 SuggestedPixelFormatIndex = ChoosePixelFormat(WindowDC, &DesiredPixelFormat);
24 | PIXELFORMATDESCRIPTOR SuggestedPixelFormat;
25 | // Get descriptor for the pixel format we got back
26 | DescribePixelFormat(WindowDC, SuggestedPixelFormatIndex, sizeof(SuggestedPixelFormat), &SuggestedPixelFormat);
27 | // Set the pixel format we got with all its descriptions
28 | SetPixelFormat(WindowDC, SuggestedPixelFormatIndex, &SuggestedPixelFormat);
29 |
30 | HGLRC OpenGLRC = wglCreateContext(WindowDC);
31 | if(wglMakeCurrent(WindowDC, OpenGLRC))
32 | {
33 | glEnable(GL_DEPTH_TEST);
34 | glEnable(GL_DEPTH);
35 | glDepthFunc(GL_LESS);
36 | if(DoBackfaceCulling)
37 | {
38 | glEnable(GL_CULL_FACE);
39 | glCullFace(GL_BACK);
40 | glFrontFace(GL_CW); // GL_CCW for counter clock-wise
41 | }
42 | }
43 | else InvalidCodePath; // Should never really happen
44 |
45 | ReleaseDC(Window, WindowDC);
46 | }
47 |
48 | internal void
49 | DrawGroundGrid()
50 | {
51 | r32 GridSize = 10.0f;
52 | u32 GridSegments = 20;
53 | r32 GridStep = GridSize / (r32)GridSegments;
54 | r32 GridOrigin = -GridSize*0.5f;
55 |
56 | glBegin(GL_LINES);
57 | glColor3f(1.0f, 1.0f, 1.0f);
58 | For (GridSegments + 1)
59 | {
60 | r32 itpos = GridOrigin + GridStep*(r32)It;
61 | glVertex3f(itpos, -1.0f, GridOrigin);
62 | glVertex3f(itpos, -1.0f, GridOrigin + GridSize);
63 |
64 | glVertex3f(GridOrigin, -1.0f, itpos);
65 | glVertex3f(GridOrigin + GridSize, -1.0f, itpos);
66 |
67 | }
68 | glEnd();
69 | }
70 |
71 | inline void
72 | GLMatrixMultiply(m4 M)
73 | {
74 | Transpose(&M);
75 | #undef glMultMatrixf
76 | glMultMatrixf(M.E);
77 | #define glMultMatrixf(m) Assert(false);
78 | }
79 |
80 | inline void
81 | ReshapeGLWindow(renderer *Renderer)
82 | {
83 | glViewport(0, 0, Renderer->Window.CurrentDim.Width, Renderer->Window.CurrentDim.Height);
84 |
85 | /*
86 | camera *Camera = &Renderer->Camera;
87 | Camera->Projection = Identity();
88 | Perspective(&Camera->Projection, Camera->FOVY, Renderer->Window.CurrentAspect,
89 | Camera->ClippingPlanes.x, Camera->ClippingPlanes.y);
90 |
91 | glMatrixMode(GL_PROJECTION);
92 | glLoadIdentity();
93 | GLMatrixMultiply(Renderer->Camera.Projection);
94 |
95 | glMatrixMode(GL_MODELVIEW);*/
96 | }
97 |
98 | inline u32
99 | CreateGLTexture(loaded_bitmap Bitmap, b32 DoSameColorFormat = false)
100 | {
101 | u32 ID;
102 |
103 | Assert(Bitmap.WasLoaded);
104 | Assert(Bitmap.Pixels);
105 |
106 | u32 BitmapColorFormat = 0;
107 | switch(Bitmap.ColorFormat)
108 | {
109 | case colorFormat_RGB:
110 | {
111 | BitmapColorFormat = GL_RGB;
112 | } break;
113 |
114 | case colorFormat_RGBA:
115 | {
116 | BitmapColorFormat = GL_RGBA;
117 | } break;
118 |
119 | case colorFormat_Alpha:
120 | {
121 | BitmapColorFormat = GL_ALPHA;
122 | } break;
123 |
124 | InvalidDefaultCase
125 | }
126 |
127 | glGenTextures(1, &ID);
128 | glBindTexture(GL_TEXTURE_2D, ID);
129 | if(DoSameColorFormat) glTexImage2D(GL_TEXTURE_2D, 0, BitmapColorFormat, Bitmap.Width, Bitmap.Height, 0, BitmapColorFormat,
130 | GL_UNSIGNED_BYTE, Bitmap.Pixels);
131 | else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Bitmap.Width, Bitmap.Height, 0, BitmapColorFormat,
132 | GL_UNSIGNED_BYTE, Bitmap.Pixels);
133 |
134 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
135 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
136 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
137 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
138 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
139 |
140 | return ++ID; // ZII:: We increment texIDs on creation to have 0 be default
141 | }
142 |
143 | inline u32
144 | LoadAndCreateGLTexture(u8 *Path)
145 | {
146 | loaded_bitmap NewTexBitmap = LoadImage_STB(Path);
147 | u32 Result = CreateGLTexture(NewTexBitmap);
148 | FreeImage_STB(NewTexBitmap);
149 |
150 | return Result;
151 | }
152 |
153 | inline u32
154 | LoadAndCreateGLTexture(u8 *Path, u8 *Filename)
155 | {
156 | NewLocalString(PathName, 260, Path);
157 | AppendStringToCompound(&PathName, Filename);
158 | loaded_bitmap NewTexBitmap = LoadImage_STB(PathName.S);
159 | u32 Result = CreateGLTexture(NewTexBitmap);
160 | FreeImage_STB(NewTexBitmap);
161 |
162 | return Result;
163 | }
164 |
165 | inline u32
166 | DecodeAndCreateGLTexture(u32 DataSize, u8 *Data)
167 | {
168 | loaded_bitmap NewTexBitmap = LoadImage_STB({DataSize, Data});
169 | u32 Result = CreateGLTexture(NewTexBitmap);
170 | FreeImage_STB(NewTexBitmap);
171 |
172 | return Result;
173 | }
174 |
175 | inline u32
176 | DecodeAndCreateGLTexture(arena_allocator *Arena, loaded_bitmap Bitmap)
177 | {
178 | loaded_bitmap IconBitmap = DecodeIcon(Arena, Bitmap.Width, Bitmap.Height,
179 | (u8 *)Bitmap.Pixels, Bitmap.Pitch); // Abusing pitch for memory size
180 | u32 Result = CreateGLTexture(IconBitmap);
181 | FreeMemory(Arena, IconBitmap.Pixels);
182 |
183 | return Result;
184 | }
185 |
186 | inline void
187 | UpdateGLTexture(loaded_bitmap Bitmap, GLuint TexID)
188 | {
189 | glBindTexture(GL_TEXTURE_2D, TexID-1);
190 |
191 | i32 GLColorFormat = 0;
192 | switch(Bitmap.ColorFormat)
193 | {
194 | case colorFormat_RGBA:
195 | {
196 | GLColorFormat = GL_RGBA;
197 | } break;
198 | case colorFormat_RGB:
199 | {
200 | GLColorFormat = GL_RGB;
201 | } break;
202 | }
203 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Bitmap.Width, Bitmap.Height, 0, GLColorFormat, GL_UNSIGNED_BYTE, Bitmap.Pixels);
204 |
205 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
206 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
207 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
208 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
209 | }
210 |
211 | inline void
212 | DecodeAndUpdateGLTexture(arena_allocator *Arena, loaded_bitmap Bitmap, GLuint TexID)
213 | {
214 | loaded_bitmap IconBitmap = DecodeIcon(Arena, Bitmap.Width, Bitmap.Height,
215 | (u8 *)Bitmap.Pixels, Bitmap.Pitch); // Abusing pitch for memory size
216 | UpdateGLTexture(IconBitmap, TexID);
217 | FreeMemory(Arena, IconBitmap.Pixels);
218 | }
219 |
220 | inline void
221 | DeleteGLTexture(u32 GLID)
222 | {
223 | GLID -= 1;
224 | glDeleteTextures(1, &GLID);
225 | }
226 |
227 | inline void
228 | ConvertToGLSpace(window_info WindowDims, render_entry *Entry, v3 *Result)
229 | {
230 | v2 CurD = V2(WindowDims.CurrentDim.Dim);
231 | ApplyTransform(Entry, Result);
232 |
233 | For(4)
234 | {
235 | // Into -1, 1 space of GL
236 | Result[It].x = Result[It].x/CurD.x;
237 | Result[It].x = (Result[It].x*2) - 1;
238 | Result[It].y = Result[It].y/CurD.y;
239 | Result[It].y = (Result[It].y*2) - 1;
240 | }
241 | }
242 |
243 | internal void
244 | DisplayBufferInWindow(HDC DeviceContext, window_info Window, render_entry_list *EntryList, v4 BGColor)
245 | {
246 | glClearColor(BGColor.r, BGColor.g, BGColor.b, BGColor.a);
247 | glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
248 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
249 | glEnable(GL_BLEND);
250 |
251 | UpdateEntryList(EntryList);
252 |
253 | for(u32 EntryID = 0; EntryID < EntryList->EntryCount; EntryID++)
254 | {
255 | render_entry *RenderEntry = EntryList->Entries + EntryID;
256 | if(!RenderEntry->Render) continue;
257 |
258 | if(RenderEntry->Scissor != NULL)
259 | {
260 | glEnable(GL_SCISSOR_TEST);
261 | v3 V[4];
262 | ApplyTransform(RenderEntry->Scissor->ID, V);
263 | glScissor((i32)V[0].x, (i32)V[0].y, (i32)(V[2].x - V[0].x), (i32)(V[2].y - V[0].y));
264 | }
265 |
266 | switch(RenderEntry->Type)
267 | {
268 | case renderType_2DBitmap:
269 | {
270 | glEnable(GL_TEXTURE_2D);
271 | glBindTexture(GL_TEXTURE_2D, RenderEntry->TexID-1); // ZII:: We increment texIDs on creation to have 0 be default
272 |
273 | glBegin(GL_QUADS);
274 | v3 V[4];
275 | ConvertToGLSpace(Window, RenderEntry, V);
276 | For(4)
277 | {
278 | v2 T = RenderEntry->TexCoords[It];
279 |
280 | glTexCoord2f(T.x, T.y);
281 | glColor4f(RenderEntry->Color->r, RenderEntry->Color->g, RenderEntry->Color->b, RenderEntry->Transparency);
282 | glVertex3fv(V[It].E);
283 | }
284 | glEnd();
285 | glDisable(GL_TEXTURE_2D);
286 | } break;
287 |
288 | case renderType_2DRectangle:
289 | {
290 | glBegin(GL_QUADS);
291 | v3 V[4];
292 | ConvertToGLSpace(Window, RenderEntry, V);
293 | For(4)
294 | {
295 | v2 T = RenderEntry->TexCoords[It];
296 |
297 | glTexCoord2f(T.x, T.y);
298 | glColor4f(RenderEntry->Color->r, RenderEntry->Color->g, RenderEntry->Color->b, RenderEntry->Transparency);
299 | glVertex3fv(V[It].E);
300 | }
301 | glEnd();
302 | } break;
303 |
304 | case renderType_Text:
305 | {
306 | glEnable(GL_TEXTURE_2D);
307 | glBegin(GL_QUADS);
308 |
309 | u32 GLID = 0;
310 | For(RenderEntry->Text->Count)
311 | {
312 | render_entry *TextEntry = RenderEntry->Text->RenderEntries+It;
313 | if(!TextEntry->Render) continue;
314 |
315 | Assert(TextEntry->TexID != 0);
316 | if(GLID != TextEntry->TexID) // Only swtich Texture if actually needed.
317 | {
318 | GLID = TextEntry->TexID;
319 | glEnd();
320 | glBindTexture(GL_TEXTURE_2D, TextEntry->TexID-1);
321 | glBegin(GL_QUADS);
322 | }
323 |
324 | v3 V[4];
325 | ConvertToGLSpace(Window, TextEntry, V);
326 | For(4)
327 | {
328 | v2 T = TextEntry->TexCoords[It];
329 |
330 | glTexCoord2f(T.x, T.y);
331 | glColor4f(TextEntry->Color->r, TextEntry->Color->g, TextEntry->Color->b, TextEntry->Transparency);
332 | glVertex3fv(V[It].E);
333 | }
334 |
335 | }
336 | glEnd();
337 | glDisable(GL_TEXTURE_2D);
338 | } break;
339 |
340 | InvalidDefaultCase;
341 | }
342 | if(RenderEntry->Scissor != NULL)
343 | glDisable(GL_SCISSOR_TEST);
344 | }
345 | }
346 |
--------------------------------------------------------------------------------
/code/GL_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #pragma comment (lib, "opengl32.lib")
4 | #include
5 |
6 | /*
7 | #define GL_X_GET_PROC_ADDRESS(name) void * name(const GLubyte * procName)
8 | typedef GL_X_GET_PROC_ADDRESS(gl_x_get_proc_address);
9 | GL_X_GET_PROC_ADDRESS(GLXGetProcAddressStub) { }
10 | global_variable gl_x_get_proc_address *GLXGetProcAddress_ = GLXGetProcAddressStub;
11 | #define glXGetProcAddress GLXGetProcAddress_
12 |
13 | #define GL_GEN_BUFFERS(name) void name(GLsizei n, GLuint * buffers)
14 | typedef GL_GEN_BUFFERS(gl_gen_buffers);
15 | GL_GEN_BUFFERS(GLGenBuffersStub) { }
16 | global_variable gl_gen_buffers *GLGenBuffers_ = GLGenBuffersStub;
17 | #define glGenBuffers GLGenBuffers_
18 |
19 | internal void
20 | LoadGLFunctions()
21 | {
22 | HMODULE GLLibrary = LoadLibraryA("opengl32.dll");
23 |
24 | if(GLLibrary)
25 | {
26 | glXGetProcAddress = (gl_x_get_proc_address *)GetProcAddress(GLLibrary, "glXGetProcAddress");
27 | if(glXGetProcAddress)
28 | {
29 | glGenBuffers = (gl_gen_buffers *)glXGetProcAddress((const GLubyte *)"glGenBuffers");
30 | }
31 | }
32 | }*/
--------------------------------------------------------------------------------
/code/GameBasics_TD.c:
--------------------------------------------------------------------------------
1 | #include "GameBasics_TD.h"
2 |
3 | inline b32
4 | IsActive(game_state *GS, mode_flags Mode)
5 | {
6 | b32 Result = (GS->ModeFlags&Mode) == Mode;
7 | return Result;
8 | }
9 |
10 | internal loaded_bitmap
11 | LoadImage_STB(u8 *Path)
12 | {
13 | loaded_bitmap Result = {};
14 |
15 | // TODO:: Small image is strange: https://github.com/nothings/stb/issues/161
16 | i32 BG_X, BG_Y, BG_N;
17 | Result.Pixels = (u32 *)stbi_load((const char *)Path, &BG_X, &BG_Y, &BG_N, 0);
18 | Result.Width = BG_X;
19 | Result.Height = BG_Y;
20 | if(Result.Pixels)
21 | {
22 | Result.WasLoaded = true;
23 | switch(BG_N)
24 | {
25 | case 3:
26 | {
27 | Result.ColorFormat = colorFormat_RGB;
28 | } break;
29 | case 4:
30 | {
31 | Result.ColorFormat = colorFormat_RGBA;
32 | } break;
33 |
34 | InvalidDefaultCase
35 | }
36 | }
37 |
38 | return Result;
39 | }
40 |
41 | internal loaded_bitmap
42 | LoadImage_STB(read_file_result Memory)
43 | {
44 | loaded_bitmap Result = {};
45 |
46 | read_file_result ImageTest = {};
47 | i32 BG_X, BG_Y, BG_N;
48 | Result.Pixels = (u32 *)stbi_load_from_memory(Memory.Data, Memory.Size, &BG_X, &BG_Y, &BG_N, 0);
49 | Result.Width = BG_X;
50 | Result.Height = BG_Y;
51 | if(Result.Pixels)
52 | {
53 | Result.WasLoaded = true;
54 | switch(BG_N)
55 | {
56 | case 3:
57 | {
58 | Result.ColorFormat = colorFormat_RGB;
59 | } break;
60 | case 4:
61 | {
62 | Result.ColorFormat = colorFormat_RGBA;
63 | } break;
64 |
65 | InvalidDefaultCase
66 | }
67 | }
68 |
69 | return Result;
70 | }
71 |
72 | inline void
73 | FreeImage_STB(loaded_bitmap Bitmap)
74 | {
75 | stbi_image_free(Bitmap.Pixels);
76 | }
77 |
78 |
79 | #if DEBUG_TD
80 |
81 | inline void
82 | InitTimers()
83 | {
84 | _debugTimerTable = HashTable(&GlobalGameState.FixArena, TIMER_MAX_COUNT);
85 | }
86 |
87 | inline void
88 | _StartTimer(u8 *Name)
89 | {
90 | timer *Timer = 0;
91 | if(AddToHashTable(&_debugTimerTable, Name, _debugTimerCount))
92 | {
93 | Assert(_debugTimerCount < TIMER_MAX_COUNT);
94 |
95 | Timer = _debugTimers + _debugTimerCount++;
96 | Timer->LastSnap = GetWallClock();
97 | Timer->Total = 0;
98 | }
99 | else
100 | {
101 | u32 ID;
102 | if(!GetFromHashTable(&_debugTimerTable, Name, ID)) Assert(false);
103 | Timer = _debugTimers + ID;
104 |
105 | if(Timer->Paused)
106 | {
107 | Timer->LastSnap = GetWallClock();
108 | }
109 | }
110 | Timer->Paused = false;
111 | }
112 |
113 | inline void
114 | _RestartTimer(u8 *Name)
115 | {
116 | Assert(_debugTimerCount < TIMER_MAX_COUNT);
117 |
118 | timer *Timer = 0;
119 | if(AddToHashTable(&_debugTimerTable, Name, _debugTimerCount))
120 | {
121 | Timer = _debugTimers + _debugTimerCount++;
122 | }
123 | else
124 | {
125 | u32 ID;
126 | if(!GetFromHashTable(&_debugTimerTable, Name, ID)) Assert(false);
127 | Timer = _debugTimers + ID;
128 | }
129 |
130 | Timer->LastSnap = GetWallClock();
131 | Timer->Total = 0;
132 | Timer->Paused = false;
133 | Timer->Count = 0;
134 | }
135 |
136 | inline void
137 | _PauseTimer(u8 *Name)
138 | {
139 | i64 NewSnap = GetWallClock();
140 |
141 | u32 ID;
142 | if(!GetFromHashTable(&_debugTimerTable, Name, ID)) Assert(false);
143 | timer *Timer = _debugTimers + ID;
144 |
145 | Timer->Paused = true;
146 | Timer->Total += NewSnap - Timer->LastSnap;
147 | }
148 |
149 | inline void
150 | _SnapTimer(u8 *Name)
151 | {
152 | i64 NewSnap = GetWallClock();
153 |
154 | u32 ID;
155 | if(!GetFromHashTable(&_debugTimerTable, Name, ID)) Assert(false);
156 | timer *Timer = _debugTimers + ID;
157 |
158 | if(!Timer->Paused) Timer->Total += NewSnap - Timer->LastSnap;
159 | else NewSnap = Timer->LastSnap;
160 | r32 CurrentSnap = GetSecondsElapsed(GlobalGameState.Time.PerfCountFrequency, Timer->LastSnap, NewSnap);
161 | r32 Total = ((r32)Timer->Total / (r32)GlobalGameState.Time.PerfCountFrequency);
162 |
163 | DebugLog(255, "%s Timer snap %i: %.8f, total: %.8f\n", Name, ++Timer->Count, CurrentSnap, Total);
164 | Timer->LastSnap = NewSnap;
165 | }
166 |
167 | #endif
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/code/GameBasics_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Renderer_TD.h"
3 | #include "ErrorHandling_TD.h"
4 | #include "Sound_Thread_TD.h"
5 | #include "Sound_Backend_TD.h"
6 | #include "Sound_Jobs.h"
7 | #include "Sound_Serialization.h"
8 | #include "Sound_Settings.h"
9 |
10 | enum mode_flags
11 | {
12 | mode_MusicPath = 1<<0,
13 | mode_StyleSettings = 1<<1,
14 | mode_Search = 1<<2,
15 | mode_PLRename = 1<<3,
16 | };
17 |
18 | enum cursor_state
19 | {
20 | cursorState_Arrow,
21 | cursorState_Drag,
22 | };
23 |
24 | struct game_state
25 | {
26 | i32 ModeFlags; // enum mode_flags
27 | string_c SettingsPath;
28 | string_c LibraryPath;
29 | string_c PlaylistPath;
30 | string_c FontPath;
31 |
32 | arena_allocator FixArena; // Never gets reset (except if a bucket is emptied again)
33 | arena_allocator ScratchArena; // Gets reset every frame.
34 |
35 | layout_definition Layout;
36 |
37 | input_info Input;
38 |
39 | serialization_settings Settings;
40 |
41 | // Time management
42 | time_management Time;
43 |
44 | renderer Renderer;
45 | music_info MusicInfo;
46 | mp3_info *MP3Info;
47 |
48 | drag_list DragableList;
49 | cursor_state CursorState;
50 |
51 | // Threading stuff
52 | arena_allocator SoundThreadArena;
53 | sound_thread_interface *SoundThreadInterface;
54 |
55 | arena_allocator JobThreadsArena;
56 | HANDLE JobHandles[THREAD_COUNT];
57 | job_thread_info JobInfos [THREAD_COUNT];
58 | circular_job_queue JobQueue;
59 |
60 | crawl_thread CrawlInfo;
61 | check_music_path CheckMusicPath;
62 |
63 | style_settings_window StyleSettings;
64 |
65 | user_error_text UserErrorText;
66 | thread_error_list ThreadErrorList;
67 | };
68 |
69 | internal loaded_bitmap LoadImage_STB(u8 *Path);
70 | internal loaded_bitmap LoadImage_STB(read_file_result Memory);
71 | inline void FreeImage_STB(loaded_bitmap Bitmap);
72 |
73 | inline b32 IsActive(game_state *GS, mode_flags Mode);
74 |
75 | #if DEBUG_TD
76 | struct timer
77 | {
78 | u32 Count;
79 | i64 LastSnap;
80 | i64 Total;
81 | b32 Paused;
82 | };
83 |
84 | #define TIMER_MAX_COUNT 200
85 | global_variable hash_table _debugTimerTable = {};
86 | global_variable timer _debugTimers[TIMER_MAX_COUNT] = {};
87 | global_variable u32 _debugTimerCount = 0;
88 |
89 | inline void InitTimers();
90 | inline void _StartTimer(u8 *Name);
91 | #define StartTimer(Name) _StartTimer((u8 *)(Name)) /* Starts a new timer, if it exists already, it gets unpaused. */
92 | inline void _RestartTimer(u8 *Name);
93 | #define RestartTimer(Name) _RestartTimer((u8 *)(Name)) /* Let's you restart a timer with the given name. */
94 | inline void _PauseTimer(u8 *Name);
95 | #define PauseTimer(Name) _PauseTimer((u8 *)(Name)) /* Stops the timer, can be unpaused with StartTimer. */
96 | inline void _SnapTimer(u8 *Name);
97 | #define SnapTimer(Name) _SnapTimer((u8 *)(Name)) /* Creates a snapshot and prints the time since last snapshot and total.*/
98 |
99 | #else
100 | #define InitTimers()
101 | #define StartTimer(n)
102 | #define RestartTimer(n)
103 | #define PauseTimer(n)
104 | #define SnapTimer(n)
105 | #endif
106 |
--------------------------------------------------------------------------------
/code/ImageToCArray_TD.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #define STB_IMAGE_IMPLEMENTATION
3 | #include "Libraries\\STB_Image.h"
4 |
5 | // TODO:: add basic huffman encoding for decoded?
6 |
7 | #include "Definitions_TD.h"
8 | #include "Math_TD.c"
9 | #include "Allocator_TD.c"
10 | #include "String_TD.h"
11 | #include "FileUtilities_TD.c"
12 |
13 | internal loaded_bitmap LoadImage_STB(read_file_result Memory);
14 |
15 | internal loaded_bitmap EncodeToSmallFormat(arena_allocator *Arena, loaded_bitmap Bitmap);
16 |
17 | i32
18 | main(i32 ArgC, char *ArgV[])
19 | {
20 | DebugPrint(250, "Start converting image...\n");
21 |
22 | if(ArgC < 3)
23 | {
24 | DebugPrint(255, "ERROR:: We need two arguments: \n> 1. is a file which lists all files to convert into a C-Array\n> 2. is the out-file\n> 3. (Optional) 'DoDecode' will decode the .png files before generating the arrays.\n");
25 | return 1;
26 | }
27 | b32 DoDecode = (ArgC > 3);
28 |
29 | arena_allocator Allocator = {};
30 | Allocator.Flags |= arenaFlags_IsTransient;
31 |
32 | string_c ListingPath = NewStaticStringCompound(ArgV[1]);
33 | string_c OutfilePath = NewStaticStringCompound(ArgV[2]);
34 | DebugPrint(255, "ImagePath: %s\n", ListingPath.S);
35 | DebugPrint(255, "OutfilePath: %s\n", OutfilePath.S);
36 | if(!WriteEntireFile(&Allocator, OutfilePath.S, 13, "#pragma once\n"))
37 | {
38 | DebugPrint(255, "ERROR:: Could not start writing into out-file.\n");
39 | return 1;
40 | }
41 |
42 |
43 | read_file_result Listing = {};
44 | if(!ReadEntireFile(&Allocator, &Listing, ListingPath.S))
45 | {
46 | DebugPrint(255, "ERROR:: Could not load list-file!\n");
47 | return 1;
48 | }
49 |
50 | u32 LineCount = Listing.Size > 0;
51 | u8 *Bytes = Listing.Data;
52 | For(Listing.Size)
53 | {
54 | if(*Bytes == '\n')
55 | {
56 | LineCount++;
57 | *Bytes = 0;
58 | }
59 | if(*Bytes == '\r') *Bytes = 0;
60 | ++Bytes;
61 | }
62 |
63 | For(LineCount)
64 | {
65 | read_file_result Image = {};
66 | if(!ReadEntireFile(&Allocator, &Image, Listing.Data))
67 | {
68 | DebugPrint(255, "ERROR:: Could not read file: %s\n", Listing.Data);
69 | return 1;
70 | }
71 | b32 DoingDecoding = false;
72 | i32 Width = 0, Height = 0;
73 | if(DoDecode)
74 | {
75 | u8 *Line = Listing.Data;
76 | u32 P = LastOccurrenceOfCharacterInString('.', Line, 0);
77 | Line += P + 1;
78 | if(Line[0] == 'p' && Line[1] == 'n' && Line[2] == 'g')
79 | {
80 | loaded_bitmap ImageMem = LoadImage_STB(Image);
81 |
82 | loaded_bitmap EncodedImage = EncodeToSmallFormat(&Allocator, ImageMem);
83 | Image.Size = EncodedImage.Pitch; //EncodedImage.Width*EncodedImage.Height*sizeof(u32);
84 | Image.Data = (u8 *)EncodedImage.Pixels;
85 | Width = EncodedImage.Width;
86 | Height = EncodedImage.Height;
87 | stbi_image_free(ImageMem.Pixels);
88 |
89 | DoingDecoding = true;
90 | }
91 | }
92 | DebugPrint(255, "...processing \"%s\"\n", Listing.Data);
93 |
94 | string_c ImageName = NewStringCompound(&Allocator, 255);
95 | AppendStringToCompound(&ImageName, Listing.Data);
96 | i32 SlashP = FindLastOccurrenceOfCharInStringCompound(&ImageName, '\\');
97 | if(SlashP < 0) SlashP = FindLastOccurrenceOfCharInStringCompound(&ImageName, '/');
98 | if(SlashP < 0) SlashP = 0;
99 | ImageName.S += SlashP+1;
100 | ImageName.Pos -= SlashP+1;
101 |
102 | i32 DotP = FindLastOccurrenceOfCharInStringCompound(&ImageName, '.');
103 | if(DotP >= 0) ImageName.Pos = DotP;
104 |
105 | string_c OutText = NewStringCompound(&Allocator, Image.Size*8 + 500); // Size*6 because of '0x00, ' chars from 1
106 |
107 | if(DoingDecoding)
108 | {
109 | AppendStringToCompound(&OutText, (u8 *)"global_variable u32 const ");
110 | AppendStringCompoundToCompound(&OutText, &ImageName);
111 | AppendStringToCompound(&OutText, (u8 *)"_Width = ");
112 | I32ToString(&OutText, Width);
113 |
114 | AppendStringToCompound(&OutText, (u8 *)";\nglobal_variable u32 const ");
115 | AppendStringCompoundToCompound(&OutText, &ImageName);
116 | AppendStringToCompound(&OutText, (u8 *)"_Height = ");
117 | I32ToString(&OutText, Height);
118 | }
119 | else
120 | {
121 | AppendStringToCompound(&OutText, (u8 *)"global_variable u32 const ");
122 | AppendStringCompoundToCompound(&OutText, &ImageName);
123 | AppendStringToCompound(&OutText, (u8 *)"_DataCount = ");
124 | I32ToString(&OutText, Image.Size);
125 | }
126 |
127 | AppendStringToCompound(&OutText, (u8 *)";\nglobal_variable u8 const ");
128 | AppendStringCompoundToCompound(&OutText, &ImageName);
129 | AppendStringToCompound(&OutText, (u8 *)"_Data[] = {");
130 |
131 | u8 *Pixel = Image.Data;
132 | For(Image.Size)
133 | {
134 | if(It%100 == 0) AppendCharToCompound(&OutText, '\n');
135 | u8 Q = *Pixel++;
136 | u8 Hex[] = { '0', 'x', ' ', ' ', 0};
137 | u32 RevCount = 3;
138 | For(2)
139 | {
140 | u8 R = Q%16;
141 | Q = Q/16;
142 |
143 | if(R < 10) R += 48;
144 | else R += 55;
145 | Hex[RevCount--] = R;
146 | }
147 |
148 | AppendStringToCompound(&OutText, Hex);
149 | AppendStringToCompound(&OutText, (u8 *)", ");
150 | }
151 | AppendStringToCompound(&OutText, (u8 *)"\n};\n\n\n\n");
152 |
153 | if(!AppendToFile(&Allocator, OutfilePath.S, OutText.Pos, OutText.S))
154 | {
155 | DebugPrint(255, "ERROR:: Could not write into out-file.\n");
156 | return 1;
157 | }
158 |
159 | if(It < LineCount-1)
160 | {
161 | while(*Listing.Data++ != 0) ;
162 | while(*Listing.Data == 0) Listing.Data++;
163 | }
164 | }
165 |
166 | DebugPrint(255, "SUCCESS:: Wrote binary data to %s\n", OutfilePath.S);
167 |
168 | return 0;
169 | }
170 |
171 | internal loaded_bitmap
172 | LoadImage_STB(read_file_result Memory)
173 | {
174 | loaded_bitmap Result = {};
175 |
176 | read_file_result ImageTest = {};
177 | i32 BG_X, BG_Y, BG_N;
178 | Result.Pixels = (u32 *)stbi_load_from_memory(Memory.Data, Memory.Size, &BG_X, &BG_Y, &BG_N, 0);
179 | Result.Width = BG_X;
180 | Result.Height = BG_Y;
181 | if(Result.Pixels)
182 | {
183 | Result.WasLoaded = true;
184 | switch(BG_N)
185 | {
186 | case 3:
187 | {
188 | Result.ColorFormat = colorFormat_RGB;
189 | } break;
190 | case 4:
191 | {
192 | Result.ColorFormat = colorFormat_RGBA;
193 | } break;
194 |
195 | InvalidDefaultCase
196 | }
197 | }
198 |
199 | return Result;
200 | }
201 |
202 | internal loaded_bitmap
203 | EncodeToSmallFormat(arena_allocator *Arena, loaded_bitmap Bitmap)
204 | {
205 | loaded_bitmap Result = Bitmap;
206 | u8 *Data = AllocateArray(Arena, Bitmap.Width*Bitmap.Height*sizeof(u32), u8);
207 | u8 *SavedData = Data;
208 |
209 | u32 It = 0;
210 | while(It < (Bitmap.Width*Bitmap.Height))
211 | {
212 | u8 Count = 0;
213 | u32 PrevPix = *Bitmap.Pixels;
214 | while(PrevPix == *Bitmap.Pixels)
215 | {
216 | ++Bitmap.Pixels;
217 | ++It;
218 | ++Count;
219 | if(Count == 255) break;
220 | }
221 |
222 | *Data++ = Count;
223 | u8 *TmpPix = (u8 *)(&PrevPix);
224 | For(4) *Data++ = *TmpPix++;
225 |
226 | Result.Pitch += 5; // Count the array fill.
227 | }
228 |
229 | Result.Pixels = (u32 *)SavedData;
230 |
231 | return Result;
232 | }
233 |
234 |
--------------------------------------------------------------------------------
/code/Input_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "Math_TD.h"
4 |
5 | // NOTE:: Defining and loading all xinput functions manually, for campaility reasons!
6 | #define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
7 | typedef X_INPUT_GET_STATE(x_input_get_state);
8 | X_INPUT_GET_STATE(XInputGetStateStub) { return 0; }
9 | global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;
10 | #define XInputGetState XInputGetState_
11 |
12 | #define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
13 | typedef X_INPUT_SET_STATE(x_input_set_state);
14 | X_INPUT_SET_STATE(XInputSetStateStub) { return 0; }
15 | global_variable x_input_set_state *XInputSetState_ = XInputSetStateStub;
16 | #define XInputSetState XInputSetState_
17 |
18 | // INPUT HANDLING
19 | enum key_code
20 | {
21 | KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I,
22 | KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
23 | KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
24 |
25 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
26 |
27 | KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
28 | KEY_ESCAPE, KEY_ENTER, KEY_SPACE, KEY_BACKSPACE,
29 | KEY_SHIFT_RIGHT, KEY_SHIFT_LEFT,
30 | KEY_CONTROL_RIGHT, KEY_CONTROL_LEFT,
31 | KEY_ALT_RIGHT, KEY_ALT_LEFT,
32 | KEY_LMB, KEY_RMB, KEY_MMB,
33 | KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
34 | // Sound buttons
35 | KEY_NEXT, KEY_PREVIOUS, KEY_STOP, KEY_PLAY_PAUSE, KEY_VOLUME_UP, KEY_VOLUME_DOWN, KEY_MUTE,
36 | KEY_PLUS, KEY_MINUS, KEY_ADD, KEY_SUBTRACT,
37 |
38 | KEY_CODE_COUNT // NOTE(Tim):: This must always be the last key_code!
39 | };
40 |
41 | enum key_change
42 | {
43 | NoChange,
44 | KeyDown,
45 | KeyUp,
46 | };
47 |
48 | #define MAX_CHAR_PER_FRAME 100
49 | #define MAX_HOTKEYS 10
50 | struct input_info
51 | {
52 | key_change KeyChange[KEY_CODE_COUNT];
53 | b32 Pressed[KEY_CODE_COUNT];
54 | i32 TapCount[KEY_CODE_COUNT];
55 |
56 | u8 Chars[MAX_CHAR_PER_FRAME];
57 | u32 CharCount;
58 |
59 | v2 MouseP;
60 | i32 WheelAmount;
61 | b32 _MouseMoved;
62 |
63 | key_code HotKeys[MAX_HOTKEYS];
64 | i32 _HotKeyCount;
65 | };
66 |
--------------------------------------------------------------------------------
/code/Renderer_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | struct rect_2D
4 | {
5 | v2 Min;
6 | v2 Max;
7 | };
8 | typedef rect_2D rect;
9 |
10 | struct rect_pe_2D
11 | {
12 | v2 Pos;
13 | v2 Extends;
14 | };
15 | typedef rect_pe_2D rect_pe;
16 |
17 | enum render_type
18 | {
19 | renderType_NONE,
20 | renderType_2DBitmap,
21 | renderType_2DRectangle,
22 | renderType_Text,
23 | };
24 |
25 | struct transform_2D
26 | {
27 | v2 Scale;
28 | v2 Translation;
29 |
30 | v2 RotationP; // TODO:: DELETE
31 | r32 Angle;
32 | };
33 |
34 | struct entry_id
35 | {
36 | struct render_entry *ID;
37 | u32 UID;
38 | };
39 |
40 | struct render_entry
41 | {
42 | entry_id *ID;
43 | render_type Type;
44 | b32 Render;
45 |
46 | // NOTE:: Vertice[0].z will be set to < -1 when marked for deletion.
47 | // It will then be deleted on the next render!
48 | v3 Vertice[4]; // Start bottom-left and goes clockwise
49 | v2 TexCoords[4];
50 | transform_2D Transform;
51 |
52 | enum fixed_to FixedTo;
53 |
54 | entry_id *Parent;
55 | entry_id *Scissor;
56 |
57 | v3 *Color;
58 | r32 Transparency;
59 |
60 | // render type specific stuff
61 | u32 TexID;
62 | struct render_text *Text; // NOTE:: Having the text not in the list is propably not the best for the cache...
63 |
64 | // TODO:: Cache the GLSpace data and us it in (isIn.. functions)
65 | };
66 |
67 | #define CHARACTERS_PER_TEXT_INFO 256u
68 | struct render_text
69 | {
70 | v2 CurrentP;
71 | entry_id *Base; // StartP is the position of base parent
72 | render_entry *RenderEntries; // These are not in the render list, only the base entry is.
73 | u32 Count;
74 | u32 MaxCount;
75 | v2 Extends;
76 |
77 | string_c Text;
78 | enum font_size_id FontSize;
79 | };
80 |
81 | enum axis
82 | {
83 | XAxis,
84 | YAxis,
85 | ZAxis
86 | };
87 |
88 | union dimensions
89 | {
90 | struct
91 | {
92 | i32 Width;
93 | i32 Height;
94 | };
95 | v2i Dim;
96 | i32 D[2];
97 | };
98 |
99 | struct window_info
100 | {
101 | HWND WindowHandle;
102 |
103 | dimensions CurrentDim;
104 | r32 CurrentAspect; // width/height
105 | r32 CurrentReverseAspect; // height/width
106 |
107 | dimensions FixedDim;
108 | r32 FixedAspect;
109 |
110 | b32 GotResized;
111 | };
112 |
113 | enum scale_axis
114 | {
115 | scaleAxis_None,
116 | scaleAxis_XY,
117 | scaleAxis_X,
118 | scaleAxis_Y,
119 | };
120 |
121 | enum fixed_to
122 | {
123 | fixedTo_None,
124 |
125 | fixedTo_BottomLeft,
126 | fixedTo_BottomRight,
127 | fixedTo_BottomCenter,
128 |
129 | fixedTo_TopLeft,
130 | fixedTo_TopRight,
131 | fixedTo_TopCenter,
132 |
133 | fixedTo_MiddleLeft,
134 | fixedTo_MiddleRight,
135 | fixedTo_MiddleCenter,
136 |
137 | // NOTE:: If the render_entry is fixed_to the screen _and_ has a parent,
138 | // it is always the parent translation used, instead of the fixed_to translation.
139 | // With the exception of the fixedTo_Original tags, where the corresponding
140 | // _original_ is the parent translation and the other axis is the fixed_to translation. TODO::Outdaten?
141 | fixedTo_FixXToGiven_YBottom,
142 | fixedTo_FixXToGiven_YCenter,
143 | fixedTo_FixXToGiven_YTop,
144 |
145 | fixedTo_FixYToGiven_XLeft,
146 | fixedTo_FixYToGiven_XCenter,
147 | fixedTo_FixYToGiven_XRight,
148 |
149 | fixedTo_FixXYToGiven,
150 |
151 | // These will only change the the given axis
152 | fixedTo_Bottom,
153 | fixedTo_MiddleY,
154 | fixedTo_Top,
155 |
156 | fixedTo_Right,
157 | fixedTo_CenterX,
158 | fixedTo_Left,
159 | };
160 |
161 | struct screen_transform_list
162 | {
163 | entry_id **Entries;
164 | v2 *FixToPosition; // Between 0-1
165 | v2 *OriginalPosition;
166 | v2 *OriginalScale;
167 | v2i *OriginalDim;
168 | fixed_to *DoTranslation;
169 | scale_axis *DoScale;
170 | u32 MaxCount;
171 | u32 Count;
172 |
173 | u32 OpenSlotCount;
174 | b32 *OpenSlots;
175 |
176 | struct renderer *Renderer;
177 | };
178 |
179 | #define START_RENDER_ENTRIES 12000
180 | struct render_entry_list
181 | {
182 | render_entry *Entries; // This array will be sorted, and changes everytime a new entry is added.
183 | u32 EntryCount;
184 | entry_id *IDs; // This has a fixed list. IDs will not be moved around.
185 | u32 IDCount;
186 |
187 | u32 MaxCount;
188 |
189 | u32 OpenSlotCount;
190 | b32 *OpenSlots;
191 |
192 | b32 _SortingNeeded;
193 | };
194 |
195 | #include "UI_TD.h"
196 |
197 | struct renderer
198 | {
199 | b32 Rerender;
200 | b32 Minimized;
201 |
202 | render_entry_list RenderEntryList;
203 | screen_transform_list TransformList;
204 |
205 | window_info Window;
206 |
207 | font_sizes FontSizes;
208 | font_atlas FontAtlas;
209 | button_group ButtonGroup;
210 |
211 | union color_palette *ColorPalette;
212 | v4 BackgroundColor;
213 | v3 DefaultEntryColor;
214 |
215 | loaded_bitmap ButtonBase;
216 | u32 ButtonBaseID;
217 | button_colors ButtonColors;
218 | u32 ButtonIconCount;
219 | };
220 | global_variable u32 GlobalUIDCounter = 0;
221 |
222 | inline v3 Color(u8 R, u8 G, u8 B);
223 |
224 | inline rect Rect(v2 Min, v2 Max);
225 | inline v2 GetCenter(rect Rect);
226 | inline v2 GetExtends(rect Rect);
227 | inline rect_pe RectToRectPE(rect Rect);
228 |
229 | inline void UpdateEntryList(render_entry_list *EntryList);
230 | internal void FixUpEntries(render_entry_list *EntryList);
231 | inline void Quicksort3(render_entry *Entries, i32 Count);
232 |
233 | internal entry_id *CreateRenderRect(render_entry_list *EntryList, rect Rect, r32 Depth, entry_id *Parent, v3 *Color);
234 | internal entry_id *CreateRenderRect(render_entry_list *EntryList, v2 Size, r32 Depth, v3 *Color, entry_id *Parent);
235 | internal entry_id *CreateRenderBitmap(render_entry_list *EntryList, rect Rect, r32 Depth, entry_id *Parent, loaded_bitmap Bitmap, v3 *DefaultColor);
236 | internal entry_id * CreateRenderBitmap(render_entry_list *EntryList, rect Rect, r32 Depth, entry_id *Parent, u32 BitmapID, v3 *DefaultColor);
237 | internal entry_id * CreateRenderBitmap(render_entry_list *EntryList, v2 Size, r32 Depth, entry_id *Parent, u32 BitmapID, v3 *DefaultColor);
238 | internal entry_id * CreateRenderBitmap(render_entry_list *EntryList, rect Rect, r32 Depth, entry_id *Parent, string_c *Path, v3 *DefaultColor);
239 | internal void RemoveRenderEntry(render_entry_list *EntryList, entry_id *EntryID);
240 |
241 | inline entry_id *CreateRenderRect(renderer *Renderer, rect Rect, r32 Depth, entry_id *Parent, v3 *Color);
242 | inline entry_id *CreateRenderRect(renderer *Renderer, v2 Size, r32 Depth, v3 *Color, entry_id *Parent = 0);
243 | inline entry_id *CreateRenderBitmap(renderer *Renderer, rect Rect, r32 Depth, entry_id *Parent, loaded_bitmap Bitmap);
244 | inline entry_id *CreateRenderBitmap(renderer *Renderer, rect Rect, r32 Depth, entry_id *Parent, u32 BitmapID);
245 | inline entry_id *CreateRenderBitmap(renderer *Renderer, v2 Size, r32 Depth, entry_id *Parent, u32 BitmapID);
246 | inline entry_id *CreateRenderBitmap(renderer *Renderer, rect Rect, r32 Depth, entry_id *Parent, string_c *Path);
247 | inline void RemoveRenderEntry(renderer *Renderer, entry_id *EntryID);
248 |
249 | internal entry_id *Copy(renderer *Renderer, entry_id *Entry);
250 |
251 | inline void SetTransparency(entry_id *Entry, r32 T);
252 | inline void ApplyTransform(render_entry *Entry, v3 *Result);
253 |
254 | inline v2 GetSize(entry_id *Entry); // Get size in pixel
255 | inline void SetSize(entry_id *Entry, v2 SizeInPixel); // Set Transform
256 | inline v2 GetScale(entry_id *Entry); // Get Transform scale (multiplier, normally 1)
257 | inline void SetScale(entry_id *Entry, v2 Scale); // Set Transform
258 | inline v2 GetExtends(v3 *RenderRectVertice); // Get Raw
259 | inline v2 GetExtends(entry_id *Entry); // Get Raw
260 | inline rect GetRect(entry_id *Entry);
261 |
262 | inline v2 GetPosition(entry_id *Entry); // Get Raw + global Transform
263 | inline void SetPosition(entry_id *Entry, v2 Position); // Set Global Transform
264 | inline void SetPositionX(entry_id *Entry, r32 X);
265 | inline void SetPositionY(entry_id *Entry, r32 Y);
266 | inline v2 GetLocalPosition(entry_id *Entry); // Get Raw + Transform
267 | inline void SetLocalPosition(entry_id *Entry, v2 Position); // Set Transform
268 | inline void SetLocalPositionY(entry_id *Entry, r32 NewY);
269 | inline void SetLocalPositionX(entry_id *Entry, r32 NewX);
270 | inline void Translate(entry_id *Entry, v2 TranslationOffset); // Move Transform
271 | inline void SetScissor(entry_id *Entry, entry_id *ScissorID);
272 |
273 | inline void SetActive(entry_id *Entry, b32 Activate);
274 | inline b32 IsActive(entry_id *Entry);
275 | inline void SetColor(entry_id *Entry, v3 *Color);
276 | inline v3 GetColor(entry_id *Entry);
277 | inline v3 *GetColorPtr(entry_id *Entry);
278 | inline void SetParent(entry_id *Entry, entry_id *Parent);
279 | inline entry_id *GetParent(entry_id *Entry);
280 | inline r32 GetDepth(entry_id *Entry);
281 | inline void SetDepth(entry_id *Entry, r32 Depth);
282 |
283 | inline r32 GetDistance(entry_id *E1, entry_id *E2);
284 |
285 | // Helper for entry relations
286 | inline rect ExtractScreenRect(entry_id *Entry);
287 | inline r32 DistanceToRectEdge(entry_id *Entry, v2 Point);
288 | inline b32 IsInRect(rect_2D Rect, v2 P);
289 | inline b32 IsInRect(entry_id *Entry, v2 P);
290 | inline b32 IsInRect(rect Rect1, rect Rect2);
291 | inline b32 IsInRect(rect Rect1, entry_id *Entry);
292 | inline b32 IsInRect(entry_id *Entry1, entry_id *Entry2);
293 |
294 | inline b32 IsIntersectingRect(entry_id *E1, entry_id *E2);
295 | inline b32 IsLowerThanRect(entry_id *Entry, entry_id *Rect);
296 | inline b32 IsHigherThanRect(entry_id *Entry, entry_id *Rect);
297 | inline b32 IsTopShowing(entry_id *Entry, entry_id *Rect);
298 | inline b32 IsBottomShowing(entry_id *Entry, entry_id *Rect);
299 | inline b32 IsIntersectingRectButTopShowing(entry_id *Entry, entry_id *Rect);
300 | inline b32 IsIntersectingRectButBottomShowing(entry_id *Entry, entry_id *Rect);
301 |
302 | inline r32 HeightBetweenRects(entry_id *RectA, entry_id *RectB);
303 | inline r32 WidthBetweenRects(entry_id *RectA, entry_id *RectB);
304 | inline r32 CenterXBetweenRects(entry_id *LeftRect, entry_id *RightRect);
305 | inline r32 CenterYBetweenRects(entry_id *BottomRect, entry_id *TopRect);
306 |
307 | inline v2 ClampToRect(v2 Pos, entry_id *Entry);
308 | inline v2 ClampToRect(v2 Pos, rect_2D Rect);
309 |
310 | // Auto screen transform stuff
311 | inline screen_transform_list CreateScreenTransformList(renderer *Renderer, arena_allocator *Arena, u32 Size = 128);
312 | inline void RemoveFromTransformList(screen_transform_list *List, entry_id *Entry);
313 | inline u32 TranslateWithScreen(screen_transform_list *List, entry_id *Entry, fixed_to FixedTo, r32 FixToPosition = 0);
314 | inline u32 TranslateWithScreen(screen_transform_list *List, entry_id *Entry, fixed_to FixedTo, v2 FixToPosition);
315 | inline u32 ScaleWithScreen(screen_transform_list *List, entry_id *Entry, scale_axis ScaleAxis);
316 | inline u32 TransformWithScreen(screen_transform_list *List, entry_id *Entry,
317 | fixed_to FixedTo, scale_axis ScaleAxis, r32 FixToPosition = 0);
318 | inline u32 TransformWithScreen(screen_transform_list *List, entry_id *Entry,
319 | fixed_to FixedTo, scale_axis ScaleAxis, v2 FixToPosition);
320 | inline void UpdateFixToPosition(screen_transform_list *List, u32 ID, r32 NewFixToPosition);
321 | inline void UpdateFixToPosition(screen_transform_list *List, entry_id *Entry, r32 NewFixToPosition);
322 | inline void UpdateFixToPosition(screen_transform_list *List, u32 ID, v2 NewFixToPosition);
323 | inline void UpdateFixToPosition(screen_transform_list *List, entry_id *Entry, v2 NewFixToPosition);
324 | inline void UpdateOriginalPosition(screen_transform_list *List, u32 ID, v2 NewOriginalPosition);
325 | inline void UpdateOriginalPosition(screen_transform_list *List, entry_id *Entry, v2 NewOriginalPosition);
326 | inline void UpdateOriginalPosition(screen_transform_list *List, entry_id *Entry); // Uses the current translation.
327 | inline void UpdateOriginalTransform(screen_transform_list *List, entry_id *Entry); // Uses the current translation.
328 | internal void PerformScreenTransform(renderer *Renderer);
329 |
330 | // Render Text stuff
331 | inline v2 GetPosition(render_text *Text);
332 | inline void SetPosition(render_text *Info, v2 P);
333 | inline void SetPositionX(render_text *Info, r32 X);
334 | inline void SetPositionY(render_text *Info, r32 Y);
335 | inline void SetLocalPosition(render_text *Text, v2 P);
336 | inline void SetActive(render_text *Text, b32 Render);
337 | inline void SetColor(render_text *Text, v3 *Color);
338 | inline void Translate(render_text *Info, v2 Translation);
339 | inline v2 GetPosition(render_text *Info, u32 LetterID);
340 | inline void RemoveRenderText(renderer *Renderer, render_text *Text);
341 | inline void SetTransparency(render_text *Text, r32 T);
342 | inline void CenterText(render_text *Text);
343 | inline v2 GetSize(render_text *Text);
344 | inline v2 GetExtends(render_text *Text);
345 | inline void SetScissor(render_text *Text, entry_id *ScissorID);
--------------------------------------------------------------------------------
/code/Sound_Backend_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | // IDEAS::
3 | // - think about making song display MDs next to each other (genre in the artist row) an if
4 | // it goes over the edge, drop it into the new line
5 | // - album image as panel background
6 | // - lyrics window when file exists?
7 | // - think about selecting all entries that are visible when pressing enter during search
8 | // - if song selected, pressing the big play should start it?
9 | // - Think about if search in song column should work differently, or search through Title/artist/album
10 | // - loading metadata could be "interactive" and all songs already loaded be available already?
11 | // - During metadata loading -> just show everything that is already crawled, live.
12 | // - add some form of highlighting on the other columns, based on what songs are visible rn.
13 | // - If app is minimized, render something different to show what is playing when hovering the task-bar preview.
14 | // - Have the UpNext list as a 'playlist' that you can switch to and see all songs listed like normal playlist. Maybe have it only appear once you have a song in it.
15 | // - Add a 'jump to playing' button?
16 |
17 | // List of Tags to search for in the code:
18 | // - TODO:: , Stuff where I want to go and make something better later/clean it up/make it more save/etc.
19 | // - @HardLimit, is a label where I set a hard limit, the user could exceed and needs to be dealt with.
20 | // - @Slow , is a label where I think it's unnecessary slow.
21 | // - @Layout , where the Layout struct should hold the magic values.
22 | //
23 |
24 | // TESTING::
25 | // - generate huge amount of fake mp3 files and test with those!
26 | // - still hardcapped at 10k mp3 files - Fixed, TEST?!
27 |
28 | // CODE CLEANUPS::
29 | // - go through and remove all unnecassary gamestate/renderer/info juggling
30 | // - Everywhere where both display_column and sortin_info is given, just give display_column, as it has a pointer to sort.
31 | // - remove all GlobalGameState references from UI.c
32 | // - Cleanup all the StringCompound procedures... Their names are sooo stupidly long..
33 | // - Sort out depth everywhere in the application
34 | // - Add a on_screen_id for tha visuals, to have typechecking on it! (like displayable_id, etc.).
35 | // - Replace for-loop copies with MemoryCopy
36 | // - Fill displayables, when album is selected, is very slow. Because we don't know which Artist has the album
37 | // which we are looking at. If we would also cache this information in CreateMusicSortingInfo this wouldn't be a problem.
38 | // - Due to the last changes, especially because of the playlist stuff, things start to get slow when we handle
39 | // Selected/Displayable arrays. Is it time to think about a bit better solution than just blank ID's? Or should
40 | // we do smaller stuff (like switch selected array from playlist_ids to displayable_ids) that help the performance.
41 | // Another 'small' thing would be to cache more information in CreateMusicSortingInfo for usage in FillDisplayables.
42 | // - IDEAS: On FillDisplayable generate more information, like ???
43 | // - @FixCreateSortingInfo, is tag for stuff I can look at as well, which is not working properly.
44 | // - Introduce explicit casting macro like cast(type)
45 |
46 | // NICE TO HAVE TODO'S::
47 | // - Switch openGL to directX?
48 | // - stop always jumping the column to the start on i.e. search end
49 | // - UpNextList is limited to 200
50 | // - InitialDisplayable count for playlist is capped to 250, should be expandable.
51 |
52 | // TODO'S::
53 | // - redraw only when necessary!
54 | // - stop rendering when no user input and no song is playing
55 | // - If a render text needs to switch fonts insider their own text, it should restart with that new font for consistency?
56 | // - Or check beforehand and then start with the other font.
57 | // - Print user error when save files could not be correctly loaded.
58 | // - PlayNext should have reset or remove and maybe be overall more controllable.
59 | // - PLAYLIST:
60 | // - make dragged song slot small like the other columns, after it is ripped off?
61 | // - Should 'Rename' button still work for 'All' as it isn't really required to be called that.
62 | // - Add drag&drop for sorting playlist slots?
63 | // - Think about job'ifying playlist-loading. The only 'problem' is the _in what playlist was the app closed_.
64 | // - Add unregister hotkey and add mute only on ctrl press, or something similar.
65 | // - Change ActiveSong to only a border or similar.
66 |
67 | // BUGS::
68 | // - fix issues regarding handmade network comment
69 | // - Find issue with drawing order bug. This one I have no clue right now...
70 | // - On large files when preload is not enough, it _seldom_crashes when using the already decoded data...
71 | // - MP3 V0 crashes?
72 | // - selecting and deselecting stuff (in combination with search) is buggy.
73 | // - Fix stutter on first play of song.
74 | // - Switching audio sources freezes playing of music entirely. On play 1 sec gets advanced...
75 | // - Crash when adding songs and then searching for them?
76 | // - Random text behind lower left corner. Find it! Found it?
77 | // - Position font sliders when resizing medium font.
78 | // - Columns still sometimes scroll up when resizing.
79 |
80 | #include "Sound_UI_TD.h"
81 |
82 | struct column_info
83 | {
84 | struct renderer *Renderer;
85 | struct music_display_info *DisplayInfo;
86 | struct music_info *MusicInfo;
87 | struct display_column *DisplayColumn;
88 | struct playlist_column *PlaylistColumn;
89 | };
90 |
91 | enum column_type // Is used to index arrays!
92 | {
93 | columnType_Genre = 0,
94 | columnType_Artist,
95 | columnType_Album,
96 | columnType_Song,
97 | columnType_Playlists,
98 | columnType_None,
99 | };
100 |
101 | enum play_loop
102 | {
103 | playLoop_NoLoop,
104 | playLoop_Loop,
105 | playLoop_Repeat
106 | };
107 |
108 | struct song_sort_info
109 | {
110 | u32 GenreBatchID;
111 | u32 ArtistBatchID;
112 | u32 AlbumBatchID;
113 | };
114 |
115 | #define PLAYLIST_MAX_NAME_LENGTH 100
116 | struct sort_batch
117 | {
118 | // These arrays of arrays contain the id for the other columns respectively.
119 | // Example for ArtistSortBatch: Band AC/DC is the first entry in Names, index 0.
120 | // The genre array with index 0 contains all genres which AC/DC had in their
121 | // metadata (i.e. heavy metal). The Artist array is empty, as the sort_batch
122 | // itself is for artists. Album contains all of their albums at index 0 and
123 | // finally, Song contains all songs. The entries in these arrays are all indexes
124 | // for the corresponding other batch. Genre contains indexes to the "Names" field
125 | // in the Genre sort_batch, and so forth.
126 | array_batch_id *Genre;
127 | array_batch_id *Artist;
128 | array_batch_id *Album;
129 | array_playlist_id *Song;
130 |
131 | string_c *Names; // ::BATCH_ID
132 | u32 BatchCount;
133 | u32 MaxBatches;
134 | };
135 |
136 | struct playlist_column
137 | {
138 | column_type Type;
139 | array_playlist_id Selected; // stores playlistIds for song column and sortBatchIDs for the rest!
140 | array_playlist_id Displayable; // ::DISPLAYABLE_ID, stores _PlaylistIDs_ for song column and sortBatchIDs for the rest!
141 |
142 | union {
143 | sort_batch Batch; // Used for Genre, Artist, Album, Playlists column_types.
144 | array_file_id FileIDs; // ::FILE_ID Used for Song column_type/Acces this with any playlist_id to get to mp3_file_info.
145 | };
146 | };
147 |
148 | inline struct mp3_metadata *GetMetadata(playlist_column *SongColumn, mp3_file_info *FileInfo, displayable_id ID);
149 | inline struct mp3_metadata *GetMetadata(playlist_column *SongColumn, mp3_file_info *FileInfo, playlist_id ID);
150 | inline string_c * GetSongFileName(playlist_column *SongColumn, mp3_file_info *FileInfo, playlist_id FileID);
151 |
152 | struct playlist_info
153 | {
154 | union {
155 | struct {
156 | playlist_column Genre;
157 | playlist_column Artist;
158 | playlist_column Album;
159 | playlist_column Song;
160 | // That the playlist information is part of playlist_info is hacky,
161 | // but it allows using all the display column stuff, which we want.
162 | // The biggest drawback for now is, that each new playlist has a
163 | // _copy_ of this Playlists, which needs to be the same for all.
164 | // That means we need to keep all playlists in sync. with each other,
165 | // which is only keeping the .Counts updated, as all memory pointers
166 | // point to the same location (so it is not as bad).
167 | // This is done with the procedure "SyncPlaylists_playlist_column".
168 | playlist_column Playlists;
169 | };
170 | playlist_column Columns[5];
171 | };
172 | u64 ShuffleSeed;
173 | b32 IsShuffled;
174 | play_loop Looping;
175 |
176 | string_c Filename_;
177 | u64 FileCreationDate; // Used for checking if we have a name duplicate on saving the PL.
178 | };
179 | internal playlist_info *CreateEmptyPlaylist(arena_allocator *Arena, music_info *MusicInfo, i32 SongIDCount = -1, i32 GenreBatchCount = -1, i32 ArtistBatchCount = -1, i32 AlbumBatchCount = -1);
180 | void SyncPlaylists_playlist_column(music_info *MusicInfo);
181 |
182 | struct playlist_array
183 | {
184 | // The ID for this List is the same for Names in sort_batch it is also called
185 | // playlist ID, because it represents that as well.
186 | // First entry is always the 'All' playlist.
187 | playlist_info *List;
188 | u32 Count;
189 | u32 MaxCount;
190 | };
191 |
192 | struct playing_song
193 | {
194 | displayable_id DisplayableID;
195 | playlist_id PlaylistID;
196 | i32 DecodeID;
197 |
198 | b32 PlayUpNext; // should only be set in SetNextSong/and OnSongPlayPressed
199 | };
200 |
201 | struct music_info
202 | {
203 | b32 IsPlaying;
204 | r32 MuteVolume; // If -1 then not muted.
205 |
206 | array_playlist_id UpNextList;
207 |
208 | playlist_info *Playlist_; // Actual playlist. This can be switched out.
209 | playlist_array Playlists;
210 |
211 | music_display_info DisplayInfo;
212 |
213 | playing_song PlayingSong;
214 | };
215 |
216 | struct scroll_load_info
217 | {
218 | r32 dTime;
219 | r32 WaitTime;
220 | b32 LoadFinished;
221 | };
222 |
223 | #define MAX_MP3_INFO_COUNT 1000
224 | #define MAX_MP3_INFO_STEP 1000
225 | #define MAX_MP3_DECODE_COUNT 50
226 | #define DECODE_PRELOAD_SECONDS 5
227 |
228 | enum metadata_flags
229 | {
230 | metadata_Title = 1<<0,
231 | metadata_Artist = 1<<1,
232 | metadata_Album = 1<<2,
233 | metadata_Genre = 1<<3,
234 | metadata_Track = 1<<4,
235 | metadata_Year = 1<<5,
236 | metadata_Duration = 1<<6,
237 | };
238 |
239 | struct mp3_metadata
240 | {
241 | string_c Title;
242 | string_c Artist;
243 | string_c Album;
244 | string_c Genre;
245 | u32 Track;
246 | string_c TrackString;
247 | u32 Year;
248 | string_c YearString;
249 | u32 Duration;
250 | i32 FoundFlags;
251 | };
252 |
253 | struct mp3_file_info //::MAPPED FILE_ID
254 | {
255 | string_c *FileNames_;
256 | string_c *SubPath;
257 | mp3_metadata *Metadata;
258 | // NoHash:: u32 *Hashes; // Hashes for specific file identification.
259 | u32 Count_;
260 | u32 MaxCount_;
261 | };
262 |
263 | struct playing_decoded
264 | {
265 | mp3dec_file_info_t Data;
266 | i32 DecodeID;
267 | b32 volatile CurrentlyDecoding;
268 | };
269 |
270 | struct mp3_decode_info
271 | {
272 | playing_decoded PlayingDecoded;
273 | b32 volatile CancelDecoding; // Exclusively written in main thread.
274 |
275 | mp3dec_file_info_t DecodedData[MAX_MP3_DECODE_COUNT];
276 | array_file_id FileIDs; // size: MAX_MP3_DECODE_COUNT
277 | u32 Count;
278 |
279 | b32 volatile CurrentlyDecoding[MAX_MP3_DECODE_COUNT];
280 | array_u32 LastTouched; // size: MAX_MP3_DECODE_COUNT
281 | u32 TouchCount;
282 | };
283 |
284 | struct mp3_info
285 | {
286 | string_c FolderPath;
287 | mp3_file_info FileInfo;
288 | mp3_decode_info DecodeInfo;
289 | music_info *MusicInfo;
290 | };
291 |
292 |
293 | internal void ChangeSong(game_state *GameState, playing_song *Song);
294 |
295 | inline displayable_id PlaylistIDToColumnDisplayID(music_info *MusicInfo, display_column *DisplayColumn, playlist_id PlaylistID);
296 | internal b32 IsHigherInAlphabet(i32 T1, i32 T2, void *Data);
297 | internal u32 ExtractMetadataSize(arena_allocator *Arena, string_c *CompletePath);
298 |
299 | internal void CreatePlaylistsSortingInfo(playlist_column *Playlists);
300 | internal void SwitchPlaylistFromDisplayID(display_column *DisplayColumn, u32 ColumnDisplayID);
301 | internal void ShufflePlaylist(playlist_info *Playlist, b32 UsePrevShuffle);
302 |
--------------------------------------------------------------------------------
/code/Sound_Dragging.h:
--------------------------------------------------------------------------------
1 | /* date = November 14th 2021 9:48 am */
2 | #ifndef _SOUND__DRAGGING_H
3 | #define _SOUND__DRAGGING_H
4 |
5 | struct edge_chain
6 | {
7 | // These arrays are a list of consecutive edges
8 | // that can be dragged and should be pushed by
9 | // each other. For now we have only max 3, so
10 | // that is the limit. These _need_ to have at
11 | // least a length of 1 -as the bordering edge-
12 | // where the dragged edge has its limit.
13 | #define EDGE_CHAIN_MAX_COUNT 4
14 | entry_id *Edges[EDGE_CHAIN_MAX_COUNT];
15 | r32 Offsets[EDGE_CHAIN_MAX_COUNT];
16 | r32 *XPercent[EDGE_CHAIN_MAX_COUNT-1];
17 | u32 Count;
18 | };
19 | struct column_edge_drag
20 | {
21 | entry_id *Edge;
22 | edge_chain LeftEdgeChain;
23 | edge_chain RightEdgeChain;
24 | r32 XPercent;
25 |
26 | struct music_info *MusicInfo;
27 | };
28 |
29 | internal void CreateColumnDragEdges(game_state *GS, r32 MinY, r32 MaxY,
30 | r32 PlaylistGenreX,
31 | r32 GenreArtistX,
32 | r32 ArtistAlbumX,
33 | r32 AlbumSongX);
34 | internal void OnDisplayColumnEdgeDrag(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
35 |
36 |
37 | struct drag_slider_data
38 | {
39 | struct music_info *MusicInfo;
40 | struct display_column *DisplayColumn;
41 | };
42 |
43 | internal void OnVerticalSliderDrag(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
44 | internal void OnHorizontalSliderDrag(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
45 | internal void OnSongDragEnd(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
46 | inline void UpdateVerticalSliders(music_info *MusicInfo);
47 | inline void UpdateHorizontalSliders(music_info *MusicInfo);
48 | inline void UpdateColumnVerticalSliderPosition(display_column *DisplayColumn, u32 DisplayableCount);
49 |
50 |
51 | struct timeline_slider_drag
52 | {
53 | game_state *GameState;
54 | b32 PausedForDragging;
55 | };
56 |
57 | internal void OnTimelineDragStart(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
58 | internal void OnTimelineDrag(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
59 | internal void OnTimelineDragEnd(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
60 |
61 | internal void ChangeVolume(game_state *GameState, r32 NewVolume);
62 | internal void OnVolumeDrag(renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
63 |
64 | // Drag&Drop ******************
65 |
66 | struct drag_drop_slot
67 | {
68 | displayable_id SlotID;
69 | v2 SlotStartP;
70 | entry_id *DragSlot;
71 | entry_id *Border;
72 | render_text SlotText;
73 | r32 TextOverhang;
74 | v2 GrabOffset;
75 | u32 DistToBaseSlot;
76 | };
77 |
78 | #define MAX_DRAG_SLOT_VISUALS 7u
79 | struct drag_drop
80 | {
81 | b32 Dragging;
82 | enum column_type Type;
83 | v2 StartMouseP;
84 | drag_drop_slot Slots[MAX_DRAG_SLOT_VISUALS];
85 | u32 SlotCount = 0;
86 | r32 TransparencyFalloff = 0.3f;
87 | b32 DragsSelected = false;
88 |
89 | i32 AnimDir = 1;
90 | r32 dAnim = 0;
91 | v2 ShakeDir;
92 |
93 | r32 ShakeThresholdDistanceDivisor = 5.0;
94 | r32 ShakeThreshold; // Depends on the distance to playlist column.
95 | r32 ShakeMaxRadius = 3.0f;
96 | r32 ShakeMaxAnimTime = 0.01f;
97 | r32 MaxTransparency = 0.95f;
98 |
99 | b32 ShakeTransition = false;
100 | v2 Velocity;
101 |
102 | // Drop Info
103 | i32 CurHoverID = -1;
104 | v3 *CurOriginalColor;
105 |
106 | // Drop delete info
107 | v3 RemoveColor;
108 | v3 *OriginalAllColor = NULL;
109 | render_text *AllRenderText = NULL;
110 | };
111 |
112 | struct select_array
113 | {
114 | select_id *SID;
115 | displayable_id *DID;
116 | playlist_id *PID;
117 | u32 Count;
118 | };
119 |
120 | struct select_pair
121 | {
122 | displayable_id DID;
123 | playlist_id PID;
124 | };
125 |
126 |
127 | #endif //_SOUND__DRAGGING_H
128 |
--------------------------------------------------------------------------------
/code/Sound_General_TD.c:
--------------------------------------------------------------------------------
1 | #include "Sound_General_TD.h"
2 |
3 | /*
4 | // CRC32 - Copy-Pasted from DearImGui.
5 | static const u32 GCrc32LookupTable[256] =
6 | {
7 | 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
8 | 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
9 | 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
10 | 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
11 | 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
12 | 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
13 | 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
14 | 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
15 | 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
16 | 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
17 | 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
18 | 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
19 | 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
20 | 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
21 | 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
22 | 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
23 | };
24 |
25 | // Known size hash
26 | internal u32
27 | ImHashData(void* Data, u32 Size, u32 Seed)
28 | {
29 | u32 crc = ~Seed;
30 | u8 *data = (u8 *)Data;
31 | const u32 *crc32_lut = GCrc32LookupTable;
32 | while (Size-- != 0)
33 | crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
34 | return ~crc;
35 | }
36 |
37 | inline song_hash_table
38 | CreateSongTable(arena_allocator *Arena, u32 Size)
39 | {
40 | song_hash_table Result;
41 | Result.Table = AllocateArray(Arena, Size, song_table_entry);
42 | Result.TableSize = Size;
43 | Result.Count = 0;
44 | return Result;
45 | }
46 |
47 | inline void
48 | DestroySongTable(song_hash_table *HashTable)
49 | {
50 | FreeMemory(HashTable->CreationArena, HashTable->Table);
51 | }
52 | */
--------------------------------------------------------------------------------
/code/Sound_General_TD.h:
--------------------------------------------------------------------------------
1 | /* date = September 23rd 2020 9:18 am */
2 | #ifndef _SOUND__GENERAL__T_D_H
3 | #define _SOUND__GENERAL__T_D_H
4 |
5 | struct file_id { i32 ID; }; // ::FILE_ID
6 | struct playlist_id { i32 ID; }; // ::PLAYLIST_ID
7 | typedef playlist_id batch_id; // ::BATCH_ID
8 | struct displayable_id { i32 ID; }; // ::DISPLAYABLE_ID
9 | typedef displayable_id select_id;
10 | typedef displayable_id decode_id;
11 |
12 | struct array_file_id { array_u32 A; };
13 | struct array_playlist_id { array_u32 A; };
14 | typedef array_playlist_id array_batch_id;
15 |
16 | // FileID Array stuff
17 | inline file_id Get(array_file_id *A, decode_id ID) { return {(i32)Get(&A->A, ID.ID)}; }
18 | inline file_id Get(array_file_id *A, playlist_id ID) { return {(i32)Get(&A->A, ID.ID)}; }
19 | inline void Push(array_file_id *Array, file_id ID) { Push(&Array->A, ID.ID); }
20 | inline void Copy(array_file_id *A1, array_file_id *A2) { Copy(&A1->A, &A2->A); }
21 | inline b32 Find(array_file_id *Array, file_id Item, u32 *Result) { return Find(&Array->A, Item.ID, Result); }
22 | inline b32 StackFind(array_file_id *A, file_id Item, i32 *Result) { return StackFind(&A->A, Item.ID, (u32 *)Result); }
23 | inline void Put(array_file_id *Array, displayable_id ID, file_id FileID) { Put(&Array->A, ID.ID, FileID.ID); }
24 | inline void AppendArray(array_file_id *A1, array_file_id *A2) { AppendArray(&A1->A, &A2->A); }
25 | inline void MergeArrays(array_file_id *A1, array_file_id *A2) { MergeArrays(&A1->A, &A2->A); }
26 | inline void PushIfNotExist(array_file_id *Array, file_id ID) { PushIfNotExist(&Array->A, ID.ID); }
27 |
28 |
29 | // FileID/BatchID stuff
30 | inline file_id NewFileID(i32 ID) { return {ID}; }
31 | inline batch_id NewBatchID(i32 ID) { return {ID}; }
32 | inline b32 operator< (file_id ID1, file_id ID2) { return ID1.ID < ID2.ID; }
33 | inline b32 operator< (file_id ID1, i32 ID2) { return ID1.ID < ID2; }
34 | inline b32 operator<=(file_id ID1, file_id ID2) { return ID1.ID <= ID2.ID; }
35 | inline b32 operator<=(file_id ID1, i32 ID2) { return ID1.ID <= ID2; }
36 | inline b32 operator> (file_id ID1, file_id ID2) { return ID1.ID > ID2.ID; }
37 | inline b32 operator> (file_id ID1, i32 ID2) { return ID1.ID > ID2; }
38 | inline b32 operator>=(file_id ID1, file_id ID2) { return ID1.ID >= ID2.ID; }
39 | inline b32 operator>=(file_id ID1, i32 ID2) { return ID1.ID >= ID2; }
40 | inline b32 operator==(file_id ID1, file_id ID2) { return ID1.ID == ID2.ID; }
41 | inline b32 operator==(file_id ID1, i32 ID2) { return ID1.ID == ID2; }
42 | inline b32 operator!=(file_id ID1, file_id ID2) { return ID1.ID != ID2.ID; }
43 | inline b32 operator!=(file_id ID1, i32 ID2) { return ID1.ID != ID2; }
44 |
45 | // DisplayableID stuff
46 | inline displayable_id NewDisplayableID(i32 ID) { return {ID}; }
47 | inline b32 operator< (displayable_id ID1, displayable_id ID2) { return ID1.ID < ID2.ID; }
48 | inline b32 operator< (displayable_id ID1, i32 ID2) { return ID1.ID < ID2; }
49 | inline b32 operator<=(displayable_id ID1, displayable_id ID2) { return ID1.ID <= ID2.ID; }
50 | inline b32 operator<=(displayable_id ID1, i32 ID2) { return ID1.ID <= ID2; }
51 | inline b32 operator> (displayable_id ID1, displayable_id ID2) { return ID1.ID > ID2.ID; }
52 | inline b32 operator> (displayable_id ID1, i32 ID2) { return ID1.ID > ID2; }
53 | inline b32 operator>=(displayable_id ID1, displayable_id ID2) { return ID1.ID >= ID2.ID; }
54 | inline b32 operator>=(displayable_id ID1, i32 ID2) { return ID1.ID >= ID2; }
55 | inline b32 operator==(displayable_id ID1, displayable_id ID2) { return ID1.ID == ID2.ID; }
56 | inline b32 operator==(displayable_id ID1, i32 ID2) { return ID1.ID == ID2; }
57 | inline b32 operator!=(displayable_id ID1, displayable_id ID2) { return ID1.ID != ID2.ID; }
58 | inline b32 operator!=(displayable_id ID1, i32 ID2) { return ID1.ID != ID2; }
59 |
60 | // PlaylistID stuff
61 | inline playlist_id NewPlaylistID(i32 ID) { return {ID}; }
62 | inline playlist_id Get(array_playlist_id *A, displayable_id ID) { return {(i32)Get(&A->A, ID.ID)}; }
63 | inline void Push(array_playlist_id *A, playlist_id ID) { Push(&A->A, ID.ID); }
64 | inline playlist_id Take(array_playlist_id *A, displayable_id ID) { return {(i32)Take(&A->A, ID.ID)}; }
65 | inline b32 StackFind(array_playlist_id *A, playlist_id Item, i32 *Result) { return StackFind(&A->A, Item.ID, (u32 *)Result); }
66 | inline void StackFindAndTake(array_playlist_id *A, playlist_id ID) { StackFindAndTake(&A->A, ID.ID); }
67 | inline b32 StackContains(array_playlist_id *A, playlist_id ID) { return StackContains(&A->A, ID.ID); }
68 | inline void Copy(array_playlist_id *A1, array_playlist_id *A2) { Copy(&A1->A, &A2->A); }
69 | inline void Reset(array_playlist_id *A) { Reset(&A->A); }
70 | inline void Clear(array_playlist_id *A, u32 Value = 0) { Clear(&A->A, Value); }
71 | internal void QuickSort(i32 Low, i32 High, array_playlist_id *SortArray, sort_info SortInfo)
72 | { QuickSort(Low, High, &SortArray->A, SortInfo); }
73 |
74 | inline b32 operator< (playlist_id ID1, playlist_id ID2) { return ID1.ID < ID2.ID; }
75 | inline b32 operator< (playlist_id ID1, i32 ID2) { return ID1.ID < ID2; }
76 | inline b32 operator<=(playlist_id ID1, playlist_id ID2) { return ID1.ID <= ID2.ID; }
77 | inline b32 operator<=(playlist_id ID1, i32 ID2) { return ID1.ID <= ID2; }
78 | inline b32 operator> (playlist_id ID1, playlist_id ID2) { return ID1.ID > ID2.ID; }
79 | inline b32 operator> (playlist_id ID1, i32 ID2) { return ID1.ID > ID2; }
80 | inline b32 operator>=(playlist_id ID1, playlist_id ID2) { return ID1.ID >= ID2.ID; }
81 | inline b32 operator>=(playlist_id ID1, i32 ID2) { return ID1.ID >= ID2; }
82 | inline b32 operator==(playlist_id ID1, playlist_id ID2) { return ID1.ID == ID2.ID; }
83 | inline b32 operator==(playlist_id ID1, i32 ID2) { return ID1.ID == ID2; }
84 | inline b32 operator!=(playlist_id ID1, playlist_id ID2) { return ID1.ID != ID2.ID; }
85 | inline b32 operator!=(playlist_id ID1, i32 ID2) { return ID1.ID != ID2; }
86 |
87 | // Miscellaneous
88 | inline select_id NewSelectID(i32 ID) { return {ID}; }
89 | inline decode_id NewDecodeID(i32 ID) { return {ID}; }
90 |
91 | /*
92 | // Start of table for songs, but this needs a better thought out plan!
93 |
94 | // Sound HashTable
95 | struct song_table_entry
96 | {
97 | u32 Key;
98 | file_id Value;
99 | };
100 |
101 | struct song_hash_table
102 | {
103 | song_table_entry *Table;
104 | u32 TableSize;
105 | u32 Count;
106 |
107 | arena_allocator *CreationArena;
108 | };
109 |
110 | inline song_hash_table CreateSongTable(arena_allocator *Arena, u32 Size);
111 | inline void DestroySongTable(song_hash_table *HashTable);
112 | */
113 |
114 | #endif //_SOUND__GENERAL__T_D_H
115 |
--------------------------------------------------------------------------------
/code/Sound_Icons.c:
--------------------------------------------------------------------------------
1 |
2 |
3 | inline u32
4 | ColorToColor32(v3 Color, u8 Alpha)
5 | {
6 | u32 Result = 0;
7 |
8 | u8 Red = (u8)(255*Color.r);
9 | u8 Blue = (u8)(255*Color.g);
10 | u8 Green = (u8)(255*Color.b);
11 |
12 | Result = (Red << 0) | (Blue << 8) | (Green << 16) | (Alpha << 24);
13 | return Result;
14 | }
15 |
16 | internal loaded_bitmap
17 | CreatePlusIcon(game_state *GS, u32 Size)
18 | {
19 | loaded_bitmap Bitmap = {};
20 | Bitmap.Pixels = AllocateArray(&GS->FixArena, Size*Size, u32);
21 | Bitmap.ColorFormat = colorFormat_RGBA;
22 | Bitmap.Width = Size;
23 | Bitmap.Height = Size;
24 | Bitmap.WasLoaded = true;
25 |
26 | r32 Border = 0.25f;
27 | r32 PlusWidth = 0.15f;
28 |
29 | u32 MinBorder = (u32)(Size*Border);
30 | u32 MaxBorder = (u32)(Size*(1-Border));
31 |
32 | u32 Left = (u32)(Size*(0.5f - (PlusWidth*0.5f)));
33 | u32 Right = (u32)(Size*(0.5f + (PlusWidth*0.5f)));
34 |
35 | u32 NewColor = ColorToColor32(V3(1, 1, 1), 0);
36 | For(Size, Y_)
37 | {
38 | For(Size, X_)
39 | {
40 | i32 Pos = Y_It*Size + X_It;
41 |
42 | u8 Alpha = 0;
43 | if(Y_It > MinBorder && Y_It < MaxBorder &&
44 | X_It > MinBorder && X_It < MaxBorder) // Border around it.
45 | {
46 | if (X_It > Left && X_It < Right) Alpha = 255;
47 | else if(Y_It > Left && Y_It < Right) Alpha = 255;
48 | }
49 | Bitmap.Pixels[Pos] = NewColor | Alpha << 24;
50 | }
51 | }
52 |
53 | return Bitmap;
54 | }
55 |
56 |
57 | internal loaded_bitmap
58 | CreatePlayPauseIcon(game_state *GS, u32 Size)
59 | {
60 | loaded_bitmap Bitmap = {};
61 | Bitmap.Pixels = AllocateArray(&GS->FixArena, Size*Size, u32);
62 | Bitmap.ColorFormat = colorFormat_RGBA;
63 | Bitmap.Width = Size;
64 | Bitmap.Height = Size;
65 | Bitmap.WasLoaded = true;
66 |
67 | r32 Border = 0.2f;
68 | r32 PauseBarWidth = 0.15f;
69 | r32 PauseStart = 0.5f;
70 | r32 PauseGap = 0.025f;
71 |
72 | u32 TriCount = 0;
73 | u32 MinBorder = (u32)(Size*Border);
74 | u32 MaxBorder = (u32)(Size*(1-Border));
75 |
76 | u32 PauseBar1Start = (u32)(Size*PauseStart);
77 | u32 PauseBar1End = PauseBar1Start + (u32)(Size*PauseBarWidth);
78 | u32 PauseBar2Start = PauseBar1End + (u32)(Size*PauseGap);
79 | u32 PauseBar2End = PauseBar2Start + (u32)(Size*PauseBarWidth);
80 |
81 |
82 | u32 NewColor = ColorToColor32(V3(1, 1, 1), 0);
83 | For(Size, Y_)
84 | {
85 | if(Y_It < Size*0.5f) ++TriCount;
86 | else --TriCount;
87 |
88 | For(Size, X_)
89 | {
90 | i32 Pos = Y_It*Size + X_It;
91 |
92 | u8 Alpha = 0;
93 | if(Y_It > MinBorder && Y_It < MaxBorder &&
94 | X_It > MinBorder && X_It < MaxBorder) // Border around it.
95 | {
96 | if (X_It < TriCount) Alpha = 255;
97 | else if(X_It > PauseBar1Start && X_It < PauseBar1End) Alpha = 255;
98 | else if(X_It > PauseBar2Start && X_It < PauseBar2End) Alpha = 255;
99 | }
100 | Bitmap.Pixels[Pos] = NewColor | Alpha << 24;
101 | }
102 | }
103 |
104 | return Bitmap;
105 | }
106 |
107 |
108 | internal loaded_bitmap
109 | _CreatePlayPauseIcon(game_state *GS, u32 Size)
110 | {
111 | Size = (u32)(Size*0.5f);
112 | loaded_bitmap Bitmap = {};
113 | Bitmap.Pixels = AllocateArray(&GS->FixArena, Size*Size, u32);
114 | Bitmap.ColorFormat = colorFormat_RGBA;
115 | Bitmap.Width = Size;
116 | Bitmap.Height = Size;
117 | Bitmap.WasLoaded = true;
118 |
119 | r32 Border = 0.0f;
120 | r32 PauseBarWidth = 0.15f;
121 | r32 PauseStart = 0.5f;
122 | r32 PauseGap = 0.025f;
123 | r32 PlayApex = 0.6f;
124 |
125 | u32 TriCount = 0;
126 | u32 MinBorder = (u32)(Size*Border);
127 | u32 MaxBorder = (u32)(Size*(1-Border));
128 |
129 | u32 PauseBar1Start = (u32)(Size*PauseStart);
130 | u32 PauseBar1End = PauseBar1Start + (u32)(Size*PauseBarWidth);
131 | u32 PauseBar2Start = PauseBar1End + (u32)(Size*PauseGap);
132 | u32 PauseBar2End = PauseBar2Start + (u32)(Size*PauseBarWidth);
133 |
134 | u32 ApexCount = (u32)(PlayApex*Size);
135 | r32 TriPart = PlayApex*2;
136 |
137 | u32 NewColor = ColorToColor32(V3(1, 1, 1), 0);
138 | For(Size, Y_)
139 | {
140 | if(Y_It < Size*0.5f) ++TriCount;
141 | else --TriCount;
142 |
143 | u32 TriBorder = Y_It;
144 | if(Y_It > Size*0.5f) TriBorder = Size - Y_It;
145 |
146 | r32 TriBorderP = (TriBorder*TriPart);
147 | TriBorder = (u32)TriBorderP;
148 |
149 | For(Size, X_)
150 | {
151 | i32 Pos = Y_It*Size + X_It;
152 |
153 | u8 Alpha = 0;
154 | if(Y_It > MinBorder && Y_It < MaxBorder &&
155 | X_It > MinBorder && X_It < MaxBorder) // Border around it.
156 | {
157 | if(X_It < TriBorder)
158 | Alpha = 255;
159 | else if(X_It == TriBorder)
160 | Alpha = (u8)(255*(TriBorderP-TriBorder));
161 |
162 | //else if(X_It > PauseBar1Start && X_It < PauseBar1End) Alpha = 255;
163 | //else if(X_It > PauseBar2Start && X_It < PauseBar2End) Alpha = 255;
164 | }
165 | Bitmap.Pixels[Pos] = NewColor | Alpha << 24;
166 | }
167 | }
168 |
169 | return Bitmap;
170 | }
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/code/Sound_Jobs.h:
--------------------------------------------------------------------------------
1 | /* date = October 19th 2020 9:31 am */
2 | #ifndef _SOUND__JOBS_H
3 | #define _SOUND__JOBS_H
4 |
5 | #define DO_METADATA_SUB_CRAWL
6 |
7 | struct job_load_decode_mp3
8 | {
9 | mp3_info *MP3Info;
10 | file_id FileID;
11 | i32 DecodeID;
12 | i32 PreloadSeconds;
13 | };
14 |
15 | struct crawl_thread_out
16 | {
17 | b32 ThreadIsRunning;
18 | b32 DoneFolderSearch;
19 | b32 DoneCrawling;
20 |
21 | u32 TestCount;
22 | u32 CurrentCount;
23 | };
24 |
25 | struct crawl_thread
26 | {
27 | mp3_info *MP3Info;
28 | string_c TestPath;
29 |
30 | crawl_thread_out *Out;
31 | };
32 |
33 | struct sub_crawl_thread
34 | {
35 | crawl_thread CrawlThread;
36 | u32 StartIt;
37 | u32 EndIt;
38 | u32 *CurrentCount;
39 | };
40 |
41 | struct check_music_path
42 | {
43 | thread_state State;
44 | mp3_info *MP3Info;
45 | mp3_file_info TestInfo;
46 | array_u32 RemoveIDs;
47 | array_u32 AddTestInfoIDs;
48 | };
49 | internal b32 AddJob_NextUndecodedInPlaylist();
50 | internal void AddJob_CheckMusicPathChanged(check_music_path *CheckMusicPath);
51 | internal i32 AddJob_LoadMP3(circular_job_queue *JobQueue, playlist_id PlaylistID, array_u32 *IgnoreDecodeIDs = 0,
52 | i32 PreloadSeconds = DECODE_PRELOAD_SECONDS);
53 |
54 |
55 |
56 |
57 | #endif //_SOUND__JOBS_H
58 |
--------------------------------------------------------------------------------
/code/Sound_Serialization.h:
--------------------------------------------------------------------------------
1 | /* date = October 19th 2020 10:09 am */
2 | #ifndef _SOUND__SERIALIZATION_H
3 | #define _SOUND__SERIALIZATION_H
4 |
5 | global_variable string_c SETTINGS_FILE_NAME = NewStaticStringCompound("MPlay3Settings.save");
6 | global_variable string_c LIBRARY_FILE_NAME = NewStaticStringCompound("MPlay3Library.save");
7 | global_variable string_c PLAYLIST_FILE_NAME = NewStaticStringCompound("MPlay3Playlist_"); // Gets build in SavePlaylist
8 |
9 | #define SETTINGS_CURRENT_VERSION 8
10 | #define LIBRARY_CURRENT_VERSION 3
11 | #define PLAYLIST_CURRENT_VERSION 1
12 |
13 | #define COLOR_PALETTE_MAX_NAME_LENGTH 100
14 | struct serialization_settings
15 | {
16 | string_c FontPath = {0, 0, 0}; // Only for users at this point.
17 |
18 | r32 Volume = 0.5f;
19 | file_id PlayingSongID = {-1};
20 | r32 PlayingSongTime = 0.0f;
21 | u32 ColorPaletteID = 5;
22 | r32 PlaylistsGenreEdgeXPercent = -1.0f;
23 | r32 GenreArtistEdgeXPercent = -1.0f;
24 | r32 ArtistAlbumEdgeXPercent = -1.0f;
25 | r32 AlbumSongEdgeXPercent = -1.0f;
26 | i32 WindowDimX = 0;
27 | i32 WindowDimY = 0;
28 | b32 Looping = false;
29 | b32 Shuffle = false;
30 | string_c ActivePlaylist;
31 |
32 | font_name_list *CachedFontNames;
33 |
34 | string_c *PaletteNames;
35 | color_palette *Palettes;
36 | u32 PaletteCount;
37 | u32 PaletteMaxCount;
38 |
39 | r32 SmallFontSize = -1;
40 | r32 MediumFontSize = -1;
41 |
42 | };
43 |
44 | internal serialization_settings TryLoadSettingsFile(game_state *GameState);
45 | internal void SaveSettingsFile(game_state *GameState, serialization_settings *Settings);
46 | inline void ApplySettings(game_state *GameState, serialization_settings Settings);
47 |
48 | internal b32 ConfirmLibraryWithCorrectVersionExists(game_state *GameState, u32 VersionToCheckFor, u32 *FileInfoCount);
49 | internal b32 CompareMP3LibraryFileSavedPath(game_state *GameState, string_c *PathToCompare);
50 | internal void LoadMP3LibraryFile(game_state *GameState, mp3_info *Info);
51 | internal void SaveMP3LibraryFile(game_state *GameState, mp3_info *Info);
52 | internal void WipeMP3LibraryFile(game_state *GameState);
53 |
54 | internal read_file_result GetUsedFontData(game_state *GameState);
55 | internal loaded_bitmap DecodeIcon(arena_allocator *Arena, u32 Width, u32 Height, u8 *Data, u32 Size);
56 |
57 | internal void SaveShuffledState(game_state *GS, playlist_info *Playlist);
58 | internal void SaveLoopingState(game_state *GS, playlist_info *Playlist);
59 | #endif //_SOUND__SERIALIZATION_H
60 |
--------------------------------------------------------------------------------
/code/Sound_Thread_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 |
5 | #define DIRECT_SOUND_CREATE(name) HRESULT WINAPI name(LPCGUID pcDuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
6 | typedef DIRECT_SOUND_CREATE(direct_sound_create);
7 |
8 | enum play_state
9 | {
10 | playState_Error,
11 | playState_Done,
12 | playState_Playing,
13 | playState_Waiting,
14 | playState_Startup,
15 | };
16 |
17 | struct dsound_instance
18 | {
19 | i32 SamplesPerSecond;
20 | WORD Channels;
21 | i32 BytesPerSample;
22 | DWORD BufferSize;
23 | DWORD SafetyBytes;
24 |
25 | LPDIRECTSOUNDBUFFER Buffer;
26 | };
27 |
28 | struct sound_info
29 | {
30 | dsound_instance SoundInstance;
31 | u32 RunningSampleIndex;
32 |
33 | b32 SoundIsValid;
34 |
35 | r32 ToneVolume;
36 | i32 PlayedSampleCount;
37 | r32 PlayedTime;
38 |
39 | DWORD PrevPlayCursor;
40 | i32 SongEndByte;
41 | };
42 |
43 | struct game_sound_output_buffer
44 | {
45 | i32 SamplesPerSecond;
46 | i32 SampleCount;
47 | i16 *Samples;
48 | };
49 |
50 | struct sound_thread_interface
51 | {
52 | HANDLE SoundMutex; // To change anything, you need to have this mutex!
53 |
54 | // In
55 | b32 IsPlaying;
56 | r32 ToneVolume;
57 | b32 ClearSoundBufferToggle;
58 | mp3dec_file_info_t PlayingSongData;
59 | b32 ChangedTimeToggle;
60 | b32 ChangedTimeAfterLoadingToggle;
61 | b32 SongChangedToggle;
62 | b32 SongFinishedLoadingToggle;
63 |
64 | // Out
65 | b32 IsFinishedPlayingToggle;
66 | b32 PreloadIsActive;
67 |
68 | // In-Out
69 | r32 CurrentPlaytime;
70 | };
71 |
72 | struct sound_thread
73 | {
74 | arena_allocator *Arena;
75 | sound_thread_interface Interface;
76 |
77 | sound_info SoundInfo;
78 | i16 *SoundSamples;
79 | };
80 |
81 |
--------------------------------------------------------------------------------
/code/Sound_settings.h:
--------------------------------------------------------------------------------
1 | /* date = September 10th 2021 9:06 am */
2 | #ifndef _SOUND_SETTINGS_H
3 | #define _SOUND_SETTINGS_H
4 |
5 | struct palette_color
6 | {
7 | entry_id *Outline;
8 | entry_id *Preview;
9 | render_text Name;
10 | };
11 |
12 | struct color_picker
13 | {
14 | entry_id *Parent;
15 | entry_id *Background;
16 | entry_id *FixedSizeHolder;
17 |
18 | loaded_bitmap Bitmap;
19 | u32 GLID;
20 | entry_id *TextureEntry;
21 | b32 IsPickingColor;
22 |
23 | slider ColorSpectrum;
24 | render_text RText;
25 | render_text GText;
26 | render_text BText;
27 |
28 | render_text HText;
29 | render_text SText;
30 | render_text VText;
31 |
32 | render_text HexText;
33 |
34 | entry_id *PickDot;
35 | entry_id *InnerDot;
36 | entry_id *InnerInnerDot;
37 | v3 SelectedColor;
38 |
39 | palette_color PaletteColors[PALETTE_COLOR_AMOUNT];
40 | u32 ActiveColor;
41 | entry_id *ActiveColorBG;
42 | u32 CurrentColorPaletteID;
43 | text_field PaletteName;
44 |
45 | button *New;
46 | button *Save;
47 | button *Remove;
48 | quit_animation NewAnim;
49 | quit_animation SaveAnim;
50 | quit_animation RemoveAnim;
51 | };
52 |
53 | enum color_picker_anim_btn
54 | {
55 | colorPickerAnimBtn_New,
56 | colorPickerAnimBtn_Save,
57 | colorPickerAnimBtn_Remove
58 | };
59 |
60 | struct font_settings
61 | {
62 | entry_id *Parent;
63 | entry_id *Background;
64 |
65 | button *EditFont;
66 | b32 EditingFont;
67 | text_field ActiveFont;
68 |
69 | render_text SmallFontText;
70 | slider SmallFontSlider;
71 |
72 | render_text MediumFontText;
73 | slider MediumFontSlider;
74 |
75 | //slider LargeFontSlider;
76 | };
77 |
78 | struct style_settings_window
79 | {
80 | b32 IsActive;
81 |
82 | b32 IsMoving;
83 | v2 MoveOffset; // For mouse drag.
84 | entry_id *Border;
85 | entry_id *Background;
86 | v2 _BGOffset;
87 |
88 | button *Cancel;
89 |
90 | entry_id *ColorPickerParent;
91 | color_picker ColorPicker;
92 |
93 | entry_id *FontParent;
94 | font_settings FontSettings;
95 | };
96 |
97 | internal void CreateStyleSettings(game_state *GS, style_settings_window *StyleSettings);
98 | internal void HandleActiveStyleSettings(game_state *GS, style_settings_window *StyleSettings, input_info *Input);
99 | inline void SetActive(style_settings_window *StyleWindow, b32 Activate);
100 | inline void OnStyleSettings(void *Data);
101 | internal void UpdateSettings(game_state *GS);
102 |
103 | // Font settings
104 | internal void CreateFontSettings(game_state *GS, font_settings *FontSettings, entry_id *Parent);
105 | inline void SetActive(font_settings *FontSettings, b32 Activate);
106 | internal void HandleActiveFontSettings(game_state *GS, font_settings *FontSettings);
107 |
108 | // Color Picker
109 | internal void CreateColorPicker(game_state *GS, color_picker *Result, v2 BitmapSize, r32 SpectrumWidth, entry_id *Parent);
110 | internal void HandleActiveColorPicker(game_state *GS, color_picker *ColorPicker);
111 | inline void SetActive(color_picker *ColorPicker, b32 Activate);
112 | internal void CreateColorPickerPaletteList(game_state *GS, color_picker *ColorPicker, v2 Offset);
113 | inline r32 GetColorPickerTextWidth(game_state *GS);
114 | //inline void CreateBasicColorPalette(color_palette *Palette);
115 | inline void CreateLushGreenColorPalette(color_palette *Palette);
116 | inline void OnPaletteSwap(void *Data);
117 | inline void UpdateColorPalette(music_display_info *DisplayInfo, b32 GoToNextPalette);
118 | inline string_c * GetCurrentPaletteName();
119 | internal void AddCustomColorPalette(color_palette *ColorPalette, string_c *Name);
120 | internal void RemoveCustomColorPalette(u32 PaletteID);
121 | inline b32 IsColorPaletteDefault();
122 |
123 | #endif //_SOUND_SETTINGS_H
124 |
--------------------------------------------------------------------------------
/code/StandardUtilities_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Math_TD.h"
3 |
4 | // HashTable
5 | #define HASH_TABLE_KEY_LENGTH 30
6 | struct key_value_pair
7 | {
8 | u8 Key[HASH_TABLE_KEY_LENGTH];
9 | u32 Value;
10 |
11 | u32 NextKeyValue;
12 | };
13 |
14 | struct hash_table
15 | {
16 | key_value_pair *KeyValuePair;
17 |
18 | u32 Count;
19 | u32 _TableSize;
20 |
21 | key_value_pair *Collisions;
22 | u32 CollisionCount;
23 | u32 CollisionSize;
24 |
25 | b32 IsTransient;
26 | };
27 |
28 | inline hash_table HashTable(arena_allocator *Arena, u32 Size);
29 | inline b32 AddToHashTable(hash_table *Table, u8 *Key, u32 Value);
30 | inline b32 GetFromHashTable(hash_table *Table, u8 *Key, u32 &Value);
31 | inline b32 UpdateValueInHashTable(hash_table *Table, u8 *Key, u32 NewValue);
32 | inline void DeleteHashTableTransient(arena_allocator *Arena, hash_table *Table);
33 | inline u32 Hash(u32 Key);
34 | inline u32 UnHash(u32 HashedKey);
35 | inline u32 Hash_djb2(char *String);
36 |
37 |
38 |
39 | // Min - Heap
40 |
41 | struct heap_node
42 | {
43 | union
44 | {
45 | i32 ValueI32;
46 | // u32 ValueU32;
47 | r32 ValueR32;
48 | };
49 | void *Data;
50 | };
51 |
52 | struct heap
53 | {
54 | heap_node *Nodes;
55 | u32 Count;
56 | u32 Size;
57 | };
58 |
59 | #define LeftChildIndex(N) (2*N+1)
60 | #define RightChildIndex(N) (2*N+2)
61 | #define ParentIndex(N) ((N-1)/2)
62 |
63 | inline heap CreateTransientHeap(arena_allocator *Arena, u32 MinHeapSize);
64 | inline heap CreateFixedHeap(arena_allocator *Arena, u32 MinHeapSize);
65 | inline void InsertIntoHeap(arena_allocator *Arena, heap *Heap, i32 Value, void* Data = 0);
66 | inline heap_node ExtractHeapMinimum(heap *Heap);
67 | inline heap_node GetHeapMinimum(heap *Heap);
68 | inline b32 IsHeapEmpty(heap *Heap);
69 |
70 | // Random
71 | global_variable u64 RandomBaseSeed = 127;
72 | global_variable u64 PrimeBig = 10019059;
73 | global_variable u64 PrimeHuge = 1000000007861;
74 |
75 | inline void SetRandomSeed(u64 NewSeed);
76 | inline u64 GetCurrentRandomSeed();
77 | internal r32 Random01();
78 | inline i32 RandomRange(i32 Minimum, i32 Maximum);
79 | inline i32 GetWeightedRandom01(u32 XTimesHigherPropabilityFor0);
80 |
81 | // Array operations
82 |
83 | struct array_u32
84 | {
85 | // Head
86 | u32 Length;
87 | u32 Count;
88 |
89 | // Data
90 | u32 *Slot;
91 | };
92 |
93 | inline array_u32 CreateArray(arena_allocator *Arena, i32 Length);
94 | inline void DestroyArray(arena_allocator *Arena, array_u32 *Array);
95 | inline void Put(array_u32 *Array, u32 Pos, u32 Item);
96 | inline u32 Get(array_u32 *Array, u32 Pos);
97 | inline u32 Take(array_u32 *Array, u32 Pos);
98 | inline void Push(array_u32 *Array, u32 Item);
99 | inline u32 Pop(array_u32 *Array);
100 | inline void Reset(array_u32 *Array);
101 | inline void Clear(array_u32 *Array, u32 Value = 0);
102 | inline b32 Contains(array_u32 *Array, u32 Item);
103 | inline b32 Find(array_u32 *Array, u32 Item, u32 *Result);
104 | inline b32 FindAndTake(array_u32 *Array, u32 Item);
105 | inline b32 StackContains(array_u32 *Array, u32 Item);
106 | inline b32 StackFind(array_u32 *Array, u32 Item, u32 *Result);
107 | inline b32 StackFindAndTake(array_u32 *Array, u32 Item);
108 | inline void StackInsert(array_u32 *Array, u32 Pos, u32 Item);
109 | inline void PushIfNotExist(array_u32 *Array, u32 Item);
110 | inline void AppendArray(array_u32 *Array1, array_u32 *Array2);
111 | inline void MergeArrays(array_u32 *Array1, array_u32 *Array2); // Slow
112 | inline array_u32 Copy(arena_allocator *Arena, array_u32 From);
113 | inline void Copy(array_u32 *To, array_u32 *From);
114 | internal void ShuffleStack(array_u32 *Array);
115 | internal void PrintArray(array_u32 Array);
116 |
117 | #define CutValueFromArray(Array, ArraySize, ID, type) CutValueFromArray_((void *)Array, ArraySize, ID, sizeof(type));
118 | inline void CutValueFromArray_(void *Array, u32 *ArraySize, u32 ID, u32 ElementSize);
119 |
120 | inline void QuickSort3(array_u32 Array, b32 SortOnLength_NotCount = false);
121 |
122 | struct sort_info
123 | {
124 | b32 (*CompareFunc)(i32 T1, i32 T2, void *Data);
125 | void *Data;
126 | void (*SwapFunc)(void *Array, i32 IndexA, i32 IndexB);
127 | };
128 |
129 | internal void QuickSort(i32 Low, i32 High, void *SortArray, sort_info SortInfo);
130 | inline void Switch(void *Array, i32 P1, i32 P2);
131 | inline void Switch(array_u32 Array, i32 P1, i32 P2);
--------------------------------------------------------------------------------
/code/Threading_TD.c:
--------------------------------------------------------------------------------
1 | #include "Threading_TD.h"
2 |
3 | #define AddJobToQueue(Queue, Callback, DataStruct) AddJobToQueue_(Queue, Callback, &(DataStruct), sizeof(DataStruct))
4 | internal void
5 | AddJobToQueue_(circular_job_queue *JobQueue, job_list_callback *Callback, void *Data, u32 DataSize)
6 | {
7 | // NOTE:: If you want multiple producer; multiple worker, then you need to
8 | // switch to interlockedCompareExchange. With single producer its not
9 | // necessery.
10 | u32 NewNextEntryToWrite = (JobQueue->NextJobToWrite+1)%MAX_ACTIVE_JOBS;
11 | Assert(NewNextEntryToWrite != JobQueue->NextJobToRead);
12 | job_queue_entry *Entry = JobQueue->Entries + JobQueue->NextJobToWrite;
13 | Entry->Callback = Callback;
14 |
15 | Assert(DataSize <= JOB_ENTRY_DATA_SIZE);
16 | For(DataSize) Entry->Data[It] = ((u8 *)Data)[It];
17 |
18 | JobQueue->CompletionGoal++;
19 |
20 | CompletePastWritesBeforeFutureWrites;
21 | //InterlockedIncrement((LONG volatile *)&JobQueue->NextJobToWrite);
22 | JobQueue->NextJobToWrite = NewNextEntryToWrite;
23 |
24 | // Activates one sleeping thread
25 | ReleaseSemaphore(JobQueue->Semaphore, 1, 0);
26 | }
27 |
28 | internal b32
29 | DoNextJobQueueEntry(job_thread_info *Info)
30 | {
31 | b32 WeShouldSleep = false;
32 |
33 | circular_job_queue *JobQueue = Info->JobQueue;
34 |
35 | u32 OriginalNextJobToRead = JobQueue->NextJobToRead;
36 | u32 NewNextEntryToRead = (OriginalNextJobToRead+1)%MAX_ACTIVE_JOBS;
37 | if(OriginalNextJobToRead != JobQueue->NextJobToWrite)
38 | {
39 | u32 Index = InterlockedCompareExchange((LONG volatile *)&JobQueue->NextJobToRead,
40 | NewNextEntryToRead,
41 | OriginalNextJobToRead);
42 | if(Index == OriginalNextJobToRead)
43 | {
44 | job_queue_entry Entry = JobQueue->Entries[Index];
45 | ResetMemoryArena(&Info->ScratchArena);
46 | Info->CurrentJob = Entry.Callback;
47 |
48 | Entry.Callback(Info, Entry.Data);
49 |
50 | Info->CurrentJob = 0;
51 | InterlockedIncrement((LONG volatile *)&JobQueue->CompletionCount);
52 | }
53 | }
54 | else
55 | {
56 | // We should only sleep if OriginalNextJobToRead and JobQueue->NextJobToWrite
57 | // are equal. Not if we actually do a job and not if we failed to get
58 | // a job, but thought there was one.
59 | WeShouldSleep = true;
60 | }
61 |
62 | return WeShouldSleep;
63 | }
64 |
65 | internal DWORD WINAPI
66 | JobThreadProc(LPVOID Data)
67 | {
68 | DWORD Result = 0;
69 | job_thread_info *Info = (job_thread_info *)Data;
70 |
71 | while(true)
72 | {
73 | if(DoNextJobQueueEntry(Info))
74 | {
75 | // Sleep
76 | WaitForSingleObjectEx(Info->JobQueue->Semaphore, INFINITE, false);
77 | }
78 | }
79 |
80 | return Result;
81 | }
82 |
83 | inline void
84 | EmptyJobQueueWhenPossible(circular_job_queue *JobQueue)
85 | {
86 | if(JobQueue->CompletionGoal == JobQueue->CompletionCount &&
87 | JobQueue->CompletionGoal && JobQueue->CompletionCount)
88 | {
89 | JobQueue->CompletionGoal = 0;
90 | JobQueue->CompletionCount = 0;
91 | DebugLog(255, "Successfully reset circular job queue counter!\n");
92 | }
93 | }
94 |
95 | internal void
96 | InitializeJobThreads(HANDLE *JobHandles, circular_job_queue *JobQueue, job_thread_info *JobThreadInfos)
97 | {
98 | JobQueue->Semaphore = CreateSemaphoreEx(0, 0, THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
99 |
100 | For(THREAD_COUNT)
101 | {
102 | JobThreadInfos[It].ThreadID = It;
103 | JobThreadInfos[It].JobQueue = JobQueue;
104 | JobThreadInfos[It].ScratchArena = {arenaFlags_IsTransient};
105 |
106 | JobHandles[It] = CreateThread(0, 0, JobThreadProc, (LPVOID)(JobThreadInfos+It), 0, 0);
107 | }
108 | }
109 |
110 | internal b32
111 | FindJobThreadStopAndRestartIt(HANDLE *ThreadHandles, job_thread_info *ThreadInfos, job_list_callback *JobCallback)
112 | {
113 | b32 Result = false;
114 |
115 | For(THREAD_COUNT)
116 | {
117 | if(ThreadInfos[It].CurrentJob)
118 | {
119 | if(*ThreadInfos[It].CurrentJob == JobCallback)
120 | {
121 | Assert(TerminateThread(ThreadHandles[It], 0));
122 |
123 | ThreadInfos[It].CurrentJob = 0;
124 | ThreadHandles[It] = CreateThread(0, 0, JobThreadProc, (LPVOID)(ThreadInfos+It), 0, 0);
125 |
126 | Result = true;
127 | }
128 | }
129 | }
130 |
131 | return Result;
132 | }
133 |
134 | // Test code
135 | internal JOB_LIST_CALLBACK(DoJobWork)
136 | {
137 | // Do Work
138 | string_c *String = (string_c *)Data;
139 | DebugLog(255, (char *const)String->S, ThreadInfo->ThreadID);
140 | }
141 |
142 |
143 | // Sound Thread
144 |
145 | inline LONGLONG GetWallClock();
146 | inline r32 GetSecondsElapsed(i64 PerfCountFrequency, LONGLONG Start, LONGLONG End);
147 |
148 | internal DWORD WINAPI
149 | SoundThreadProc(LPVOID Data)
150 | {
151 | sound_thread_data *ThreadData = (sound_thread_data *)Data;
152 | ThreadData->Callback(ThreadData->SoundThreadInfo);
153 |
154 | return 0;
155 | }
156 |
157 | internal void
158 | InitializeSoundThread(sound_thread_data *SoundThreadData, sound_thread_callback *Callback, struct sound_thread *Data)
159 | {
160 |
161 | SoundThreadData->Callback = Callback;
162 | SoundThreadData->SoundThreadInfo = Data;
163 |
164 | CreateThread(0, 0, SoundThreadProc, (LPVOID)SoundThreadData, 0, 0);
165 | }
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/code/Threading_TD.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // TODO:: mm_sfence might not be the right instruction!
4 | // INFO:: First: Compilerbarrier, second: processorbarrier
5 | #define CompletePastWritesBeforeFutureWrites _WriteBarrier(); _mm_sfence();
6 | #define CompletePastReadsBeforeFutureReads _ReadBarrier();
7 |
8 | // INFO:: Thread safe instructions:
9 | // - volatile - tells compiler that somebody at anytime can change this. So do a load everytime
10 | // - InterlockedIncrement(LONG volatile *Value) - Increments given value
11 | // - semaphore - a counter that helps keeping track of thread status sleep/awake
12 | // - CreateSemaphoreEx() - returns handle that can be used for synchronisation functions (bottom msdn page)(access type: SEMAPHORE_ALL_ACCESS)
13 | // - WaitForSingleObjectEX - suspends thread the specified amount of time, until semaphore handle "triggers"
14 | // - ReleaseSemaphore - Inreases semaphore count by specified amount, triggers for waitforsingle. When thread is released, it is decremented by 1
15 | #define THREAD_COUNT 5
16 |
17 | #define JOB_LIST_CALLBACK(name) void name(struct job_thread_info *ThreadInfo, void *Data)
18 | typedef JOB_LIST_CALLBACK(job_list_callback);
19 |
20 | #define JOB_ENTRY_DATA_SIZE 8*10
21 | struct job_queue_entry
22 | {
23 | job_list_callback *Callback;
24 | u8 Data[JOB_ENTRY_DATA_SIZE];
25 | };
26 |
27 | enum thread_state
28 | {
29 | threadState_Inactive,
30 | threadState_Running,
31 | threadState_Finished,
32 | };
33 |
34 | #define MAX_ACTIVE_JOBS 256
35 | struct circular_job_queue
36 | {
37 | HANDLE Semaphore;
38 | u32 volatile CompletionGoal;
39 | u32 volatile CompletionCount;
40 | u32 volatile NextJobToWrite;
41 | u32 volatile NextJobToRead;
42 | job_queue_entry Entries[MAX_ACTIVE_JOBS];
43 | };
44 |
45 | struct job_thread_info
46 | {
47 | u32 ThreadID;
48 | circular_job_queue *JobQueue;
49 | arena_allocator ScratchArena;
50 |
51 | job_list_callback *CurrentJob;
52 | };
53 |
54 |
55 | // ***********************************
56 | // API *******************************
57 | // ***********************************
58 | internal void AddJobToQueue(circular_job_queue *JobQueue, job_list_callback *Callback, void *Data);
59 |
60 |
61 | // Example work callback function:
62 | // internal JOB_LIST_CALLBACK(DoJobWork)
63 | // {
64 | // Do Work
65 | // char *const String = (char *const)Data;
66 | // DebugLog(255, String, GetCurrentThreadId());
67 | // }
68 |
69 |
70 | // Sound Thread
71 |
72 | #define SOUND_THREAD_CALLBACK(name) void name(struct sound_thread *ThreadInfo)
73 | typedef SOUND_THREAD_CALLBACK(sound_thread_callback);
74 |
75 | #define SOUND_THREAD_DATA_SIZE 8*10
76 | struct sound_thread_data
77 | {
78 | sound_thread_callback *Callback;
79 | struct sound_thread *SoundThreadInfo;
80 | };
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/code/UI_TD.h:
--------------------------------------------------------------------------------
1 | /* date = September 6th 2020 8:04 am */
2 | #ifndef _U_I__T_D_H
3 | #define _U_I__T_D_H
4 | #include "Font_TD.h"
5 |
6 | // Button stuff
7 | enum button_state
8 | {
9 | buttonState_Unpressed,
10 | buttonState_Pressed,
11 | buttonState_Hover,
12 | };
13 |
14 | struct function_pointer
15 | {
16 | void (*Func)(void *Data);
17 | void *Data;
18 | };
19 |
20 | struct button
21 | {
22 | entry_id *Entry;
23 | v3 *BaseColor;
24 | v3 *DownColor;
25 | v3 *HoverColor;
26 | entry_id *Icon;
27 | entry_id *ToggleIcon;
28 | v3 *IconColor;
29 |
30 | function_pointer OnHoverEnter;
31 | function_pointer OnHoverExit;
32 | function_pointer OnPressed;
33 | function_pointer OnPressedToggleOff; // Only when the button is toggle
34 |
35 | // TODO:: Make toggle btn its super form?
36 | // TODO:: Make this toggle btn interaction stuff simpler with the new child-structure
37 | b32 IsToggle;
38 | button_state State;
39 | b32 ClickedInBtn;
40 |
41 | b32 IsDisabled;
42 | };
43 |
44 | #define MAX_BUTTONS 120
45 | struct button_group
46 | {
47 | button Buttons[MAX_BUTTONS];
48 | u32 Count;
49 | };
50 |
51 | struct button_colors
52 | {
53 | v3 *BaseColor;
54 | v3 *DownColor;
55 | v3 *HoverColor;
56 | v3 *IconColor;
57 | };
58 |
59 | inline button *NewButton(struct renderer *Renderer, rect Rect, r32 Depth, b32 IsToggle,
60 | string_c *BtnPath, v3 *BaseColor, v3 *DownColor, v3 *HoverColor, string_c *IconPath, v3 *IconColor,
61 | entry_id *Parent, string_c *ToggleIconPath = 0);
62 | inline button *NewButton(struct renderer *Renderer, rect Rect, r32 Depth, b32 IsToggle,
63 | u32 ButtonBitmapID, v3 *BaseColor, v3 *DownColor, v3 *HoverColor,
64 | u32 IconBitmapID, v3 *IconColor, entry_id *Parent, i32 ToggleIconBitmapID = -1);
65 | inline button *NewButton(struct renderer *Renderer, rect Rect, r32 Depth, b32 IsToggle, u32 ButtonBitmapID, u32 IconBitmapID,
66 | button_colors Colors, entry_id *Parent, i32 ToggleIconBitmapID = -1);
67 | inline void SetDisabled(button *Button, b32 Disable, v3 *Color);
68 | inline void SetActive(button *Button, b32 SetActive);
69 | inline void ResetBtnState(button *Button);
70 | inline void Translate(button *Button, v2 Translation);
71 | inline void SetLocalPosition(button *Button, v2 Translation);
72 | inline void SetLocalPositionX(button *Button, r32 X);
73 | inline void SetPosition(button *Button, v2 Translation);
74 | inline v2 GetPosition(button *Button);
75 | inline v2 GetLocalPosition(button *Button);
76 | inline void ToggleButtonVisuals(button *Button, b32 ToggleOn);
77 | internal void ButtonTestMouseInteraction(renderer *Renderer, input_info *Input, button *Button);
78 | inline b32 IsButtonHovering(button *Button);
79 | inline b32 IsOnButton(button *Button, v2 Position);
80 | inline void SetScissor(button *Button, entry_id *ScissorID);
81 | inline v2 GetSize(button *Button);
82 | inline void SetSize(button *Button, v2 Size);
83 |
84 | // Dragable UI stuff
85 | struct drag_func_pointer
86 | {
87 | void (*Func)(struct renderer *Renderer, v2 AdjustedMouseP, entry_id *Dragable, void *Data);
88 | void *Data;
89 | };
90 |
91 | #define DRAGABLE_MAX_COUNT 20
92 | struct drag_list
93 | {
94 | i32 DraggingID;
95 | b32 IsActive[DRAGABLE_MAX_COUNT];
96 | entry_id *Dragables[DRAGABLE_MAX_COUNT];
97 | drag_func_pointer OnDragStart[DRAGABLE_MAX_COUNT];
98 | drag_func_pointer OnDragging [DRAGABLE_MAX_COUNT];
99 | drag_func_pointer OnDragEnd [DRAGABLE_MAX_COUNT];
100 | u32 Count;
101 | };
102 |
103 | // Text Fields stuff
104 |
105 | #define BLINK_TIME 0.5f
106 | #define BACKSPACE_CONTIUOUS_TIME 0.5f
107 | #define BACKSPACE_CONTIUOUS_SPEED 0.05f
108 |
109 | enum process_text_field_flag
110 | {
111 | processTextField_TextChanged = 1<<0,
112 | processTextField_Confirmed = 1<<1,
113 | };
114 | struct text_field_flag_result
115 | {
116 | i32 Flag;
117 | };
118 |
119 | struct text_field
120 | {
121 | v3 *TextColor;
122 | r32 Transparency;
123 | r32 ZValue;
124 |
125 | entry_id *Background;
126 | entry_id *LeftAlign;
127 | entry_id *Cursor;
128 | r32 dBlink;
129 |
130 | render_text Text;
131 | string_c TextString;
132 | string_c NoText;
133 | font_size_id FontSize;
134 | v2 _FontOffset; // Internal
135 |
136 | r32 dBackspacePress;
137 | r32 dBackspaceSpeed;
138 |
139 | b32 DoMouseHover;
140 | b32 IsActive;
141 | };
142 |
143 | internal text_field CreateTextField(renderer *Renderer, arena_allocator *Arena, v2 Size, r32 ZValue, u8 *EmptyFieldString, entry_id *Parent, v3 *TextColor, v3 *BGColor, font_size_id FontSize, u32 MaxStringLength = 255);
144 | inline void Translate(text_field *TextField, v2 Translation);
145 | inline void SetLocalPosition(text_field *TextField, v2 Position);
146 | inline void SetActive(text_field *TextField, b32 MakeActive);
147 | inline void SetParent(text_field *TextField, entry_id *Parent);
148 | inline v2 GetSize(text_field *TextField);
149 | inline void SetSize(text_field *TextField, v2 Size);
150 | inline void UpdateTextField(renderer *Renderer, text_field *TextField);
151 | internal text_field_flag_result ProcessTextField(renderer *Renderer, r32 dTime, input_info *Input, text_field *TextField);
152 | inline void SetScissor(text_field *TextField, entry_id *Rect);
153 |
154 | // LOAD BAR *********************
155 |
156 | struct loading_bar
157 | {
158 | entry_id *BG;
159 | entry_id *ProgressBar;
160 | };
161 |
162 | inline loading_bar CreateLoadingBar(v2 Size, r32 Depth, entry_id *Parent = 0);
163 | inline void UpdateLoadingBar(loading_bar *LoadingBar, r32 ProgressPercentage);
164 | inline void UpdateIndeterminiteLoadingBar(loading_bar *LoadingBar, r32 RoundtripPercentage);
165 | inline void SetPosition(loading_bar *LoadingBar, v2 NewP);
166 | inline void SetLocalPosition(loading_bar *LoadingBar, v2 NewP);
167 | inline void SetActive(loading_bar *LoadingBar, b32 IsActive);
168 |
169 |
170 | // slider ***********************
171 |
172 | enum slider_axis
173 | {
174 | sliderAxis_X,
175 | sliderAxis_Y,
176 | };
177 |
178 | struct slider
179 | {
180 | entry_id *Background;
181 | entry_id *GrabThing;
182 | r32 MaxSlidePix;
183 |
184 | v2 MouseOffset;
185 | slider_axis Axis;
186 |
187 | r32 SlidePercentage;
188 | b32 SliderIsDragged;
189 |
190 | r32 OverhangP; // CLEANUP:: This is for the column stuff only
191 | };
192 |
193 | inline void SetTransparency(slider *Slider, r32 Alpha);
194 | inline void Translate(slider *Slider, v2 T);
195 | inline void SetLocalPosition(slider *Slider, v2 T);
196 | inline void SetLocalPositionX(slider *Slider, r32 X);
197 | inline v2 GetLocalPosition(slider *Slider);
198 | inline v2 GetSize(slider *Slider);
199 | inline void SetSize(slider *Slider, v2 Size);
200 | inline void SetSize(slider *Slider, v2 Size, v2 GrabSize);
201 | inline void SetActive(slider *Slider, b32 Activate);
202 |
203 | internal void CreateSlider(game_state *GS, slider *Result, slider_axis Axis, rect BGRect, rect GrabRect, r32 Depth, b32 ShouldAutoDrag, entry_id *Parent = 0);
204 | internal void CreateSlider(game_state *GS, slider *Result, slider_axis Axis, v2 BGSize, v2 GrabSize, r32 Depth, loaded_bitmap BGBitmap, v3 *GrabColor, entry_id *Parent = 0);
205 |
206 | // quit curtain
207 |
208 | struct quit_animation
209 | {
210 | b32 AnimationStart;
211 | b32 WindowExit;
212 | entry_id *Curtain;
213 | render_text Text;
214 | r32 dAnim;
215 | r32 Time;
216 |
217 | r64 LastEscapePressTime;
218 | b32 Activated;
219 |
220 | render_text BonusText;
221 | };
222 |
223 | internal void CreateQuitAnimation(quit_animation *Result, v2 Size, string_c *ClosingText, r32 AnimationTime, font_size_id FontSize = font_Big, string_c *BonusText = NULL, r32 Depth = -0.99f);
224 | inline void SetActive(quit_animation *Quit, b32 Activate);
225 | internal b32 QuitAnimation(quit_animation *Quit, r32 Dir, v2 Position, v2 Size);
226 |
227 | // Popup text
228 |
229 | struct popup
230 | {
231 | entry_id *Anchor;
232 | entry_id *BG;
233 | render_text Text;
234 |
235 | r32 AnimTime;
236 | r32 dAnim;
237 | i32 AnimDir;
238 | };
239 |
240 | inline void SetActive(popup *Popup, b32 Activate);
241 | inline b32 IsActive(popup *Popup);
242 | inline void SetPosition(popup *Popup, v2 P);
243 | inline void SetLocalPosition(popup *Popup, v2 P);
244 | inline void SetParent(popup *Popup, entry_id *Parent);
245 | internal void CreatePopup(renderer *Renderer, arena_allocator *Arena, popup *Result, string_c Text, font_size FontSize, r32 Depth = -0.95f, r32 AnimTime = 0.1f);
246 | internal void ChangeText(renderer *Renderer, arena_allocator *Arena, popup *Popup, string_c NewText, font_size FontSize);
247 | internal void DoAnimation(popup *Popup, r32 dTime);
248 |
249 | // Border - Rectangle
250 |
251 | struct border_rectangle
252 | {
253 | entry_id *Top;
254 | entry_id *Bottom;
255 | entry_id *Right;
256 | entry_id *Left;
257 |
258 | r32 Thickness;
259 | };
260 | internal border_rectangle CreateBorderRectangle(renderer *Renderer, v2 Size, r32 Depth, r32 Thickness, v3 *Color, entry_id *Parent = NULL);
261 | inline void SetSize(border_rectangle *BorderRect, v2 Size);
262 | inline b32 IsActive(border_rectangle *BorderRect);
263 | inline void SetActive(border_rectangle *BorderRect, b32 Activate);
264 | inline void SetParent(border_rectangle *BorderRect, entry_id *Parent);
265 |
266 | #endif //_U_I__T_D_H
267 |
--------------------------------------------------------------------------------
/data/Buttons/Add_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Add_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Cancel_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Cancel_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/ColorPicker_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/ColorPicker_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Confirm_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Confirm_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/FastForward_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/FastForward_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Help_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Help_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Help_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Help_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Loop_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Loop_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Loop_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Loop_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Minus_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Minus_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/MusicPath_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/MusicPath_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Next_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Next_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/PaletteSwap_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PaletteSwap_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/PaletteSwap_Icon2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PaletteSwap_Icon2.png
--------------------------------------------------------------------------------
/data/Buttons/Pause_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Pause_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/PlayPause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PlayPause.png
--------------------------------------------------------------------------------
/data/Buttons/PlayPauseDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PlayPauseDown.png
--------------------------------------------------------------------------------
/data/Buttons/PlayPauseHover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PlayPauseHover.png
--------------------------------------------------------------------------------
/data/Buttons/PlayPause_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/PlayPause_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Play_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Play_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Previous_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Previous_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Randomize_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Randomize_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Randomize_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Randomize_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Rescan_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Rescan_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Save_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Save_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Search_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Search_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Shuffle_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Shuffle_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Shuffle_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Shuffle_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/Buttons/Stop_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Buttons/Stop_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Add_Large_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Add_Large_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Add_Medium_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Add_Medium_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Add_Small_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Add_Small_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Add_Tiny_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Add_Tiny_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Background_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Background_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Cancel_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Cancel_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/ColorPicker_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/ColorPicker_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Confirm_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Confirm_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Help_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Help_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Help_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Help_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Loop_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Loop_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Loop_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Loop_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Minus_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Minus_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/MusicPath_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/MusicPath_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Next_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Next_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Old/Minus_Icon_old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Old/Minus_Icon_old.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Old/Plus_Icon_old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Old/Plus_Icon_old.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Old/Save_Icon_old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Old/Save_Icon_old.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/PaletteSwap_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/PaletteSwap_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Pause_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Pause_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/PlayPause_Large_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/PlayPause_Large_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/PlayPause_Medium_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/PlayPause_Medium_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/PlayPause_Small_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/PlayPause_Small_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/PlayPause_Tiny_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/PlayPause_Tiny_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Play_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Play_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Playlist_AddSelection_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Playlist_AddSelection_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Playlist_Remove_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Playlist_Remove_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Playlist_Rename_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Playlist_Rename_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Plus_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Plus_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Previous_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Previous_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Randomize_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Randomize_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Randomize_Pressed_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Randomize_Pressed_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Rescan_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Rescan_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Save_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Save_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Search_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Search_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Stop_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Stop_Icon.png
--------------------------------------------------------------------------------
/data/ButtonsExactSize/Style_Settings_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/ButtonsExactSize/Style_Settings_Icon.png
--------------------------------------------------------------------------------
/data/Fonts/CarminaBoldBT.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaBoldBT.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaBoldItalicBT.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaBoldItalicBT.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMdBTBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMdBTBold.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMdBTBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMdBTBoldItalic.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMdBTMedium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMdBTMedium.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMdBTMediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMdBTMediumItalic.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMediumBT.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMediumBT.ttf
--------------------------------------------------------------------------------
/data/Fonts/CarminaMediumItalicBT.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/CarminaMediumItalicBT.ttf
--------------------------------------------------------------------------------
/data/Fonts/carmini.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Fonts/carmini.ttf
--------------------------------------------------------------------------------
/data/Fonts/sharefonts.net.txt:
--------------------------------------------------------------------------------
1 | Free download fonts at http://sharefonts.net
--------------------------------------------------------------------------------
/data/Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
208 |
--------------------------------------------------------------------------------
/data/Logo_V0.1.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Logo_V0.1.ico
--------------------------------------------------------------------------------
/data/Logo_V0.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Logo_V0.1.png
--------------------------------------------------------------------------------
/data/Logo_V0.1_Large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Logo_V0.1_Large.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_AquaticBlue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_AquaticBlue.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_Custom_Marshmallow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_Custom_Marshmallow.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_DeepNightGrey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_DeepNightGrey.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_LushGreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_LushGreen.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_MonochromeGrey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_MonochromeGrey.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_SmolderingRed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_SmolderingRed.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_ColorPalette_SummerSunrise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_ColorPalette_SummerSunrise.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_GatherMetadataMusicPath.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_GatherMetadataMusicPath.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_Goodbye_Curtain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_Goodbye_Curtain.png
--------------------------------------------------------------------------------
/data/Screenshots/MPlay3_MiniVersion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/MPlay3_MiniVersion.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_BluePalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_BluePalette.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_ColorPicker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_ColorPicker.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_CustomColorPalette_Pink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_CustomColorPalette_Pink.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_GreenPalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_GreenPalette.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_GreyscaleInvertedPalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_GreyscaleInvertedPalette.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_GreyscalePalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_GreyscalePalette.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_LargeFiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_LargeFiles.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_MiniVersion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_MiniVersion.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_QuitAnimation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_QuitAnimation.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_RedPalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_RedPalette.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_ScanMusicFolder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_ScanMusicFolder.png
--------------------------------------------------------------------------------
/data/Screenshots/Pre_01.6/MPlay3_Searching.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Pre_01.6/MPlay3_Searching.png
--------------------------------------------------------------------------------
/data/Screenshots/Thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Thumbnail.png
--------------------------------------------------------------------------------
/data/Screenshots/Thumbnail2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/Screenshots/Thumbnail2.png
--------------------------------------------------------------------------------
/data/resources/EmbeddedResourcesSTUB.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | global_variable u32 const Background_Icon_Width = 0;
4 | global_variable u32 const Background_Icon_Height = 0;
5 | global_variable u8 const Background_Icon_Data[] = {0};
6 |
7 |
8 |
9 | global_variable u32 const Loop_Icon_Width = 0;
10 | global_variable u32 const Loop_Icon_Height = 0;
11 | global_variable u8 const Loop_Icon_Data[] = {0};
12 |
13 |
14 |
15 | global_variable u32 const Loop_Pressed_Icon_Width = 0;
16 | global_variable u32 const Loop_Pressed_Icon_Height = 0;
17 | global_variable u8 const Loop_Pressed_Icon_Data[] = {0};
18 |
19 |
20 |
21 | global_variable u32 const Randomize_Icon_Width = 0;
22 | global_variable u32 const Randomize_Icon_Height = 0;
23 | global_variable u8 const Randomize_Icon_Data[] = {0};
24 |
25 |
26 |
27 | global_variable u32 const Randomize_Pressed_Icon_Width = 0;
28 | global_variable u32 const Randomize_Pressed_Icon_Height = 0;
29 | global_variable u8 const Randomize_Pressed_Icon_Data[] = {0};
30 |
31 |
32 |
33 | global_variable u32 const Play_Icon_Width = 0;
34 | global_variable u32 const Play_Icon_Height = 0;
35 | global_variable u8 const Play_Icon_Data[] = {0};
36 |
37 |
38 |
39 | global_variable u32 const Pause_Icon_Width = 0;
40 | global_variable u32 const Pause_Icon_Height = 0;
41 | global_variable u8 const Pause_Icon_Data[] = {0};
42 |
43 |
44 |
45 | global_variable u32 const PlayPause_Icon_Width = 0;
46 | global_variable u32 const PlayPause_Icon_Height = 0;
47 | global_variable u8 const PlayPause_Icon_Data[] = {0};
48 |
49 |
50 |
51 | global_variable u32 const AddSong_Icon_Width = 0;
52 | global_variable u32 const AddSong_Icon_Height = 0;
53 | global_variable u8 const AddSong_Icon_Data[] = {0};
54 |
55 |
56 |
57 | global_variable u32 const Stop_Icon_Width = 0;
58 | global_variable u32 const Stop_Icon_Height = 0;
59 | global_variable u8 const Stop_Icon_Data[] = {0};
60 |
61 |
62 |
63 | global_variable u32 const Next_Icon_Width = 0;
64 | global_variable u32 const Next_Icon_Height = 0;
65 | global_variable u8 const Next_Icon_Data[] = {0};
66 |
67 |
68 |
69 | global_variable u32 const Previous_Icon_Width = 0;
70 | global_variable u32 const Previous_Icon_Height = 0;
71 | global_variable u8 const Previous_Icon_Data[] = {0};
72 |
73 |
74 |
75 | global_variable u32 const MusicPath_Icon_Width = 0;
76 | global_variable u32 const MusicPath_Icon_Height = 0;
77 | global_variable u8 const MusicPath_Icon_Data[] = {0};
78 |
79 |
80 |
81 | global_variable u32 const Confirm_Icon_Width = 0;
82 | global_variable u32 const Confirm_Icon_Height = 0;
83 | global_variable u8 const Confirm_Icon_Data[] = {0};
84 |
85 |
86 |
87 | global_variable u32 const Cancel_Icon_Width = 0;
88 | global_variable u32 const Cancel_Icon_Height = 0;
89 | global_variable u8 const Cancel_Icon_Data[] = {0};
90 |
91 |
92 |
93 | global_variable u32 const PaletteSwap_Icon_Width = 0;
94 | global_variable u32 const PaletteSwap_Icon_Height = 0;
95 | global_variable u8 const PaletteSwap_Icon_Data[] = {0};
96 |
97 |
98 |
99 | global_variable u32 const Rescan_Icon_Width = 0;
100 | global_variable u32 const Rescan_Icon_Height = 0;
101 | global_variable u8 const Rescan_Icon_Data[] = {0};
102 |
103 |
104 |
105 | global_variable u32 const ColorPicker_Icon_Width = 0;
106 | global_variable u32 const ColorPicker_Icon_Height = 0;
107 | global_variable u8 const ColorPicker_Icon_Data[] = {0};
108 |
109 |
110 |
111 | global_variable u32 const Help_Icon_Width = 0;
112 | global_variable u32 const Help_Icon_Height = 0;
113 | global_variable u8 const Help_Icon_Data[] = {0};
114 |
115 |
116 |
117 | global_variable u32 const Help_Pressed_Icon_Width = 0;
118 | global_variable u32 const Help_Pressed_Icon_Height = 0;
119 | global_variable u8 const Help_Pressed_Icon_Data[] = {0};
120 |
121 |
122 |
123 | global_variable u32 const Plus_Icon_Width = 0;
124 | global_variable u32 const Plus_Icon_Height = 0;
125 | global_variable u8 const Plus_Icon_Data[] = {0};
126 |
127 |
128 |
129 | global_variable u32 const Minus_Icon_Width = 0;
130 | global_variable u32 const Minus_Icon_Height = 0;
131 | global_variable u8 const Minus_Icon_Data[] = {0};
132 |
133 |
134 |
135 | global_variable u32 const Save_Icon_Width = 0;
136 | global_variable u32 const Save_Icon_Height = 0;
137 | global_variable u8 const Save_Icon_Data[] = {0};
138 |
139 |
140 |
141 | global_variable u32 const Search_Icon_Width = 0;
142 | global_variable u32 const Search_Icon_Height = 0;
143 | global_variable u8 const Search_Icon_Data[] = {0};
144 |
145 |
146 |
147 | global_variable u32 const Playlist_Add_Icon_Width = 0;
148 | global_variable u32 const Playlist_Add_Icon_Height = 0;
149 | global_variable u8 const Playlist_Add_Icon_Data[] = {0};
150 |
151 |
152 |
153 | global_variable u32 const Playlist_Remove_Icon_Width = 0;
154 | global_variable u32 const Playlist_Remove_Icon_Height = 0;
155 | global_variable u8 const Playlist_Remove_Icon_Data[] = {0};
156 |
157 |
158 |
159 | global_variable u32 const Playlist_Rename_Icon_Width = 0;
160 | global_variable u32 const Playlist_Rename_Icon_Height = 0;
161 | global_variable u8 const Playlist_Rename_Icon_Data[] = {0};
162 |
163 |
164 |
165 | global_variable u32 const carmini_DataCount = 0;
166 | global_variable u8 const carmini_Data[] = {0};
167 |
168 |
169 |
--------------------------------------------------------------------------------
/data/resources/Resource.rc:
--------------------------------------------------------------------------------
1 | #include "resource.h"
2 |
3 | MAIN_ICON ICON "../data/Logo_V0.1.ico"
--------------------------------------------------------------------------------
/data/resources/ResourceListing.txt:
--------------------------------------------------------------------------------
1 | ../data/Buttons/PlayPause.png
2 | ../data/Buttons/Shuffle_Icon.png
3 | ../data/Buttons/Shuffle_Pressed_Icon.png
4 | ../data/Buttons/Loop_Icon.png
5 | ../data/Buttons/Loop_Pressed_Icon.png
6 | ../data/Buttons/Randomize_Icon.png
7 | ../data/Buttons/Randomize_Pressed_Icon.png
8 | ../data/Buttons/Play_Icon.png
9 | ../data/Buttons/Pause_Icon.png
10 | ../data/Buttons/Stop_Icon.png
11 | ../data/Buttons/Next_Icon.png
12 | ../data/Buttons/Previous_Icon.png
13 | ../data/Buttons/MusicPath_Icon.png
14 | ../data/Buttons/Confirm_Icon.png
15 | ../data/Buttons/Cancel_Icon.png
16 | ../data/Buttons/PaletteSwap_Icon2.png
17 | ../data/Buttons/Rescan_Icon.png
18 | ../data/Buttons/ColorPicker_Icon.png
19 | ../data/Buttons/Help_Icon.png
20 | ../data/Buttons/Help_Pressed_Icon.png
21 | ../data/Buttons/Add_Icon.png
22 | ../data/Buttons/Minus_Icon.png
23 | ../data/Buttons/Save_Icon.png
24 | ../data/Buttons/Search_Icon.png
25 | ../data/Fonts/carmini.ttf
--------------------------------------------------------------------------------
/data/resources/ResourceListingExactSize.txt:
--------------------------------------------------------------------------------
1 | ../data/ButtonsExactSize/Background_Icon.png
2 | ../data/ButtonsExactSize/Loop_Icon.png
3 | ../data/ButtonsExactSize/Loop_Pressed_Icon.png
4 | ../data/ButtonsExactSize/Randomize_Icon.png
5 | ../data/ButtonsExactSize/Randomize_Pressed_Icon.png
6 | ../data/ButtonsExactSize/Play_Icon.png
7 | ../data/ButtonsExactSize/Pause_Icon.png
8 | ../data/ButtonsExactSize/PlayPause_Large_Icon.png
9 | ../data/ButtonsExactSize/PlayPause_Medium_Icon.png
10 | ../data/ButtonsExactSize/PlayPause_Small_Icon.png
11 | ../data/ButtonsExactSize/PlayPause_Tiny_Icon.png
12 | ../data/ButtonsExactSize/Add_Large_Icon.png
13 | ../data/ButtonsExactSize/Add_Medium_Icon.png
14 | ../data/ButtonsExactSize/Add_Small_Icon.png
15 | ../data/ButtonsExactSize/Add_Tiny_Icon.png
16 | ../data/ButtonsExactSize/Stop_Icon.png
17 | ../data/ButtonsExactSize/Next_Icon.png
18 | ../data/ButtonsExactSize/Previous_Icon.png
19 | ../data/ButtonsExactSize/MusicPath_Icon.png
20 | ../data/ButtonsExactSize/Confirm_Icon.png
21 | ../data/ButtonsExactSize/Cancel_Icon.png
22 | ../data/ButtonsExactSize/PaletteSwap_Icon.png
23 | ../data/ButtonsExactSize/Rescan_Icon.png
24 | ../data/ButtonsExactSize/ColorPicker_Icon.png
25 | ../data/ButtonsExactSize/Help_Icon.png
26 | ../data/ButtonsExactSize/Help_Pressed_Icon.png
27 | ../data/ButtonsExactSize/Minus_Icon.png
28 | ../data/ButtonsExactSize/Save_Icon.png
29 | ../data/ButtonsExactSize/Search_Icon.png
30 | ../data/ButtonsExactSize/Playlist_AddSelection_Icon.png
31 | ../data/ButtonsExactSize/Playlist_Remove_Icon.png
32 | ../data/ButtonsExactSize/Playlist_Rename_Icon.png
33 | ../data/ButtonsExactSize/Style_Settings_Icon.png
34 | ../data/Fonts/carmini.ttf
--------------------------------------------------------------------------------
/data/resources/Resources.res:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CaptainTimberTim/MPlay3/31d2cbde59a9f5f64afe7623edc79b1b8c9fef25/data/resources/Resources.res
--------------------------------------------------------------------------------
/data/resources/resource.h:
--------------------------------------------------------------------------------
1 | #define MAIN_ICON 102
2 |
--------------------------------------------------------------------------------
/editor.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | start "" "%cd%\..\..\4coder\4ed.exe"
3 | cd build
4 | devenv MPlay3.exe
5 |
--------------------------------------------------------------------------------
/project.4coder:
--------------------------------------------------------------------------------
1 | version(2);
2 | project_name = "MPlay3";
3 | patterns = {
4 | "*.c",
5 | "*.cpp",
6 | "*.h",
7 | "*.m",
8 | "*.bat",
9 | "*.sh",
10 | "*.4coder",
11 | };
12 | blacklist_patterns = {
13 | ".*", "resources",
14 | };
15 | load_paths_base = {
16 | { ".", .relative = true, .recursive = true, },
17 | };
18 | load_paths = {
19 | .win = load_paths_base,
20 | };
21 |
22 | commands = {
23 | .build = { .out = "*compilation*", .footer_panel = true, .save_dirty_files = true,
24 | .win = "build.bat", },
25 | .buildOptimized = { .out = "*compilation optimized*", .footer_panel = true, .save_dirty_files = true,
26 | .win = "buildOptimized.bat", },
27 | .run = { .out = "*run*", .footer_panel = false, .save_dirty_files = false,
28 | .win = ".\\build\\MPlay3.exe", }
29 | };
30 | fkey_command = {
31 | .F1 = "build",
32 | .F2 = "buildOptimized",
33 | .F4 = "run",
34 | };
35 |
--------------------------------------------------------------------------------
/search.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | start "" "%cd%\..\..\..\..\Portable_Programms\baregrep.exe"
--------------------------------------------------------------------------------
/shell.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
3 | set path="%cd%";"%cd%\code";%path%
4 | "editor"
--------------------------------------------------------------------------------