├── .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 | 20 | 22 | 25 | 29 | 33 | 37 | 38 | 46 | 51 | 52 | 58 | 69 | 70 | 88 | 90 | 91 | 93 | image/svg+xml 94 | 96 | 97 | 98 | 99 | 100 | 104 | 114 | 124 | 132 | 138 | 144 | MPlay3 153 | 163 | 171 | 176 | 184 | 190 | 196 | MPlay3 205 | 206 | 207 | 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" --------------------------------------------------------------------------------