Compare commits

..
645 Commits
Author SHA1 Message Date
Krzosa Karol ba6de21396 Query file add UI indicator (but need something better ...), fix remedy 2026-01-23 22:36:11 +01:00
Krzosa Karol b75e0a8a55 Add '..' to file listing 2026-01-23 22:35:12 +01:00
Krzosa Karol 9a64fd8e01 BIG OPTIMIZATIONS: WTF IT WORKS SO FAST NOW, 9000 files open easy WHAAAT 2026-01-22 22:59:17 +01:00
Krzosa Karol b0a0fca8ee SelfAttachDebugger command 2026-01-22 10:43:22 +01:00
Krzosa Karol 710269a876 plugin_file_commands 2026-01-22 10:25:34 +01:00
Krzosa Karol 4a410c3c1a Profiler as plugin 2026-01-22 08:57:56 +01:00
Krzosa Karol 4fa1a49765 :BeginProfile :EndProfile 2026-01-21 23:00:59 +01:00
Krzosa Karol 9614f01e20 Build1 and Build2 2026-01-21 22:29:38 +01:00
Krzosa Karol 36839df841 Make GotoNextInList only skip things that are in range of first caret 2026-01-21 09:05:30 +01:00
Krzosa Karol 2b1eab54b3 Since we are doing column searches, don't skip entries in GoToNext on same line 2026-01-21 09:00:07 +01:00
Krzosa Karol 8128c2932e Fix search anchor with ctrl-f 2026-01-21 08:59:32 +01:00
Krzosa Karol 851eac0ec2 Try open with selection always opening first line 2026-01-21 08:59:21 +01:00
Krzosa Karol df963b0893 LogBuffer and NullBuffer separation, More indicators in status as new line as sep, eval multiple carets with Open, :Errors 2026-01-21 08:28:12 +01:00
Krzosa Karol 84c992c574 CreateProject OpenProject 2026-01-19 23:16:32 +01:00
Krzosa Karol 1ce128a5d5 CoroutineLeakCheck 2026-01-19 09:08:26 +01:00
Krzosa Karol 372287f557 CMD_SetProjectHere, look for project files 2026-01-19 08:44:05 +01:00
Krzosa Karol 8ecfc82d8f RemedyBGPlugin: Look for .rdbg file in project dir if BinaryUnderDebug not set 2026-01-19 08:43:52 +01:00
Krzosa Karol 9d60b110f5 RemedyBG asks for binary 2026-01-19 08:17:43 +01:00
Krzosa Karol 70f28de0e1 Add QueryUserString. QueryUserFile working, fix bug in Open with line,col. 2026-01-18 22:53:10 +01:00
Krzosa Karol 76e279920f Prototyping QueryUserFile 2026-01-17 13:22:33 +01:00
Krzosa Karol 37cb6248a5 RegisterCoroutineCommand, 2026-01-17 13:12:34 +01:00
Krzosa Karol 37154a2067 Continuing cleanup, ui.cpp 2026-01-17 11:12:18 +01:00
Krzosa Karol e52450a3df Big UI cleanup 2026-01-17 10:26:39 +01:00
Krzosa Karol 6fc5f0538f CMD_RunFile 2026-01-17 09:51:40 +01:00
Krzosa Karol c970c1c7d6 UndoEdit, RedoEdit fix recursion, search buffers uses temp buffers now 2026-01-17 08:22:32 +01:00
Krzosa Karol 01488e4eca Search all temp buffers opens a new buffer 2026-01-17 08:03:13 +01:00
Krzosa Karol ce1fe5feb1 Fix ReplaceAll bug 2026-01-16 23:27:04 +01:00
Krzosa Karol 270109a56b Fix ctrl-shift-f and AddCommand bugs 2026-01-16 23:15:23 +01:00
Krzosa Karol 663286b45c plugin_config.cpp continuing the experiment 2026-01-16 23:04:11 +01:00
Krzosa Karol d5c3794a93 Toying with structure, using #if instead of #ifdef because of name checking 2026-01-16 21:31:50 +01:00
Krzosa Karol dcda334767 Cut down on header files 2026-01-16 20:51:10 +01:00
Krzosa Karol 69c9f7a336 Toying with structure, plugin_record_events, record_gc 2026-01-16 20:43:02 +01:00
Krzosa Karol ca3d087aa3 window_management_commands 2026-01-16 09:05:17 +01:00
Krzosa Karol d2be40a282 plugin_directory_navigation 2026-01-16 08:58:13 +01:00
Krzosa Karol 6c200f7764 plugin_basic_commands.cpp 2026-01-15 23:26:14 +01:00
Krzosa Karol 8de20eb0e2 plugin_basic_commands.cpp 2026-01-15 23:26:06 +01:00
Krzosa Karol 86c91668e1 Fix 2026-01-15 23:15:05 +01:00
Krzosa Karol 1e4e9fbccc Toying with the new plugin idea 2026-01-15 23:14:39 +01:00
Krzosa Karol 36180c5c90 Fix NullWindow going white 2026-01-15 22:52:18 +01:00
Krzosa Karol 5ab20ce8ab Remove hooks fully, replace with commands again 2026-01-15 22:41:16 +01:00
Krzosa Karol 61fc0cd339 Continuing refactor 2026-01-15 22:24:05 +01:00
Krzosa Karol 3864060699 Begin new plugin system refactor, removing hooks 2026-01-15 22:23:04 +01:00
Krzosa Karol db06c783a9 Misc improvements 2026-01-15 20:24:12 +01:00
Krzosa Karol f33c9873d0 Use system config path for config 2026-01-15 09:13:39 +01:00
Krzosa Karol 66483f6c99 Testing gitea 2026-01-15 09:08:43 +01:00
Krzosa Karol da821cb581 Add icon back 2026-01-15 09:03:08 +01:00
Krzosa Karol f85697d037 Debugger fix 2026-01-15 08:57:54 +01:00
Krzosa Karol 02c45e0dfd Continuing with remedybg integration 2026-01-10 15:20:56 +01:00
Krzosa Karol 05d5de4b7d RemedyBG integration plugin 2026-01-10 14:03:00 +01:00
Krzosa Karol e575569d8a Misc 2026-01-10 10:36:09 +01:00
Krzosa Karol 4c9c0e5210 Continuing the hook refactor, BeforeSaveBuffer 2026-01-10 10:28:12 +01:00
Krzosa Karol 507bd57854 Continuing hook refactor 2026-01-09 23:07:47 +01:00
Krzosa Karol 0dd4641044 Continuing hook refactor 2026-01-09 23:02:22 +01:00
Krzosa Karol 57c179970e Moving stuff over to new system 2026-01-09 09:09:58 +01:00
Krzosa Karol 005a22a93d New hook design 2026-01-09 08:23:48 +01:00
Krzosa Karol de06ea05cc Hooks sketch 2026-01-08 10:15:02 +01:00
Krzosa Karol 5fecc74193 Remove header files, consolidate text_editor.h again because it was annoying 2026-01-07 22:47:05 +01:00
Krzosa Karol 101fed6d7d Release build and packaging 2026-01-07 22:26:18 +01:00
Krzosa Karol 239126db70 f12 2026-01-07 09:00:06 +01:00
Krzosa Karol 59320a749a Start the guide 2026-01-07 08:59:54 +01:00
Krzosa Karol a43b1db424 New ReplaceAll 2026-01-07 08:39:11 +01:00
Krzosa Karol 3ba9a9380e FormatSelection 2026-01-06 14:57:43 +01:00
Krzosa Karol a96cead179 Fix indenting 2026-01-06 14:15:20 +01:00
Krzosa Karol 73a19e2260 Try decreasing number of events, testing period 2026-01-06 13:40:45 +01:00
Krzosa Karol 94b3bc832b Improve SearchProject and misc 2026-01-06 10:50:55 +01:00
Krzosa Karol ecbc800fdd Indent on open scope 2026-01-05 19:40:05 +01:00
Krzosa Karol 753c9199b6 CenterView on jumping back and forward 2026-01-05 19:17:55 +01:00
Krzosa Karol eb19ba6037 Fix jump back on ctrl-enter and ctrl-shift-enter, 2026-01-05 19:17:32 +01:00
Krzosa Karol 1a6159e0ec Fix OS layer returning with "/" at the end for directories 2026-01-05 15:10:29 +01:00
Krzosa Karol c90857eb46 Change order of loading config because of OpenCode patterns not applying 2026-01-05 15:04:50 +01:00
Krzosa Karol 146273afd8 ExcludePatterns for OpenCode 2026-01-05 15:01:43 +01:00
Krzosa Karol 8f4d3a218f Improve OpenCode 2026-01-05 14:52:00 +01:00
Krzosa Karol 8c0c9c82f1 Redesign OpenConfigOptions 2026-01-05 14:42:27 +01:00
Krzosa Karol d694a374d6 Improve fuzzy finding 2026-01-05 14:41:19 +01:00
Krzosa Karol f646a6d22c Improve ctrl deletes 2026-01-05 12:28:09 +01:00
Krzosa Karol c0d00a6211 Add IsDebuggerPresent 2026-01-05 12:03:25 +01:00
Krzosa Karol 96d9847639 Project configs 2026-01-05 11:54:10 +01:00
Krzosa Karol 233ebe0eba Misc 2026-01-05 10:34:00 +01:00
Krzosa Karol 80ea09b3ea Improving the jump history 2026-01-05 10:30:17 +01:00
Krzosa Karol 77c6bf3da9 Add config.te 2026-01-05 10:15:31 +01:00
Krzosa Karol 565a005dcb Misc improvements and add config.te 2026-01-05 10:15:26 +01:00
Krzosa Karol 40b15ec7aa Fix bug in coroutine of SearchProject and use selected string as seed for search 2026-01-05 10:14:35 +01:00
Krzosa Karol 9073909cfc Redesign of show buffers / show debug buffers 2026-01-05 10:13:59 +01:00
Krzosa Karol cc57da69fd Argument parsing executes commands now 2026-01-05 10:13:17 +01:00
Krzosa Karol 31ebf0bb14 SkipWhitespace fix and LoadWord change 2026-01-05 00:25:23 +01:00
Krzosa Karol a7afdac4fa Fix automatic buffer reopen, modifying ctrl-left/right semantics inline with vscode/sublime, modifying load word semantics 2026-01-04 18:28:55 +01:00
Krzosa Karol 04e5642ce3 IndentKind, config is not automatically visible on start, fix automatic ReopenBuffer 2026-01-04 14:00:35 +01:00
Krzosa Karol f059c33940 BasicSaveBuffer and SaveAll improvements 2026-01-04 00:33:02 +01:00
Krzosa Karol 1b8f0b12e8 Don't GC view when process is active, don't show some buffers 2026-01-03 15:04:46 +01:00
Krzosa Karol bfcab9b3c3 Fix EvalCommandsLineByLine wholly failing on any error, redesign :Set 2026-01-03 14:48:27 +01:00
Krzosa Karol da96fb847c Don't wait when scrolling with middle click 2026-01-02 23:23:44 +01:00
Krzosa Karol 1767b2767e SetWorkDirAt, OpenCodeAt, fix bug there, fill more doc strings 2026-01-02 19:57:53 +01:00
Krzosa Karol 215dd4a03f Layout window to PrimaryWindow, command documentation 2026-01-02 16:05:56 +01:00
Krzosa Karol 9730aa944d Expanding go to next in list functionality 2026-01-02 15:21:33 +01:00
Krzosa Karol bedc2b15e2 ActiveSearch/SearchAll command and beginnings of ReplaceAll command, coroutine interface change 2026-01-02 09:08:34 +01:00
Krzosa Karol ee1ba86f74 Update todo 2026-01-01 20:18:18 +01:00
Krzosa Karol 82e1c33db5 Fix SetWorkDir 2026-01-01 18:33:53 +01:00
Krzosa Karol 78917e28fb Misc 2026-01-01 18:01:40 +01:00
Krzosa Karol 505b2d0ffa Improving command parsing semantics, gofmt, warn when command reported 2026-01-01 18:00:21 +01:00
Krzosa Karol dd7e2ff655 lock in SDL version 2026-01-01 14:57:11 +01:00
Krzosa Karol 9affcd546a README and image 2026-01-01 14:52:10 +01:00
Krzosa Karol e4f2401633 FormatUsingClangFormatWhenCCode and TrimTrailingWhitespace 2026-01-01 14:44:11 +01:00
Krzosa Karol 65a6c372e0 FormatUsingClangFormatWhenCCode and TrimTrailingWhitespace 2026-01-01 14:41:37 +01:00
Krzosa Karol bbab59fa0a NonCodePatterns_EndsWith 2026-01-01 14:29:33 +01:00
Krzosa Karol 6cf9731959 Wheel scrolling 2026-01-01 13:48:21 +01:00
Krzosa Karol c4b4460cbd List the build buffer 2026-01-01 13:31:38 +01:00
Krzosa Karol 5b50a49416 SmallFix 2025-12-31 17:36:19 +01:00
Krzosa Karol c6bff29bef Center on Search, fix crash on GC, Remove repo 2025-12-31 17:34:46 +01:00
Krzosa Karol 193c3b36ef secondary_window_stylw 2025-12-31 15:34:20 +01:00
Krzosa Karol 1d1e865745 Misc 2025-12-31 15:33:43 +01:00
Krzosa Karol 9758d83856 Rename colors 2025-12-31 15:33:32 +01:00
Krzosa Karol 59081eb4bd ReloadFont when variables change 2025-12-31 15:25:00 +01:00
Krzosa Karol a40797abb2 Config files 2025-12-31 13:47:15 +01:00
Krzosa Karol 6c0a4d0633 Command_ to CMD_ 2025-12-31 12:46:52 +01:00
Krzosa Karol edafe05b5b EvalCommandsLineByLine 2025-12-31 12:45:28 +01:00
Krzosa Karol b40873d54c :Set command 2025-12-31 11:50:21 +01:00
Krzosa Karol 0921054b6e Fix view centering 2025-12-31 10:34:11 +01:00
Krzosa Karol f8f9e33032 Directory fuzzy search and fix C: not opening 2025-12-31 08:27:22 +01:00
Krzosa Karol beaf072740 Show dirty buffer in status window 2025-12-30 18:23:34 +01:00
Krzosa Karol e5a028ff93 Misc refactor 2025-12-30 13:08:18 +01:00
Krzosa Karol 8270fe2542 Assign ActiveWindowID to NullWindowID if window doesn't exist, misc 2025-12-30 13:06:36 +01:00
Krzosa Karol 5214ce61ac Hook code cleanup 2025-12-30 12:56:36 +01:00
Krzosa Karol ebf0f5de27 Remove jump history, Make sure these windows are visible one at a time 2025-12-30 12:42:05 +01:00
Krzosa Karol ca464c314b Add build window 2025-12-30 12:18:08 +01:00
Krzosa Karol b140d9c3f1 Optimizing search, buggy BlockArena on emscripten, cleanup MergeSort, address sanitizer, compile web on linux 2025-12-30 11:59:20 +01:00
krzosa a57ebb49be Allocator memes 2025-12-30 10:09:46 +01:00
krzosa 187bbcc5fc Update todos 2025-12-30 09:20:48 +01:00
krzosa 50ac0600cb Update todo 2025-12-29 22:36:55 +01:00
krzosa 9da85fadbd Ctrl-tab 2025-12-29 22:28:08 +01:00
krzosa ab8558ef43 Misc changes 2025-12-29 16:22:51 +01:00
krzosa c5afe78b91 UX improvements 2025-12-29 13:07:28 +01:00
krzosa c1828a51c4 Improvement to mouse navigation 2025-12-29 13:00:17 +01:00
krzosa 97ba82ab7d Better Rename 2025-12-29 12:26:03 +01:00
krzosa cde431549c :Prev :Next, CatchAll 2025-12-29 12:02:08 +01:00
krzosa ccf55d6d74 Naming and fix CloseAll 2025-12-29 10:48:06 +01:00
krzosa 0f03f248c7 Coroutine arenas 2025-12-29 10:36:16 +01:00
krzosa 35d68bda61 UIMessagef 2025-12-29 10:33:50 +01:00
krzosa 1ae20a46b2 Renaming, I don't like this 2025-12-29 09:13:38 +01:00
krzosa 10fb5d77a1 Replace SDL dialogs with coroutine UI 2025-12-29 08:32:24 +01:00
krzosa 19d5a26966 UIYesNoCancel 2025-12-28 16:22:39 +01:00
krzosa e9db3d7386 Misc 2025-12-28 16:15:51 +01:00
krzosa 2acf2c189c First prototype of coroutine based UI 2025-12-28 16:12:22 +01:00
krzosa 06cb073832 New UI buffer thing 2025-12-28 10:29:53 +01:00
krzosa 00442da5dd Misc improvements 2025-12-28 10:29:05 +01:00
Krzosa Karol 1011c63494 Open dir, small fixes 2025-12-27 21:37:41 +01:00
Krzosa Karol 28d8348b89 OpenCode opens everything except few 2025-12-27 19:14:18 +01:00
Krzosa Karol e4b84dde90 Search case sensitive and word boundary 2025-12-27 15:54:10 +01:00
Krzosa Karol b6f3a1ebec NextActiveWindowID to fix the bug where ctrl+q would trigger for 2 registered commands and it would work on 2 different active windows 2025-12-27 12:46:46 +01:00
Krzosa Karol 9ae73e5c04 Find all: alt-enter, alt-f3 2025-12-27 11:29:40 +01:00
Krzosa Karol 6f9299e557 Misc changes 2025-12-26 21:01:54 +01:00
Krzosa Karol 29ad3a8f08 Checkpoint automation 2025-12-26 20:59:52 +01:00
Krzosa Karol 44bf7c68ff Misc 2025-12-26 15:41:29 +01:00
Krzosa Karol 4221aa8fb7 Finite size jump history, improving backtrace, redo, undo grouping, similar for jump history 2025-12-26 15:40:03 +01:00
Krzosa Karol 509db7af46 Ctrl-f fills with currently selected 2025-12-26 11:57:09 +01:00
Krzosa Karol 5c46844747 Buffer directories design change 2025-12-25 12:08:49 +01:00
Krzosa Karol 2f638c731a Fix Open 2025-12-25 11:52:02 +01:00
krzosa b98d14f9dd Build panel and reworking Open paths, not compiling 2025-12-24 11:19:23 +01:00
krzosa ceb6747fcd Add Find: to search window 2025-12-24 08:54:46 +01:00
krzosa 938edcc321 Improving the design 2025-12-24 08:49:01 +01:00
krzosa 28308f58b2 Optimizations and profiling (fix draw line numbers, coroutines) 2025-12-23 13:18:41 +01:00
krzosa 74ae806978 When coroutines active don't wait 2025-12-23 09:41:03 +01:00
krzosa c67db4e495 Implement new search window 2025-12-23 08:52:42 +01:00
krzosa edc941bf53 Make OpenCode into coroutine 2025-12-23 08:14:22 +01:00
krzosa edb2379bce Invert command window 2025-12-22 21:24:35 +01:00
krzosa 05652240f1 Don't show special buffers, misc 2025-12-22 17:54:33 +01:00
krzosa af1d88b07c Optimize GarbageCollect and DebugWindowUpdate, bring back profiler 2025-12-22 17:44:21 +01:00
krzosa 6243cace7d Command_CloseAll, Command_Quit, Command_NewWindow 2025-12-22 11:31:06 +01:00
krzosa 3ba7eeb1f2 Command_Close 2025-12-22 11:01:10 +01:00
krzosa 32efabac6a Add message dialog asking to save on quit 2025-12-22 09:50:38 +01:00
krzosa 725cdde007 Rename to Config, Fix slowness of ShowCommands and improve quality 2025-12-21 22:26:15 +01:00
krzosa 79d709d391 Build on new PC, fix wheel not scrolling 2025-12-21 22:04:39 +01:00
krzosa c8a7c75dbe Remove old build_web.sh 2025-12-21 20:21:08 +01:00
krzosa c99c3881ed Remove generated config 2025-12-21 20:20:34 +01:00
krzosa 868c95f7d6 Remove metaprogram 2025-12-21 20:16:22 +01:00
Krzosa Karol 0a315760f7 Moving Open code to C 2025-12-21 19:04:19 +01:00
Krzosa Karol 56b8b09f35 Broken, remove lua 2025-12-21 08:51:53 +01:00
Krzosa Karol 266378154a Windows refactor and moving things around 2025-12-20 18:17:28 +01:00
Krzosa Karol f637352669 RegisterVariable 2025-12-20 11:37:02 +01:00
Krzosa Karol bb9809b956 Fix pagedown/up 2025-12-20 10:29:06 +01:00
Krzosa Karol ce93a769f6 Remove hooks, file modifications 2025-12-20 09:54:19 +01:00
Krzosa Karol 7720176e60 First hooks 2025-12-18 08:29:54 +01:00
Krzosa Karol 29002c965c Commands and keybindings 2025-12-16 23:07:16 +01:00
Krzosa Karol 5e7acd4a20 Binding parser, TestFunctions 2025-12-15 23:29:18 +01:00
Krzosa Karol 4e5a0f6a9b Remove NextActiveWindowID 2025-12-14 23:08:22 +01:00
Krzosa Karol f297006dcb RegisterLua and ShowCommands, continue refactor 2025-12-14 21:54:37 +01:00
Krzosa Karol 85ca1a6a9e RegisterCommand 2025-12-14 17:32:48 +01:00
Krzosa Karol 5a12ab8d8c Linux add backtrace, fixing scaling / DPI problems 2025-12-14 17:05:55 +01:00
Krzosa Karol 2d79790d83 Remove init.project.lua 2025-12-14 12:04:03 +01:00
Krzosa Karol a351d2eb41 restructuring 2025-12-14 10:32:42 +01:00
Krzosa Karol 0424ca62f2 Fix eval error 2025-12-14 08:18:17 +01:00
Krzosa Karol 83d5ddff9d Fix lua bug 2025-12-09 08:31:31 +01:00
Krzosa Karol b600361278 Refactor Command_s 2025-12-08 09:23:07 +01:00
Krzosa Karol 9d29a1c187 Refactoring Command_s, NextWindowID 2025-12-08 09:16:31 +01:00
Krzosa Karol 20207e6040 jump history 2025-12-08 08:37:52 +01:00
Krzosa Karol ef6a7be285 Command bar, undo merge time 2025-12-07 13:57:51 +01:00
Krzosa Karol df84d1605d Bring back status bar with new design, fixing bugs 2025-12-07 10:40:30 +01:00
Krzosa Karol 88a5adaa0a Big refactor new layout 2025-12-06 19:12:06 +01:00
Krzosa Karol e6e1ae0223 Switch to using arrays for Windows, Views, Buffers list, try to make DeleteWindow work 2025-12-05 08:58:46 +01:00
Krzosa Karol 05f0197d50 Fixing tests, Fixed buffer dealloc bug, fixed clipboard bug 2025-12-03 10:38:27 +01:00
Krzosa Karol e34c2b0cef Allow multiple fonts 2025-12-01 09:05:06 +01:00
Krzosa Karol c2f4686bc4 BlockArena, a bit of allocator rework 2025-11-30 19:54:46 +01:00
Krzosa Karol c19c60fe22 Tracking allocator, buffer tests 2025-11-28 09:59:09 +01:00
Krzosa Karol d72485a137 Format string refactor 2025-11-27 23:13:28 +01:00
Krzosa Karol e9e8751981 Refactor windows and web compiling 2025-11-27 22:45:10 +01:00
Krzosa Karol 781c2dc53c Start refactor, restructure basic 2025-11-27 09:00:10 +01:00
Krzosa Karol 38b9b7df10 luaunity.c 2025-11-26 10:21:18 +01:00
Krzosa Karol a2cf5f2284 Misc 2025-11-26 09:49:39 +01:00
Krzosa Karol 38a20bd97a Fix rendering of whitespace, continue wasm porting 2025-11-25 09:47:03 +01:00
Krzosa Karol fcefe9f827 Porting to WASM 2025-11-24 22:59:39 +01:00
Krzosa Karol 56cdb9557d Porting to WASM 2025-11-24 22:59:11 +01:00
krzosa 166f06d1fb Trace buffer vs Debug buffer, print Buffer info, Add SaveAll 2025-08-21 09:16:31 +02:00
krzosa 24533dfe7f Print and print in lua 2025-08-21 08:53:31 +02:00
krzosa 8408f400c8 Cleanup debug reporting situation 2025-08-21 08:46:58 +02:00
krzosa 48574d634c Small fixes 2025-08-20 08:46:55 +02:00
krzosa ad3e58d455 Fix cursor stutter 2025-08-19 09:18:40 +02:00
krzosa 0dc020c429 Add missing config vars 2025-08-19 08:59:34 +02:00
krzosa 2e70d33364 Simplify development config management, reintroduce metaprogram 2025-08-19 08:59:23 +02:00
krzosa b0f314c9e3 release build, fix process kill, baked in font, fix goto on build 2025-08-17 19:05:37 +02:00
krzosa 1276c565da Fix process polling exit code 2025-08-11 18:27:02 +02:00
krzosa 955d92bcc7 Small fixes 2025-08-11 17:57:48 +02:00
krzosa 4e330de1d5 Fix config not loading 2025-08-11 16:03:20 +02:00
krzosa 77b337aed8 Fix Ctrl Period to navigate folders 2025-08-11 15:53:11 +02:00
krzosa b6ef63e817 Fix browser, fix font, GetExeDir 2025-08-11 13:41:28 +02:00
krzosa e6414908b7 Small unix improvements 2025-08-11 11:17:22 +02:00
krzosa 55eecf3177 Bring back linked list 2025-08-11 09:10:31 +02:00
krzosa 12ac285456 Remove build system and those files 2025-08-11 08:42:11 +02:00
krzosa a911707613 Fix working dir when spawning process 2025-08-11 08:41:29 +02:00
krzosa 3e7f09f33f Improve fuzzy search 2025-08-10 23:04:26 +02:00
krzosa 4b55faa41e Porting to linux 2025-08-10 18:44:10 +02:00
Karol Krzosa 720fdd9f34 Success running on linux 2025-05-17 08:22:27 +02:00
Krzosa Karol 76d52d9e1c Testing flag 2025-05-15 08:34:50 +02:00
Krzosa Karol c74c256968 Test stuff 2025-05-15 08:33:18 +02:00
Krzosa Karol aa5b51b88c Small Command_Open fixes 2025-05-13 14:20:41 +02:00
Krzosa Karol cf72182d56 Setting up windows using project lua file 2025-05-13 12:42:11 +02:00
Krzosa Karol 2e9147c47d Fix Command_Open jumping to beginning every time 2025-05-13 09:11:42 +02:00
Krzosa Karol f7f2aafc56 FKey function, fix goto build, GetLine, remedybg 2025-05-13 09:04:52 +02:00
Krzosa Karol 7eec390752 Fix dirty buffer after doing anything in title bar, OnCommand in lua stops c code, FKeys 2025-05-12 22:44:45 +02:00
Krzosa Karol 0c7a424f5e ListCode with || 2025-05-12 17:40:19 +02:00
Krzosa Karol 6aaff7573a ListCode improvements 2025-05-12 17:20:23 +02:00
Krzosa Karol 70858fdec5 ListCode, fix unique buffer opening an existing file on disk 2025-05-12 17:12:37 +02:00
Krzosa Karol a94b914e06 WorkDir concept 2025-05-12 16:35:06 +02:00
Krzosa Karol fd842a1f70 Fix switching windows 2025-05-12 09:25:02 +02:00
Krzosa Karol 872c46c43d Search bar anchor 2025-05-12 08:53:42 +02:00
Krzosa Karol a79f11d137 EncloseSpace, EncloseScope changes 2025-05-11 16:24:06 +02:00
Krzosa Karol 3b48954bc1 EncloseLine, add $ and @ as part of load word 2025-05-11 15:43:32 +02:00
Krzosa Karol 9884ba7dab Exec command as meta to Open 2025-05-11 15:25:07 +02:00
Krzosa Karol 78ea184868 Drawing split, fix split left right behaviour 2025-05-10 11:37:03 +02:00
Krzosa Karol a2b081ec15 Setting window sizes, NewDir 2025-05-10 11:19:09 +02:00
Krzosa Karol c139c44503 "New" command better, GetUniqueBufferName no longer big numbers 2025-05-10 08:12:49 +02:00
Krzosa Karol 8370a2ae67 Lua.OnSave, GetViewForFixingWhenBufferCommand 2025-05-09 20:25:05 +02:00
Krzosa Karol 1590f12b43 Shift selects on last/first line 2025-05-09 10:56:17 +02:00
Krzosa Karol 3180625a41 Open improvements 2025-05-09 10:50:40 +02:00
Krzosa Karol d2ca655178 Add metadata to Command_Open and move the logic that denies the NextGotoBuild to lua 2025-05-09 09:17:45 +02:00
Krzosa Karol c57eedce49 Reorganizing a bit 2025-05-09 08:40:29 +02:00
Krzosa Karol bc9be4927b white search bar 2025-05-08 22:56:47 +02:00
Krzosa Karol a1282af0b5 Change console behaviour 2025-05-08 22:53:56 +02:00
Krzosa Karol 46c109dce4 Fix garbage collect bug, ReplaceWithoutMovingCarets takes buffer now, Reopen buffer happens automatically when not dirty 2025-05-08 22:42:04 +02:00
Krzosa Karol abb2cfb1c4 Fuzzy search, working dir as nullbuffer dir 2025-05-06 16:41:43 +02:00
Krzosa Karol 9ddfed92ff title bar renaming 2025-05-05 21:21:31 +02:00
Krzosa Karol c4419490b6 console goto build results 2025-05-05 20:53:25 +02:00
Krzosa Karol 20422d9023 Bring back GC and new files for commands 2025-05-05 16:49:28 +02:00
Krzosa Karol 2c29df0171 Save state window buffers? 2025-05-05 15:51:21 +02:00
Krzosa Karol 8fc1081cef Go to end, start 2025-05-05 10:18:33 +02:00
Krzosa Karol 556b05cb78 New splitting 2025-05-05 08:49:22 +02:00
Krzosa Karol 4a1554ce28 The new window splits 2025-05-05 08:37:41 +02:00
Krzosa Karol 542b0f0a0a Text editor object management change 2025-05-04 09:57:34 +02:00
Krzosa Karol 101e844ac5 window pos 2025-05-04 09:16:34 +02:00
Krzosa Karol dec70c10e7 Color of title bar when active and window size 2025-05-03 21:16:16 +02:00
Krzosa Karol 7a5d949a12 console size, ListCommands, Indent on bracket 2025-05-03 18:45:05 +02:00
krzosa 93c1ba606a Console update 2025-05-02 22:20:09 +02:00
krzosa 4871494c50 Eval on click, fix reopen buffers, detecting change 2025-05-02 12:53:13 +02:00
krzosa d7908bee54 Improving basic commands 2025-05-02 12:02:13 +02:00
krzosa fd8a319b18 init.lua 2025-05-01 15:06:48 +02:00
krzosa d1d9b39200 save 2025-05-01 15:06:43 +02:00
krzosa 6374f3cd1a Fix mouse, fix allocator in file iter, GetCFiles 2025-05-01 08:26:55 +02:00
krzosa e652d5b0e2 lua api improvements 2025-04-30 22:34:00 +02:00
krzosa dc3861adfe Lua_GetProjectPath, SDLK_Period 2025-04-30 21:38:21 +02:00
krzosa a00f8acd9a Get info for lua commands on buffer, ctrl shift Q thing, packaging 2025-04-30 09:34:54 +02:00
krzosa 46dcd1cc4e unspecial directory buffer 2025-04-29 22:41:44 +02:00
krzosa a5d99ffb9a search bar 2025-04-29 22:25:04 +02:00
krzosa daa0d2d4c4 VCVarsall improvements, reload entire config every time 2025-04-29 18:02:25 +02:00
krzosa 92139cf799 ALOT OF CHANGES 2025-04-29 16:22:26 +02:00
Krzosa Karol ed9ec06eee Reporting errors, set active to console 2024-12-02 08:35:15 +01:00
Krzosa Karol f1e674ca37 Return to project, refactoring 2024-11-30 11:08:08 +01:00
Krzosa Karol 35cc5ae48d Remove exec word, insert titlebar command, error reporting in titlebar, some lua commands 2024-09-28 07:40:00 +02:00
Krzosa Karol 9ea1e254e0 Lua_SetProjectFile 2024-08-17 07:19:43 +02:00
Krzosa Karol 1c0063e834 String16, commands, Lua_New, layout next, build and encodings 2024-08-16 15:40:18 +02:00
Krzosa Karol afd4e1d21c Misc 2024-08-16 07:23:50 +02:00
Krzosa Karol 2065c9ded7 String16 routines 2024-08-15 15:32:51 +02:00
Krzosa Karol bafe0af407 Stop using WindowSize and actually make use of event window size, provide default 2024-08-15 15:09:14 +02:00
Krzosa Karol d0bc7bdc4a Lua_ToggleFullscreen .lua_project 2024-08-15 14:57:20 +02:00
Krzosa Karol fbe34b2d40 Fix autoenclose and override F1 in config 2024-08-15 12:44:27 +02:00
Krzosa Karol e49838b974 Lua_Error, ClangFormatOnSave 2024-08-15 12:28:39 +02:00
Krzosa Karol 7ed46b9724 Report errors idea using titlebar 2024-08-15 11:54:32 +02:00
Krzosa Karol 41a05fb08c Add coroutines on C++ side, Implement the test in C++ 2024-08-15 11:28:27 +02:00
Krzosa Karol 8f09e25710 Move test to data folder 2024-08-15 10:04:46 +02:00
Krzosa Karol a28c172ac1 Add the test projec 2024-08-15 10:03:50 +02:00
Krzosa Karol b5772fa52c OnCommand and OnInit 2024-08-15 10:03:44 +02:00
Krzosa Karol d4ac1dd817 Describe event using macros 2024-08-15 08:50:04 +02:00
Krzosa Karol 5e51e2fbad Auto enclose 2024-08-15 08:22:56 +02:00
Krzosa Karol a3e87b2508 Fix ApplyRules misfires on weird paths, gotos don't include gc buffers 2024-08-15 07:27:05 +02:00
Krzosa Karol eeb6caa58d Improve ApplyRules 2024-08-14 17:22:33 +02:00
Krzosa Karol 212392386c Testing setup using project files 2024-08-14 16:03:29 +02:00
Krzosa Karol a84a7073dc Lua_Play now works in coroutines 2024-08-14 15:08:27 +02:00
Krzosa Karol 8cd754c923 Lua project config 2024-08-14 13:05:38 +02:00
Krzosa Karol 225d1ffc06 Implement coroutine handling 2024-08-14 12:41:09 +02:00
Krzosa Karol f38c20b975 Lua_Play events 2024-08-14 12:17:50 +02:00
Krzosa Karol a0315f161c Serialize and playback events 2024-08-14 09:55:54 +02:00
Krzosa Karol cac092a344 Serializing and de serializing events 2024-08-14 08:40:18 +02:00
Krzosa Karol 5fd790bd54 Event move to separate file 2024-08-14 07:43:39 +02:00
Krzosa Karol b60f846209 Improve reopen buffer 2024-08-14 07:42:11 +02:00
Krzosa Karol 2b4a43ddc1 Reopen changed files 2024-08-14 07:35:12 +02:00
Krzosa Karol f125a38c50 Improve GC 2024-08-13 16:02:22 +02:00
Krzosa Karol 40cb8582fd Begin garbage collector 2024-08-13 13:51:36 +02:00
Krzosa Karol 7db1fc7bd6 Ls and some improvements 2024-08-13 12:27:45 +02:00
Krzosa Karol 50e642483d Refactor 2024-08-13 12:11:16 +02:00
Krzosa Karol 915679b87b Refactor WindowCommands 2024-08-13 11:43:56 +02:00
Krzosa Karol 2ada434925 CtrlF Search 2024-08-13 10:52:41 +02:00
Krzosa Karol 26c1180fad Refactor 2024-08-13 10:43:47 +02:00
Krzosa Karol 9cac98d961 Refactor references to pointers 2024-08-13 10:38:57 +02:00
Krzosa Karol c0877bfe1d Refactor 2024-08-13 10:35:48 +02:00
Krzosa Karol 5ce418995f Some more refactoring 2024-08-13 09:55:28 +02:00
Krzosa Karol 7b21cba834 Refactoring Add BSet 2024-08-13 09:49:34 +02:00
Krzosa Karol b3e95a705f Remove titlebar modification, small refactor 2024-08-13 09:09:48 +02:00
Krzosa Karol da80e2c731 F3, ShiftF3 search, works on main window 2024-08-12 17:31:25 +02:00
Krzosa Karol fcabf96347 Improve process logic 2024-08-12 17:01:33 +02:00
Krzosa Karol 2b48f30cfe Clang format, mouse rebind 2024-08-12 13:45:58 +02:00
Krzosa Karol 3251df6068 ExecAndWait 2024-08-12 08:12:30 +02:00
Krzosa Karol d6dd7c9eab Validate buffer name uniqueness constraint, update todo 2024-08-12 07:28:38 +02:00
Krzosa Karol 3fd728543c Ctrl + P to list buffers 2024-08-10 10:16:55 +02:00
Krzosa Karol b4bc061b76 Remove array alloc, not a good idea 2024-08-10 09:44:44 +02:00
Krzosa Karol f10212f4a0 Move off from object arrays to id arrays 2024-08-10 09:43:23 +02:00
Krzosa Karol 08a385b050 Simplify active windows 2024-08-10 09:08:35 +02:00
Krzosa Karol d5f903eaa2 Reword ListBuffers 2024-08-10 08:46:40 +02:00
Krzosa Karol 26b0ba4828 Remove console designate null view/buffer as console 2024-08-10 08:41:04 +02:00
Krzosa Karol 90aaa375d0 Remove command window 2024-08-10 08:31:14 +02:00
Krzosa Karol a12a10ee0b Generate lua function table 2024-08-10 08:17:37 +02:00
Krzosa Karol 97b1cf9e73 Fix infinite loop in GotoNextInList 2024-08-10 07:32:39 +02:00
Krzosa Karol 3aa4806515 Fix non-edit doing caret adjustment 2024-08-10 07:25:44 +02:00
Krzosa Karol 4e1ae87a8e Del popup window 2024-08-10 07:06:20 +02:00
Krzosa Karol 6bc8c549fc GoToNextInList scans multiple lines, EncloseExecWord looks for an anchor, Add Ctrl Period chop path open 2024-08-10 07:04:25 +02:00
Krzosa Karol 2137a0990e Hack in the goto next in list 2024-08-09 17:45:45 +02:00
Krzosa Karol 7f8b22ff43 Search back 2024-08-09 17:28:50 +02:00
Krzosa Karol d1e645b17e LuaSearch 2024-08-09 16:56:37 +02:00
Krzosa Karol 8bf32a557b Debug memes 2024-08-09 16:33:23 +02:00
Krzosa Karol 93cfe71c21 Remove search window 2024-08-09 16:28:50 +02:00
Krzosa Karol 65ef0b1b0f Lua OnUpdate 2024-08-09 16:19:00 +02:00
Krzosa Karol d98086d869 Improved git pathing 2024-08-09 15:01:15 +02:00
Krzosa Karol 00c1f405c6 GotoForward 2024-08-09 10:36:33 +02:00
Krzosa Karol 19546eea4d Improve ctrl movement, fix delete indent bug 2024-08-09 10:11:19 +02:00
Krzosa Karol 6d9792b1a6 Stop using stack in win32 2024-08-09 09:53:40 +02:00
Krzosa Karol 47ec2b55c7 LuaAppendCmd 2024-08-09 09:46:16 +02:00
Krzosa Karol 68ff6dc2b5 Add lua interrupt on F9 2024-08-09 09:39:40 +02:00
Krzosa Karol ad847a3eaa Save line to clipboard on right click 2024-08-09 09:03:11 +02:00
Krzosa Karol 4564e7bbc2 Even never mouse design 2024-08-09 09:00:04 +02:00
Krzosa Karol 3fb0c131f1 Rework mouse bindings 2024-08-09 08:08:24 +02:00
Krzosa Karol 91ba202562 Simplify mouse left 2024-08-09 07:50:03 +02:00
Krzosa Karol 93530bd089 Convert to LF during copy paste 2024-08-09 07:42:31 +02:00
Krzosa Karol a7dc343fd6 Exec word now tries to extend the lua function call syntax 2024-08-09 07:24:29 +02:00
Krzosa Karol 4c179e3965 Select title bar 2024-08-08 17:52:27 +02:00
Krzosa Karol a5756ab2f5 Improve console behaviour 2024-08-08 17:42:03 +02:00
Krzosa Karol 95b7ded031 Adjust carets in title bar, Command_ReplaceEx, adjust look of underline 2024-08-08 17:36:18 +02:00
Krzosa Karol a004976c6b Toying with windows paths, ExecInNewBuffer, c'', Fix caret loss in title bar 2024-08-08 16:33:19 +02:00
Krzosa Karol eecff81093 Fix crash in LuaPrint 2024-08-08 12:04:55 +02:00
Krzosa Karol d47482bc04 String interning, forgot file 2024-08-08 11:50:30 +02:00
Krzosa Karol 4434cd5764 String interning 2024-08-08 11:50:23 +02:00
Krzosa Karol 3488c71155 Syntax for executing shell commands 2024-08-08 11:07:15 +02:00
Krzosa Karol ad2efab7c8 Add icon and drop file event 2024-08-08 10:49:13 +02:00
Krzosa Karol 28a9656db1 Process error handling and process killing 2024-08-08 08:56:01 +02:00
Krzosa Karol 58db05fcb3 Match git commit properly 2024-08-08 08:14:08 +02:00
Krzosa Karol bfff188726 Opening git commit works properly now 2024-08-08 08:01:49 +02:00
Krzosa Karol 080669b5e9 Opening new buffer which is git show commit command 2024-08-08 07:24:13 +02:00
Krzosa Karol 161a9e3965 Command_Append 2024-08-08 07:02:05 +02:00
Krzosa Karol bb44eab406 Fixing array resize bugs 2024-08-08 06:47:29 +02:00
Krzosa Karol b3b50715b4 Add dynamic array debug - resize on every item added, fix window bug 2024-08-08 06:35:37 +02:00
Krzosa Karol 2565cefe70 Equality operators for ids 2024-08-08 06:22:18 +02:00
Krzosa Karol 8e73057cfb Move selected windows to ids instead of pointers 2024-08-08 06:18:45 +02:00
Krzosa Karol 74ab76344b Remove WaitForExit for now 2024-08-08 06:08:37 +02:00
Krzosa Karol 38afbe8816 Delete raylib_utils, update todo 2024-08-08 06:07:58 +02:00
Krzosa Karol 6d66986b5b Small refactor 2024-08-07 07:56:21 +02:00
Krzosa Karol 327f352872 Create process, poll and send output to console buffer 2024-08-07 07:51:50 +02:00
Krzosa Karol 7b8b8c751d Process polling api 2024-08-07 07:31:37 +02:00
Krzosa Karol fe20d05e13 Add friendly remainders, better console experience 2024-08-06 18:36:58 +02:00
Krzosa Karol b036e48cee Improve edit api 2024-08-06 18:21:52 +02:00
Krzosa Karol 4aaae7773d Update notes 2024-08-06 18:15:37 +02:00
Krzosa Karol 1145a13987 Convert line endings command 2024-08-06 07:55:52 +02:00
Krzosa Karol f8c9e8fd3e Open and navigate directories 2024-08-06 07:49:33 +02:00
Krzosa Karol f419ffd1ca Add dirs to special buffers 2024-08-06 07:35:48 +02:00
Krzosa Karol fa99475912 Command_MoveLine 2024-08-06 07:25:33 +02:00
Krzosa Karol 6e61816e1c Execute and load selection 2024-08-06 06:50:36 +02:00
Krzosa Karol b552f73ac9 Fix underline bug and draw selection underline 2024-08-06 06:44:45 +02:00
Krzosa Karol f0df0b69f0 Refactor cursor underlining 2024-08-06 06:38:21 +02:00
Krzosa Karol f7100ae8ee Misc 2024-08-05 21:03:19 +02:00
Krzosa Karol e514c29de4 EncloseFullLine and enclose scopes on multiple click 2024-08-05 15:49:27 +02:00
Krzosa Karol d81c403a5d Click multiple times to enclose load word or exec word 2024-08-05 15:31:38 +02:00
Krzosa Karol 956f2319b5 Ctrl + G 2024-08-05 13:17:54 +02:00
Krzosa Karol bb2c9a2f32 Misc 2024-08-05 12:45:51 +02:00
Krzosa Karol 3928e2eb96 Fallback font, configure font in lua 2024-08-05 12:39:10 +02:00
Krzosa Karol c4bc48bba1 Backup font based on imgui stuff 2024-08-05 11:50:43 +02:00
Krzosa Karol 8eb58e7dd8 Add debug references to ids 2024-08-05 11:26:55 +02:00
Krzosa Karol e4af56e3eb Remove non-implemented feature 2024-08-05 11:11:15 +02:00
Krzosa Karol 331f75c7ab Address sanitizer 2024-08-05 10:44:43 +02:00
Krzosa Karol 55465ad6de Fix memory issues because of pointer to item in dynamic array, add clang-cl, add address sanitizer stuff 2024-08-05 10:44:00 +02:00
Krzosa Karol 10f0d7dca2 Add titlebar windows everywhere and make them selectable even in disappearing windows 2024-08-05 08:37:46 +02:00
Krzosa Karol c9aabdec68 Experimenting with execution 2024-08-05 08:25:33 +02:00
Krzosa Karol da1def101b Highlight exec word 2024-08-05 07:29:02 +02:00
Krzosa Karol 4d22995ea3 Fix line number matching bug 2024-08-05 07:19:38 +02:00
Krzosa Karol d3b89d22fb Add some external libs to source tree 2024-08-05 07:13:04 +02:00
Krzosa Karol 9215205aba Load lua functions from an array 2024-08-05 07:12:52 +02:00
Krzosa Karol 7fc071154f Small Open improvements 2024-08-04 14:49:02 +02:00
Krzosa Karol e3c1bcb56e Fix wrong selection after cut 2024-08-04 14:25:07 +02:00
Krzosa Karol 7e35e0cbed Misc 2024-08-04 14:22:42 +02:00
Krzosa Karol d59a8d9c8b Mouse rewrite 2024-08-04 14:14:15 +02:00
Krzosa Karol 605f3aa68d Mouse rewrite 2024-08-04 14:08:46 +02:00
Krzosa Karol c6a415f642 Mouse rewrite 2024-08-04 14:00:42 +02:00
Krzosa Karol edff7a4267 Mouse rewrite 2024-08-04 13:37:05 +02:00
Krzosa Karol 48bbef0b10 Before mouse rewrite 2024-08-04 11:00:25 +02:00
Krzosa Karol b267000394 Delete indent in multiples of indent size 2024-08-04 10:40:03 +02:00
Krzosa Karol c3bd96d5d6 Move back mouse stuff to window 2024-08-04 10:19:43 +02:00
Krzosa Karol 28dbac4a35 Ctrl + Q Alt + Q 2024-08-04 10:15:09 +02:00
Krzosa Karol 22dc4be100 Go to last bread crumb but mouse is bugging 2024-08-04 10:07:36 +02:00
Krzosa Karol ffb38664b8 Fix GetWordEnd type of functions to make sure range.max is past the last index even on buffer end 2024-08-04 08:54:08 +02:00
Krzosa Karol 3f16888fe0 Home + left stops at indent 2024-08-04 08:34:09 +02:00
Krzosa Karol 2b5f441e92 Indented new line 2024-08-04 08:28:42 +02:00
Krzosa Karol e761761108 Improve load 2024-08-04 08:09:07 +02:00
Krzosa Karol 324e5e1ea1 Fixing ActiveWindow switching, actual happens switch after event is handled 2024-08-04 08:01:25 +02:00
Krzosa Karol cc04fec1de Command window opens files and move fuzzy search to view 2024-08-04 07:55:49 +02:00
Krzosa Karol b68b80f317 Movement with new semantics fully completed 2024-08-04 07:35:55 +02:00
Krzosa Karol cfad821e8e Command_Move down 2024-08-04 07:10:36 +02:00
Krzosa Karol 815e3c9670 Work on Open 2024-08-03 19:11:36 +02:00
Krzosa Karol 0c4dc62170 EncloseLoadWord 2024-08-03 15:50:55 +02:00
Krzosa Karol 7655ece178 Implement a lot of position moving functions 2024-08-03 12:58:53 +02:00
Krzosa Karol 22899c2523 Add kill selected lines 2024-08-03 10:47:12 +02:00
Krzosa Karol 7f85f8348e Trim whitespace on save and skip lines with cursor 2024-08-03 10:30:35 +02:00
Krzosa Karol ee863e3b09 MoveOnWhitespaceBoundaryVertical 2024-08-03 10:14:22 +02:00
Krzosa Karol 1ebe8d9929 buffer_ops.cpp unify MoveOnWhitespaceBoundary 2024-08-03 10:05:43 +02:00
Krzosa Karol 6c975b98a1 Underline enclose word of main cursor and fix Enclose word 2024-08-03 08:45:49 +02:00
Krzosa Karol e4a248bb60 Fix wrong cursor on line numbers and scroll 2024-08-03 08:27:42 +02:00
Krzosa Karol d382735b80 Fix mouse in full-screen scrolling on edge of monitor 2024-08-03 08:21:25 +02:00
Krzosa Karol a42a4e435d Fixed mouse 2024-08-03 08:05:08 +02:00
Krzosa Karol f79fce83ca Update todo, add indent size option 2024-08-03 07:26:37 +02:00
Krzosa Karol 4c7f6340d6 Add Trim trailing whitespace 2024-08-02 21:52:44 +02:00
Krzosa Karol f3059ec8ea Shift Mouse Press works now 2024-08-02 21:38:12 +02:00
Krzosa Karol 4f12887a91 Fix offseting carets after edit without killing selection, add dedent 2024-08-02 21:30:12 +02:00
Krzosa Karol 03b6b80568 Indent selected lines 2024-08-02 21:16:46 +02:00
Krzosa Karol cbf1cb8c4a Redesign lua reloading and other generation stuff 2024-08-02 20:42:02 +02:00
Krzosa Karol 7fc8e6e8bb Search now has title bar, title bars now have history 2024-08-02 14:51:40 +02:00
Krzosa Karol 48dc808dcb Improve command window 2024-08-02 12:49:03 +02:00
Krzosa Karol 95dc31be91 Fix focus on console buffer and console buffer not drawing 2024-08-02 12:16:08 +02:00
Krzosa Karol 55223b763a Fixing small bugs and add console window 2024-08-02 12:03:51 +02:00
Krzosa Karol cff301499f SDL passthrough hint and default size 2024-08-02 07:51:47 +02:00
Krzosa Karol 4cdb8a986a Basic splitting, column concept 2024-08-02 07:43:33 +02:00
Krzosa Karol 0ae0c03775 Fix a bug 2024-08-01 16:47:44 +02:00
Krzosa Karol d6378922cf Remove dependence on FrameID 2024-08-01 16:44:58 +02:00
Krzosa Karol 6ce5fd59a3 New event loop setup 2024-08-01 16:28:10 +02:00
Krzosa Karol b93cdd8f4c Title bar adjust looks 2024-08-01 08:20:58 +02:00
Krzosa Karol cadf7742ab Add title bar windows 2024-08-01 08:07:13 +02:00
Krzosa Karol 5f8021c570 Improve font rendering 2024-08-01 08:06:57 +02:00
Krzosa Karol 1b0d0520bc Append to end of console 2024-07-31 07:37:56 +02:00
Krzosa Karol be99b0aabb Editing infobar applies changes to buffer 2024-07-31 07:32:42 +02:00
Krzosa Karol 2ab1917b73 Update todo 2024-07-31 06:39:33 +02:00
Krzosa Karol 111781dc71 SetActiveView 2024-07-30 07:31:51 +02:00
Krzosa Karol 7df09a9ebd Implement circular array 2024-07-30 07:27:05 +02:00
Krzosa Karol 7b13dff29c Remove window view children 2024-07-30 06:56:54 +02:00
Krzosa Karol c48abbf5c9 Don't draw carets when inactive, todo update 2024-07-28 21:43:33 +02:00
Krzosa Karol 12b459507a Fix memory corruption 2024-07-28 20:49:40 +02:00
Krzosa Karol 77a6cc5e53 Improve alignment of infobar, set buffer name in window title 2024-07-28 15:16:12 +02:00
Krzosa Karol 978d2d603a Add xwheel 2024-07-28 14:49:46 +02:00
Krzosa Karol 01a0d5f05f Don't draw out of bounds line numbers 2024-07-28 14:38:12 +02:00
Krzosa Karol 0569d64cc9 Highlight line number part 2024-07-28 14:36:04 +02:00
Krzosa Karol f55f895cfd Remove tabs 2024-07-28 14:31:38 +02:00
Krzosa Karol de7f084633 Experimenting with tabs 2024-07-28 14:30:24 +02:00
Krzosa Karol 0c2683afaa Fixing stuff 2024-07-28 11:42:12 +02:00
Krzosa Karol d6b850178e Using file path rules 2024-07-28 10:39:57 +02:00
Krzosa Karol a486a09d9e Error reporting and popup, debug window 2024-07-28 10:12:18 +02:00
Krzosa Karol 07a41e0266 Using app data path, deleting config every time, improve loop 2024-07-27 22:07:58 +02:00
Krzosa Karol 052894a628 Config magic 2024-07-27 20:34:20 +02:00
Krzosa Karol 60f26ca40e Fix delete and loading lua config dynamically 2024-07-27 16:47:28 +02:00
Krzosa Karol d5e392c3bc Debug buffer, scroll highlight 2024-07-27 15:04:21 +02:00
Krzosa Karol 8b00f15710 Improve search 2024-07-27 14:14:47 +02:00
Krzosa Karol 0ebe63eff3 Misc 2024-07-27 14:10:38 +02:00
Krzosa Karol 9955181b0d Small refactor 2024-07-27 13:01:11 +02:00
Krzosa Karol 477b485a34 Replace text_editor and bring back ctrl + f, fix circle rendering pos 2024-07-27 11:38:41 +02:00
Krzosa Karol 03eece4e41 Restructure and reload font 2024-07-27 11:35:14 +02:00
Krzosa Karol a43fe1789b Ported mouse movement and conditional update 2024-07-27 09:43:46 +02:00
Krzosa Karol 1e0c5dac83 Porting mouse related events and abstraction idea 2024-07-27 08:58:52 +02:00
Krzosa Karol 680c782a56 Remove platform, small rendering improvement 2024-07-27 08:30:27 +02:00
Krzosa Karol dfe8aa56e9 Port window commands 2024-07-27 08:21:14 +02:00
Krzosa Karol 71494984de Scrolling clip and global commands 2024-07-27 07:41:15 +02:00
Krzosa Karol 8117d043aa Porting focus based features and fix rendering 2024-07-26 22:27:36 +02:00
Krzosa Karol 9d02d5ab78 Fixing scissoring 2024-07-26 21:47:23 +02:00
Krzosa Karol 7803bc87a6 Transitioning text editor to SDL 2024-07-26 17:08:14 +02:00
Krzosa Karol 27b322bf25 Transitioning text editor to SDL 2024-07-26 17:08:05 +02:00
Krzosa Karol def8b6bdc2 Opengl render and font 2024-07-26 14:47:03 +02:00
Krzosa Karol ee6df45e2d Begin move to SDL 2024-07-26 11:33:12 +02:00
Krzosa Karol a74409c3ec Optimize cursor rendering 2024-07-26 09:57:15 +02:00
Krzosa Karol 672a0b3561 Fix line number rendering 2024-07-26 08:25:42 +02:00
Krzosa Karol 48b918a551 Eval lua, fix ordering and fix caret overdraw 2024-07-26 08:09:19 +02:00
Krzosa Karol 4aa738fcc9 Tried to introduce NextActiveWindow but then we lose events like mouse press 2024-07-26 07:52:53 +02:00
Krzosa Karol 7eefa2e6c2 Fix merge carets 2024-07-26 07:37:02 +02:00
Krzosa Karol d4136ef0e3 Performance - not drawing selection outside of line range, add select all matches 2024-07-25 14:55:56 +02:00
Krzosa Karol 469cf3dd24 FindInBuffer, improve find 2024-07-25 13:50:04 +02:00
Krzosa Karol 2d60e795c0 Scrolling even when window inactive 2024-07-25 13:35:10 +02:00
Krzosa Karol 754d6cd3bd Begin search buffer 2024-07-24 17:07:10 +02:00
Krzosa Karol d1b4053205 Small improvements 2024-07-24 16:28:44 +02:00
Krzosa Karol 1cd5e71904 Improve open command 2024-07-24 16:16:57 +02:00
Krzosa Karol cb4f380313 List files and fix scrolling 2024-07-24 14:16:58 +02:00
Krzosa Karol 93e0104c1e Ctrl + Enter 2024-07-24 13:53:21 +02:00
Krzosa Karol c9aed019d5 Refactor active windows 2024-07-24 13:48:56 +02:00
Krzosa Karol 8b8229f73a Line range refactor 2024-07-24 13:23:20 +02:00
Krzosa Karol 039d2f9350 No history buffer, Active window stack 2024-07-24 13:03:52 +02:00
Krzosa Karol bb3044d168 lua improvements 2024-07-24 10:30:33 +02:00
Krzosa Karol 8dace27f56 Font size adjustment, toying with command windows and lua 2024-07-24 08:33:59 +02:00
Krzosa Karol 30932b0d7c Listing open windows, views and buffers 2024-07-24 08:02:46 +02:00
Krzosa Karol afdd3834b9 Info bar and exec bar 2024-07-24 07:30:36 +02:00
Krzosa Karol 02b63bf8d2 Improving window/view/buffer management 2024-07-24 07:12:50 +02:00
Krzosa Karol fb19abb69f Forgot management.cpp 2024-07-23 22:33:08 +02:00
Krzosa Karol 1528ecac52 Working on resource management stuff 2024-07-23 22:33:01 +02:00
Krzosa Karol 4cb892133f Only one infobar 2024-07-23 17:14:11 +02:00
Krzosa Karol 5864b060a9 Misc 2024-07-23 17:02:25 +02:00
Krzosa Karol 0ebfedbf4d Lua and better cursor movement 2024-07-23 16:49:13 +02:00
Krzosa Karol 45c6495121 Small refactor work on focus and windows 2024-07-23 14:13:03 +02:00
Krzosa Karol 24ad9464b5 Z ordering, prep for command window 2024-07-23 13:34:12 +02:00
Krzosa Karol 0f34416726 Window flags, improve mouse cursor, 2024-07-23 13:04:33 +02:00
Krzosa Karol 7249bbf92b Move globals to text_editor.h 2024-07-23 09:09:18 +02:00
Krzosa Karol 5f18779f1d Null objects 2024-07-23 09:06:39 +02:00
Krzosa Karol 740b0f217f View, window and buffer ids 2024-07-23 08:57:09 +02:00
Krzosa Karol bc4fbfd28a Initial window implementation 2024-07-22 17:16:48 +02:00
Krzosa Karol 37a0c73dc3 Prepare for adding windows 2024-07-22 16:46:41 +02:00
Krzosa Karol 53e153a696 Improve double click 2024-07-22 16:26:50 +02:00
Krzosa Karol 06082f2273 Ctrl + D 2024-07-22 15:35:22 +02:00
Krzosa Karol b1c123977d Fix line numbers 2024-07-22 15:26:39 +02:00
Krzosa Karol 535b6d00c4 Draw line numbers 2024-07-22 15:20:54 +02:00
Krzosa Karol 5594b55e5c Info bar 2024-07-22 15:05:55 +02:00
Krzosa Karol 9229135588 Improve scrollbar 2024-07-22 14:49:09 +02:00
Krzosa Karol 9f2aafb95e Improve scrollbar 2024-07-22 14:43:27 +02:00
Krzosa Karol ce20a1d940 Ctrl + A 2024-07-22 10:36:53 +02:00
Krzosa Karol c2b2c2a6ae Improve scrolling 2024-07-22 10:31:02 +02:00
Krzosa Karol b2d9688fbe Scrollbar 2024-07-22 09:59:52 +02:00
Krzosa Karol 254407e89e Clipboard 2024-07-22 08:15:40 +02:00
Krzosa Karol a5069cd148 Undo redo 2024-07-22 08:03:22 +02:00
Krzosa Karol 91d2db6116 Create cursor above, double click, render whitespace when selecting 2024-07-22 07:30:40 +02:00
Krzosa Karol 4c9366d495 Fix merge carets with mouse 2024-07-21 18:12:43 +02:00
Krzosa Karol 915620da34 Full width line highlight and commands.cpp 2024-07-21 17:47:41 +02:00
Krzosa Karol 5d3f1fcf08 Command refactor 2024-07-21 17:38:02 +02:00
Krzosa Karol 9554160edc Experimenting with key bindings 2024-07-21 15:10:54 +02:00
Krzosa Karol fc928da75b Tune the looks 2024-07-21 14:16:09 +02:00
Krzosa Karol 8c1118b429 Refactor and Escape+Delete+Backspace 2024-07-21 12:39:31 +02:00
Krzosa Karol 846d4e7ab5 Add more testing load buffers 2024-07-21 11:07:32 +02:00
Krzosa Karol 816c24c1b6 Manual rendering and small fixes 2024-07-21 10:46:07 +02:00
Krzosa Karol 6ac1c8711c Forgot to add math int 2024-07-21 10:00:01 +02:00
Krzosa Karol c9cd2e6c1e Move to integer based rendering, fix Big line 2024-07-21 09:59:50 +02:00
Krzosa Karol 4c1630d61d Line highlight improvements and misc 2024-07-21 09:03:30 +02:00
Krzosa Karol ddbee2f0ec Optimize, working on a buffer with million lines 2024-07-21 08:30:27 +02:00
Krzosa Karol 8de8938be1 Mouse scrolling, BUFFER_DEBUG, todo list 2024-07-21 08:09:38 +02:00
Krzosa Karol 675e4a10dd Page up and page down, home and end 2024-07-21 07:43:13 +02:00
Krzosa Karol 2b2cc9cf6c Mouse click add cursor 2024-07-21 06:40:44 +02:00
Krzosa Karol 0b74fd81e3 Writing text 2024-07-20 10:06:25 +02:00
Krzosa Karol 941652b4bc Rename cursor to caret because cursor can be confused with mouse pointer 2024-07-20 09:48:40 +02:00
Krzosa Karol 2ba9d991bf Scrolling left right 2024-07-20 09:45:36 +02:00
Krzosa Karol ba5930b585 Scrolling up and scrolling down 2024-07-20 09:37:02 +02:00
Krzosa Karol 3868afce93 Refactor movement code 2024-07-20 09:20:25 +02:00
Krzosa Karol ba4ed9afff Ctrl cursor movement and fix selection draw bug 2024-07-20 09:15:15 +02:00
Krzosa Karol adeb2de366 Implement decently fast selection 2024-07-20 07:56:56 +02:00
Krzosa Karol 0071136146 Cursor movement, draw selection and fixing bugs 2024-07-20 07:41:02 +02:00
Krzosa Karol cd48094a18 Split buffer into multiple files 2024-07-18 14:19:48 +02:00
Krzosa Karol e0ac9654c3 Buffer multi cursor 2024-07-18 14:10:35 +02:00
Krzosa Karol 196d5353c8 Buffer cursor work 2024-07-18 13:22:55 +02:00
Krzosa Karol e9783b2317 Buffer work 2024-07-18 12:25:40 +02:00
Krzosa Karol 47d92dba14 Working on the buffer 2024-07-18 10:08:16 +02:00
Krzosa Karol 24eeca8f79 New project 2024-07-17 07:30:55 +02:00
Krzosa Karol f7ac92cd01 New project 2024-07-17 07:30:46 +02:00
Krzosa Karol 63bd416e7c Convert to SDL3 and static link 2024-07-13 08:58:30 +02:00
Krzosa Karol e6b23b2a98 MenuOpen mode, deffered read on start, cleanup todos 2024-07-13 07:19:22 +02:00
Krzosa Karol 83bc33015d Delete _main.cpp 2024-07-13 06:53:35 +02:00
Krzosa Karol c660118f8b Read on start and omit file type 2024-07-12 12:47:29 +02:00
Krzosa Karol 1ec217905d Config 2024-07-12 10:34:17 +02:00
Krzosa Karol bd97ecb9eb Big update 2024-07-12 08:27:24 +02:00
Krzosa Karol 9891a302ac Big update 2024-07-12 08:27:19 +02:00
Krzosa Karol 37982e0448 Add pdfio 2024-07-08 10:38:35 +02:00
Krzosa Karol 22828c9d23 Print loaded files and errors, enable loading and searching 2024-07-06 09:51:39 +02:00
Krzosa Karol e3a176b2f9 Trying to improve threading, thread queue 2024-07-06 07:55:38 +02:00
Krzosa Karol 30fa22aed5 Gui improvements and optimizations 2024-07-06 06:56:18 +02:00
Krzosa Karol 0dd6289509 Rewrite to IMGUI 2024-07-05 15:24:58 +02:00
Krzosa Karol e23a7b9c02 Fix move down out of selection 2024-07-04 16:23:12 +02:00
Krzosa Karol b48cffd880 Page up page down 2024-07-04 16:21:02 +02:00
Krzosa Karol 2f52c018cd Add spall profiler and stop generating layout every frame 2024-07-04 14:30:20 +02:00
Krzosa Karol 143a88ac1d String coloring 2024-07-04 10:02:51 +02:00
Krzosa Karol 21df381d12 Coloring strings 2024-07-04 07:35:29 +02:00
Krzosa Karol e7f53d2c07 Line highlights 2024-07-04 07:20:45 +02:00
Krzosa Karol a77a149664 Basic line wrapping works 2024-07-03 07:14:57 +02:00
Krzosa Karol 0a75cde80c Fix scrolling 2024-07-02 11:09:20 +02:00
Krzosa Karol 8250058296 Scroll clamping 2024-07-02 11:06:04 +02:00
Krzosa Karol d3c4c4cd02 Add line number drawing 2024-07-02 08:56:29 +02:00
Krzosa Karol aa41d9e15b Basic scroll bars 2024-07-02 08:42:39 +02:00
Krzosa Karol 186ec3c11d Adding bars to the window 2024-07-02 07:36:40 +02:00
Krzosa Karol 620954631a Add math ops 2024-07-02 07:36:21 +02:00
Krzosa Karol e0505dc974 Implement double click 2024-07-02 07:10:32 +02:00
Krzosa Karol ce13f83d46 Multicursor clipboard 2024-07-01 15:13:23 +02:00
Krzosa Karol 1a420e2f22 Redo working 2024-07-01 07:41:44 +02:00
Krzosa Karol d1f83fa669 Undo working 2024-07-01 07:23:46 +02:00
Krzosa Karol 4425db7ca3 Fix cursor offsetting after change 2024-07-01 07:16:11 +02:00
Krzosa Karol ceecb6cc81 Trying to add undo 2024-06-29 12:15:39 +02:00
Krzosa Karol c8ad9222fd Hopefully fixed BeforeEdit, needs a refactor though 2024-06-29 10:49:07 +02:00
Krzosa Karol 7e68e09b22 Fix BeforeEdit cursor removal, add multicursor deletion 2024-06-29 10:27:16 +02:00
Krzosa Karol e3150f8203 Implement Ctrl + D 2024-06-29 09:52:08 +02:00
Krzosa Karol 93ef620448 Improve mouse selection, add multicursor for mouse selection 2024-06-29 09:05:26 +02:00
Krzosa Karol ba711b7f14 Improve mouse scrolling 2024-06-29 08:55:16 +02:00
Krzosa Karol 0d3cb029d8 Toying with event recording to see if it can be used for testing 2024-06-29 07:35:22 +02:00
Krzosa Karol 2807573012 Toying with raylib automation 2024-06-28 18:04:39 +02:00
Krzosa Karol 8528bfefc1 Fix shadowing bug 2024-06-28 17:26:28 +02:00
Krzosa Karol d561883144 Work on end of buffer 2024-06-28 17:24:58 +02:00
Krzosa Karol 2dacc969a3 Refactored lines to contain 'new line' 2024-06-28 15:43:41 +02:00
Krzosa Karol 63adca1fac Cursor scrolling working 2024-06-28 13:43:58 +02:00
Krzosa Karol 4dfa9b432e Refactor y cursor, add small utility for debugging, fix bug in buffer 2024-06-28 13:30:55 +02:00
Krzosa Karol b8cdb49ea5 Fix visual bug when scrolling 2024-06-28 10:37:47 +02:00
Krzosa Karol ffe1ca643e Fixing bugs, bring back mouse selection 2024-06-28 10:20:17 +02:00
Krzosa Karol 95cafa3200 Major refactor of text layout 2024-06-28 09:30:22 +02:00
Krzosa Karol 784028c7a9 X scrolling using main cursor 2024-06-26 07:31:21 +02:00
Krzosa Karol fcb4d361bc Add todos 2024-06-25 09:57:48 +02:00
Krzosa Karol ceb9985242 Scrolling the main cursor properly 2024-06-25 09:38:43 +02:00
Krzosa Karol 03644c0561 Ctrl+c, ctrlv, ctrlx 2024-06-25 07:45:30 +02:00
Krzosa Karol 7ef502f3b0 Adding commands, BeforeEdit AfterEdit 2024-06-25 07:29:28 +02:00
Krzosa Karol 84f0b65fa9 Fix multiple cursors crashes by sorting cursors by min range 2024-06-24 07:27:38 +02:00
Krzosa Karol 66b9a5d15f Fix cursor merging on boundary 2024-06-24 07:00:15 +02:00
Krzosa Karol e82edb89ae Small improvements 2024-06-24 06:51:34 +02:00
Krzosa Karol 37518ed7b0 Selecting text using mouse and new abstraction for cursors 2024-06-23 12:24:22 +02:00
Krzosa Karol b76d825f55 Drawing selection and overlapping selections 2024-06-23 10:05:54 +02:00
Krzosa Karol 10afbd3e4f Port Seek word, add ctrl+left 2024-06-23 09:17:54 +02:00
Krzosa Karol c0d69521fe More proper offseting of cursors during char insert 2024-06-23 07:53:30 +02:00
Krzosa Karol e54596809e Drawing line numbers 2024-06-23 07:46:00 +02:00
Krzosa Karol 6347b56751 Adding scrollbars and titlebars, laying it out 2024-06-23 07:22:03 +02:00
Krzosa Karol 48eca55a4c Move up down and multi cursor 2024-06-22 20:58:29 +02:00
Krzosa Karol 5ba9975c10 Basic cursor movement, handling end of buffer, end of line in drawing 2024-06-22 16:09:26 +02:00
Krzosa Karol 7b818c5cde Drawing the cursor and cell setup 2024-06-22 14:48:32 +02:00
Krzosa Karol 443e88b4a9 Extract font grid from raylib 2024-06-22 12:29:40 +02:00
Krzosa Karol 64540d2d36 Working on rendering lines and clipping 2024-06-22 10:02:12 +02:00
Krzosa Karol 94555d2a60 Working on rendering 2024-06-22 08:35:11 +02:00
Krzosa Karol a329bc2424 Improving the buffer and bug fixing 2024-06-20 16:35:18 +02:00
Krzosa Karol b3b8a54f7f Buffer iterator and utf8 2024-06-20 11:52:33 +02:00
Krzosa Karol 5539bbd3b9 Basic multiline buffer concept 2024-06-20 09:40:05 +02:00
Krzosa Karol b919678913 Add text editor, misc changes 2024-06-20 08:17:54 +02:00
Krzosa Karol 7fe6aa2a97 Reading multiple directories in transcript browser 2024-06-19 10:40:20 +02:00
Krzosa Karol 055be9b058 Refactor to be more input/output, remove globals from parsing 2024-06-19 07:11:18 +02:00
Krzosa Karol a75c8a2e4f Init repo 2024-06-19 06:51:06 +02:00
124 changed files with 34562 additions and 13864 deletions
+18 -14
View File
@@ -1,16 +1,20 @@
build/
backup
subl.bat
multimedia.c
multimedia.h
playground.py
ui_notes.txt
run_linux.bat
l.log
vendor
x64/Debug
x64/Release
.vs/
*.10x
src/external/SDL/
build/
package/
project.te
*.rdbg
*.spall
*.sublime-workspace
*.pdb
te
te_debug
*.wasm
*.o
*sublime-project*
*sublime-workspace*
*.html
text_editor.js
*.map
*.exe
+9
View File
@@ -0,0 +1,9 @@
# te, a text editor
![preview](preview.jpg)
In order to build on windows you need to call build.bat from
the x64 Native Command Tools prompt that ships with Visual Studio.
For Linux you will need clang, SDL3 and libbacktrace libraries to be installed and
available on your system. Just call build.sh when these are available.
Regular → Executable
+37 -11
View File
@@ -1,19 +1,45 @@
@echo off
setlocal enabledelayedexpansion
cd /D "%~dp0"
for %%a in (%*) do set "%%~a=1"
if not "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug mode]
if "%release%"=="1" set debug=0 && echo [release mode]
if "%package%"=="1" echo [package zip]
set common=-I ../src/ -g -fdiagnostics-absolute-paths -Wno-unsequenced -Wno-single-bit-bitfield-constant-conversion -Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers
set wasm_flags=--target=wasm32 -nostdlib -mbulk-memory -msimd128 -Wl,-export-dynamic,--allow-undefined,--import-memory,--no-entry,--initial-memory=131072000,--max-memory=4294967296
if not exist build (
mkdir build
if not exist "src\external\SDL" (
pushd src\external
git clone https://github.com/libsdl-org/SDL.git
pushd SDL
git checkout release-3.4.0
cmake -S . -B build_win32_static -DCMAKE_BUILD_TYPE=Release -DSDL_STATIC=ON
pushd build_win32_static
msbuild SDL3.sln -maxCpuCount:16 -p:Configuration=Release
popd
popd
popd
)
set sdl=..\src\external\SDL
set sdllib=%sdl%\build_win32_static\Release
mkdir build
pushd build
if "%testing%"=="1" echo [testing] && set didbuild=1 && clang ../src/testing/testing_main.c -o testing.exe %common% || exit 1 /b
if "%scratch%"=="1" echo [scratch] && set didbuild=1 && clang ../src/scratch/scratch_main.c -o ../src/scratch/main.wasm %common% %wasm_flags% || exit 1 /b
set flags=/EHsc- /MT /Zi /FC /nologo /WX /W3 /wd4200 /wd4334 /diagnostics:column
if "%release%"=="1" set flags=%flags% -O2 -DDEBUG_BUILD=0
set libs=%sdllib%/SDL3-static.lib %sdllib%/SDL_uclibc.lib kernel32.lib gdi32.lib user32.lib Imm32.lib ole32.lib Shell32.lib OleAut32.lib Cfgmgr32.lib Setupapi.lib Advapi32.lib version.lib winmm.lib
rem rc ..\data\icon.rc
cl %flags% ../src/text_editor/text_editor.cpp -Fe:te.exe -I%sdl%/include -I../src/external/glad -I../src/ %libs% -link /SUBSYSTEM:WINDOWS /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCRTD ..\data\icon.res
:: small util when working on the editor using the editor
copy te.exe te2.exe
popd
if "%didbuild%"=="" (
echo [WARNING] no valid build target specified
exit /b 1
)
if "%package%"=="1" (
copy build\te.exe .
"C:\Program Files\7-Zip\7z.exe" a te.zip te.exe
del te.exe
)
+8 -7
View File
@@ -1,9 +1,10 @@
cd "$(dirname "$0")"
#!/usr/bin/bash
if [ ! -d build ]; then
mkdir build
fi
mkdir build
cd build
# clang ../src/testing/testing_main.c -o testing_main -I../src/ -ldl -lm -lbacktrace -g -Wall -Wextra -Wno-missing-braces -Wno-missing-field-initializers -Wno-single-bit-bitfield-constant-conversion -fdiagnostics-absolute-paths -Wno-writable-strings -Wno-unsequenced
tcc $(realpath ../src/testing/testing_main.c) -o testing_main -I$(realpath ../src/) -b -g -ldl -lm -Wall -Wextra
./testing_main
FLAGS="-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fsanitize=address -fno-exceptions -fdiagnostics-absolute-paths -g -I../src -DDEBUG_BUILD=1"
I="-I../src/external/SDL/include -I../src/external/lua/src -I../src/external/glad"
clang -o te $FLAGS ../src/text_editor/text_editor.cpp $I -lSDL3 -lm -lbacktrace
# -v -Wl,--verbose
Executable
+9
View File
@@ -0,0 +1,9 @@
@echo off
set incs=-Isrc/external/SDL/include -Isrc/external/lua/src -Isrc/external/glad -Lsrc/external/SDL/build_web -Isrc
set wasmflags=-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb -msimd128 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256mb -sUSE_WEBGL2 -sFULL_ES3=1 -sASYNCIFY -sASSERTIONS=2
set flags=-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths
set dbg=-g -DDEBUG_BUILD=1 -gsource-map
set rel=-O3 -DDEBUG_BUILD=0
emcc -o text_editor.html --shell-file=data/shell.html %flags% %incs% %wasmflags% %dbg% -lm -lSDL3 src/text_editor/text_editor.cpp
Executable
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/bash
incs="-Isrc/external/SDL/include -Isrc/external/lua/src -Isrc/external/glad -Lsrc/external/SDL/build_web -Isrc"
wasmflags="-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb -msimd128 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256mb -sUSE_WEBGL2 -sFULL_ES3=1 -sUSE_SDL=3 -sASYNCIFY -sASSERTIONS=2"
flags="-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths"
dbg="-g -DDEBUG_BUILD=1 -gsource-map"
rel="-O3 -DDEBUG_BUILD=0"
emcc -o text_editor.html --shell-file=data/shell.html $flags $incs $wasmflags $dbg -lm -lSDL3 src/text_editor/text_editor.cpp
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+1
View File
@@ -0,0 +1 @@
id ICON "icon.ico"
BIN
View File
Binary file not shown.
+19
View File
@@ -0,0 +1,19 @@
left_mouse :: ctrl add cursor, selections work, alt load word
right_mouse :: ctrl exec word,alt go back
ctrl+q exec alt+q load
alt+w go back
ctrl mleft - add cursor
ctrl shift mleft - add cursor and set selection
alt mleft -
alt ctrl mleft -
alt shift mleft -
mright - destroy pointed at selection and copy | copy line
alt mright - go back
ctrl mright - load word
shift mright -
alt shift mright -
alt ctrl mright - go forward
ctrl shift mright - exec word
mmiddle -
+26
View File
@@ -0,0 +1,26 @@
https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
https://github.com/sheredom/subprocess.h
https://github.com/4coder-archive/4coder/blob/master/platform_win32/win32_4ed.cpp :486
https://stackoverflow.com/questions/67551213/read-processs-stdout-output-in-win32-c-desktop-application
https://handmade.network/forums/t/1219-win32_asynchronous_pipes_question
- I guess you can just do color matching in rendering, have a table and try matching words etc.
- maybe I should disallow somehow taking pointers to dynamic array items? Just references!
- create process with buffer (append to end)
- create process and put it at specific cursor position in buffer?
- create process without buffer attached (maybe for error?) (we want some notification that it failed or something)
- code indexing: maybe we can do that line based since you want to jump to line not a particular place.
- on edit we could reparse the line for symbol
- I think 4coder first tries to offset the index file on immediate edit, on frame tick it tries to reparse the modified file in entirety
- offseting things doesn't seem that hard since we already figured it out with cursors
- would it be fast enough to just reparse the entire file of certain size every time?
- coloring seems even more hairy to do correctly because there are multiline comments etc.
- it honestly seems no matter what you do it's a very hairy problem, text was not meant for this
+12
View File
@@ -0,0 +1,12 @@
absolute path C:/notes
lower case c:/notes
backwards slash C:\
go back ../notes
current dir ./notes
file without slash notes
allows spaces C:\Program Files/
multiple slashes C:\\\\\\\\\\\\\\\\\\\\\\\\\thing
you can combine the slashes C:\/Work
disallowed characters for names * \ / ? > < | : "
There is literally no way to consistently skip the windows path, you always have to relay on heuristics
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

+56
View File
@@ -0,0 +1,56 @@
! What precise workflow do I need for me to be viable to use this?
! From a user (novice) point of view, how does it look like?
- Buffer edit history separate from caret history (tagging history blocks with carets???)
- We need regex for: [FormatCode matching, IsCode matching,
- Macros
- Window position: vscode opens in fullscreen and then remembers what position it was close in (could be a config option)
- On Linux: Try to implement is_debugger_present()
- Maybe IPC for te.exe when it's already open and file arguments are passed it should perhaps open a buffer in current window??
- Add <<File>> <<ProjectDirectory>> template strings to Open (Then remove SEtWorkdirhere)
- :Set Filename to name current buffer ??? :O and others like that!!
- Make a fuzzy command !> grep and fuzzy over it??? (doesn't seem very useful for grep)
- Make the equivalent of SearchOpenBuffers but for cmds like !@git grep -n "@>"
- Add Bool variable
- Guide on the first page for new users with links to configs, tutorials
Debug session:
- Report errorf - use coroutine dialogs
- Replace in render layer also
- BlockAllocator something is not working there which only showed after executing OpenCode on many files
- Some bad allocating happening in Clipboard for sure OR MAYBE BLOCK ALLOCATOR ACTION
New UI Session
- Uneditable buffers ?
- Maybe marked allocations??? So that we can associate allocations with a buffer or view and then dealloc all at the same time
- Open with seek string (open at pattern) filename:32 filename:/^Window$/
- Show what process/coroutines are running and allow to kill (active process buffer?)
- Database idea: use special buffers to store information
- Editing the buffer doesn't seem to be the slow part rather, accessing the data and putting it into the buffer (potentially hitting many different memory locations) I have a crazy idea to use buffers in order to store the names in a serialized format
- non editable buffers (raw ops ok, non-raw no op)
- DBBuffer
- Try to add Tracking Allocator and rewrite the app, free all memory at the end of the app and check all is well
FEATURE Some decl/function indexing in fuzzy format
FEATURE dump text editor state to file, restore state
- Search and replace
- word complete
- escapeing multiple cursor after ctrl + d should put the cursor where it was (probably will need to swap secondary and primary cursor for new cursor
- draw indentation levels like in sublime (those lines) - we render chars one by one so seems relatively easy to figure out if whitespace belongs to beginning of line (make sure to add max value like 40 because of big files)
- code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey!
- combine glyph and selection rendering
- Test stdin writing code
- Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?)
- drop text into window
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
- make the editor replayable, store events and then replay, be careful about globals
- maybe open should return multiple options if there are many more? (like in sublime if many symbols you get a window and you choose and it automatically jumps you to the symbol in the background)
- I want a way to assign flags to buffers/views/windows from user perspective so that console window concept can be created from user space
- font cache and on demand unicode loads
- color parens, braces
- gap buffer
- optimize rendering - command buffer, and vertice buffer instead of vertice buffer with scissor
+98
View File
@@ -0,0 +1,98 @@
Basic Latin
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
Latin-1 Supplement
¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
Latin Extended-A
Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž ſ
Latin Extended-B
ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ Ǟ ǟ Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ DZ Dz dz Ǵ ǵ Ǻ ǻ Ǽ ǽ Ǿ ǿ Ȁ ȁ Ȃ ȃ ...
IPA Extensions
ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ ɛ ɜ ɝ ɞ ɟ ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ ɺ ɻ ɼ ɽ ɾ ɿ ʀ ʁ ʂ ʃ ʄ ʅ ʆ ʇ ʈ ʉ ʊ ʋ ʌ ʍ ʎ ʏ ʐ ʑ ʒ ʓ ʔ ʕ ʖ ʗ ʘ ʙ ʚ ʛ ʜ ʝ ʞ ʟ ʠ ʡ ʢ ʣ ʤ ʥ ʦ ʧ ʨ
Spacing Modifier Letters
ʰ ʱ ʲ ʳ ʴ ʵ ʶ ʷ ʸ ʹ ʺ ʻ ʼ ʽ ʾ ʿ ˀ ˁ ˂ ˃ ˄ ˅ ˆ ˇ ˈ ˉ ˊ ˋ ˌ ˍ ˎ ˏ ː ˑ ˒ ˓ ˔ ˕ ˖ ˗ ˘ ˙ ˚ ˛ ˜ ˝ ˞ ˠ ˡ ˢ ˣ ˤ ˥ ˦ ˧ ˨ ˩
Combining Diacritical Marks
̀ ́ ̂ ̃ ̄ ̅ ̆ ̇ ̈ ̉ ̊ ̋ ̌ ̍ ̎ ̏ ̐ ̑ ̒ ̓ ̔ ̕ ̖ ̗ ̘ ̙ ̚ ̛ ̜ ̝ ̞ ̟ ̠ ̡ ̢ ̣ ̤ ̥ ̦ ̧ ̨ ̩ ̪ ̫ ̬ ̭ ̮ ̯ ̰ ̱ ̲ ̳ ̴ ̵ ̶ ̷ ̸ ̹ ̺ ̻ ̼ ̽ ̾ ̿ ̀ ́ ͂ ̓ ̈́ ͅ ͠ ͡
Greek
ʹ ͵ ͺ ; ΄ ΅ Ά · Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ ϐ ϑ ϒ ϓ ϔ ϕ ϖ Ϛ Ϝ Ϟ Ϡ Ϣ ϣ Ϥ ϥ Ϧ ϧ Ϩ ϩ Ϫ ϫ Ϭ ϭ Ϯ ϯ ϰ ϱ ϲ ϳ
Cyrillic
Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ Ќ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я ё ђ ѓ є ѕ і ї ј љ њ ћ ќ ў џ Ѡ ѡ Ѣ ѣ Ѥ ѥ Ѧ ѧ Ѩ ѩ Ѫ ѫ Ѭ ѭ Ѯ ѯ Ѱ ѱ Ѳ ѳ Ѵ ѵ Ѷ ѷ Ѹ ѹ Ѻ ѻ Ѽ ѽ Ѿ ѿ Ҁ ҁ ҂ ҃ ...
Armenian
Ա Բ Գ Դ Ե Զ Է Ը Թ Ժ Ի Լ Խ Ծ Կ Հ Ձ Ղ Ճ Մ Յ Ն Շ Ո Չ Պ Ջ Ռ Ս Վ Տ Ր Ց Ւ Փ Ք Օ Ֆ ՙ ՚ ՛ ՜ ՝ ՞ ՟ ա բ գ դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն շ ո չ պ ջ ռ ս վ տ ր ց ւ փ ք օ ֆ և ։
Hebrew
֑ ֒ ֓ ֔ ֕ ֖ ֗ ֘ ֙ ֚ ֛ ֜ ֝ ֞ ֟ ֠ ֡ ֣ ֤ ֥ ֦ ֧ ֨ ֩ ֪ ֫ ֬ ֭ ֮ ֯ ְ ֱ ֲ ֳ ִ ֵ ֶ ַ ָ ֹ ֻ ּ ֽ ־ ֿ ׀ ׁ ׂ ׃ ׄ א ב ג ד ה ו ז ח ט י ך כ ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת װ ױ ײ ׳ ״
Arabic
، ؛ ؟ ء آ أ ؤ إ ئ ا ب ة ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ـ ف ق ك ل م ن ه و ى ي ً ٌ ٍ َ ُ ِ ّ ْ ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٪ ٫ ٬ ٭ ٰ ٱ ٲ ٳ ٴ ٵ ٶ ٷ ٸ ٹ ٺ ٻ ټ ٽ پ ٿ ڀ ځ ڂ ڃ ڄ څ چ ڇ ڈ ډ ڊ ڋ ڌ ڍ ڎ ڏ ڐ ڑ ڒ ړ ڔ ڕ ږ ڗ ژ ڙ ښ ڛ ڜ ڝ ڞ ڟ ڠ ڡ ڢ ڣ ڤ ڥ ڦ ڧ ڨ ک ڪ ګ ڬ ڭ ڮ گ ڰ ڱ ...
Devanagari
ँ ं ः अ आ इ ई उ ऊ ऋ ऌ ऍ ऎ ए ऐ ऑ ऒ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न ऩ प फ ब भ म य र ऱ ल ळ ऴ व श ष स ह ़ ऽ ा ि ी ु ू ृ ॄ ॅ ॆ े ै ॉ ॊ ो ौ ् ॐ ॑ ॒ ॓ ॔ क़ ख़ ग़ ज़ ड़ ढ़ फ़ य़ ॠ ॡ ॢ ॣ । ॥ ० १ २ ३ ४ ५ ६ ७ ८ ९ ॰
Bengali
ঁ ং ঃ অ আ ই ঈ উ ঊ ঋ ঌ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ ় া ি ী ু ূ ৃ ৄ ে ৈ ো ৌ ্ ৗ ড় ঢ় য় ৠ ৡ ৢ ৣ ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ ৰ ৱ ৲ ৳ ৴ ৵ ৶ ৷ ৸ ৹ ৺
Gurmukhi
ਂ ਅ ਆ ਇ ਈ ਉ ਊ ਏ ਐ ਓ ਔ ਕ ਖ ਗ ਘ ਙ ਚ ਛ ਜ ਝ ਞ ਟ ਠ ਡ ਢ ਣ ਤ ਥ ਦ ਧ ਨ ਪ ਫ ਬ ਭ ਮ ਯ ਰ ਲ ਲ਼ ਵ ਸ਼ ਸ ਹ ਼ ਾ ਿ ੀ ੁ ੂ ੇ ੈ ੋ ੌ ੍ ਖ਼ ਗ਼ ਜ਼ ੜ ਫ਼ ੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯ ੰ ੱ ੲ ੳ ੴ
Gujarati
ઁ ં ઃ અ આ ઇ ઈ ઉ ઊ ઋ ઍ એ ઐ ઑ ઓ ઔ ક ખ ગ ઘ ઙ ચ છ જ ઝ ઞ ટ ઠ ડ ઢ ણ ત થ દ ધ ન પ ફ બ ભ મ ય ર લ ળ વ શ ષ સ હ ઼ ઽ ા િ ી ુ ૂ ૃ ૄ ૅ ે ૈ ૉ ો ૌ ્ ૐ ૠ ૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯
Oriya
ଁ ଂ ଃ ଅ ଆ ଇ ଈ ଉ ଊ ଋ ଌ ଏ ଐ ଓ ଔ କ ଖ ଗ ଘ ଙ ଚ ଛ ଜ ଝ ଞ ଟ ଠ ଡ ଢ ଣ ତ ଥ ଦ ଧ ନ ପ ଫ ବ ଭ ମ ଯ ର ଲ ଳ ଶ ଷ ସ ହ ଼ ଽ ା ି ୀ ୁ ୂ ୃ େ ୈ ୋ ୌ ୍ ୖ ୗ ଡ଼ ଢ଼ ୟ ୠ ୡ ୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯ ୰
Tamil
ஂ ஃ அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஜ ஞ ட ண த ந ன ப ம ய ர ற ல ள ழ வ ஷ ஸ ஹ ா ி ீ ு ூ ெ ே ை ொ ோ ௌ ் ௗ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯ ௰ ௱ ௲
Telugu
ఁ ం ః అ ఆ ఇ ఈ ఉ ఊ ఋ ఌ ఎ ఏ ఐ ఒ ఓ ఔ క ఖ గ ఘ ఙ చ ఛ జ ఝ ఞ ట ఠ డ ఢ ణ త థ ద ధ న ప ఫ బ భ మ య ర ఱ ల ళ వ శ ష స హ ా ి ీ ు ూ ృ ౄ ె ే ై ొ ో ౌ ్ ౕ ౖ ౠ ౡ ౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯
Kannada
ಂ ಃ ಅ ಆ ಇ ಈ ಉ ಊ ಋ ಌ ಎ ಏ ಐ ಒ ಓ ಔ ಕ ಖ ಗ ಘ ಙ ಚ ಛ ಜ ಝ ಞ ಟ ಠ ಡ ಢ ಣ ತ ಥ ದ ಧ ನ ಪ ಫ ಬ ಭ ಮ ಯ ರ ಱ ಲ ಳ ವ ಶ ಷ ಸ ಹ ಾ ಿ ೀ ು ೂ ೃ ೄ ೆ ೇ ೈ ೊ ೋ ೌ ್ ೕ ೖ ೞ ೠ ೡ ೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯
Malayalam
ം ഃ അ ആ ഇ ഈ ഉ ഊ ഋ ഌ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഠ ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര റ ല ള ഴ വ ശ ഷ സ ഹ ാ ി ീ ു ൂ ൃ െ േ ൈ ൊ ോ ൌ ് ൗ ൠ ൡ ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯
Thai
ก ข ฃ ค ฅ ฆ ง จ ฉ ช ซ ฌ ญ ฎ ฏ ฐ ฑ ฒ ณ ด ต ถ ท ธ น บ ป ผ ฝ พ ฟ ภ ม ย ร ฤ ล ฦ ว ศ ษ ส ห ฬ อ ฮ ฯ ะ ั า ำ ิ ี ึ ื ุ ู ฺ ฿ เ แ โ ใ ไ ๅ ๆ ็ ่ ้ ๊ ๋ ์ ํ ๎ ๏ ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙ ๚ ๛
Lao
ກ ຂ ຄ ງ ຈ ຊ ຍ ດ ຕ ຖ ທ ນ ບ ປ ຜ ຝ ພ ຟ ມ ຢ ຣ ລ ວ ສ ຫ ອ ຮ ຯ ະ ັ າ ຳ ິ ີ ຶ ື ຸ ູ ົ ຼ ຽ ເ ແ ໂ ໃ ໄ ໆ ່ ້ ໊ ໋ ໌ ໍ ໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙ ໜ ໝ
Tibetan
ༀ ༁ ༂ ༃ ༄ ༅ ༆ ༇ ༈ ༉ ༊ ་ ༌ ། ༎ ༏ ༐ ༑ ༒ ༓ ༔ ༕ ༖ ༗ ༘ ༙ ༚ ༛ ༜ ༝ ༞ ༟ ༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩ ༪ ༫ ༬ ༭ ༮ ༯ ༰ ༱ ༲ ༳ ༴ ༵ ༶ ༷ ༸ ༹ ༺ ༻ ༼ ༽ ༾ ༿ ཀ ཁ ག གྷ ང ཅ ཆ ཇ ཉ ཊ ཋ ཌ ཌྷ ཎ ཏ ཐ ད དྷ ན པ ཕ བ བྷ མ ཙ ཚ ཛ ཛྷ ཝ ཞ ཟ འ ཡ ར ལ ཤ ཥ ས ཧ ཨ ཀྵ ཱ ི ཱི ུ ཱུ ྲྀ ཷ ླྀ ཹ ེ ཻ ོ ཽ ཾ ཿ ྀ ཱྀ ྂ ྃ ྄ ྅ ྆ ྇ ...
Georgian
Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჻
Hangul Jamo
ᄀ ᄁ ᄂ ᄃ ᄄ ᄅ ᄆ ᄇ ᄈ ᄉ ᄊ ᄋ ᄌ ᄍ ᄎ ᄏ ᄐ ᄑ ᄒ ᄓ ᄔ ᄕ ᄖ ᄗ ᄘ ᄙ ᄚ ᄛ ᄜ ᄝ ᄞ ᄟ ᄠ ᄡ ᄢ ᄣ ᄤ ᄥ ᄦ ᄧ ᄨ ᄩ ᄪ ᄫ ᄬ ᄭ ᄮ ᄯ ᄰ ᄱ ᄲ ᄳ ᄴ ᄵ ᄶ ᄷ ᄸ ᄹ ᄺ ᄻ ᄼ ᄽ ᄾ ᄿ ᅀ ᅁ ᅂ ᅃ ᅄ ᅅ ᅆ ᅇ ᅈ ᅉ ᅊ ᅋ ᅌ ᅍ ᅎ ᅏ ᅐ ᅑ ᅒ ᅓ ᅔ ᅕ ᅖ ᅗ ᅘ ᅙ ᅟ ᅠ ᅡ ᅢ ᅣ ᅤ ᅥ ᅦ ᅧ ᅨ ᅩ ᅪ ᅫ ᅬ ᅭ ᅮ ᅯ ᅰ ᅱ ᅲ ᅳ ᅴ ᅵ ᅶ ᅷ ᅸ ᅹ ᅺ ᅻ ᅼ ᅽ ᅾ ᅿ ᆀ ᆁ ᆂ ᆃ ᆄ ...
Latin Extended Additional
Ḁ ḁ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ḉ ḉ Ḋ ḋ Ḍ ḍ Ḏ ḏ Ḑ ḑ Ḓ ḓ Ḕ ḕ Ḗ ḗ Ḙ ḙ Ḛ ḛ Ḝ ḝ Ḟ ḟ Ḡ ḡ Ḣ ḣ Ḥ ḥ Ḧ ḧ Ḩ ḩ Ḫ ḫ Ḭ ḭ Ḯ ḯ Ḱ ḱ Ḳ ḳ Ḵ ḵ Ḷ ḷ Ḹ ḹ Ḻ ḻ Ḽ ḽ Ḿ ḿ Ṁ ṁ Ṃ ṃ Ṅ ṅ Ṇ ṇ Ṉ ṉ Ṋ ṋ Ṍ ṍ Ṏ ṏ Ṑ ṑ Ṓ ṓ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ṡ ṡ Ṣ ṣ Ṥ ṥ Ṧ ṧ Ṩ ṩ Ṫ ṫ Ṭ ṭ Ṯ ṯ Ṱ ṱ Ṳ ṳ Ṵ ṵ Ṷ ṷ Ṹ ṹ Ṻ ṻ Ṽ ṽ Ṿ ṿ ...
Greek Extended
ἀ ἁ ἂ ἃ ἄ ἅ ἆ ἇ Ἀ Ἁ Ἂ Ἃ Ἄ Ἅ Ἆ Ἇ ἐ ἑ ἒ ἓ ἔ ἕ Ἐ Ἑ Ἒ Ἓ Ἔ Ἕ ἠ ἡ ἢ ἣ ἤ ἥ ἦ ἧ Ἠ Ἡ Ἢ Ἣ Ἤ Ἥ Ἦ Ἧ ἰ ἱ ἲ ἳ ἴ ἵ ἶ ἷ Ἰ Ἱ Ἲ Ἳ Ἴ Ἵ Ἶ Ἷ ὀ ὁ ὂ ὃ ὄ ὅ Ὀ Ὁ Ὂ Ὃ Ὄ Ὅ ὐ ὑ ὒ ὓ ὔ ὕ ὖ ὗ Ὑ Ὓ Ὕ Ὗ ὠ ὡ ὢ ὣ ὤ ὥ ὦ ὧ Ὠ Ὡ Ὢ Ὣ Ὤ Ὥ Ὦ Ὧ ὰ ά ὲ έ ὴ ή ὶ ί ὸ ό ὺ ύ ὼ ώ ᾀ ᾁ ᾂ ᾃ ᾄ ᾅ ᾆ ᾇ ᾈ ᾉ ᾊ ᾋ ᾌ ᾍ ...
General Punctuation
          ​ ‌ ‍ ‎ ‏ ‐ ‑ ‒ – — ― ‖ ‗ ‘ ’ ‚ ‛ “ ” „ ‟ † ‡ • ‣ ․ ‥ … ‧

 ‪ ‫ ‬ ‭ ‮ ‰ ‱ ′ ″ ‴ ‵ ‶ ‷ ‸ ‹ › ※ ‼ ‽ ‾ ‿ ⁀ ⁁ ⁂ ⁃ ⁄ ⁅ ⁆      
Superscripts and Subscripts
⁰ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ⁿ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎
Currency Symbols
₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫
Combining Marks for Symbols
⃐ ⃑ ⃒ ⃓ ⃔ ⃕ ⃖ ⃗ ⃘ ⃙ ⃚ ⃛ ⃜ ⃝ ⃞ ⃟ ⃠ ⃡
Letterlike Symbols
℀ ℁ ℂ ℃ ℄ ℅ ℆ ℇ ℈ ℉ ℊ ℋ ℌ ℍ ℎ ℏ ℐ ℑ ℒ ℓ ℔ ℕ № ℗ ℘ ℙ ℚ ℛ ℜ ℝ ℞ ℟ ℠ ℡ ™ ℣ ℤ ℥ Ω ℧ ℨ ℩ K Å ℬ ℭ ℮ ℯ ℰ ℱ Ⅎ ℳ ℴ ℵ ℶ ℷ ℸ
Number Forms
⅓ ⅔ ⅕ ⅖ ⅗ ⅘ ⅙ ⅚ ⅛ ⅜ ⅝ ⅞ ⅟ Ⅰ Ⅱ Ⅲ Ⅳ Ⅴ Ⅵ Ⅶ Ⅷ Ⅸ Ⅹ Ⅺ Ⅻ Ⅼ Ⅽ Ⅾ Ⅿ ⅰ ⅱ ⅲ ⅳ ⅴ ⅵ ⅶ ⅷ ⅸ ⅹ ⅺ ⅻ ⅼ ⅽ ⅾ ⅿ ↀ ↁ ↂ
Arrows
← ↑ → ↓ ↔ ↕ ↖ ↗ ↘ ↙ ↚ ↛ ↜ ↝ ↞ ↟ ↠ ↡ ↢ ↣ ↤ ↥ ↦ ↧ ↨ ↩ ↪ ↫ ↬ ↭ ↮ ↯ ↰ ↱ ↲ ↳ ↴ ↵ ↶ ↷ ↸ ↹ ↺ ↻ ↼ ↽ ↾ ↿ ⇀ ⇁ ⇂ ⇃ ⇄ ⇅ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌ ⇍ ⇎ ⇏ ⇐ ⇑ ⇒ ⇓ ⇔ ⇕ ⇖ ⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪
Mathematical Operators
∀ ∁ ∂ ∃ ∄ ∅ ∆ ∇ ∈ ∉ ∊ ∋ ∌ ∍ ∎ ∏ ∐ ∑ − ∓ ∔ ∕ ∖ ∗ ∘ ∙ √ ∛ ∜ ∝ ∞ ∟ ∠ ∡ ∢ ∣ ∤ ∥ ∦ ∧ ∨ ∩ ∪ ∫ ∬ ∭ ∮ ∯ ∰ ∱ ∲ ∳ ∴ ∵ ∶ ∷ ∸ ∹ ∺ ∻ ∼ ∽ ∾ ∿ ≀ ≁ ≂ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≏ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≠ ≡ ≢ ≣ ≤ ≥ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ...
Miscellaneous Technical
⌀ ⌂ ⌃ ⌄ ⌅ ⌆ ⌇ ⌈ ⌉ ⌊ ⌋ ⌌ ⌍ ⌎ ⌏ ⌐ ⌑ ⌒ ⌓ ⌔ ⌕ ⌖ ⌗ ⌘ ⌙ ⌚ ⌛ ⌜ ⌝ ⌞ ⌟ ⌠ ⌡ ⌢ ⌣ ⌤ ⌥ ⌦ ⌧ ⌨ 〈 〉 ⌫ ⌬ ⌭ ⌮ ⌯ ⌰ ⌱ ⌲ ⌳ ⌴ ⌵ ⌶ ⌷ ⌸ ⌹ ⌺ ⌻ ⌼ ⌽ ⌾ ⌿ ⍀ ⍁ ⍂ ⍃ ⍄ ⍅ ⍆ ⍇ ⍈ ⍉ ⍊ ⍋ ⍌ ⍍ ⍎ ⍏ ⍐ ⍑ ⍒ ⍓ ⍔ ⍕ ⍖ ⍗ ⍘ ⍙ ⍚ ⍛ ⍜ ⍝ ⍞ ⍟ ⍠ ⍡ ⍢ ⍣ ⍤ ⍥ ⍦ ⍧ ⍨ ⍩ ⍪ ⍫ ⍬ ⍭ ⍮ ⍯ ⍰ ⍱ ⍲ ⍳ ⍴ ⍵ ⍶ ⍷ ⍸ ⍹ ⍺
Control Pictures
␀ ␁ ␂ ␃ ␄ ␅ ␆ ␇ ␈ ␉ ␊ ␋ ␌ ␍ ␎ ␏ ␐ ␑ ␒ ␓ ␔ ␕ ␖ ␗ ␘ ␙ ␚ ␛ ␜ ␝ ␞ ␟ ␠ ␡ ␢ ␣ ␤
Optical Character Recognition
⑀ ⑁ ⑂ ⑃ ⑄ ⑅ ⑆ ⑇ ⑈ ⑉ ⑊
Enclosed Alphanumerics
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ...
Box Drawing
─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏ ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿
Block Elements
▀ ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▉ ▊ ▋ ▌ ▍ ▎ ▏ ▐ ░ ▒ ▓ ▔ ▕
Geometric Shapes
■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▪ ▫ ▬ ▭ ▮ ▯ ▰ ▱ ▲ △ ▴ ▵ ▶ ▷ ▸ ▹ ► ▻ ▼ ▽ ▾ ▿ ◀ ◁ ◂ ◃ ◄ ◅ ◆ ◇ ◈ ◉ ◊ ○ ◌ ◍ ◎ ● ◐ ◑ ◒ ◓ ◔ ◕ ◖ ◗ ◘ ◙ ◚ ◛ ◜ ◝ ◞ ◟ ◠ ◡ ◢ ◣ ◤ ◥ ◦ ◧ ◨ ◩ ◪ ◫ ◬ ◭ ◮ ◯
Miscellaneous Symbols
☀ ☁ ☂ ☃ ☄ ★ ☆ ☇ ☈ ☉ ☊ ☋ ☌ ☍ ☎ ☏ ☐ ☑ ☒ ☓ ☚ ☛ ☜ ☝ ☞ ☟ ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯ ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☸ ☹ ☺ ☻ ☼ ☽ ☾ ☿ ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟ ♠ ♡ ♢ ♣ ♤ ♥ ♦ ♧ ♨ ♩ ♪ ♫ ♬ ♭ ♮ ♯
Dingbats
✁ ✂ ✃ ✄ ✆ ✇ ✈ ✉ ✌ ✍ ✎ ✏ ✐ ✑ ✒ ✓ ✔ ✕ ✖ ✗ ✘ ✙ ✚ ✛ ✜ ✝ ✞ ✟ ✠ ✡ ✢ ✣ ✤ ✥ ✦ ✧ ✩ ✪ ✫ ✬ ✭ ✮ ✯ ✰ ✱ ✲ ✳ ✴ ✵ ✶ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✿ ❀ ❁ ❂ ❃ ❄ ❅ ❆ ❇ ❈ ❉ ❊ ❋ ❍ ❏ ❐ ❑ ❒ ❖ ❘ ❙ ❚ ❛ ❜ ❝ ❞ ❡ ❢ ❣ ❤ ❥ ❦ ❧ ❶ ❷ ❸ ❹ ❺ ❻ ❼ ❽ ❾ ❿ ➀ ➁ ➂ ➃ ➄ ➅ ➆ ➇ ➈ ➉ ➊ ➋ ➌ ➍ ➎ ➏ ➐ ➑ ➒ ➓ ➔ ➘ ➙ ➚ ➛ ➜ ➝ ...
CJK Symbols and Punctuation
  、 。 〃 〄 々 〆 〇 〈 〉 《 》 「 」 『 』 【 】 〒 〓 〔 〕 〖 〗 〘 〙 〚 〛 〜 〝 〞 〟 〠 〡 〢 〣 〤 〥 〦 〧 〨 〩 〪 〫 〬 〭 〮 〯 〰 〱 〲 〳 〴 〵 〶 〷 〿
Hiragana
ぁ あ ぃ い ぅ う ぇ え ぉ お か が き ぎ く ぐ け げ こ ご さ ざ し じ す ず せ ぜ そ ぞ た だ ち ぢ っ つ づ て で と ど な に ぬ ね の は ば ぱ ひ び ぴ ふ ぶ ぷ へ べ ぺ ほ ぼ ぽ ま み む め も ゃ や ゅ ゆ ょ よ ら り る れ ろ ゎ わ ゐ ゑ を ん ゔ ゙ ゚ ゛ ゜ ゝ ゞ
Katakana
ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ ゲ コ ゴ サ ザ シ ジ ス ズ セ ゼ ソ ゾ タ ダ チ ヂ ッ ツ ヅ テ デ ト ド ナ ニ ヌ ネ ノ ハ バ パ ヒ ビ ピ フ ブ プ ヘ ベ ペ ホ ボ ポ マ ミ ム メ モ ャ ヤ ュ ユ ョ ヨ ラ リ ル レ ロ ヮ ワ ヰ ヱ ヲ ン ヴ ヵ ヶ ヷ ヸ ヹ ヺ ・ ー ヽ ヾ
Bopomofo
ㄅ ㄆ ㄇ ㄈ ㄉ ㄊ ㄋ ㄌ ㄍ ㄎ ㄏ ㄐ ㄑ ㄒ ㄓ ㄔ ㄕ ㄖ ㄗ ㄘ ㄙ ㄚ ㄛ ㄜ ㄝ ㄞ ㄟ ㄠ ㄡ ㄢ ㄣ ㄤ ㄥ ㄦ ㄧ ㄨ ㄩ ㄪ ㄫ ㄬ
+9
View File
@@ -0,0 +1,9 @@
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#include "basic_string.cpp"
#include "basic_string16.cpp"
#include "basic_unicode.cpp"
#include "basic_alloc.cpp"
#include "basic_os.cpp"
#include "math.cpp"
#include "math_int.cpp"
+10
View File
@@ -0,0 +1,10 @@
#include "basic_head.h"
#include "basic_alloc.h"
#include "basic_array.h"
#include "basic_string.h"
#include "basic_table.h"
#include "basic_string16.h"
#include "basic_unicode.h"
#include "basic_os.h"
#include "basic_list.h"
#include "basic_math.h"
+437
View File
@@ -0,0 +1,437 @@
#if defined(USE_ADDRESS_SANITIZER)
#include <sanitizer/asan_interface.h>
#endif
#if !defined(ASAN_POISON_MEMORY_REGION)
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#else
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
#endif
#include <stdlib.h>
#if OS_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
API void *VReserve(size_t size) {
void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
API bool VCommit(void *p, size_t size) {
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
return result ? true : false;
}
API bool VRelease(void *p, size_t size) {
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
return result ? true : false;
}
API bool VDecommit(void *p, size_t size) {
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
return result ? true : false;
}
#elif OS_LINUX || OS_MAC
#include <sys/mman.h>
API void *VReserve(size_t size) {
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t)0);
return result == (void *)-1 ? 0 : result;
}
API bool VCommit(void *p, size_t size) {
int result = mprotect(p, size, PROT_READ | PROT_WRITE);
return result == 0;
}
API bool VRelease(void *p, size_t size) {
int result = munmap(p, size);
return result == 0;
}
API bool VDecommit(void *p, size_t size) {
mprotect(p, size, PROT_NONE);
madvise(p, size, MADV_DONTNEED);
return true;
}
#else
API void *VReserve(size_t size) {
InvalidCodepath();
return NULL;
}
API bool VCommit(void *p, size_t size) {
InvalidCodepath();
return false;
}
API bool VRelease(void *p, size_t size) {
InvalidCodepath();
return false;
}
API bool VDecommit(void *p, size_t size) {
InvalidCodepath();
return false;
}
#endif
API void *SystemAllocatorProc(void *object, int kind, void *p, size_t size) {
void *result = NULL;
if (kind == AllocatorKind_Allocate) {
result = malloc(size);
Assert(result);
} else if (kind == AllocatorKind_Deallocate) {
free(p);
} else {
InvalidCodepath();
}
return result;
}
API Allocator GetSystemAllocator() {
Allocator result = {SystemAllocatorProc};
return result;
}
API void *_AllocSize_(Allocator alo, size_t size) {
void *result = alo.proc(alo.object, AllocatorKind_Allocate, NULL, size);
memset(result, 0, size);
return result;
}
struct MemoryRecord {
size_t size;
void *addr;
char *file;
int line;
};
thread_local Array<MemoryRecord> MemoryTrackingRecord;
API void *TrackingAllocatorProc(void *object, int kind, void *p, size_t size) {
void *result = NULL;
if (kind == AllocatorKind_Allocate) {
result = malloc(size);
Add(&MemoryTrackingRecord, {size, result, LocationTraceO.file, LocationTraceO.line});
Assert(result);
} else if (kind == AllocatorKind_Deallocate) {
free(p);
bool found = false;
For(IterateInReverse(&MemoryTrackingRecord)) {
if (it.addr == p) {
found = true;
UnorderedRemove(&MemoryTrackingRecord, it);
break;
}
}
Assert(found);
} else {
InvalidCodepath();
}
return result;
}
API Allocator GetTrackingAllocator() {
Allocator result = {TrackingAllocatorProc};
return result;
}
///////////////////////////////
// Virtual Arena
API void InitArena(VirtualArena *arena, size_t reserve) {
reserve = AlignUp(reserve, PAGE_SIZE);
arena->align = DEFAULT_ALIGNMENT;
arena->data = (uint8_t *)VReserve(reserve);
if (arena->data) {
arena->reserve = reserve;
}
}
API VirtualArena *AllocArena(Allocator allocator, size_t size) {
VirtualArena *result = AllocType(allocator, VirtualArena);
result->data = (uint8_t *)AllocSize(allocator, size);
result->reserve = size;
result->commit = size;
result->align = DEFAULT_ALIGNMENT;
return result;
}
API VirtualArena *AllocArena(size_t reserve) {
VirtualArena *result = NULL;
void *data = VReserve(reserve);
if (!data) return result;
bool success = VCommit(data, PAGE_SIZE);
if (!success) {
VRelease(data, reserve);
return result;
}
result = (VirtualArena *)data;
result->data = (uint8_t *)data;
result->reserve = reserve;
result->commit = PAGE_SIZE;
result->len = result->base_len = sizeof(VirtualArena);
result->align = DEFAULT_ALIGNMENT;
return result;
}
API void *PushSize(VirtualArena *arena, size_t size) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
Assert(arena->len >= arena->base_len);
size_t align_offset = 0;
if (arena->align) {
align_offset = GetAlignOffset((uintptr_t)arena->data + arena->len, arena->align);
}
size_t size_with_alignment = size + align_offset;
size_t new_len = arena->len + size_with_alignment;
if (new_len > arena->commit) {
size_t new_len_aligned_to_page_size = AlignUp(new_len, PAGE_SIZE);
size_t to_commit = new_len_aligned_to_page_size - arena->commit;
size_t to_commit_clamped = ClampTop(to_commit, arena->reserve);
if (to_commit_clamped > 0) {
bool success = VCommit(arena->data + arena->commit, to_commit_clamped);
if (success) {
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
arena->commit += to_commit_clamped;
}
}
if (new_len > arena->commit) {
return NULL;
}
}
uint8_t *result = arena->data + arena->len + align_offset;
arena->len = new_len;
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
return (void *)result;
}
API void Release(VirtualArena *arena) {
if (arena == NULL || arena->data == NULL) return;
bool zero_memory = (uint8_t *)arena != arena->data;
VRelease(arena->data, arena->reserve);
if (zero_memory) MemoryZero(arena, sizeof(VirtualArena));
}
API void PopToPos(VirtualArena *arena, size_t pos) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
Assert(arena->len >= arena->base_len);
pos = Clamp(pos, arena->base_len, arena->len);
size_t size = arena->len - pos;
arena->len = pos;
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
}
API void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
if (kind == AllocatorKind_Allocate) {
return PushSize((VirtualArena *)object, size);
} else if (AllocatorKind_Deallocate) {
} else {
Assert(!"invalid codepath");
}
return NULL;
}
///////////////////////////////
// Block Arena
void AddBlock(BlockArena *arena, size_t size = MiB(1)) {
size_t block_size = MiB(1);
if (size > block_size) {
block_size = size;
}
if (arena->allocator.proc == NULL) {
arena->allocator = GetSystemAllocator();
}
BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode));
Assert(GetAlignOffset((size_t)new_block->start, DEFAULT_ALIGNMENT) == 0);
arena->start = new_block->start;
new_block->end = arena->end = new_block->start + block_size;
SLL_STACK_ADD(arena->blocks, new_block);
}
API void Init(BlockArena *arena) {
AddBlock(arena);
}
API void *PushSize(BlockArena *arena, size_t size) {
if (size > (size_t)(arena->end - arena->start)) {
AddBlock(arena, size);
}
U8 *result = arena->start;
Assert(GetAlignOffset((size_t)result, DEFAULT_ALIGNMENT) == 0);
arena->start = (U8 *)AlignUp((size_t)(arena->start + size), DEFAULT_ALIGNMENT);
return result;
}
API void Release(BlockArena *arena) {
for (BlockArenaNode *it = arena->blocks, *next = NULL; it; it = next) {
next = it->next;
Dealloc(arena->allocator, it);
}
MemoryZero(arena, sizeof(BlockArena));
}
API void Unwind(BlockArena *arena, U8 *pos) {
bool contains = false;
for (BlockArenaNode *it = arena->blocks, *next = NULL; it; it = next) {
next = it->next;
if ((pos >= it->start) && (pos <= it->end)) {
contains = true;
break;
} else {
arena->blocks = arena->blocks->next;
Dealloc(arena->allocator, it);
}
}
Assert(contains || pos == NULL);
arena->start = pos;
arena->end = arena->blocks ? arena->blocks->end : NULL;
}
API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
BlockArena *arena = (BlockArena *)object;
if (kind == AllocatorKind_Allocate) {
return PushSize(arena, size);
} else if (AllocatorKind_Deallocate) {
} else {
Assert(!"invalid codepath");
}
return NULL;
}
#if OS_WASM
API void InitScratch() {
}
#else
thread_local VirtualArena ScratchArenas[4];
API void InitScratch() {
for (int i = 0; i < 4; i += 1) {
InitArena(&ScratchArenas[i]);
}
}
API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count) {
VirtualArena *unoccupied = 0;
for (int i = 0; i < Lengthof(ScratchArenas); i += 1) {
VirtualArena *from_pool = &ScratchArenas[i];
unoccupied = from_pool;
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
VirtualArena *from_conflict = conflicts[conflict_i];
if (from_pool == from_conflict) {
unoccupied = 0;
break;
}
}
if (unoccupied) {
break;
}
}
// Failed to get free scratch memory, this is a fatal error, this shouldnt happen
Assert(unoccupied);
return unoccupied;
}
#endif
void RunArenaTest() {
Allocator memory_tracking_allocator = GetTrackingAllocator();
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
for (int i = 0; i < 10000; i += 1) {
int *vals = (int *)PushSize(&arena, sizeof(int)*i);
for (int j = 0; j < i; j += 1) {
vals[j] = j;
}
}
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
}
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
for (int i = 0; i < 32; i += 1) vals[i] = i;
Unwind(&arena, (U8 *)vals);
Assert(arena.blocks);
Assert(arena.blocks->next == NULL);
Assert(arena.start == (U8 *)vals);
Assert(arena.blocks[0].start == (U8 *)vals);
Unwind(&arena, NULL);
Dealloc(arena.allocator, arena.blocks);
Assert(MemoryTrackingRecord.len == 0);
}
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
for (int i = 0; i < 32; i += 1) vals[i] = i;
U8 *p = arena.start;
U8 *a = (U8 *)PushSize(&arena, KiB(32));
PushSize(&arena, KiB(1000));
Assert(arena.blocks);
Assert(arena.blocks->next);
Assert(arena.blocks->next->next == NULL);
Unwind(&arena, a);
Assert(arena.blocks);
Assert(arena.blocks->next == NULL);
Assert(arena.start == p);
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
}
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
PushSize(&arena, KiB(2000));
Assert((size_t)(arena.blocks[0].end - arena.blocks[0].start) == KiB(2000));
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
}
{
BlockArena arena = {};
arena.allocator = memory_tracking_allocator;
PushSize(&arena, KiB(2000));
Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 0);
PushSize(&arena, MiB(1));
PushSize(&arena, MiB(3));
Assert(MemoryTrackingRecord.len == 2);
Unwind(&arena, 0);
Assert(MemoryTrackingRecord.len == 0);
Release(&arena);
Assert(MemoryTrackingRecord.len == 0);
}
}
+153
View File
@@ -0,0 +1,153 @@
#pragma once
struct LocationTrace {
char *file;
int line;
};
thread_local LocationTrace LocationTraceO;
#define LOCATION_TRACE (LocationTraceO.file = __FILE__, LocationTraceO.line = __LINE__)
const int AllocatorKind_Allocate = 1;
const int AllocatorKind_Deallocate = 2;
struct Allocator {
void *(*proc)(void *object, int kind, void *p, size_t size);
void *object;
};
#define AllocType(alo, Type) (Type *)AllocSize(alo, sizeof(Type))
#define AllocArray(alo, Type, count) (Type *)AllocSize(alo, sizeof(Type) * (count))
#define AllocSize(alo, size) (LOCATION_TRACE, _AllocSize_(alo, size))
API void *_AllocSize_(Allocator alo, size_t size);
inline void Dealloc(Allocator alo, void *p) { if (p) (alo).proc((alo).object, AllocatorKind_Deallocate, (p), 0); }
API Allocator GetSystemAllocator();
API void TrackingAllocatorCheck();
API Allocator GetTrackingAllocator();
#define MemoryZero(x, size) memset(x, 0, size)
#define MemoryZeroStruct(x) memset(x, 0, sizeof(*x))
#define MemoryCopy(dst, src, size) memcpy(dst, src, size)
#define MemoryMove(dst, src, size) memmove(dst, src, size)
///////////////////
// Block Arena
///////////////////
API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size);
struct BlockArenaNode {
BlockArenaNode *next;
U8 *end;
U8 start[0];
};
struct BlockArena {
U8 *start;
U8 *end;
BlockArenaNode *blocks;
Allocator allocator;
int refs; // :CoroutineLeakCheck
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
};
API void *PushSize(BlockArena *arena, size_t size);
API void Release(BlockArena *arena);
API void Unwind(BlockArena *arena, U8 *pos);
///////////////////
// Virtual Arena
///////////////////
struct VirtualArena {
uint8_t *data;
size_t len;
size_t base_len; // to prevent self deleting the arena
size_t reserve;
size_t commit;
size_t align;
int refs; // :CoroutineLeakCheck
operator Allocator() {
void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size);
return {ArenaAllocatorProc, this};
}
};
inline void SetLen(VirtualArena *arena, size_t len) { arena->len = Clamp(len, arena->base_len, arena->len); }
inline void Pop(VirtualArena *arena, size_t size) { SetLen(arena, arena->len - size); }
inline void Clear(VirtualArena *arena) { SetLen(arena, 0); }
API void *VReserve(size_t size);
API bool VCommit(void *p, size_t size);
API bool VRelease(void *p, size_t size);
API bool VDecommit(void *p, size_t size);
API void InitArena(VirtualArena *arena, size_t reserve = MiB(256));
API VirtualArena *AllocArena(size_t reserve = MiB(256));
API VirtualArena *AllocArena(Allocator allocator, size_t size);
API void *PushSize(VirtualArena *arena, size_t size);
API void Release(VirtualArena *arena);
///////////////////////////////
// Scratch
#if OS_WASM
struct Scratch {
BlockArena arena = {};
Scratch() {}
Scratch(BlockArena *conflict) {}
Scratch(BlockArena *c1, BlockArena *c2) {}
Scratch(Allocator conflict) {}
Scratch(Allocator c1, Allocator c2) {}
~Scratch() { Release(&arena); }
operator BlockArena *() { return &arena; }
operator Allocator() { return arena; }
private: // @Note: Disable copy constructors, cause its error prone
Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2);
};
#else
extern thread_local VirtualArena ScratchArenas[4];
API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count);
struct Scratch {
VirtualArena *arena;
U64 p;
Scratch() {arena = &ScratchArenas[0]; p = arena->len; arena->refs += 1;}
Scratch(VirtualArena *conflict) {
VirtualArena *conf[] = {conflict};
arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len;
arena->refs += 1;
}
Scratch(VirtualArena *c1, VirtualArena *c2) {
VirtualArena *conf[] = {c1, c2};
arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len;
arena->refs += 1;
}
Scratch(Allocator conflict) {
VirtualArena *conf[] = {(VirtualArena *)conflict.object};
arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len;
arena->refs += 1;
}
Scratch(Allocator c1, Allocator c2) {
VirtualArena *conf[] = {(VirtualArena *)c1.object, (VirtualArena *)c2.object};
arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len;
arena->refs += 1;
}
~Scratch() { SetLen(arena, p); arena->refs -= 1; }
operator VirtualArena *() { return arena; }
operator Allocator() { return *arena; }
private: // @Note: Disable copy constructors, cause its error prone
Scratch(Scratch &arena);
Scratch(Scratch &arena, Scratch &a2);
};
#endif
const int PAGE_SIZE = 4096;
const int DEFAULT_ALIGNMENT = sizeof(void *);
+498
View File
@@ -0,0 +1,498 @@
#pragma once
/*
// Iterating and removing elements
for (int i = 0; i < array.len; i += 1) {
auto &it = array[i];
bool remove_item = false;
defer {
if (remove_item) {
array.ordered_remove(it);
i -= 1;
}
}
}
// Simple delete
IterRemove(arr) {
IterRemovePrepare(arr);
remove_item = true;
}
// Deleting backwards
For(arr.reverse_iter()) {
defer{ arr.unordered_remove(it); };
}
*/
#define IterRemove(a) for (int i = 0; i < (a).len; i += 1)
#define IterRemovePrepare(a) \
auto &it = (a)[i]; \
bool remove_item = false; \
defer { \
if (remove_item) { \
Remove(&(a), it); \
i -= 1; \
} \
}
#define ForItem(it, array) for (auto &it : (array))
#define For(array) ForItem(it, array)
template <class T>
struct Slice {
T *data;
int64_t len;
Slice() = default;
Slice(T *s, int64_t l) : data(s), len(l) {}
T &operator[](int64_t index) {
Assert(index < len);
return data[index];
}
T *begin() { return data; }
T *end() { return data + len; }
};
template <class T>
Slice<T> Copy(Allocator alo, Slice<T> array) {
Slice<T> result = {};
result.data = AllocArray(alo, T, array.len);
memcpy(result.data, array.data, sizeof(T) * array.len);
result.len = array.len;
return result;
}
template <class T>
T Pop(Slice<T> *arr) {
Assert(arr->len > 0);
return arr->data[--arr->len];
}
template <class T>
bool Contains(Slice<T> &arr, T item) {
For(arr) if (it == item) return true;
return false;
}
template <class T>
int64_t GetIndex(Slice<T> &arr, const T &item) {
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
Assert(index >= 0 && index < arr.len);
return (int64_t)index;
}
template <class T>
T Get(Slice<T> &arr, int64_t i, T default_value = {}) {
T result = default_value;
if (i >= 0 && i < arr.len) result = arr[i];
return result;
}
template <class T>
bool IsLast(Slice<T> &arr, T &item) {
bool result = arr.last() == &item;
return result;
}
template <class T>
bool IsFirst(Slice<T> &arr, T &item) {
bool result = arr.first() == &item;
return result;
}
template <class T>
T *GetFirst(Slice<T> &arr) {
Assert(arr.len > 0);
return arr.data;
}
template <class T>
T *GetLast(Slice<T> &arr) {
Assert(arr.len > 0);
return arr.data + arr.len - 1;
}
template <class T>
Slice<T> Chop(Slice<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data, arr.len - len};
return result;
}
template <class T>
Slice<T> Skip(Slice<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data + len, arr.len - len};
return result;
}
template <class T>
Slice<T> GetPostfix(Slice<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
int64_t remain_len = arr.len - len;
Slice<T> result = {arr.data + remain_len, len};
return result;
}
template <class T>
Slice<T> GetPrefix(Slice<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data, len};
return result;
}
template <class T>
Slice<T> GetSlice(Slice<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
// Negative indexes work in python style, they return you the index counting from end of list
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
if (first_index == SLICE_LAST) first_index = arr.len;
if (first_index < 0) first_index = arr.len + first_index;
Slice<T> result = {arr.data, arr.len};
if (arr.len > 0) {
if (one_past_last_index > first_index) {
first_index = ClampTop(first_index, arr.len - 1);
one_past_last_index = ClampTop(one_past_last_index, arr.len);
result.data += first_index;
result.len = one_past_last_index - first_index;
} else {
result.len = 0;
}
}
return result;
}
// Make arrays resize on every item
#define ARRAY_DEBUG 0
#if ARRAY_DEBUG
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) IF
#else
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) ELSE
#endif
template <class T>
struct Array {
Allocator allocator;
int64_t cap;
union {
Slice<T> slice;
struct {
T *data;
int64_t len;
};
};
T &operator[](int64_t index) {
Assert(index >= 0 && index < len);
return data[index];
}
T *begin() { return data; }
T *end() { return data + len; }
};
template <class T>
T *GetFirst(Array<T> &arr) {
Assert(arr.len > 0);
return arr.data;
}
template <class T>
T *GetLast(Array<T> &arr) {
Assert(arr.len > 0);
return arr.data + arr.len - 1;
}
template <class T>
void Reserve(Array<T> *arr, int64_t size) {
if (size > arr->cap) {
if (!arr->allocator.proc) arr->allocator = GetSystemAllocator();
T *new_data = AllocArray(arr->allocator, T, size);
Assert(new_data);
memcpy(new_data, arr->data, arr->len * sizeof(T));
Dealloc(arr->allocator, arr->data);
arr->data = new_data;
arr->cap = size;
}
}
template <class T>
void TryGrowing(Array<T> *arr) {
if (arr->len + 1 > arr->cap) {
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
int64_t new_size = ClampBottom(initial_size, arr->cap ARRAY_IF_DEBUG_ELSE(+1, *2));
Reserve(arr, new_size);
}
}
template <class T>
void TryGrowing(Array<T> *arr, int64_t item_count) {
if (arr->len + item_count > arr->cap) {
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
int64_t new_size = ClampBottom(initial_size, (arr->cap + item_count) ARRAY_IF_DEBUG_ELSE(+1, *2));
Reserve(arr, new_size);
}
}
template <class T>
void Add(Array<T> *arr, T item) {
TryGrowing(arr);
arr->data[arr->len++] = item;
}
template <class T>
void Add(Array<T> *arr, Array<T> &another) {
For(another) Add(arr, it);
}
template <class T>
void Add(Array<T> *arr, T *items, int64_t item_count) {
for (int64_t i = 0; i < item_count; i += 1) Add(arr, items[i]);
}
template <class T>
void BoundedAdd(Array<T> *arr, T item) {
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
}
template <class T>
void BoundedAddError(Array<T> *arr, T item) {
Assert(arr->len + 1 <= arr->cap);
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
}
template <class T>
void Insert(Array<T> *arr, T item, int64_t index) {
if (index == arr->len) {
Add(arr, item);
return;
}
Assert(index < arr->len);
Assert(index >= 0);
TryGrowing(arr);
int64_t right_len = arr->len - index;
memmove(arr->data + index + 1, arr->data + index, sizeof(T) * right_len);
arr->data[index] = item;
arr->len += 1;
}
template <class T>
Array<T> Copy(Allocator alo, Array<T> array) {
Array<T> result = {alo};
Reserve(&result, array.cap);
memcpy(result.data, array.data, sizeof(T) * array.len);
result.len = array.len;
return result;
}
template <class T>
Array<T> TightCopy(Allocator alo, Array<T> array) {
Array<T> result = {alo};
Reserve(&result, array.len);
memcpy(result.data, array.data, sizeof(T) * array.len);
result.len = array.len;
return result;
}
template <class T>
T Pop(Array<T> *arr) {
Assert(arr->len > 0);
return arr->data[--arr->len];
}
template <class T>
bool Contains(Array<T> &arr, T item) {
For(arr) if (it == item) return true;
return false;
}
template <class T>
int64_t GetIndex(Array<T> &arr, const T &item) {
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
Assert(index >= 0 && index < arr.len);
return (int64_t)index;
}
template <class T>
void RemoveByIndex(Array<T> *arr, int64_t index) {
Assert(index >= 0 && index < arr->len);
int64_t right_len = arr->len - index - 1;
memmove(arr->data + index, arr->data + index + 1, right_len * sizeof(T));
arr->len -= 1;
}
template <class T>
void RemoveManyByIndex(Array<T> *arr, int64_t index, int64_t count) {
if (count == 0) return;
Assert(index >= 0 && index < arr->len);
Assert((index + count) > 0 && (index + count) <= arr->len);
int64_t right_len = arr->len - index - count;
memmove(arr->data + index, arr->data + index + count, right_len * sizeof(T));
arr->len -= count;
}
template <class T>
void RemoveMany(Array<T> *arr, T &item, int64_t count) {
Assert(arr->len > 0);
Assert(&item >= arr->begin() && &item < arr->end());
int64_t index = GetIndex(*arr, item);
RemoveManyByIndex(arr, index, count);
}
template <class T>
void Remove(Array<T> *arr, T &item) {
Assert(arr->len > 0);
Assert(&item >= arr->begin() && &item < arr->end());
int64_t index = GetIndex(*arr, item);
RemoveByIndex(arr, index);
}
template <class T>
void UnorderedRemove(Array<T> *arr, T &item) {
Assert(arr->len > 0);
Assert((&item >= arr->begin()) && (&item < arr->end()));
item = arr->data[--arr->len];
}
template <class T>
void UnorderedRemoveByIndex(Array<T> *arr, int64_t index) {
Assert(arr->len > 0);
Assert(index >= 0 && index < arr->len);
arr->data[index] = arr->data[--arr->len];
}
template <class T>
void InsertArray(Array<T> *arr, T *items, int64_t count, int64_t index) {
if (index == arr->len) {
Add(arr, items, count);
return;
}
Assert(index < arr->len);
TryGrowing(arr, count);
T *gap_begin = arr->data + index;
T *gap_end = gap_begin + count;
int64_t item_count = arr->len - index;
memmove(gap_end, gap_begin, item_count * sizeof(T));
for (int64_t i = 0; i < count; i += 1) arr->data[index + i] = items[i];
arr->len += count;
}
template <class T>
T Get(Array<T> &arr, int64_t i, T default_value = {}) {
T result = default_value;
if (i >= 0 && i < arr.len) result = arr[i];
return result;
}
template <class T>
void Dealloc(Array<T> *arr) {
if (arr->data) {
Dealloc(arr->allocator, arr->data);
arr->data = NULL;
}
arr->len = arr->cap = 0;
}
template <class T>
bool IsLast(Array<T> &arr, T &item) {
bool result = GetLast(arr) == &item;
return result;
}
template <class T>
bool IsFirst(Array<T> &arr, T &item) {
bool result = GetFirst(arr) == &item;
return result;
}
template <class T>
Slice<T> Chop(Array<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data, arr.len - len};
return result;
}
template <class T>
Slice<T> Skip(Array<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data + len, arr.len - len};
return result;
}
template <class T>
Slice<T> GetPostfix(Array<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
int64_t remain_len = arr.len - len;
Slice<T> result = {arr.data + remain_len, len};
return result;
}
template <class T>
Slice<T> GetPrefix(Array<T> &arr, int64_t len) {
len = ClampTop(len, arr.len);
Slice<T> result = {arr.data, len};
return result;
}
template <class T>
Slice<T> GetSlice(Array<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
// Negative indexes work in python style, they return you the index counting from end of list
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
if (first_index == SLICE_LAST) first_index = arr.len;
if (first_index < 0) first_index = arr.len + first_index;
Slice<T> result = {arr.data, arr.len};
if (arr.len > 0) {
if (one_past_last_index > first_index) {
first_index = ClampTop(first_index, arr.len - 1);
one_past_last_index = ClampTop(one_past_last_index, arr.len);
result.data += first_index;
result.len = one_past_last_index - first_index;
} else {
result.len = 0;
}
}
return result;
}
template <class T>
struct ReverseIter {
T *data;
Slice<T> *arr;
ReverseIter operator++(int) {
ReverseIter ret = *this;
data -= 1;
return ret;
}
ReverseIter &operator++() {
data -= 1;
return *this;
}
T &operator*() { return data[0]; }
T *operator->() { return data; }
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
};
template <class T>
ReverseIter<T> IterateInReverse(Array<T> *arr) {
return {arr->end() - 1, &arr->slice};
}
template <class T>
ReverseIter<T> IterateInReverse(Slice<T> *slice) {
return {slice->end() - 1, slice};
}
+239
View File
@@ -0,0 +1,239 @@
#pragma once
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#if defined(__APPLE__) && defined(__MACH__)
#define OS_POSIX 1
#define OS_MAC 1
#elif defined(_WIN32)
#define OS_WINDOWS 1
#elif defined(__linux__)
#define OS_POSIX 1
#define OS_LINUX 1
#elif defined(__EMSCRIPTEN__)
#define OS_WASM 1
#else
#error Unsupported platform
#endif
#if defined(__clang__)
#define COMPILER_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__)
#define COMPILER_GCC 1
#elif defined(_MSC_VER)
#define COMPILER_MSVC 1
#else
#error Unsupported compiler
#endif
#ifndef OS_WASM
#define OS_WASM 0
#endif
#ifndef OS_MAC
#define OS_MAC 0
#endif
#ifndef OS_WINDOWS
#define OS_WINDOWS 0
#endif
#ifndef OS_LINUX
#define OS_LINUX 0
#endif
#ifndef OS_POSIX
#define OS_POSIX 0
#endif
#ifndef COMPILER_MSVC
#define COMPILER_MSVC 0
#endif
#ifndef COMPILER_CLANG
#define COMPILER_CLANG 0
#endif
#ifndef COMPILER_GCC
#define COMPILER_GCC 0
#endif
#ifndef DEBUG_BUILD
#define DEBUG_BUILD 1
#endif
#if DEBUG_BUILD
#define IF_DEBUG(x) x
#else
#define IF_DEBUG(x)
#endif
#if OS_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#define BREAK() if (IsDebuggerPresent()) {__debugbreak();}
#elif OS_LINUX
#define BREAK() raise(SIGTRAP)
#elif OS_WASM
#include <emscripten.h>
EM_JS(void, JS_Breakpoint, (), {
debugger;
})
#define BREAK() JS_Breakpoint()
#endif
#define API
#define Assert(x) \
if (!(x)) { \
BREAK(); \
}
#define InvalidCodepath() Assert(!"invalid codepath")
#define ElseInvalidCodepath() else {InvalidCodepath();}
#define KiB(x) ((x##ull) * 1024ull)
#define MiB(x) (KiB(x) * 1024ull)
#define GiB(x) (MiB(x) * 1024ull)
#define TiB(x) (GiB(x) * 1024ull)
#define Lengthof(x) ((int64_t)((sizeof(x) / sizeof((x)[0]))))
#define SLICE_LAST INT64_MAX
using U8 = uint8_t;
using U16 = uint16_t;
using U32 = uint32_t;
using U64 = uint64_t;
using S8 = int8_t;
using S16 = int16_t;
using S32 = int32_t;
using S64 = int64_t;
using Int = S64;
using UInt = U64;
using Float = double;
template <class T>
T Min(T a, T b) {
if (a > b) return b;
return a;
}
template <class T>
T ClampTop(T a, T top) {
return Min(a, top);
}
template <class T>
T Max(T a, T b) {
if (a > b) return a;
return b;
}
template <class T>
T ClampBottom(T bottom, T b) {
return Max(bottom, b);
}
template <class T>
T Clamp(T value, T min, T max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
template <class T>
void Swap(T *a, T *b) {
T temp = *a;
*a = *b;
*b = temp;
}
inline bool IsPowerOf2(size_t x) {
size_t result = (((x) & ((x)-1)) == 0);
return result;
}
inline size_t WrapAroundPowerOf2(size_t x, size_t pow2) {
Assert(IsPowerOf2(pow2));
size_t result = (((x) & ((pow2)-1llu)));
return result;
}
inline uint64_t HashBytes(void *data, int64_t size) {
uint8_t *data8 = (uint8_t *)data;
uint64_t hash = (uint64_t)14695981039346656037ULL;
for (int64_t i = 0; i < size; i++) {
hash = hash ^ (uint64_t)(data8[i]);
hash = hash * (uint64_t)1099511628211ULL;
}
return hash;
}
inline size_t GetAlignOffset(size_t size, size_t align) {
Assert(IsPowerOf2(align));
size_t mask = align - 1;
size_t val = size & mask;
if (val) {
val = align - val;
}
return val;
}
inline size_t AlignUp(size_t size, size_t align) {
size_t result = size + GetAlignOffset(size, align);
return result;
}
inline size_t AlignDown(size_t size, size_t align) {
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
size_t result = size - (align - GetAlignOffset(size, align));
return result;
}
template <typename T>
struct DEFER_ExitScope {
T lambda;
DEFER_ExitScope(T lambda) : lambda(lambda) {}
~DEFER_ExitScope() { lambda(); }
DEFER_ExitScope(const DEFER_ExitScope &i) : lambda(i.lambda){};
private:
DEFER_ExitScope &operator=(const DEFER_ExitScope &);
};
class DEFER_ExitScopeHelp {
public:
template <typename T>
DEFER_ExitScope<T> operator+(T t) { return t; }
};
#define DEFER_CONCAT_INTERNAL(x, y) x##y
#define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y)
#define defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]()
struct RandomSeed {
uint64_t a;
};
inline uint64_t GetRandomU64(RandomSeed *state) {
uint64_t x = state->a;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return state->a = x;
}
#define STRINGIFY_(x) x
#define STRINGIFY(x) STRINGIFY_(x)
#define CONCAT_(a, b) a ## b
#define CONCAT(a, b) CONCAT_(a, b)
+117
View File
@@ -0,0 +1,117 @@
#pragma once
#define SLL_QUEUE_ADD_MOD(f, l, n, next) \
do { \
(n)->next = 0; \
if ((f) == 0) { \
(f) = (l) = (n); \
} else { \
(l) = (l)->next = (n); \
} \
} while (0)
#define SLL_QUEUE_ADD(f, l, n) SLL_QUEUE_ADD_MOD(f, l, n, next)
#define SLL_QUEUE_POP_FIRST_MOD(f, l, next) \
do { \
if ((f) == (l)) { \
(f) = (l) = 0; \
} else { \
(f) = (f)->next; \
} \
} while (0)
#define SLL_QUEUE_POP_FIRST(f, l) SLL_QUEUE_POP_FIRST_MOD(f, l, next)
#define SLL_STACK_ADD_MOD(stack_base, new_stack_base, next) \
do { \
(new_stack_base)->next = (stack_base); \
(stack_base) = (new_stack_base); \
} while (0)
#define SLL_STACK_ADD(stack_base, new_stack_base) \
SLL_STACK_ADD_MOD(stack_base, new_stack_base, next)
#define SLL_STACK_POP_AND_STORE(stack_base, out_node) \
do { \
if (stack_base) { \
(out_node) = (stack_base); \
(stack_base) = (stack_base)->next; \
(out_node)->next = 0; \
} \
} while (0)
#define DLL_QUEUE_ADD_MOD(f, l, node, next, prev) \
do { \
if ((f) == 0) { \
(f) = (l) = (node); \
(node)->prev = 0; \
(node)->next = 0; \
} else { \
(l)->next = (node); \
(node)->prev = (l); \
(node)->next = 0; \
(l) = (node); \
} \
} while (0)
#define DLL_QUEUE_ADD(f, l, node) DLL_QUEUE_ADD_MOD(f, l, node, next, prev)
#define DLL_QUEUE_ADD_FRONT(f, l, node) DLL_QUEUE_ADD_MOD(l, f, node, prev, next)
#define DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev) \
do { \
if ((first) == (last)) { \
(first) = (last) = 0; \
} else if ((last) == (node)) { \
(last) = (last)->prev; \
(last)->next = 0; \
} else if ((first) == (node)) { \
(first) = (first)->next; \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLL_QUEUE_REMOVE(first, last, node) DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev)
#define DLL_STACK_ADD_MOD(first, node, next, prev) \
do { \
(node)->next = (first); \
if ((first)) \
(first)->prev = (node); \
(first) = (node); \
(node)->prev = 0; \
} while (0)
#define DLL_STACK_ADD(first, node) DLL_STACK_ADD_MOD(first, node, next, prev)
#define DLL_STACK_REMOVE_MOD(first, node, next, prev) \
do { \
if ((node) == (first)) { \
(first) = (first)->next; \
if ((first)) \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
if ((node)->next) \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLL_STACK_REMOVE(first, node) DLL_STACK_REMOVE_MOD(first, node, next, prev)
#define DLL_INSERT_NEXT_MOD(base, new, next, prev) \
do { \
if ((base) == 0) { \
(base) = (new); \
(new)->next = 0; \
(new)->prev = 0; \
} else { \
(new)->next = (base)->next; \
(base)->next = (new); \
(new)->prev = (base); \
if ((new)->next) (new)->next->prev = (new); \
} \
} while (0)
#define DLL_INSERT_NEXT(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
#define DLL_INSERT_PREV(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <math.h>
struct Vec2 {
float x;
float y;
};
union Vec4 {
struct {
float x;
float y;
float z;
float w;
};
struct {
float r;
float g;
float b;
float a;
};
};
union Vec3 {
struct {
float x;
float y;
float z;
};
struct {
float r;
float g;
float b;
};
};
struct Rect2 {
Vec2 min;
Vec2 max;
};
struct Vec2I {
Int x;
Int y;
};
struct Rect2I {
Vec2I min;
Vec2I max;
};
union Color {
struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
uint32_t value;
};
#define PI32 3.14159265359f
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
#pragma once
struct FileIter {
bool is_valid;
bool is_directory;
String absolute_path;
String relative_path;
String filename;
String path;
Allocator allocator;
union {
struct Win32_FileIter *w32;
void *dir;
};
};
String ReadFile(Allocator arena, String path);
bool WriteFile(String path, String data);
String GetAbsolutePath(Allocator arena, String relative);
bool IsValid(const FileIter &it);
void Advance(FileIter *it);
FileIter IterateFiles(Allocator allocator, String path);
void InitOS(void (*error_proc)(const char *, ...));
bool DeleteFile(String path);
String GetExePath(Allocator allocator);
String GetExeDir(Allocator allocator);
bool FileExists(String path);
bool IsDir(String path);
bool IsFile(String path);
String GetWorkingDir(Allocator arena);
bool IsAbsolute(String path);
int64_t GetFileModTime(String file);
struct Process {
bool is_valid;
int exit_code;
char platform[6 * 8];
int64_t id;
int64_t view_id; // text editor view
bool scroll_to_end;
};
Process SpawnProcess(String command_line, String working_dir, String write_stdin = {}, Array<String> enviroment = {});
bool IsValid(Process *process);
void KillProcess(Process *process);
String PollStdout(Allocator allocator, Process *process, bool force_read);
void WriteStdin(Process *process, String string);
void CloseStdin(Process *process);
double GetTimeMicros(void);
enum MakeDirResult {
MakeDirResult_Success,
MakeDirResult_Exists,
MakeDirResult_NotFound,
MakeDirResult_ErrorOther,
};
MakeDirResult MakeDir(String path);
+515
View File
@@ -0,0 +1,515 @@
API char ToLowerCase(char a) {
if (a >= 'A' && a <= 'Z') a += 32;
return a;
}
API char ToUpperCase(char a) {
if (a >= 'a' && a <= 'z') a -= 32;
return a;
}
API bool IsWhitespace(char w) {
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result;
}
API bool IsAlphabetic(char a) {
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
return result;
}
API bool IsIdent(char a) {
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
return result;
}
API bool IsDigit(char a) {
bool result = a >= '0' && a <= '9';
return result;
}
API bool IsAlphanumeric(char a) {
bool result = IsDigit(a) || IsAlphabetic(a);
return result;
}
API bool IsSymbol(char w) {
bool result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
return result;
}
API bool IsNonWord(char w) {
if (w == '_') return false;
bool result = IsSymbol(w) || IsWhitespace(w);
return result;
}
API bool IsWord(char w) {
bool result = !IsNonWord(w);
return result;
}
API bool IsBrace(char c) {
bool result = c == '{' || c == '}';
return result;
}
API bool IsParen(char c) {
bool result = c == '(' || c == ')';
return result;
}
API String Chop(String a, int64_t len) {
len = ClampTop(len, a.len);
String result = {a.data, a.len - len};
return result;
}
API String Skip(String a, int64_t len) {
len = ClampTop(len, a.len);
String result = {a.data + len, a.len - len};
return result;
}
API String GetPostfix(String a, int64_t len) {
len = ClampTop(len, a.len);
int64_t remain_len = a.len - len;
String result = {a.data + remain_len, len};
return result;
}
API String GetPrefix(String a, int64_t len) {
len = ClampTop(len, a.len);
String result = {a.data, len};
return result;
}
API char At(String a, int64_t idx) {
if (idx < a.len) {
return a.data[idx];
}
return 0;
}
API String GetSlice(String arr, int64_t first_index, int64_t one_past_last_index) {
// Negative indexes work in python style, they return you the index counting from end of list
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
if (first_index == SLICE_LAST) first_index = arr.len;
if (first_index < 0) first_index = arr.len + first_index;
String result = {arr.data, arr.len};
if (arr.len > 0) {
if (one_past_last_index > first_index) {
first_index = ClampTop(first_index, arr.len - 1);
one_past_last_index = ClampTop(one_past_last_index, arr.len);
result.data += first_index;
result.len = one_past_last_index - first_index;
} else {
result.len = 0;
}
}
return result;
}
API bool AreEqual(String a, String b, unsigned ignore_case) {
if (a.len != b.len) return false;
for (int64_t i = 0; i < a.len; i++) {
char A = a.data[i];
char B = b.data[i];
if (ignore_case) {
A = ToLowerCase(A);
B = ToLowerCase(B);
}
if (A != B)
return false;
}
return true;
}
API bool EndsWith(String a, String end, unsigned ignore_case) {
String a_end = GetPostfix(a, end.len);
bool result = AreEqual(end, a_end, ignore_case);
return result;
}
API bool StartsWith(String a, String start, unsigned ignore_case) {
String a_start = GetPrefix(a, start.len);
bool result = AreEqual(start, a_start, ignore_case);
return result;
}
API String Trim(String string) {
if (string.len == 0)
return string;
int64_t whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!IsWhitespace(string.data[whitespace_begin])) {
break;
}
}
int64_t whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!IsWhitespace(string.data[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
} else {
string = GetSlice(string, whitespace_begin, whitespace_end);
}
return string;
}
API String TrimEnd(String string) {
int64_t whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!IsWhitespace(string.data[whitespace_end - 1])) {
break;
}
}
String result = GetPrefix(string, whitespace_end);
return result;
}
API String Copy(Allocator allocator, String string) {
char *copy = (char *)AllocSize(allocator, sizeof(char) * (string.len + 1));
memcpy(copy, string.data, string.len);
copy[string.len] = 0;
String result = {copy, string.len};
return result;
}
API String Copy(Allocator allocator, char *string) {
return Copy(allocator, {string, (int64_t)strlen(string)});
}
API void NormalizePathInPlace(String s) {
for (int64_t i = 0; i < s.len; i++) {
if (s.data[i] == '\\')
s.data[i] = '/';
}
}
API String NormalizePath(Allocator allocator, String s) {
String copy = Copy(allocator, s);
NormalizePathInPlace(copy);
return copy;
}
API bool Seek(String string, String find, int64_t *index_out, SeekFlag flags) {
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
bool result = false;
if (flags & SeekFlag_MatchFindLast) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
String substring = GetSlice(string, index, index + find.len);
if (AreEqual(substring, find, ignore_case)) {
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String left = GetSlice(string, i - 1, i);
String right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = index;
}
result = true;
break;
}
}
}
} else {
for (int64_t i = 0; i < string.len; i++) {
String substring = GetSlice(string, i, i + find.len);
if (AreEqual(substring, find, ignore_case)) {
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String left = GetSlice(string, i - 1, i);
String right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = i;
}
result = true;
break;
}
}
}
}
return result;
}
API String CutLastSlash(String *s) {
String result = *s;
Seek(*s, "/", &s->len, SeekFlag_MatchFindLast);
result = Skip(result, s->len);
return result;
}
API String ChopLastSlash(String s) {
String result = s;
Seek(s, "/", &result.len, SeekFlag_MatchFindLast);
return result;
}
API String ChopLastPeriod(String s) {
String result = s;
Seek(s, ".", &result.len, SeekFlag_MatchFindLast);
return result;
}
API String SkipToLastSlash(String s) {
int64_t pos;
String result = s;
if (Seek(s, "/", &pos, SeekFlag_MatchFindLast)) {
result = Skip(result, pos + 1);
}
return result;
}
API String SkipToLastPeriod(String s) {
int64_t pos;
String result = s;
if (Seek(s, ".", &pos, SeekFlag_MatchFindLast)) {
result = Skip(result, pos + 1);
}
return result;
}
API String CutPrefix(String *string, int64_t len) {
String result = GetPrefix(*string, len);
*string = Skip(*string, len);
return result;
}
API String CutPostfix(String *string, int64_t len) {
String result = GetPostfix(*string, len);
*string = Chop(*string, len);
return result;
}
API String FormatV(Allocator allocator, const char *data, va_list args1) {
va_list args2;
va_copy(args2, args1);
int64_t len = stbsp_vsnprintf(0, 0, data, args2);
va_end(args2);
char *result = (char *)AllocSize(allocator, sizeof(char) * (len + 1));
stbsp_vsnprintf(result, (int)(len + 1), data, args1);
String res = {result, len};
return res;
}
API String Format(Allocator allocator, const char *data, ...) {
STRING_FORMAT(allocator, data, result);
return result;
}
API Array<String> Split(Allocator allocator, String string, String delimiter) {
Array<String> result = {allocator};
int64_t index = 0;
while (Seek(string, delimiter, &index)) {
String before_match = {string.data, index};
Add(&result, before_match);
string = Skip(string, index + delimiter.len);
}
Add(&result, string);
return result;
}
API Array<String> SplitWhitespace(Allocator allocator, String string) {
Array<String> result = {allocator};
String it = {string.data, 0};
for (int64_t i = 0; i < string.len; i += 1) {
if (IsWhitespace(string[i])) {
if (it.len) Add(&result, it);
it.len = 0;
it.data = string.data + (i + 1);
} else {
it.len += 1;
}
}
if (it.len) Add(&result, it);
return result;
}
API String Merge(Allocator allocator, Array<String> list, String separator) {
int64_t char_count = 0;
For(list) char_count += it.len;
if (char_count == 0) return {};
int64_t node_count = list.len;
int64_t base_size = (char_count + 1);
int64_t sep_size = (node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char *buff = (char *)AllocSize(allocator, sizeof(char) * (size + 1));
String string = {buff, 0};
For(list) {
Assert(string.len + it.len <= size);
memcpy(string.data + string.len, it.data, it.len);
string.len += it.len;
if (!IsLast(list, it)) {
memcpy(string.data + string.len, separator.data, separator.len);
string.len += separator.len;
}
}
Assert(string.len == size - 1);
string.data[size] = 0;
return string;
}
API Int GetSize(Array<String> array) {
Int result = 0;
For (array) result += it.len;
return result;
}
API bool Chop(String *string, String ending) {
if (EndsWith(*string, ending)) {
*string = Chop(*string, ending.len);
return true;
}
return false;
}
API String SkipIntEx(String *string) {
String col = {string->data, 0};
for (int64_t i = 0; i < string->len; i += 1) {
if (IsDigit(string->data[i])) {
col.len += 1;
} else {
break;
}
}
*string = Skip(*string, col.len);
return col;
}
API Int SkipInt(String *string) {
String col = SkipIntEx(string);
if (col.len == 0) return -1;
Int result = strtoll(col.data, NULL, 10);
return result;
}
API String SkipUntil(String *string, String str) {
String begin = *string;
begin.len = 0;
for (; string->len; begin.len += 1) {
String match = GetPrefix(*string, str.len);
if (StartsWith(match, str)) break;
*string = Skip(*string, 1);
}
return begin;
}
API String SkipWhitespace(String *string) {
String begin = {string->data, 0};
for (;string->len;) {
if (!IsWhitespace(At(*string, 0))) {
break;
}
*string = Skip(*string, 1);
begin.len += 1;
}
return begin;
}
API String ChopNumberEx(String *string) {
String col = {};
for (int64_t i = string->len - 1; i >= 0; i -= 1) {
if (IsDigit(string->data[i])) {
col.data = string->data + i;
col.len += 1;
} else {
break;
}
}
*string = Chop(*string, col.len);
return col;
}
API Int ChopNumber(String *string) {
Scratch scratch;
String col = ChopNumberEx(string);
if (col.len == 0) return -1;
Int result = strtoll(col.data, NULL, 10) - 1;
return result;
}
String SkipIdent(String *string) {
String begin = {string->data, 0};
if (IsIdent(At(*string, 0))) {
for (;string->len;) {
char c = At(*string, 0);
if (!IsIdent(c) && !IsDigit(c)) {
break;
}
*string = Skip(*string, 1);
begin.len += 1;
}
}
return begin;
}
String SkipString(String *string) {
String saved_string = *string;
char c = At(*string, 0);
String q = {&c, 1};
if (c == '"' || c == '\'') {
*string = Skip(*string, 1);
String quote = SkipUntil(string, q);
if (At(*string, 0) != c) {
*string = saved_string;
return {};
}
return quote;
}
return {};
}
API String SkipFloatEx(String *string) {
String col = {string->data, 0};
if (At(*string, 0) == '-') {
col.len += 1;
*string = Skip(*string, 1);
}
for (int64_t i = 0; i < string->len; i += 1) {
if (IsDigit(string->data[i]) || string->data[i] == u'.') {
col.len += 1;
} else {
break;
}
}
*string = Skip(*string, col.len);
return col;
}
API Float SkipFloat(String *string) {
String col = SkipFloatEx(string);
if (col.len == 0) return 0;
Float result = strtod(string->data, NULL);
return result;
}
+106
View File
@@ -0,0 +1,106 @@
#pragma once
struct String {
char *data;
int64_t len;
String() = default;
String(char *s) : data(s), len(strlen(s)) {}
String(char *s, int64_t l) : data((char *)s), len(l) {}
String(const char *s) : data((char *)s), len(strlen((char *)s)) {}
String(const char *s, int64_t l) : data((char *)s), len(l) {}
char &operator[](int64_t index) {
Assert(index < len);
return data[index];
}
char *begin() { return data; }
char *end() { return data + len; }
struct ReverseIter {
char *data;
String *arr;
ReverseIter operator++(int) {
ReverseIter ret = *this;
data -= 1;
return ret;
}
ReverseIter &operator++() {
data -= 1;
return *this;
}
char &operator*() { return data[0]; }
char *operator->() { return data; }
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
};
ReverseIter reverse() { return {this->end() - 1, this}; }
};
API char ToLowerCase(char a);
API char ToUpperCase(char a);
API bool IsWhitespace(char w);
API bool IsAlphabetic(char a);
API bool IsIdent(char a);
API bool IsDigit(char a);
API bool IsAlphanumeric(char a);
API bool IsSymbol(char w);
API bool IsNonWord(char w);
API bool IsWord(char w);
API bool IsBrace(char c);
API bool IsParen(char c);
API bool EndsWith(String a, String end, unsigned ignore_case = false);
API bool StartsWith(String a, String start, unsigned ignore_case = false);
API bool AreEqual(String a, String b, unsigned ignore_case = false);
inline bool operator==(String a, String b) { return AreEqual(a, b); }
inline bool operator!=(String a, String b) { return !AreEqual(a, b); }
API String Trim(String string);
API String TrimEnd(String string);
API String Chop(String a, int64_t len);
API String Skip(String a, int64_t len);
API String GetPostfix(String a, int64_t len);
API String GetPrefix(String a, int64_t len);
API String GetSlice(String arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST);
API String CutLastSlash(String *s);
API String ChopLastSlash(String s);
API String ChopLastPeriod(String s);
API String SkipToLastSlash(String s);
API String SkipToLastPeriod(String s);
API String CutPrefix(String *string, int64_t len);
API String CutPostfix(String *string, int64_t len);
API String Copy(Allocator allocator, String string);
API String Copy(Allocator allocator, char *string);
API void NormalizePathInPlace(String s);
API String NormalizePath(Allocator allocator, String s);
API String FormatV(Allocator allocator, const char *data, va_list args1);
API String Format(Allocator allocator, const char *data, ...);
#define STRING_FORMAT(allocator, data, result) \
va_list args1; \
va_start(args1, data); \
String result = FormatV(allocator, data, args1); \
va_end(args1)
typedef int SeekFlag;
enum {
SeekFlag_None = 0,
SeekFlag_IgnoreCase = 1,
SeekFlag_MatchFindLast = 2,
SeekFlag_WordBoundary = 4,
};
API bool Seek(String string, String find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);
API Array<String> Split(Allocator allocator, String string, String delimiter = " ");
API String Merge(Allocator allocator, Array<String> list, String separator);
API Int GetSize(Array<String> array);
+547
View File
@@ -0,0 +1,547 @@
#include <stdlib.h>
API int64_t WideLength(char16_t *string) {
if (!string) return 0;
int64_t len = 0;
while (*string++ != 0)
len++;
return len;
}
API char16_t ToLowerCase(char16_t a) {
if (a >= u'A' && a <= u'Z') a += 32;
return a;
}
API char16_t ToUpperCase(char16_t a) {
if (a >= u'a' && a <= u'z') a -= 32;
return a;
}
API bool IsWhitespace(char16_t w) {
bool result = w == u'\n' || w == u' ' || w == u'\t' || w == u'\v' || w == u'\r';
return result;
}
API bool IsAlphabetic(char16_t a) {
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z');
return result;
}
API bool IsIdent(char16_t a) {
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z') || a == u'_';
return result;
}
API bool IsDigit(char16_t a) {
bool result = a >= u'0' && a <= u'9';
return result;
}
API bool IsHexDigit(char16_t a) {
bool result = a >= u'0' && a <= u'9' || a == 'a' || a == 'b' || a == 'c' || a == 'd' || a == 'e' || a == 'f';
return result;
}
API bool IsAlphanumeric(char16_t a) {
bool result = IsDigit(a) || IsAlphabetic(a);
return result;
}
API bool IsSymbol(char16_t w) {
bool result = (w >= u'!' && w <= u'/') || (w >= u':' && w <= u'@') || (w >= u'[' && w <= u'`') || (w >= u'{' && w <= u'~');
return result;
}
API bool IsNonWord(char16_t w) {
if (w == u'_') return false;
bool result = IsSymbol(w) || IsWhitespace(w);
return result;
}
API bool IsWord(char16_t w) {
bool result = !IsNonWord(w);
return result;
}
API bool IsBrace(char16_t c) {
bool result = c == u'{' || c == u'}';
return result;
}
API bool IsParen(char16_t c) {
bool result = c == u'(' || c == u')';
return result;
}
API String16 Chop(String16 a, int64_t len) {
len = ClampTop(len, a.len);
String16 result = {a.data, a.len - len};
return result;
}
API String16 Skip(String16 a, int64_t len) {
len = ClampTop(len, a.len);
String16 result = {a.data + len, a.len - len};
return result;
}
API String16 GetPostfix(String16 a, int64_t len) {
len = ClampTop(len, a.len);
int64_t remain_len = a.len - len;
String16 result = {a.data + remain_len, len};
return result;
}
API String16 GetPrefix(String16 a, int64_t len) {
len = ClampTop(len, a.len);
String16 result = {a.data, len};
return result;
}
API char16_t At(String16 a, int64_t idx) {
if (idx < a.len) {
return a.data[idx];
}
return 0;
}
API String16 GetSlice(String16 arr, int64_t first_index, int64_t one_past_last_index) {
// Negative indexes work in python style, they return you the index counting from end of list
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
if (first_index == SLICE_LAST) first_index = arr.len;
if (first_index < 0) first_index = arr.len + first_index;
String16 result = {arr.data, arr.len};
if (arr.len > 0) {
if (one_past_last_index > first_index) {
first_index = ClampTop(first_index, arr.len - 1);
one_past_last_index = ClampTop(one_past_last_index, arr.len);
result.data += first_index;
result.len = one_past_last_index - first_index;
} else {
result.len = 0;
}
}
return result;
}
API bool AreEqual(String16 a, String16 b, unsigned ignore_case) {
if (a.len != b.len) return false;
for (int64_t i = 0; i < a.len; i++) {
char16_t A = a.data[i];
char16_t B = b.data[i];
if (ignore_case) {
A = ToLowerCase(A);
B = ToLowerCase(B);
}
if (A != B)
return false;
}
return true;
}
API bool EndsWith(String16 a, String16 end, unsigned ignore_case) {
String16 a_end = GetPostfix(a, end.len);
bool result = AreEqual(end, a_end, ignore_case);
return result;
}
API bool StartsWith(String16 a, String16 start, unsigned ignore_case) {
String16 a_start = GetPrefix(a, start.len);
bool result = AreEqual(start, a_start, ignore_case);
return result;
}
API String16 Trim(String16 string) {
if (string.len == 0)
return string;
int64_t whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!IsWhitespace(string.data[whitespace_begin])) {
break;
}
}
int64_t whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!IsWhitespace(string.data[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
} else {
string = GetSlice(string, whitespace_begin, whitespace_end);
}
return string;
}
API String16 TrimEnd(String16 string) {
int64_t whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!IsWhitespace(string.data[whitespace_end - 1])) {
break;
}
}
String16 result = GetPrefix(string, whitespace_end);
return result;
}
API String16 Copy16(Allocator allocator, String16 string) {
char16_t *copy = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (string.len + 1));
memcpy(copy, string.data, string.len * sizeof(char16_t));
copy[string.len] = 0;
String16 result = {copy, string.len};
return result;
}
API String16 Copy16(Allocator allocator, char16_t *string) {
return Copy16(allocator, {string, (int64_t)WideLength(string)});
}
API void NormalizePathInPlace(String16 s) {
for (int64_t i = 0; i < s.len; i++) {
if (s.data[i] == u'\\')
s.data[i] = u'/';
}
}
API String16 NormalizePath(Allocator allocator, String16 s) {
String16 copy = Copy16(allocator, s);
NormalizePathInPlace(copy);
return copy;
}
API bool Seek(String16 string, String16 find, int64_t *index_out, SeekFlag flags) {
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
bool result = false;
if (flags & SeekFlag_MatchFindLast) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
String16 substring = GetSlice(string, index, index + find.len);
if (AreEqual(substring, find, ignore_case)) {
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String16 left = GetSlice(string, i - 1, i);
String16 right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = index;
}
result = true;
break;
}
}
}
} else {
for (int64_t i = 0; i < string.len; i++) {
String16 substring = GetSlice(string, i, i + find.len);
if (AreEqual(substring, find, ignore_case)) {
bool ok_boundary = true;
if (flags & SeekFlag_WordBoundary) {
String16 left = GetSlice(string, i - 1, i);
String16 right = GetSlice(string, i + find.len, i + find.len + 1);
if (left.len != 0 && !IsNonWord(left.data[0])) {
ok_boundary = false;
}
if (right.len != 0 && !IsNonWord(right.data[0])) {
ok_boundary = false;
}
}
if (ok_boundary) {
if (index_out) {
*index_out = i;
}
result = true;
break;
}
}
}
}
return result;
}
API String16 CutLastSlash(String16 *s) {
String16 result = *s;
Seek(*s, u"/", &s->len, SeekFlag_MatchFindLast);
result = Skip(result, s->len);
return result;
}
API String16 ChopLastSlash(String16 s) {
String16 result = s;
Seek(s, u"/", &result.len, SeekFlag_MatchFindLast);
return result;
}
API String16 ChopLastPeriod(String16 s) {
String16 result = s;
Seek(s, u".", &result.len, SeekFlag_MatchFindLast);
return result;
}
API String16 SkipToLastSlash(String16 s) {
int64_t pos;
String16 result = s;
if (Seek(s, u"/", &pos, SeekFlag_MatchFindLast)) {
result = Skip(result, pos + 1);
}
return result;
}
API String16 SkipToLastPeriod(String16 s) {
int64_t pos;
String16 result = s;
if (Seek(s, u".", &pos, SeekFlag_MatchFindLast)) {
result = Skip(result, pos + 1);
}
return result;
}
API String16 CutPrefix(String16 *string, int64_t len) {
String16 result = GetPrefix(*string, len);
*string = Skip(*string, len);
return result;
}
API String16 CutPostfix(String16 *string, int64_t len) {
String16 result = GetPostfix(*string, len);
*string = Chop(*string, len);
return result;
}
API String16 Format16V(Allocator allocator, const char *data, va_list args1) {
Scratch scratch(allocator);
va_list args2;
va_copy(args2, args1);
int64_t len = stbsp_vsnprintf(0, 0, data, args2);
va_end(args2);
char *result = (char *)AllocSize(scratch, sizeof(char) * (len + 1));
stbsp_vsnprintf(result, (int)(len + 1), data, args1);
String res = {result, len};
String16 res16 = ToString16(allocator, res);
return res16;
}
API String16 Format16(Allocator allocator, const char *data, ...) {
Scratch scratch(allocator);
STRING_FORMAT(scratch, data, result);
String16 result16 = ToString16(allocator, result);
return result16;
}
API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter) {
Array<String16> result = {allocator};
int64_t index = 0;
while (Seek(string, delimiter, &index)) {
String16 before_match = {string.data, index};
Add(&result, before_match);
string = Skip(string, index + delimiter.len);
}
Add(&result, string);
return result;
}
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator) {
int64_t char_count = 0;
For(list) char_count += it.len;
if (char_count == 0) return {};
int64_t node_count = list.len;
int64_t base_size = (char_count + 1);
int64_t sep_size = (node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char16_t *buff = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (size + 1));
String16 string = {buff, 0};
For(list) {
Assert(string.len + it.len <= size);
memcpy(string.data + string.len, it.data, it.len * sizeof(char16_t));
string.len += it.len;
if (!IsLast(list, it)) {
memcpy(string.data + string.len, separator.data, separator.len * sizeof(char16_t));
string.len += separator.len;
}
}
Assert(string.len == size - 1);
string.data[size] = 0;
return string;
}
API Int GetSize(Array<String16> array) {
Int result = 0;
For (array) result += it.len;
return result;
}
API String16 SkipIntEx(String16 *string) {
String16 col = {string->data, 0};
if (At(*string, 0) == '-') {
col.len += 1;
*string = Skip(*string, 1);
}
for (int64_t i = 0; i < string->len; i += 1) {
if (IsDigit(string->data[i])) {
col.len += 1;
} else {
break;
}
}
*string = Skip(*string, col.len);
return col;
}
API Int SkipInt(String16 *string) {
String16 col = SkipIntEx(string);
if (col.len == 0) return 0;
Scratch scratch;
String num_string = ToString(scratch, col);
Int result = strtoll(num_string.data, NULL, 10);
return result;
}
API String16 SkipFloatEx(String16 *string) {
String16 col = {string->data, 0};
if (At(*string, 0) == '-') {
col.len += 1;
*string = Skip(*string, 1);
}
for (int64_t i = 0; i < string->len; i += 1) {
if (IsDigit(string->data[i]) || string->data[i] == u'.') {
col.len += 1;
} else {
break;
}
}
*string = Skip(*string, col.len);
return col;
}
API Float SkipFloat(String16 *string) {
String16 col = SkipFloatEx(string);
if (col.len == 0) return 0;
Scratch scratch;
String num_string = ToString(scratch, col);
Float result = strtod(num_string.data, NULL);
return result;
}
API String16 SkipUntil(String16 *string, String16 str) {
String16 begin = *string;
begin.len = 0;
for (; string->len; begin.len += 1) {
String16 match = GetPrefix(*string, str.len);
if (StartsWith(match, str)) break;
*string = Skip(*string, 1);
}
return begin;
}
API String16 SkipWhitespace(String16 *string) {
String16 begin = {string->data, 0};
for (;string->len;) {
if (!IsWhitespace(At(*string, 0))) {
break;
}
*string = Skip(*string, 1);
begin.len += 1;
}
return begin;
}
String16 SkipIdent(String16 *string) {
String16 begin = {string->data, 0};
if (IsIdent(At(*string, 0))) {
for (;string->len;) {
char16_t c = At(*string, 0);
if (!IsIdent(c) && !IsDigit(c)) {
break;
}
*string = Skip(*string, 1);
begin.len += 1;
}
}
return begin;
}
String16 SkipString(String16 *string) {
String16 saved_string = *string;
char16_t c = At(*string, 0);
String16 q = {&c, 1};
if (c == u'"' || c == u'\'') {
*string = Skip(*string, 1);
String16 quote = SkipUntil(string, q);
if (At(*string, 0) != c) {
*string = saved_string;
return {};
}
return quote;
}
return {};
}
bool MatchIdent(String16 *string, String16 expect) {
String16 copy = *string;
String16 ident = SkipIdent(&copy);
if (ident == expect) {
*string = copy;
return true;
}
return false;
}
API bool Chop(String16 *string, String16 ending) {
if (EndsWith(*string, ending)) {
*string = Chop(*string, ending.len);
return true;
}
return false;
}
// chop this - 324
API String16 ChopNumberEx(String16 *string) {
String16 col = {};
for (int64_t i = string->len - 1; i >= 0; i -= 1) {
if (IsDigit(string->data[i])) {
col.data = string->data + i;
col.len += 1;
} else {
break;
}
}
*string = Chop(*string, col.len);
return col;
}
API Int ChopNumber(String16 *string) {
Scratch scratch;
String16 col = ChopNumberEx(string);
if (col.len == 0) return -1;
String num_string = ToString(scratch, col);
Int result = strtoll(num_string.data, NULL, 10) - 1;
return result;
}
API String16 Concat(Allocator allocator, String16 a, String16 b) {
char16_t *p = AllocArray(allocator, char16_t, a.len + b.len + 1);
MemoryCopy(p, a.data, sizeof(char16_t) * a.len);
MemoryCopy(p + a.len, b.data, sizeof(char16_t) * b.len);
String16 result = {p, a.len + b.len};
result.data[result.len] = 0;
return result;
}
+104
View File
@@ -0,0 +1,104 @@
#pragma once
API int64_t WideLength(char16_t *string);
struct String16 {
char16_t *data;
int64_t len;
String16() = default;
String16(char16_t *s) : data(s), len(WideLength(s)) {}
String16(char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}
String16(const char16_t *s) : data((char16_t *)s), len(WideLength((char16_t *)s)) {}
String16(const char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}
char16_t &operator[](int64_t index) {
Assert(index < len);
return data[index];
}
char16_t *begin() { return data; }
char16_t *end() { return data + len; }
struct ReverseIter {
char16_t *data;
String16 *arr;
ReverseIter operator++(int) {
ReverseIter ret = *this;
data -= 1;
return ret;
}
ReverseIter &operator++() {
data -= 1;
return *this;
}
char16_t &operator*() { return data[0]; }
char16_t *operator->() { return data; }
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
};
ReverseIter reverse() { return {this->end() - 1, this}; }
};
API char16_t ToLowerCase(char16_t a);
API char16_t ToUpperCase(char16_t a);
API bool IsWhitespace(char16_t w);
API bool IsAlphabetic(char16_t a);
API bool IsIdent(char16_t a);
API bool IsDigit(char16_t a);
API bool IsAlphanumeric(char16_t a);
API bool IsSymbol(char16_t w);
API bool IsNonWord(char16_t w);
API bool IsWord(char16_t w);
API bool IsBrace(char16_t c);
API bool IsParen(char16_t c);
API bool EndsWith(String16 a, String16 end, unsigned ignore_case = false);
API bool StartsWith(String16 a, String16 start, unsigned ignore_case = false);
API bool AreEqual(String16 a, String16 b, unsigned ignore_case = false);
inline bool operator==(String16 a, String16 b) { return AreEqual(a, b); }
inline bool operator!=(String16 a, String16 b) { return !AreEqual(a, b); }
API String16 Trim(String16 string);
API String16 TrimEnd(String16 string);
API String16 Chop(String16 a, int64_t len);
API String16 Skip(String16 a, int64_t len);
API String16 GetPostfix(String16 a, int64_t len);
API String16 GetPrefix(String16 a, int64_t len);
API String16 GetSlice(String16 arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST);
API String16 CutLastSlash(String16 *s);
API String16 ChopLastSlash(String16 s);
API String16 ChopLastPeriod(String16 s);
API String16 SkipToLastSlash(String16 s);
API String16 SkipToLastPeriod(String16 s);
API String16 CutPrefix(String16 *string, int64_t len);
API String16 CutPostfix(String16 *string, int64_t len);
// @todo: think about this API, for parsing, maybe redesign or something
API String16 SkipIntEx(String16 *string);
API Int SkipInt(String16 *string);
API String16 SkipUntil(String16 *string, String16 str);
API String16 SkipWhitespace(String16 *string);
API String16 ChopNumberEx(String16 *string);
API Int ChopNumber(String16 *string);
API String16 Copy16(Allocator allocator, String16 string);
API String16 Copy16(Allocator allocator, char16_t *string, int64_t len);
API String16 Copy16(Allocator allocator, char *string);
API void NormalizePathInPlace(String16 s);
API String16 NormalizePath(Allocator allocator, String16 s);
API String16 Format16V(Allocator allocator, const char *data, va_list args1);
API String16 Format16(Allocator allocator, const char *data, ...);
API bool Seek(String16 string, String16 find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);
API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter = u" ");
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator);
API Int GetSize(Array<String16> array);
+187
View File
@@ -0,0 +1,187 @@
/*
Hash table implementation:
Pointers to values
Open adressing
Linear Probing
Power of 2
Robin Hood hashing
Resizes on high probe count (min max load factor)
Hash 0 is reserved for empty hash table entry
*/
template <class Value>
struct HashTable {
struct Entry {
uint64_t hash;
uint64_t key;
size_t distance;
Value value;
};
Allocator allocator;
size_t len, cap;
Entry *values;
static const size_t max_load_factor = 80;
static const size_t min_load_factor = 50;
static const size_t significant_distance = 8;
// load factor calculation was rearranged
// to get rid of division:
//> 100 * len / cap = load_factor
//> len * 100 = load_factor * cap
inline bool reached_load_factor(size_t lfactor) {
return (len + 1) * 100 >= lfactor * cap;
}
inline bool is_empty(Entry *entry) { return entry->hash == 0; }
inline bool is_occupied(Entry *entry) { return entry->hash != 0; }
void reserve(size_t size) {
Assert(size > cap && "New size is smaller then original size");
Assert(IsPowerOf2(size));
if (!allocator.proc) allocator = GetSystemAllocator();
Entry *old_values = values;
size_t old_cap = cap;
values = (Entry *)AllocSize(allocator, sizeof(Entry) * size);
for (size_t i = 0; i < size; i += 1) values[i] = {};
cap = size;
Assert(!(old_values == 0 && len != 0));
if (len == 0) {
if (old_values) {
Dealloc(allocator, old_values);
}
return;
}
len = 0;
for (size_t i = 0; i < old_cap; i += 1) {
Entry *it = old_values + i;
if (is_occupied(it)) {
insert(it->key, it->value);
}
}
Dealloc(allocator, old_values);
}
Entry *get_table_entry(uint64_t key) {
if (len == 0) return 0;
uint64_t hash = HashBytes(&key, sizeof(key));
if (hash == 0) hash += 1;
uint64_t index = WrapAroundPowerOf2(hash, cap);
uint64_t i = index;
uint64_t distance = 0;
for (;;) {
Entry *it = values + i;
if (distance > it->distance) {
return 0;
}
if (it->hash == hash && it->key == key) {
return it;
}
distance += 1;
i = WrapAroundPowerOf2(i + 1, cap);
if (i == index) return 0;
}
Assert(!"Invalid codepath");
}
void insert(uint64_t key, const Value &value) {
if (reached_load_factor(max_load_factor)) {
if (cap == 0) cap = 16; // 32 cause cap*2
reserve(cap * 2);
}
uint64_t hash = HashBytes(&key, sizeof(key));
if (hash == 0) hash += 1;
uint64_t index = WrapAroundPowerOf2(hash, cap);
uint64_t i = index;
Entry to_insert = {hash, key, 0, value};
for (;;) {
Entry *it = values + i;
if (is_empty(it)) {
*it = to_insert;
len += 1;
// If we have more then 8 consecutive items we try to resize
if (to_insert.distance > 8 && reached_load_factor(min_load_factor)) {
reserve(cap * 2);
}
return;
}
if (it->hash == hash && it->key == key) {
*it = to_insert;
// If we have more then 8 consecutive items we try to resize
if (to_insert.distance > 8 && reached_load_factor(min_load_factor)) {
reserve(cap * 2);
}
return;
}
// Robin hood hashing
if (to_insert.distance > it->distance) {
Entry temp = to_insert;
to_insert = *it;
*it = temp;
}
to_insert.distance += 1;
i = WrapAroundPowerOf2(i + 1, cap);
Assert(i != index && "Did a full 360 through a hash table, no good :( that shouldnt be possible");
}
Assert(!"Invalid codepath");
}
void remove(uint64_t key) {
Entry *entry = get_table_entry(key);
entry->hash = 0;
entry->distance = 0;
len -= 1;
}
Value *get(uint64_t key) {
Entry *v = get_table_entry(key);
if (!v) return 0;
return &v->value;
}
Value get(uint64_t key, Value default_value) {
Entry *v = get_table_entry(key);
if (!v) return default_value;
return v->value;
}
Value *get(String s) {
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
return get(hash);
}
Value get(String s, Value default_value) {
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
return get(hash, default_value);
}
void put(String s, const Value &value) {
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
insert(hash, value);
}
void reset() {
len = 0;
for (size_t i = 0; i < cap; i += 1) {
Entry *it = values + i;
it->hash = 0;
}
}
void dealloc() {
Dealloc(allocator, values);
values = NULL;
len = 0;
cap = 0;
}
};
+237
View File
@@ -0,0 +1,237 @@
API UTF32Result UTF16ToUTF32(uint16_t *c, int64_t max_advance) {
UTF32Result result;
MemoryZero(&result, sizeof(result));
if (max_advance >= 1) {
result.advance = 1;
result.out_str = c[0];
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
if (max_advance >= 2) {
result.out_str = 0x10000;
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
result.advance = 2;
} else
result.error = 2;
}
} else {
result.error = 1;
}
return result;
}
API UTF8Result UTF32ToUTF8(uint32_t codepoint) {
UTF8Result result;
MemoryZero(&result, sizeof(result));
if (codepoint <= 0x7F) {
result.len = 1;
result.out_str[0] = (char)codepoint;
} else if (codepoint <= 0x7FF) {
result.len = 2;
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
result.out_str[1] = 0x80 | (0x3f & codepoint);
} else if (codepoint <= 0xFFFF) { // 16 bit word
result.len = 3;
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
} else if (codepoint <= 0x10FFFF) { // 21 bit word
result.len = 4;
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
} else {
result.error = 1;
}
return result;
}
API UTF32Result UTF8ToUTF32(uint8_t *c, int64_t max_advance) {
UTF32Result result;
MemoryZero(&result, sizeof(result));
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
if (max_advance >= 1) {
result.out_str = c[0];
result.advance = 1;
} else result.error = 1;
}
else if ((c[0] & 0xe0) == 0xc0) {
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
if (max_advance >= 2) {
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
result.advance = 2;
} else result.error = 2;
} else result.error = 2;
}
else if ((c[0] & 0xf0) == 0xe0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
if (max_advance >= 3) {
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
result.advance = 3;
} else result.error = 3;
} else result.error = 3;
}
else if ((c[0] & 0xf8) == 0xf0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
if (max_advance >= 4) {
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
result.advance = 4;
} else result.error = 4;
} else result.error = 4;
} else result.error = 4;
return result;
}
API UTF16Result UTF32ToUTF16(uint32_t codepoint) {
UTF16Result result;
MemoryZero(&result, sizeof(result));
if (codepoint < 0x10000) {
result.out_str[0] = (uint16_t)codepoint;
result.out_str[1] = 0;
result.len = 1;
} else if (codepoint <= 0x10FFFF) {
uint32_t code = (codepoint - 0x10000);
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
result.len = 2;
} else {
result.error = 1;
}
return result;
}
#define UTF__HANDLE_DECODE_ERROR(question_mark, I) \
{ \
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
i += I; \
}
API int64_t CreateCharFromWidechar(char *buffer, int64_t buffer_size, char16_t *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen && in[i];) {
UTF32Result decode = UTF16ToUTF32((uint16_t *)(in + i), (int64_t)(inlen - i));
if (!decode.error) {
i += decode.advance;
UTF8Result encode = UTF32ToUTF8(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
} else UTF__HANDLE_DECODE_ERROR('?', 0);
} else UTF__HANDLE_DECODE_ERROR('?', 1);
}
buffer[outlen] = 0;
return outlen;
}
API int64_t CreateWidecharFromChar(char16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen;) {
UTF32Result decode = UTF8ToUTF32((uint8_t *)(in + i), (int64_t)(inlen - i));
if (!decode.error) {
i += decode.advance;
UTF16Result encode = UTF32ToUTF16(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
} else UTF__HANDLE_DECODE_ERROR(0x003f, 0);
} else UTF__HANDLE_DECODE_ERROR(0x003f, 1);
}
buffer[outlen] = 0;
return outlen;
}
API bool IsValid(UTF8Iter &iter) {
return iter.item;
}
API void Advance(UTF8Iter *iter) {
iter->i += iter->utf8_codepoint_byte_size;
UTF32Result r = UTF8ToUTF32((uint8_t *)(iter->data + iter->i), iter->len - iter->i);
if (r.error) {
iter->item = 0;
return;
}
iter->utf8_codepoint_byte_size = r.advance;
iter->item = r.out_str;
}
API UTF8Iter IterateUTF8Ex(char *data, int64_t len) {
UTF8Iter result;
MemoryZero(&result, sizeof(result));
result.data = data;
result.len = len;
if (len) Advance(&result);
return result;
}
API UTF8Iter IterateUTF8(char *data) {
int64_t length = 0;
while (data[length]) length += 1;
return IterateUTF8Ex(data, length);
}
API UTF8Iter IterateUTF8(String string) {
return IterateUTF8Ex(string.data, string.len);
}
API bool IsUTF8ContinuationByte(char c) {
char result = (c & 0b11000000) == 0b10000000;
return result;
}
API String16 ToString16(Allocator allocator, String string) {
char16_t *buffer = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (string.len + 1));
int64_t size = CreateWidecharFromChar(buffer, string.len + 1, string.data, string.len);
String16 result = {buffer, size};
return result;
}
API String16 ToString16(Allocator allocator, char *in_string) {
String string(in_string);
String16 result = ToString16(allocator, string);
return result;
}
API char16_t *ToWidechar(Allocator allocator, String string) {
String16 result = ToString16(allocator, string);
return result.data;
}
API String ToString(Allocator allocator, String16 string) {
Assert(sizeof(char16_t) == 2);
int64_t buffer_size = (string.len + 1) * 2;
char *buffer = (char *)AllocSize(allocator, buffer_size);
int64_t size = CreateCharFromWidechar(buffer, buffer_size, string.data, string.len);
String result = {buffer, size};
Assert(size < buffer_size);
return result;
}
API String ToString(Allocator allocator, char16_t *string, int64_t len) {
return ToString(allocator, {string, len});
}
API String ToString(Allocator allocator, char16_t *wstring) {
int64_t size = WideLength(wstring);
String result = ToString(allocator, {wstring, size});
return result;
}
+60
View File
@@ -0,0 +1,60 @@
#pragma once
struct UTF32Result {
uint32_t out_str;
int64_t advance;
int64_t error;
};
struct UTF8Result {
uint8_t out_str[4];
int64_t len;
int64_t error;
};
struct UTF16Result {
uint16_t out_str[2];
int64_t len;
int64_t error;
};
struct UTF8Iter {
char *data;
int64_t len;
int64_t utf8_codepoint_byte_size;
int64_t i;
uint32_t item;
UTF8Iter &operator++() {
void Advance(UTF8Iter * iter);
Advance(this);
return *this;
}
friend bool operator!=(const UTF8Iter &a, const UTF8Iter &b) { return a.item != b.item; }
UTF8Iter &operator*() { return *this; }
UTF8Iter begin() {
UTF8Iter IterateUTF8Ex(char *data, int64_t len);
return {IterateUTF8Ex(data, len)};
}
UTF8Iter end() { return {}; }
};
API UTF32Result UTF16ToUTF32(uint16_t *c, int64_t max_advance);
API UTF8Result UTF32ToUTF8(uint32_t codepoint);
API UTF32Result UTF8ToUTF32(uint8_t *c, int64_t max_advance);
API UTF16Result UTF32ToUTF16(uint32_t codepoint);
API int64_t CreateCharFromWidechar(char *buffer, int64_t buffer_size, char16_t *in, int64_t inlen);
API int64_t CreateWidecharFromChar(char16_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
API char16_t *ToWidechar(Allocator allocator, String string);
API String16 ToString16(Allocator allocator, String string);
API String ToString(Allocator allocator, String16 string);
API String ToString(Allocator allocator, char16_t *string, int64_t len);
API String ToString(Allocator allocator, char16_t *wstring);
API bool IsValid(UTF8Iter &iter);
API void Advance(UTF8Iter *iter);
API UTF8Iter IterateUTF8Ex(char *data, int64_t len);
API UTF8Iter IterateUTF8(char *data);
API UTF8Iter IterateUTF8(String string);
API bool IsUTF8ContinuationByte(char c);
+186
View File
@@ -0,0 +1,186 @@
Vec2 GetSize(Rect2 r) {
Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Vec2 GetSizeF(Rect2I r) {
Vec2 result = {(float)(r.max.x - r.min.x), (float)(r.max.y - r.min.y)};
return result;
}
Vec2 ToVec2(Vec2I v) { return {(float)v.x, (float)v.y}; }
Vec2I ToVec2I(Vec2 v) { return {(Int)v.x, (Int)v.y}; }
Rect2I ToRect2I(Rect2 r) { return {ToVec2I(r.min), ToVec2I(r.max)}; }
Rect2 ToRect2(Rect2I r) { return {ToVec2(r.min), ToVec2(r.max)}; }
// clang-format off
Rect2 operator-(Rect2 r, Rect2 value) { return { {r.min.x - value.min.x, r.min.y - value.min.y}, {r.max.x - value.max.x, r.max.y - value.max.y} }; }
Rect2 operator+(Rect2 r, Rect2 value) { return { {r.min.x + value.min.x, r.min.y + value.min.y}, {r.max.x + value.max.x, r.max.y + value.max.y} }; }
Rect2 operator*(Rect2 r, Rect2 value) { return { {r.min.x * value.min.x, r.min.y * value.min.y}, {r.max.x * value.max.x, r.max.y * value.max.y} }; }
Rect2 operator/(Rect2 r, Rect2 value) { return { {r.min.x / value.min.x, r.min.y / value.min.y}, {r.max.x / value.max.x, r.max.y / value.max.y} }; }
Rect2 operator-(Rect2 r, Vec2 value) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
Rect2 operator+(Rect2 r, Vec2 value) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
Rect2 operator*(Rect2 r, Vec2 value) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
Rect2 operator/(Rect2 r, Vec2 value) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
Rect2 operator-(Vec2 value, Rect2 r) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
Rect2 operator+(Vec2 value, Rect2 r) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
Rect2 operator*(Vec2 value, Rect2 r) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
Rect2 operator/(Vec2 value, Rect2 r) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
Rect2 operator-(Rect2 r, float value) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
Rect2 operator+(Rect2 r, float value) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
Rect2 operator*(Rect2 r, float value) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
Rect2 operator/(Rect2 r, float value) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
Rect2 operator-(float value, Rect2 r) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
Rect2 operator+(float value, Rect2 r) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
Rect2 operator*(float value, Rect2 r) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
Rect2 operator/(float value, Rect2 r) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
Rect2 operator-=(Rect2 &r, Rect2 value) { r = r - value; return r; }
Rect2 operator+=(Rect2 &r, Rect2 value) { r = r + value; return r; }
Rect2 operator*=(Rect2 &r, Rect2 value) { r = r * value; return r; }
Rect2 operator/=(Rect2 &r, Rect2 value) { r = r / value; return r; }
Rect2 operator-=(Rect2 &r, Vec2 value) { r = r - value; return r; }
Rect2 operator+=(Rect2 &r, Vec2 value) { r = r + value; return r; }
Rect2 operator*=(Rect2 &r, Vec2 value) { r = r * value; return r; }
Rect2 operator/=(Rect2 &r, Vec2 value) { r = r / value; return r; }
Rect2 operator-=(Rect2 &r, float value) { r = r - value; return r; }
Rect2 operator+=(Rect2 &r, float value) { r = r + value; return r; }
Rect2 operator*=(Rect2 &r, float value) { r = r * value; return r; }
Rect2 operator/=(Rect2 &r, float value) { r = r / value; return r; }
bool operator==(Rect2 a, Rect2 b) {
bool result = a.min.x == b.min.x && a.min.y == b.min.y && a.max.x == b.max.x && a.max.y == b.max.y;
return result;
}
bool operator!=(Rect2 a, Rect2 b) {
bool result = !(a == b);
return result;
}
Vec2 operator-(Vec2 a, Vec2 b) { return {a.x - b.x, a.y - b.y}; }
Vec2 operator+(Vec2 a, Vec2 b) { return {a.x + b.x, a.y + b.y}; }
Vec2 operator*(Vec2 a, Vec2 b) { return {a.x * b.x, a.y * b.y}; }
Vec2 operator/(Vec2 a, Vec2 b) { return {a.x / b.x, a.y / b.y}; }
Vec2 operator-(Vec2 a, float b) { return {a.x - b, a.y - b}; }
Vec2 operator+(Vec2 a, float b) { return {a.x + b, a.y + b}; }
Vec2 operator*(Vec2 a, float b) { return {a.x * b, a.y * b}; }
Vec2 operator/(Vec2 a, float b) { return {a.x / b, a.y / b}; }
Vec2 operator-(float b, Vec2 a) { return {a.x - b, a.y - b}; }
Vec2 operator+(float b, Vec2 a) { return {a.x + b, a.y + b}; }
Vec2 operator*(float b, Vec2 a) { return {a.x * b, a.y * b}; }
Vec2 operator/(float b, Vec2 a) { return {a.x / b, a.y / b}; }
Vec2 operator-=(Vec2 &a, Vec2 b) { a = a - b; return a; }
Vec2 operator+=(Vec2 &a, Vec2 b) { a = a + b; return a; }
Vec2 operator*=(Vec2 &a, Vec2 b) { a = a * b; return a; }
Vec2 operator/=(Vec2 &a, Vec2 b) { a = a / b; return a; }
Vec2 operator-=(Vec2 &a, float b) { a = a - b; return a; }
Vec2 operator+=(Vec2 &a, float b) { a = a + b; return a; }
Vec2 operator*=(Vec2 &a, float b) { a = a * b; return a; }
Vec2 operator/=(Vec2 &a, float b) { a = a / b; return a; }
// clang-format on
Rect2 Rect0Size(float x, float y) {
Rect2 rect = {0, 0, x, y};
return rect;
}
Rect2 Rect2FromSize(Vec2 pos, Vec2 size) {
Rect2 result = {};
result.min = pos;
result.max = pos + size;
return result;
}
Rect2 Rect2MidHalf(Vec2 mid, Vec2 half_size) {
Rect2 result = {};
result.min = mid - half_size;
result.max = mid + half_size;
return result;
}
Rect2 Shrink(Rect2 result, float v) {
result.min.x += v;
result.max.x -= v;
result.min.y += v;
result.max.y -= v;
return result;
}
Rect2 ShrinkVertical(Rect2 result, float v) {
result.min.y += v;
result.max.y -= v;
return result;
}
Rect2 ShrinkHorizontal(Rect2 result, float v) {
result.min.x += v;
result.max.x -= v;
return result;
}
Vec2 GetMid(Rect2 r) {
Vec2 size = GetSize(r);
size.x /= 2.f;
size.y /= 2.f;
Vec2 result = r.min + size;
return result;
}
Rect2 CutLeft(Rect2 *r, float value) {
float minx = r->min.x;
r->min.x = Min(r->min.x + value, r->max.x);
Rect2 result = {
{ minx, r->min.y},
{r->min.x, r->max.y}
};
return result;
}
Rect2 CutRight(Rect2 *r, float value) {
float maxx = r->max.x;
r->max.x = Max(r->min.x, r->max.x - value);
Rect2 result = {
{r->max.x, r->min.y},
{ maxx, r->max.y},
};
return result;
}
// Y is up
Rect2 CutBottom(Rect2 *r, float value) {
float maxy = r->max.y;
r->max.y = Max(r->min.y, r->max.y - value);
Rect2 result = {
{r->min.x, r->max.y},
{r->max.x, maxy},
};
return result;
}
// Y is up
Rect2 CutTop(Rect2 *r, float value) {
float miny = r->min.y;
r->min.y = Min(r->min.y + value, r->max.y);
Rect2 result = {
{r->min.x, miny},
{r->max.x, r->min.y},
};
return result;
}
float SafeDivide(float a, float b) {
if (b == 0.f) {
return 0.f;
}
return a / b;
}
bool AreOverlapping(Vec2 point, Rect2 rec) {
bool result = (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y);
return result;
}
+145
View File
@@ -0,0 +1,145 @@
Rect2I operator-(Rect2I r, Rect2I value) { return { {r.min.x - value.min.x, r.min.y - value.min.y}, {r.max.x - value.max.x, r.max.y - value.max.y} }; }
Rect2I operator+(Rect2I r, Rect2I value) { return { {r.min.x + value.min.x, r.min.y + value.min.y}, {r.max.x + value.max.x, r.max.y + value.max.y} }; }
Rect2I operator*(Rect2I r, Rect2I value) { return { {r.min.x * value.min.x, r.min.y * value.min.y}, {r.max.x * value.max.x, r.max.y * value.max.y} }; }
Rect2I operator/(Rect2I r, Rect2I value) { return { {r.min.x / value.min.x, r.min.y / value.min.y}, {r.max.x / value.max.x, r.max.y / value.max.y} }; }
Rect2I operator-(Rect2I r, Vec2I value) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
Rect2I operator+(Rect2I r, Vec2I value) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
Rect2I operator*(Rect2I r, Vec2I value) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
Rect2I operator/(Rect2I r, Vec2I value) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
Rect2I operator-(Vec2I value, Rect2I r) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
Rect2I operator+(Vec2I value, Rect2I r) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
Rect2I operator*(Vec2I value, Rect2I r) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
Rect2I operator/(Vec2I value, Rect2I r) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
Rect2I operator-(Int value, Rect2I r) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
Rect2I operator+(Int value, Rect2I r) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
Rect2I operator*(Int value, Rect2I r) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
Rect2I operator/(Int value, Rect2I r) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
Rect2I operator-(Rect2I r, Int value) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
Rect2I operator+(Rect2I r, Int value) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
Rect2I operator*(Rect2I r, Int value) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
Rect2I operator/(Rect2I r, Int value) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
Rect2I operator-=(Rect2I &r, Rect2I value) { r = r - value; return r; }
Rect2I operator+=(Rect2I &r, Rect2I value) { r = r + value; return r; }
Rect2I operator*=(Rect2I &r, Rect2I value) { r = r * value; return r; }
Rect2I operator/=(Rect2I &r, Rect2I value) { r = r / value; return r; }
Rect2I operator-=(Rect2I &r, Vec2I value) { r = r - value; return r; }
Rect2I operator+=(Rect2I &r, Vec2I value) { r = r + value; return r; }
Rect2I operator*=(Rect2I &r, Vec2I value) { r = r * value; return r; }
Rect2I operator/=(Rect2I &r, Vec2I value) { r = r / value; return r; }
Rect2I operator-=(Rect2I &r, Int value) { r = r - value; return r; }
Rect2I operator+=(Rect2I &r, Int value) { r = r + value; return r; }
Rect2I operator*=(Rect2I &r, Int value) { r = r * value; return r; }
Rect2I operator/=(Rect2I &r, Int value) { r = r / value; return r; }
Vec2I operator-(Vec2I a, Vec2I b) { return {a.x - b.x, a.y - b.y}; }
Vec2I operator+(Vec2I a, Vec2I b) { return {a.x + b.x, a.y + b.y}; }
Vec2I operator*(Vec2I a, Vec2I b) { return {a.x * b.x, a.y * b.y}; }
Vec2I operator/(Vec2I a, Vec2I b) { return {a.x / b.x, a.y / b.y}; }
Vec2I operator-(Vec2I a, Int b) { return {a.x - b, a.y - b}; }
Vec2I operator+(Vec2I a, Int b) { return {a.x + b, a.y + b}; }
Vec2I operator*(Vec2I a, Int b) { return {a.x * b, a.y * b}; }
Vec2I operator/(Vec2I a, Int b) { return {a.x / b, a.y / b}; }
Vec2I operator-(Int b, Vec2I a) { return {a.x - b, a.y - b}; }
Vec2I operator+(Int b, Vec2I a) { return {a.x + b, a.y + b}; }
Vec2I operator*(Int b, Vec2I a) { return {a.x * b, a.y * b}; }
Vec2I operator/(Int b, Vec2I a) { return {a.x / b, a.y / b}; }
Vec2I operator-=(Vec2I &a, Vec2I b) { a = a - b; return a; }
Vec2I operator+=(Vec2I &a, Vec2I b) { a = a + b; return a; }
Vec2I operator*=(Vec2I &a, Vec2I b) { a = a * b; return a; }
Vec2I operator/=(Vec2I &a, Vec2I b) { a = a / b; return a; }
Vec2I operator-=(Vec2I &a, Int b) { a = a - b; return a; }
Vec2I operator+=(Vec2I &a, Int b) { a = a + b; return a; }
Vec2I operator*=(Vec2I &a, Int b) { a = a * b; return a; }
Vec2I operator/=(Vec2I &a, Int b) { a = a / b; return a; }
Vec2I GetSize(Rect2I r) {
Vec2I result = {r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
Rect2I RectI0Size(Int x, Int y) {
Rect2I rect = {0, 0, x, y};
return rect;
}
Rect2I Rect2IFromSize(Vec2I pos, Vec2I size) {
Rect2I result = {};
result.min = pos;
result.max = pos + size;
return result;
}
Rect2I Shrink(Rect2I result, Int v) {
result.min.x += v;
result.max.x -= v;
result.min.y += v;
result.max.y -= v;
return result;
}
Vec2I GetMid(Rect2I r) {
Vec2I size = GetSize(r);
size.x /= 2;
size.y /= 2;
Vec2I result = r.min + size;
return result;
}
Rect2I CutLeft(Rect2I *r, Int value) {
Int minx = r->min.x;
r->min.x = Min(r->min.x + value, r->max.x);
Rect2I result = {
{ minx, r->min.y},
{r->min.x, r->max.y}
};
return result;
}
Rect2I CutRight(Rect2I *r, Int value) {
Int maxx = r->max.x;
r->max.x = Max(r->min.x, r->max.x - value);
Rect2I result = {
{r->max.x, r->min.y},
{ maxx, r->max.y},
};
return result;
}
// Y is up
Rect2I CutBottom(Rect2I *r, Int value) {
Int maxy = r->max.y;
r->max.y = Max(r->min.y, r->max.y - value);
Rect2I result = {
{r->min.x, r->max.y},
{r->max.x, maxy},
};
return result;
}
// Y is up
Rect2I CutTop(Rect2I *r, Int value) {
Int miny = r->min.y;
r->min.y = Min(r->min.y + value, r->max.y);
Rect2I result = {
{r->min.x, miny},
{r->max.x, r->min.y},
};
return result;
}
Int SafeDivide(Int a, Int b) {
if (b == 0) {
return 0;
}
return a / b;
}
bool AreOverlapping(Vec2I point, Rect2I rec) {
bool result = (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y);
return result;
}
File diff suppressed because it is too large Load Diff
-15
View File
@@ -1,15 +0,0 @@
#include "core_platform.c"
#include "core_intrin.c"
#include "core_unicode.c"
#include "core_math.c"
#include "core_arena.c"
#include "stb_sprintf.c"
#include "core_string.c"
#include "core_string16.c"
#include "core_log.c"
#include "core_lexer.c"
#include "core_type_info.c"
#include "core_hash_table.c"
#include "core_array.c"
#include "core_math.gen.c"
#include "core_ctx.c"
-14
View File
@@ -1,14 +0,0 @@
#include "core_basic.h"
#include "core_unicode.h"
#include "core_arena.h"
#include "core_string.h"
#include "core_string16.h"
#include "core_math.h"
#include "core_type_info.h"
#include "core_lexer.h"
#include "core_log.h"
#include "core_intrin.h"
#include "core_platform.h"
#include "core_hash_table.h"
#include "core_ctx.h"
#include "core_array.h"
-202
View File
@@ -1,202 +0,0 @@
#include "core_arena.h"
#include "core_platform.h"
#include "core_intrin.h"
#include "core_ctx.h"
#if PLATFORM_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif
#if !defined(ASAN_POISON_MEMORY_REGION)
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#else
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
#endif
fn b32 is_pow2(usize x) {
b32 result = (((x) & ((x)-1)) == 0);
return result;
}
fn usize get_align_offset(usize size, usize align) {
assert(is_pow2(align));
if (align == 0) return 0;
usize mask = align - 1;
usize val = size & mask;
if (val) {
val = align - val;
}
return val;
}
fn usize align_up(usize size, usize align) {
usize result = size + get_align_offset(size, align);
return result;
}
fn usize align_down(usize size, usize align) {
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
usize result = size - (align - get_align_offset(size, align));
return result;
}
fn void ma_init(ma_arena_t *arena, usize reserve) {
reserve = align_up(reserve, ma_page_size);
arena->align = ma_default_alignment;
arena->data = (u8 *)os_vmem_reserve(reserve);
if (arena->data) {
arena->reserve = reserve;
}
}
fn ma_arena_t *ma_create(usize reserve) {
ma_arena_t *result = NULL;
void *data = os_vmem_reserve(reserve);
if (!data) return result;
b32 success = os_vmem_commit(data, ma_page_size);
if (!success) {
os_vmem_release(data);
return result;
}
result = (ma_arena_t *)data;
result->data = (u8 *)data;
result->reserve = reserve;
result->commit = ma_page_size;
result->len = result->base_len = sizeof(ma_arena_t);
result->align = ma_default_alignment;
return result;
}
fn void *ma_push_size_ex(ma_arena_t *arena, usize size) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
assert(arena->len >= arena->base_len);
usize align_offset = 0;
if (arena->align) {
align_offset = get_align_offset((usize)arena->data + arena->len, arena->align);
}
usize size_with_alignment = size + align_offset;
usize new_len = arena->len + size_with_alignment;
if (new_len > arena->commit) {
if (arena->reserve == 0) {
ma_init(arena, ma_default_reserve_size);
}
usize new_len_aligned_to_page_size = align_up(new_len, ma_page_size);
usize to_commit = new_len_aligned_to_page_size - arena->commit;
usize to_commit_clamped = CLAMP_TOP(to_commit, arena->reserve);
if (to_commit_clamped > 0) {
b32 success = os_vmem_commit(arena->data + arena->commit, to_commit_clamped);
if (success) {
MA_ASAN_UNPOISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
arena->commit += to_commit_clamped;
}
}
if (new_len > arena->commit) {
invalid_codepath;
return NULL;
}
}
u8 *result = arena->data + arena->len + align_offset;
arena->len = new_len;
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
return (void *)result;
}
fn void *ma_push_size(ma_arena_t *arena, usize size) {
void *result = ma_push_size_ex(arena, size);
if (result) memory_zero(result, size);
return result;
}
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size) {
result->data = (u8 *)ma_push_size(allocator, size);
result->reserve = size;
result->commit = size;
result->align = ma_default_alignment;
}
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size) {
ma_arena_t *result = ma_push_type(allocator, ma_arena_t);
ma_push_arena_ex(allocator, result, size);
return result;
}
fn void ma_destroy(ma_arena_t *arena) {
if (arena == NULL || arena->data == NULL) return;
b32 zero_memory = (u8 *)arena != arena->data;
os_vmem_release(arena->data);
if (zero_memory) memory_zero(arena, sizeof(ma_arena_t));
}
fn void ma_set_len(ma_arena_t *arena, usize pos) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
assert(arena->len >= arena->base_len);
pos = CLAMP(pos, arena->base_len, arena->len);
usize size = arena->len - pos;
arena->len = pos;
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
}
fn void ma_pop(ma_arena_t *arena, usize size) { ma_set_len(arena, arena->len - size); }
fn ma_temp_t ma_begin_temp(ma_arena_t *arena) { return (ma_temp_t){arena, arena->len}; }
fn void ma_end_temp(ma_temp_t temp) { ma_set_len(temp.arena, temp.len); }
fn void ma_set0(ma_arena_t *arena) { ma_set_len(arena, 0); }
//
// Scratch arena
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count) {
ma_arena_t *unoccupied = 0;
for (int i = 0; i < lengthof(tcx->scratch); i += 1) {
ma_arena_t *from_pool = tcx->scratch + i;
unoccupied = from_pool;
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
ma_arena_t *from_conflict = conflicts[conflict_i];
if (from_pool == from_conflict) {
unoccupied = 0;
break;
}
}
if (unoccupied) {
break;
}
}
assert(unoccupied); // failed to get free scratch memory, this is a fatal error, this shouldnt happen
ma_temp_t result = ma_begin_temp(unoccupied);
return result;
}
fn ma_temp_t ma_begin_scratch(void) {
ma_temp_t result = ma_begin_temp(tcx->scratch + 0);
return result;
}
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict) {
ma_arena_t *conflicts[] = {conflict};
return ma_begin_scratch_ex(conflicts, 1);
}
fn ma_temp_t ma_begin_scratch2(ma_arena_t *a, ma_arena_t *b) {
ma_arena_t *conflicts[] = {a, b};
return ma_begin_scratch_ex(conflicts, 2);
}
fn void *ma_push__copy(ma_arena_t *arena, void *data, u64 size) {
void *result = ma_push_size_ex(arena, size);
if (result) {
memory_copy(result, data, size);
}
return result;
}
-59
View File
@@ -1,59 +0,0 @@
#pragma once
#include "core_basic.h"
static const usize ma_page_size = 4096;
static const usize ma_default_alignment = sizeof(void *);
static const usize ma_default_reserve_size = mib(256);
typedef struct ma_arena_t ma_arena_t;
struct ma_arena_t {
u8 *data;
usize len;
usize base_len; // to prevent self deleting the arena
usize reserve;
usize commit;
usize align;
};
typedef struct ma_temp_t ma_temp_t;
struct ma_temp_t {
ma_arena_t *arena;
usize len;
};
//
// constructors
fn void ma_init(ma_arena_t *arena, usize reserve);
fn ma_arena_t *ma_create(usize reserve);
fn void ma_destroy(ma_arena_t *arena);
//
// push
fn void *ma_push_size(ma_arena_t *arena, usize size);
fn void *ma_push_size_ex(ma_arena_t *arena, usize size);
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size);
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size);
#define ma_push_type(arena, Type) (Type *)ma_push_size((arena), sizeof(Type))
#define ma_push_array(arena, Type, count) (Type *)ma_push_size((arena), sizeof(Type) * (count))
#define ma_push_type_copy(ma, data) ma_push__copy((ma), (data), sizeof(*(data)))
#define ma_push_array_copy(ma, data, count) ma_push__copy((ma), (data), (count) * sizeof(*(data)))
//
// pop
fn void ma_set_len(ma_arena_t *arena, usize pos);
fn void ma_pop(ma_arena_t *arena, usize size);
fn void ma_set0(ma_arena_t *arena);
//
// temp
fn ma_temp_t ma_begin_temp(ma_arena_t *arena);
fn void ma_end_temp(ma_temp_t temp);
#define ma_temp_scope(name, InArena) for (ma_temp_t name = ma_begin_temp(InArena); name.arena; (ma_end_temp(name), name.arena = 0))
//
// scratch
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count);
fn ma_temp_t ma_begin_scratch(void);
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict);
#define ma_end_scratch(x) ma_end_temp(x)
#define ma_scratch_scope(x) for (ma_temp_t x = ma_begin_scratch(); x.arena; (ma_end_temp(x), x.arena = 0))
-122
View File
@@ -1,122 +0,0 @@
#include "core_array.h"
#include "core_basic.h"
#include "core_platform.h"
#include "core_ctx.h"
#include "core_intrin.h"
fn void array__init(alo_t alo, array_void_t *this, size_t item_size, i64 count) {
assert_expr(this->data == NULL);
this->data = alloc_size(alo, item_size * count);
this->cap = count;
this->len = 0;
this->alo = alo;
}
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size) {
dst->data = alloc_size(alo, item_size * src->cap);
memory_copy(dst->data, src->data, item_size * src->len);
dst->cap = src->cap;
dst->len = src->len;
dst->alo = alo;
}
fn void array__grow(array_void_t *this, size_t item_size, i64 item_count) {
if (this->len + 1 > this->cap) {
i64 new_cap = this->cap == 0 ? 16 : (this->cap + item_count - 1) * 2;
void *new_data = alloc_size(this->alo, new_cap * item_size);
if (this->data) {
memory_copy(new_data, this->data, this->len*item_size);
dealloc(this->alo, this->data);
}
this->data = new_data;
this->cap = new_cap;
}
}
fn void array__del(array_void_t *this, size_t item_size, i64 idx, i64 count) {
if (count == 0) return;
assert(idx >= 0 && idx < this->len);
assert((idx + count) > 0 && (idx + count) <= this->len);
i64 right_len = this->len - idx - count;
u8 *data = (u8 *)this->data;
memory_move(data + idx * item_size, data + (idx + count) * item_size, right_len * item_size);
this->len -= count;
}
fn void array__insert(array_void_t *this, size_t item_size, i64 idx) {
array__grow(this, item_size, 1);
assert(idx >= 0);
assert(idx <= this->len);
assert(this->alo.object);
u8 *data = (u8 *)this->data;
i64 right_len = this->len - idx;
memory_move(data + (idx + 1) * item_size, data + idx * item_size, item_size * right_len);
this->len += 1;
}
fn_test void test_array(void) {
ma_temp_t scratch = ma_begin_scratch();
{
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
for (int i = 0; i < 512; i += 1) {
array_add(&arr, i);
}
for (int i = 0; i < 512; i += 1) {
assert(arr.data[i] == i);
}
assert(arr.len == 512);
assert(arr.cap == 512);
for (int i = 511; i >= 0; i -= 1) {
i64 a = array_pop(&arr);
assert(a == i);
}
assert(arr.len == 0);
array_dealloc(&arr);
}
{
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
i64 *i = array_addn(&arr, 10);
assert(arr.len == 10 && arr.cap == 16);
i64 *j = array_addn(&arr, 2);
assert(i == arr.data);
assert(j == arr.data + 10);
array_dealloc(&arr);
}
{
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
for (int i = 0; i < 512; i += 1) {
array_add(&arr, i);
}
array_insert(&arr, 256, 111);
assert(arr.data[256] == 111);
assert(arr.data[255] == 255);
assert(arr.data[257] == 256);
assert(arr.len == 513);
array_insert(&arr, 4, 222);
assert(arr.len == 514);
assert(arr.data[4] == 222);
assert(arr.data[3] == 3);
assert(arr.data[5] == 4);
array_swapdel(&arr, 2);
assert(arr.len == 513);
assert(arr.data[2] == 511);
assert(arr.data[1] == 1);
assert(arr.data[3] == 3);
array_i64_t copy = {0};
array_copy(malot(scratch), &copy, &arr);
for (i64 i = 0; i < arr.len; i += 1) {
assert(arr.data[i] == copy.data[i]);
}
assert(copy.len == arr.len);
}
ma_end_scratch(scratch);
}
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include "core_basic.h"
#define array(type) struct { alo_t alo; type *data; i64 len; i64 cap; }
typedef array(void) array_void_t;
typedef array(i64) array_i64_t;
#define arrisz(x) sizeof((x)->data[0])
#define arrcst(x) ((array_void_t *)(x))
#define array_init(a, this, count) (array__init((a), arrcst(this), arrisz(this), (count)))
#define array_add(this, ...) (array__grow(arrcst(this), arrisz(this), 1), (this)->data[(this)->len++] = __VA_ARGS__)
#define array_pop(this) (assert_expr((this)->len > 0), (this)->data[--(this)->len])
#define array_dealloc(this) (dealloc((this)->alo, (this)->data))
#define array_addn(this, n) (array__grow(arrcst(this), arrisz(this), (n)), (this)->len += (n), &(this)->data[(this)->len - (n)])
#define array_insert(this, i, item) (array__insert(arrcst(this), arrisz(this), (i)), (this)->data[(i)] = (item))
#define array_swapdel(this, i) (assert_expr((i) < (this)->len), (this)->data[(i)] = (this)->data[--(this)->len])
#define array_del(this, i) (array__del(arrcst(this), arrisz(this), (i), 1))
#define array_deln(this, i, count) (array__del(arrcst(this), arrisz(this), (i), (count)))
#define array_copy(alo, dst, src) (array__copy((alo), arrcst(dst), (array_void_t *)(src), arrisz(dst)))
#define array_last(x) ((x)->data[(x)->len - 1])
#define array_for(type, it, array) for (type *it = (array)->data; it < (array)->data + (array)->len; it += 1)
fn void array__init(alo_t alo, array_void_t *, size_t item_size, i64 count);
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size);
fn void array__grow(array_void_t *, size_t item_size, i64 item_count);
fn void array__del(array_void_t *, size_t item_size, i64 idx, i64 count);
fn void array__insert(array_void_t *, size_t item_size, i64 idx);
-427
View File
@@ -1,427 +0,0 @@
#pragma once
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define PLATFORM_MAC_OS 1
#define PLATFORM_POSIX 1
#elif defined(_WIN32)
#define PLATFORM_WINDOWS 1
#elif defined(__linux__)
#define PLATFORM_POSIX 1
#define PLATFORM_LINUX 1
#elif defined(__wasm)
#define PLATFORM_WASM 1
#endif
#if defined(__clang__)
#define PLATFORM_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__)
#define PLATFORM_GCC 1
#elif defined(_MSC_VER)
#define PLATFORM_CL 1
#elif defined(__TINYC__)
#define PLATFORM_TCC 1
#endif
#if defined(__EMSCRIPTEN__)
#define PLATFORM_EMSCRIPTEN 1
#endif
#ifndef PLATFORM_EMSCRIPTEN
#define PLATFORM_EMSCRIPTEN 0
#endif
#ifndef PLATFORM_WASM
#define PLATFORM_WASM 0
#endif
#ifndef PLATFORM_WINDOWS
#define PLATFORM_WINDOWS 0
#endif
#ifndef PLATFORM_LINUX
#define PLATFORM_LINUX 0
#endif
#ifndef PLATFORM_POSIX
#define PLATFORM_POSIX 0
#endif
#ifndef PLATFORM_MAC_OS
#define PLATFORM_MAC_OS 0
#endif
#ifndef PLATFORM_CLANG
#define PLATFORM_CLANG 0
#endif
#ifndef PLATFORM_GCC
#define PLATFORM_GCC 0
#endif
#ifndef PLATFORM_CL
#define PLATFORM_CL 0
#endif
#ifndef PLATFORM_TCC
#define PLATFORM_TCC 0
#endif
#ifndef PLATFORM_ADDRESS_SANITIZER
#define PLATFORM_ADDRESS_SANITIZER 0
#endif
#ifndef PLATFORM_DEBUG_ASSERT
#define PLATFORM_DEBUG_ASSERT 1
#endif
#if PLATFORM_WINDOWS
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WINDOWS
#elif PLATFORM_WASM
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WASM
#else
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) ELSE
#endif
#if PLATFORM_CLANG
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) IF
#else
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) ELSE
#endif
#if PLATFORM_WINDOWS
#define IF_PLATFORM_WINDOWS(x) x
#else
#define IF_PLATFORM_WINDOWS(x)
#endif
#if PLATFORM_LINUX && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
typedef uintptr_t usize;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef intptr_t isize;
typedef int64_t i64;
typedef int32_t i32;
typedef int16_t i16;
typedef int8_t i8;
typedef int64_t b64;
typedef int32_t b32;
typedef int16_t b16;
typedef int8_t b8;
typedef float f32;
typedef double f64;
#define f32_max FLT_MAX
#define f32_min FLT_MIN
#define f64_max DBL_MAX
#define f64_min DBL_MIN
#define i8_max INT8_MAX
#define i8_min INT8_MIN
#define i16_max INT16_MAX
#define i16_min INT16_MIN
#define i32_max INT32_MAX
#define i32_min INT32_MIN
#define i64_max INT64_MAX
#define i64_min INT64_MIN
#define u8_max UINT8_MAX
#define u8_min 0
#define u16_max UINT16_MAX
#define u16_min 0
#define u32_max UINT32_MAX
#define u32_min 0
#define u64_max UINT64_MAX
#define u64_min 0
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define fn
#define fn_test
#define gb
#define locl static
typedef union convert_f64_u64_t convert_f64_u64_t;
union convert_f64_u64_t { f64 f; u64 i; };
typedef union convert_f64_i64_t convert_f64_i64_t;
union convert_f64_i64_t { f64 f; i64 i; };
typedef union convert_f32_u32_t convert_f32_u32_t;
union convert_f32_u32_t { f32 f; u32 i; };
typedef union convert_f32_i32_t convert_f32_i32_t;
union convert_f32_i32_t { f32 f; i32 i; };
#define U64_TO_F64(x) (((convert_f64_u64_t) { .i = (x) }).f)
#define U32_TO_F32(x) (((convert_f32_u32_t) { .i = (x) }).f)
#define F64_TO_U64(x) (((convert_f64_u64_t) { .f = (x) }).i)
#define F32_TO_U32(x) (((convert_f32_u32_t) { .f = (x) }).i)
#define I64_TO_F64(x) (((convert_f64_i64_t) { .i = (x) }).f)
#define I32_TO_F32(x) (((convert_f32_i32_t) { .i = (x) }).f)
#define F64_TO_I64(x) (((convert_f64_i64_t) { .f = (x) }).i)
#define F32_TO_I32(x) (((convert_f32_i32_t) { .f = (x) }).i)
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define CLAMP_TOP(A,X) MIN(A,X)
#define CLAMP_BOT(X,B) MAX(X,B)
#define CLAMP(x,a,b) (((x)<(a))?(a):((x)>(b))?(b):(x))
#define set_bit(x) (1ULL << (x))
#define lengthof(x) ((int)(sizeof((x))/sizeof((x)[0])))
#ifndef offsetof
#define offsetof(st, m) ((usize)&(((st *)0)->m))
#endif
#define expect(x) if (!(x))
#define unused(x) (void)(x)
#define kib(x) (1024ULL * (x##ULL))
#define mib(x) (1024ULL * kib(x))
#define gib(x) (1024ULL * mib(x))
#define thousand(n) ((n)*1000)
#define million(n) ((n)*1000000)
#define billion(n) ((n)*1000000000)
#define zero_struct(x) memory_zero((x), sizeof(*(x)))
#define defer_if(begin, cond_end) for (b32 PASTE(_i_, __LINE__) = !!begin; PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) = (cond_end, 0))
#define defer_block(begin, end) for (i32 PASTE(_i_, __LINE__) = (begin, 0); !PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) += (end, 1))
#define stack_t(type, size) struct { type data[size]; i32 len; }
#define STACK_CAP(stack) (lengthof((stack).data))
#define STACK_EMPTY(stack) ((stack).len == 0)
#define STACK_FULL(stack) ((stack).len == STACK_CAP(stack))
#define STACK_PUSH(stack, ...) (assert_expr(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
#define STACK_POP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
#define STACK_TOP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
#define STRINGIFY_(S) #S
#define STRINGIFY(S) STRINGIFY_(S)
#define PASTE_(a, b) a##b
#define PASTE(a, b) PASTE_(a, b)
#define SWAP(t, a, b) do { t PASTE(temp__, __LINE__) = a; a = b; b = PASTE(temp__, __LINE__); } while(0)
#define SWAP_PTR(t, a, b) do { t PASTE(temp__, __LINE__) = *a; *a = *b; *b = PASTE(temp__, __LINE__); } while(0)
#define CODE(...) #__VA_ARGS__
#if PLATFORM_CL || (PLATFORM_CLANG && PLATFORM_WINDOWS)
#pragma section(".rdata$", read)
#define gb_read_only __declspec(allocate(".rdata$"))
#elif PLATFORM_CLANG && PLATFORM_LINUX
#define gb_read_only __attribute__((section(".rodata")))
#else
#define gb_read_only
#endif
#if PLATFORM_CL
#define fn_inline __forceinline
#elif PLATFORM_CLANG || PLATFORM_GCC
#define fn_inline __attribute__((always_inline))
#else
#define fn_inline
#endif
#ifndef FILE_AND_LINE_GCC_FORMAT
#define FILE_AND_LINE __FILE__ "(" STRINGIFY(__LINE__) ")"
#else
#define FILE_AND_LINE __FILE__ ":" STRINGIFY(__LINE__)
#endif
#if PLATFORM_WINDOWS
int IsDebuggerPresent(void);
#define debug__break() (IsDebuggerPresent() && (__debugbreak(), 1))
#elif PLATFORM_UNIX
// https://github.com/r-lyeh/tinybits/blob/master/tinyassert.c
#include <signal.h>
static void os_unix_sigtrap(int signum) { signal(SIGTRAP, SIG_DFL); }
#define debug__break() (signal(SIGTRAP, os_unix_sigtrap), raise(SIGTRAP))
#elif PLATFORM_WASM
void wasm_trap(void);
#define debug__break() wasm_trap()
#elif PLATFORM_TCC
#define debug__break() raise(SIGTRAP)
#else
#define debug__break() __builtin_trap()
#endif
#define debug_break() (debug__break(), 1)
#if PLATFORM_WASM | PLATFORM_TCC
#define gb_thread
#elif PLATFORM_GCC | PLATFORM_CLANG
#define gb_thread __thread
#elif PLATFORM_CL
#define gb_thread __declspec(thread)
#else
#define gb_thread _Thread_local
#endif
#if PLATFORM_CL
#pragma warning(disable: 4116)
#endif
// Single linked list Queue
#define SLLQ_APPEND_EX(f, l, n, next) \
do { \
assert_expr((n)->next == NULL); \
if ((f) == 0) { \
(f) = (l) = (n); \
} else { \
(l) = (l)->next = (n); \
} \
} while (0)
#define SLLQ_APPEND(f, l, n) SLLQ_APPEND_EX(f, l, n, next)
#define SLLQ_PREPEND_EX(f, l, n, next) \
do { \
assert_expr((n)->next == NULL); \
if ((f) == 0) { \
(f) = (l) = (n); \
} else { \
(n)->next = (f); \
(f) = (n); \
} \
} while (0)
#define SLLQ_PREPEND(f, l, n) SLLQ_PREPEND_EX(f, l, n, next)
#define SLLQ_REMOVE_FIRST_EX(f, l, next) \
do { \
if ((f) == (l)) { \
(f) = (l) = 0; \
} else { \
(f) = (f)->next; \
} \
} while (0)
#define SLLQ_REMOVE_FIRST(f, l) SLLQ_REMOVE_FIRST_EX(f, l, next)
// Singly linked list stack
#define SLLS_PUSH_EX(stack_base, new_stack_base, next) \
do { \
(new_stack_base)->next = (stack_base); \
(stack_base) = (new_stack_base); \
} while (0)
#define SLLS_PUSH(stack_base, new_stack_base) \
SLLS_PUSH_EX(stack_base, new_stack_base, next)
#define SLLS_POP(stack_base) ((stack_base) = (stack_base)->next)
#define SLLS_POP_AND_STORE(stack_base, out_node) \
do { \
if (stack_base) { \
(out_node) = (stack_base); \
(stack_base) = (stack_base)->next; \
(out_node)->next = 0; \
} \
} while (0)
// Doubly linked list Queue
#define DLLQ_APPEND_EX(f, l, node, next, prev) \
do { \
assert_expr((node)->next == NULL); \
assert_expr((node)->prev == NULL); \
if ((f) == 0) { \
(f) = (l) = (node); \
} else { \
(l)->next = (node); \
(node)->prev = (l); \
(l) = (node); \
} \
} while (0)
#define DLLQ_APPEND(f, l, node) DLLQ_APPEND_EX(f, l, node, next, prev)
#define DLLQ_PREPEND_EX(f, l, node, next, prev) \
do { \
assert_expr((node)->next == NULL); \
assert_expr((node)->prev == NULL); \
if ((f) == 0) { \
(f) = (l) = (node); \
} else { \
(node)->next = (f); \
(f)->prev = (node); \
(f) = (node); \
} \
} while (0)
#define DLLQ_PREPEND(f, l, node) DLLQ_PREPEND_EX(f, l, node, next, prev)
#define DLLQ_CONTAINS(f, l, n, next, prev) for (
#define DLLQ_REMOVE_EX(first, last, node, next, prev) \
do { \
if ((first) == (last)) { \
assert_expr((node) == (first)); \
(first) = (last) = 0; \
} else if ((last) == (node)) { \
(last) = (last)->prev; \
(last)->next = 0; \
} else if ((first) == (node)) { \
(first) = (first)->next; \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLLQ_REMOVE(first, last, node) DLLQ_REMOVE_EX(first, last, node, next, prev)
// Doubly linked list Stack
#define DLLS_PUSH_EX(first, node, next, prev) \
do { \
assert_expr((node)->next == NULL); \
assert_expr((node)->prev == NULL); \
(node)->next = (first); \
if ((first)) \
(first)->prev = (node); \
(first) = (node); \
} while (0)
#define DLLS_PUSH(first, node) DLLS_PUSH_EX(first, node, next, prev)
#define DLLS_REMOVE_EX(first, node, next, prev) \
do { \
if ((node) == (first)) { \
(first) = (first)->next; \
if ((first)) \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
if ((node)->next) \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLLS_REMOVE(first, node) DLLS_REMOVE_EX(first, node, next, prev)
typedef enum {
alokind_alloc,
alokind_dealloc,
} alokind_t;
typedef struct alo_t alo_t;
struct alo_t {
void *object;
void *(*proc)(alo_t alo, alokind_t kind, void *ptr, size_t size);
};
-30
View File
@@ -1,30 +0,0 @@
#include "core_ctx.h"
#include "core_platform.h"
gb_thread thread_ctx_t *tcx;
fn void *ma_arena_alo_proc(alo_t alo, alokind_t kind, void *ptr, size_t size) {
unused(ptr);
if (kind == alokind_alloc) {
return ma_push_size(alo.object, size);
} else if (kind == alokind_dealloc) {
return NULL;
} else_is_invalid;
return NULL;
}
fn alo_t malo(ma_arena_t *arena) {
return (alo_t){arena, ma_arena_alo_proc};
}
fn alo_t malot(ma_temp_t temp) {
return malo(temp.arena);
}
fn void dealloc(alo_t alo, void *ptr) {
alo.proc(alo, alokind_dealloc, ptr, 0);
}
fn void *alloc_size(alo_t alo, size_t size) {
return alo.proc(alo, alokind_alloc, NULL, size);
}
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include "core_arena.h"
#include "core_log.h"
typedef struct thread_ctx_t thread_ctx_t;
struct thread_ctx_t {
ma_arena_t scratch[3];
ma_arena_t temp; // application specific arena
// I probably want to discourage using it implicitly like: tcx.perm, instead just pass it around
// to functions that allocate pernament memory. temp and scratch very nicely create reusable code
// perm is basically gb state so it would be nice to annotate which functions are reusable
// and which functions have state
ma_arena_t perm;
void *app_ctx;
void *rn_ctx;
void *ui_ctx;
void *te_ctx;
void *user_ctx;
logger_t log;
int thread_index;
};
#define alloc_type(alo, type) (type *)alloc_size((aloc), sizeof(type))
#define alloc_array(alo, type, count) (type *)alloc_size((alo), sizeof(type) * (count))
fn alo_t malo(ma_arena_t *arena);
fn alo_t malot(ma_temp_t temp);
fn void dealloc(alo_t alo, void *ptr);
fn void *alloc_size(alo_t alo, size_t size);
fn int tcx_alloc_id(void);
extern gb_thread thread_ctx_t *tcx;
-217
View File
@@ -1,217 +0,0 @@
#include "core_hash_table.h"
#include "core_platform.h"
// xorshift64
fn u64 get_random_u64(random_seed_t *seed) {
u64 x = seed->a;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return seed->a = x;
}
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end) {
u64 r = get_random_u64(seed);
u64 diff = one_past_end - start;
u64 rr = r % diff;
u64 rrr = rr + start;
return rrr;
}
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end) {
u64 r = get_random_u64(seed);
i64 diff = one_past_end - start;
u64 rr = r % diff;
i64 rrr = (i64)rr + start;
return rrr;
}
fn f64 get_random_f64(random_seed_t *seed) {
f64 random = (f64)get_random_in_range_u64(seed, 0, UINT32_MAX);
f64 result = random / (f64)(UINT32_MAX - 1u);
return result;
}
fn u64 hash_data(s8_t string) {
u8 *data = (u8 *)string.str;
u64 hash = (u64)14695981039346656037ULL;
for (i64 i = 0; i < string.len; i++) {
hash = hash ^ (u64)(data[i]);
hash = hash * (u64)1099511628211ULL;
}
return hash;
}
fn u64 hash_mix(u64 x, u64 y) {
x ^= y;
x *= 0xff51afd7ed558ccd;
x ^= x >> 32;
return x;
}
fn ht_t *ht_create(ma_arena_t *arena, i32 size) {
ht_t *result = ma_push_type(arena, ht_t);
result->buckets = ma_push_array(arena, ht_bucket_t, size);
result->bucket_count = size;
result->arena = arena;
return result;
}
fn ht_node_t *ht_insert_kv(ht_t *ht, u64 hash, ht_key_value_t kv) {
ht_node_t *result = ma_push_type(ht->arena, ht_node_t);
result->kv = kv;
i64 idx = hash % ht->bucket_count;
SLLQ_APPEND(ht->buckets[idx].first, ht->buckets[idx].last, result);
ht->item_count += 1;
return result;
}
fn ht_node_t *ht_insert_u64(ht_t *ht, u64 key, u64 value) {
u64 hash = hash_data(s8_struct(key));
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_u64 = key, .value_u64 = value});
}
fn ht_node_t *ht_insert_ptr(ht_t *ht, void *key, void *value) {
return ht_insert_u64(ht, (u64)key, (u64)value);
}
fn ht_node_t *ht_insert_string(ht_t *ht, s8_t key, s8_t value) {
u64 hash = hash_data(key);
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_string = value});
}
fn ht_node_t *ht_insert_string_ptr(ht_t *ht, s8_t key, void *value) {
u64 hash = hash_data(key);
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_ptr = value});
}
fn ht_node_t *ht_search_u64_ex(ht_t *ht, u64 key) {
u64 hash = hash_data(s8_struct(key));
i64 idx = hash % ht->bucket_count;
ht_bucket_t *bucket = ht->buckets + idx;
for (ht_node_t *it = bucket->first; it; it = it->next) {
if (it->kv.key_u64 == key) {
return it;
}
}
return NULL;
}
fn ht_node_t *ht_search_ptr_ex(ht_t *ht, void *key) {
u64 hash = hash_data(s8_struct(key));
i64 idx = hash % ht->bucket_count;
ht_bucket_t *bucket = ht->buckets + idx;
for (ht_node_t *it = bucket->first; it; it = it->next) {
if (it->kv.key_ptr == key) {
return it;
}
}
return NULL;
}
fn ht_node_t *ht_search_string_ex(ht_t *ht, s8_t key) {
u64 hash = hash_data(key);
i64 idx = hash % ht->bucket_count;
ht_bucket_t *bucket = ht->buckets + idx;
for (ht_node_t *it = bucket->first; it; it = it->next) {
if (s8_are_equal(it->kv.key_string, key)) {
return it;
}
}
return NULL;
}
fn u64 *ht_search_u64(ht_t *ht, u64 key) {
ht_node_t *node = ht_search_u64_ex(ht, key);
if (node) return &node->kv.value_u64;
return NULL;
}
fn void **ht_search_ptr(ht_t *ht, void *key) {
ht_node_t *node = ht_search_ptr_ex(ht, key);
if (node) return &node->kv.value_ptr;
return NULL;
}
fn s8_t *ht_search_string(ht_t *ht, s8_t key) {
ht_node_t *node = ht_search_string_ex(ht, key);
if (node) return &node->kv.value_string;
return NULL;
}
fn void **ht_search_string_ptr(ht_t *ht, s8_t key) {
ht_node_t *node = ht_search_string_ex(ht, key);
if (node) return &node->kv.value_ptr;
return NULL;
}
///////////////////////////////
// string interning
fn s8i_t *intern_string(ht_t *ht, s8_t string) {
s8_t *item = ht_search_string(ht, string);
if (!item) {
string = s8_copy(ht->arena, string);
ht_node_t *node = ht_insert_string(ht, string, string);
item = &node->kv.value_string;
}
return item;
}
fn s8i_t *internf(ht_t *ht, char *str, ...) {
S8_FMT(ht->arena, str, string);
return intern_string(ht, string);
}
///////////////////////////////
// testing
fn_test void test_hash_table(void) {
ma_temp_t scratch = ma_begin_scratch();
{
ht_t *ht = ht_create(scratch.arena, 16);
for (u64 i = 0; i < 128; i += 1) {
ht_insert_u64(ht, i, i);
ht_node_t *node = ht_search_u64_ex(ht, i);
assert_expr(node->kv.value_u64 == i);
assert(node->kv.key_u64 == i);
}
for (u64 i = 0; i < 128; i += 1) {
ht_node_t *node = ht_search_u64_ex(ht, i);
assert(node->kv.value_u64 == i);
assert(node->kv.key_u64 == i);
}
ht_node_t *node = ht_search_u64_ex(ht, 1111);
assert(node == NULL);
}
{
ht_t *ht = ht_create(scratch.arena, 16);
for (i32 i = 0; i < 128; i += 1) {
s8_t s = s8_printf(scratch.arena, "%d", i);
ht_insert_string(ht, s, s);
ht_node_t *node = ht_search_string_ex(ht, s);
assert(s8_are_equal(node->kv.value_string, s));
assert(s8_are_equal(node->kv.key_string, s));
}
ht_node_t *node = ht_search_string_ex(ht, s8("memes"));
assert(node == NULL);
}
ma_end_scratch(scratch);
}
fn_test void test_intern_table(void) {
ma_temp_t scratch = ma_begin_scratch();
ht_t *ht = ht_create(scratch.arena, 4);
assert(internf(ht, "asd") == internf(ht, "asd"));
assert(internf(ht, "asdf") != internf(ht, "asd"));
assert(internf(ht, "asdf") == internf(ht, "asdf"));
assert(internf(ht, "123asdf") == internf(ht, "123asdf"));
assert(internf(ht, "123asdf") != internf(ht, "133asdf"));
assert(internf(ht, "") == internf(ht, ""));
assert(internf(ht, "") != internf(ht, "a"));
ma_end_scratch(scratch);
}
-73
View File
@@ -1,73 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_arena.h"
#include "core_string.h"
typedef struct ht_key_value_t ht_key_value_t;
struct ht_key_value_t {
union {
s8_t key_string;
u64 key_u64;
void *key_ptr;
};
union {
s8_t value_string;
void *value_ptr;
u64 value_u64;
};
};
typedef struct ht_node_t ht_node_t;
struct ht_node_t {
ht_node_t *next;
ht_key_value_t kv;
};
typedef struct ht_bucket_t ht_bucket_t;
struct ht_bucket_t {
ht_node_t *first;
ht_node_t *last;
};
typedef struct ht_t ht_t;
struct ht_t {
ma_arena_t *arena;
i32 item_count;
i32 bucket_count;
ht_bucket_t *buckets;
};
fn ht_t *ht_create (ma_arena_t *arena, i32 size);
fn ht_node_t *ht_insert_kv (ht_t *ht, u64 hash, ht_key_value_t kv);
fn ht_node_t *ht_insert_u64 (ht_t *ht, u64 key, u64 value);
fn ht_node_t *ht_insert_ptr (ht_t *ht, void *key, void *value);
fn ht_node_t *ht_insert_string (ht_t *ht, s8_t key, s8_t value);
fn ht_node_t *ht_insert_string_ptr (ht_t *ht, s8_t key, void *value);
fn u64 *ht_search_u64 (ht_t *ht, u64 key);
fn void **ht_search_ptr (ht_t *ht, void *key);
fn s8_t *ht_search_string (ht_t *ht, s8_t key);
fn void **ht_search_string_ptr (ht_t *ht, s8_t key);
fn ht_node_t *ht_search_u64_ex (ht_t *ht, u64 key);
fn ht_node_t *ht_search_ptr_ex (ht_t *ht, void *key);
fn ht_node_t *ht_search_string_ex (ht_t *ht, s8_t key);
///////////////////////////////
// string interning
#define s8i_t s8_t
fn s8i_t *intern_string(ht_t *ht, s8_t string);
fn s8i_t *internf(ht_t *ht, char *str, ...);
///////////////////////////////
// Hashing
typedef struct random_seed_t random_seed_t;
struct random_seed_t {
u64 a;
};
fn u64 get_random_u64(random_seed_t *seed);
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end);
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end);
fn f64 get_random_f64(random_seed_t *seed);
fn u64 hash_data(s8_t string);
fn u64 hash_mix(u64 x, u64 y);
-242
View File
@@ -1,242 +0,0 @@
#include "core_intrin.h"
#include "core_basic.h"
#include "core_platform.h"
fn void memory_copy(void *dst, void *src, usize n) {
IF_PLATFORM_CLANG_ELSE(__builtin_memcpy(dst, src, n), memcpy(dst, src, n));
}
fn void memory_move(void *dest, const void *src, usize n) {
IF_PLATFORM_CLANG_ELSE(__builtin_memmove(dest, src, n), memmove(dest, src, n));
}
fn void memory_set(void *dst, i32 c, usize size) {
IF_PLATFORM_CLANG_ELSE(__builtin_memset(dst, c, size), memset(dst, c, size));
}
fn int bad_memory__compare(void *left, void *right, usize size) {
u8 *l = left;
u8 *r = right;
for (usize i = 0; i < size; i += 1) {
if (l[i] != r[i]) return 1;
}
return 0;
}
fn b32 memory_equal(void *left, void *right, usize size) {
int cmp = IF_PLATFORM_CLANG_ELSE(bad_memory__compare(left, right, size), memcmp(left, right, size));
return cmp == 0;
}
fn void memory_zero(void *dst, usize size) {
memory_set(dst, 0, size);
}
fn f32 f32_sqrt(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrtf(x), sqrtf(x)); }
fn f64 f64_sqrt(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrt(x), sqrt(x)); }
fn f32 f32_ceil(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceilf(x), ceilf(x)); }
fn f64 f64_ceil(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceil(x), ceil(x)); }
fn f32 f32_floor(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floorf(x), floorf(x)); }
fn f64 f64_floor(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floor(x), floor(x)); }
fn f32 f32_abs(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabsf(x), fabsf(x)); }
fn f64 f64_abs(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabs(x), fabs(x)); }
// fn f32 f32_round(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_roundf(x), roundf(x)); }
fn f64 f64_round(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_round(x), round(x)); }
fn f64 f64_mod(f64 a, f64 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmod(a, b), fmod(a, b)); }
fn f32 f32_mod(f32 a, f32 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmodf(a, b), fmodf(a, b)); }
/* https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
**
*/
fn f64 f64_exp2(f64 x) {
f64 a = f64_floor(x * 8);
int64_t ai = (i64)a;
if (ai < -1024) {
return 0;
}
f64 b = x - a / 8;
f64 y = U64_TO_F64(0x3FF0000000000000) +
b * (U64_TO_F64(0x3FE62E42FEFA3A00) +
b * (U64_TO_F64(0x3FCEBFBDFF829140) +
b * (U64_TO_F64(0x3FAC6B08D73C4A40) +
b * (U64_TO_F64(0x3F83B2AB53873280) +
b * (U64_TO_F64(0x3F55D88F363C6C00) +
b * (U64_TO_F64(0x3F242C003E4A2000) +
b * U64_TO_F64(0x3EF0B291F6C00000)))))));
f64 m[8] = {
U64_TO_F64(0x3FF0000000000000),
U64_TO_F64(0x3FF172B83C7D517B),
U64_TO_F64(0x3FF306FE0A31B715),
U64_TO_F64(0x3FF4BFDAD5362A27),
U64_TO_F64(0x3FF6A09E667F3BCD),
U64_TO_F64(0x3FF8ACE5422AA0DB),
U64_TO_F64(0x3FFAE89F995AD3AD),
U64_TO_F64(0x3FFD5818DCFBA487),
};
y *= m[ai & 7];
convert_f64_u64_t c;
c.f = y;
c.i += (ai >> 3) << 52;
return c.f;
}
fn f32 f32_exp2(f32 x) {
f32 a = f32_floor(x);
i32 ai = (i32)a;
if (ai < -128) {
return 0;
}
f32 b = x - a;
f32 y = U32_TO_F32(0x3F7FFFFE) + b * (U32_TO_F32(0x3F31729A) + b * (U32_TO_F32(0x3E75E700) + b * (U32_TO_F32(0x3D64D520) + b * (U32_TO_F32(0x3C128280) + b * U32_TO_F32(0x3AF89400)))));
convert_f32_u32_t c;
c.f = y;
c.i += ai << 23;
return c.f;
}
fn f64 f64_log2(f64 x) {
convert_f64_u64_t c;
c.f = x;
int64_t e = ((c.i >> 52) & 2047) - 0x3FF;
c.i = (c.i & ~((uint64_t)0x7FF << 52)) + ((uint64_t)0x3FF << 52);
x = c.f;
f64 a;
if (x < 1.125) {
a = 0;
} else if (x < 1.250) {
x *= 1.125 / 1.250;
a = U64_TO_F64(0xBFC374D65D9E608E);
} else if (x < 1.375) {
x *= 1.125 / 1.375;
a = U64_TO_F64(0xBFD28746C334FECB);
} else if (x < 1.500) {
x *= 1.125 / 1.500;
a = U64_TO_F64(0xBFDA8FF971810A5E);
} else if (x < 1.625) {
x *= 1.125 / 1.625;
a = U64_TO_F64(0xBFE0F9F9FFC8932A);
} else if (x < 1.750) {
x *= 1.125 / 1.750;
a = U64_TO_F64(0xBFE465D36ED11B11);
} else if (x < 1.875) {
x *= 1.125 / 1.875;
a = U64_TO_F64(0xBFE79538DEA712F5);
} else {
x *= 1.125 / 2.000;
a = U64_TO_F64(0xBFEA8FF971810A5E);
}
f64 y = U64_TO_F64(0xC00FF8445026AD97) + x * (U64_TO_F64(0x40287A7A02D9353F) + x * (U64_TO_F64(0xC03711C58D55CEE2) + x * (U64_TO_F64(0x4040E8263C321A26) + x * (U64_TO_F64(0xC041EB22EA691BB3) + x * (U64_TO_F64(0x403B00FB376D1F10) + x * (U64_TO_F64(0xC02C416ABE857241) + x * (U64_TO_F64(0x40138BA7FAA3523A) + x * (U64_TO_F64(0xBFF019731AF80316) + x * U64_TO_F64(0x3FB7F1CD3852C200)))))))));
return y - a + e;
}
fn f32 f32_log2(f32 x) {
// TODO f32_log2(0.9999971379999999f) gives 0.00000143051147460938 (should be negative!!).
convert_f32_u32_t c;
c.f = x;
i32 e = ((c.i >> 23) & 255) - 0x7F;
c.i = (c.i & ~(0xFF << 23)) + (0x7F << 23);
x = c.f;
f32 y = U32_TO_F32(0xC05B5154) + x * (U32_TO_F32(0x410297C6) + x * (U32_TO_F32(0xC1205CEB) + x * (U32_TO_F32(0x4114DF63) + x * (U32_TO_F32(0xC0C0DBBB) + x * (U32_TO_F32(0x402942C6) + x * (U32_TO_F32(0xBF3FF98A) + x * (U32_TO_F32(0x3DFE1050) + x * U32_TO_F32(0xBC151480))))))));
return y + e;
}
fn f64 f64_pow(f64 x, f64 y) {
return f64_exp2(y * f64_log2(x));
}
fn f32 f32_pow(f32 x, f32 y) {
return f32_exp2(y * f32_log2(x));
}
//
/* https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/s_round.c;hb=master
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
**/
fn f32 f32_round(f32 x) {
u32 w = F32_TO_U32(x);
/* Most significant word, least significant word. */
int exponent_less_127;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23) {
if (exponent_less_127 < 0) {
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((u32)127 << 23);
} else {
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
} else {
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
x = U32_TO_F32(w);
return x;
}
///////////////////////////////
// other
fn u32 u32_safe_cast(u64 v) {
assert_expr(v <= u32_max);
return (u32)v;
}
fn u16 u16_safe_cast(u64 v) {
assert(v <= u16_max);
return (u16)v;
}
fn u8 u8_safe_cast(u64 v) {
assert(v <= u8_max);
return (u8)v;
}
fn i32 i32_safe_cast(i64 v) {
assert(v >= i32_min && v <= i32_max);
return (i32)v;
}
-32
View File
@@ -1,32 +0,0 @@
#pragma once
#include "core_basic.h"
fn void memory_copy(void *dst, void *src, usize n);
fn void memory_move(void *dest, const void *src, usize n);
fn void memory_set(void *dst, i32 c, usize size);
fn b32 memory_equal(void *left, void *right, usize size);
fn void memory_zero(void *dst, usize size);
fn f32 f32_sqrt(f32 x);
fn f64 f64_sqrt(f64 x);
fn f32 f32_ceil(f32 x);
fn f64 f64_ceil(f64 x);
fn f32 f32_floor(f32 x);
fn f64 f64_floor(f64 x);
fn f32 f32_abs(f32 x);
fn f64 f64_abs(f64 x);
fn f32 f32_round(f32 x);
fn f64 f64_round(f64 x);
fn f64 f64_mod(f64 a, f64 b);
fn f32 f32_mod(f32 a, f32 b);
fn f64 f64_exp2(f64 x);
fn f32 f32_exp2(f32 x);
fn f64 f64_log2(f64 x);
fn f32 f32_log2(f32 x);
fn f64 f64_pow(f64 x, f64 y);
fn f32 f32_pow(f32 x, f32 y);
fn f32 f32_round(f32 x);
fn u32 u32_safe_cast(u64 v);
fn u16 u16_safe_cast(u64 v);
fn u8 u8_safe_cast(u64 v);
fn i32 i32_safe_cast(i64 v);
-469
View File
@@ -1,469 +0,0 @@
#include "core_lexer.h"
#include "core_log.h"
#include "core_platform.h"
#include "core_ctx.h"
#define lex_error(TOKEN, STRING) do {\
errorf(STRING);\
TOKEN->kind = lex_kind_error;\
TOKEN->string = s8(STRING);\
} while (0)
fn lexer_t lex_make(s8_t stream, char *file_name) {
lexer_t result = {.at = stream.str, .end = stream.str + stream.len, .file = file_name};
return result;
}
fn b32 lex_at_end(lexer_t *lex) {
b32 result = lex->at >= lex->end;
return result;
}
fn void lex_advance(lexer_t *lex) {
if (lex_at_end(lex)) return;
if (lex->at[0] == '\n') { lex->column = 0; lex->line += 1; }
lex->column += 1;
lex->at += 1;
}
fn b32 lex_match(lexer_t *lex, char c) {
if (lex->at[0] == c) {
lex_advance(lex);
return true;
}
return false;
}
fn void lex_eat_whitespace(lexer_t *lex) {
for (;;) {
if (char_is_whitespace(lex->at[0])) {
if (lex->at[0] == '\n') lex->inside_macro = false;
lex_advance(lex);
} else if (lex->at[0] == '\\' && lex->at[1] == '\n') {
lex_advance(lex); lex_advance(lex);
} else if (lex->at[0] == '\\' && lex->at[1] == '\r' && lex->at[2] == '\n') {
lex_advance(lex); lex_advance(lex); lex_advance(lex);
} else {
break;
}
}
}
fn void lex_eat_macro_whitespace(lexer_t *lex) {
while (lex->at[0] == ' ' || lex->at[0] == '\t') lex_advance(lex);
}
fn void lex_suffix(lexer_t *lex, lex_t *token) {
if (lex_match(lex, 'f')) {
token->kind = lex_kind_real;
token->suffix = lex_suffix_f;
} else if (lex_match(lex, 'd')) {
token->kind = lex_kind_real;
token->suffix = lex_suffix_d;
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l' && lex->at[2] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L' && lex->at[2] == 'L'))) {
token->suffix = lex_suffix_ull;
lex_advance(lex); lex_advance(lex); lex_advance(lex);
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L'))) {
token->suffix = lex_suffix_ul;
lex_advance(lex); lex_advance(lex);
} else if (token->kind == lex_kind_integer && (lex->at[0] == 'l' || lex->at[0] == 'L')) {
token->suffix = lex_suffix_l;
lex_advance(lex);
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'l' && lex->at[1] == 'l') || (lex->at[0] == 'L' && lex->at[1] == 'L'))) {
token->suffix = lex_suffix_ll;
lex_advance(lex); lex_advance(lex);
}
}
fn void lex_eat_number(lexer_t *lex, lex_t *token) {
token->kind = lex_kind_integer;
for (;;) {
if (char_is_digit(lex->at[0])) {
lex_advance(lex);
continue;
}
if (lex_match(lex, '.')) {
if (token->kind == lex_kind_real) {
lex_error(token, "multiple '.' periods in floating point number literal");
return;
}
token->kind = lex_kind_real;
continue;
}
break;
}
lex_suffix(lex, token);
}
fn void lex_eat_until(lexer_t *lex, char c) {
while (lex->at[0] != c && !lex_at_end(lex)) lex_advance(lex);
}
fn void lex_eat_string(lexer_t *lex, lex_t *token) {
token->kind = lex_kind_string;
for (;;) {
if (lex->at[0] == '\\') {
lex_advance(lex);
} else if (lex_match(lex, token->str[0])) {
break;
}
if (lex->at[0] == 0) {
lex_error(token, "unclosed string");
return;
}
lex_advance(lex);
}
}
fn b32 lex_macro(lexer_t *lex, lex_t *token) {
lex_eat_macro_whitespace(lex);
token->str = lex->at;
while (char_is_alphabetic(lex->at[0])) lex_advance(lex);
token->len = (i32)(lex->at - token->str);
if (s8_are_equal(token->string, s8("define"))) {
token->kind = lex_kind_preproc_define;
} else if (s8_are_equal(token->string, s8("ifdef"))) {
token->kind = lex_kind_preproc_ifdef;
} else if (s8_are_equal(token->string, s8("ifndef"))) {
token->kind = lex_kind_preproc_ifndef;
} else if (s8_are_equal(token->string, s8("include"))) {
token->kind = lex_kind_preproc_include;
lex_eat_macro_whitespace(lex);
char end = 0;
if (lex_match(lex, '"')) {
end = '"';
} else if (lex_match(lex, '<')) {
end = '>';
token->system_include = true;
} else {
lex_error(token, "invalid include directive, should be followed by string or '<'");
return false;
}
token->str = lex->at;
while (lex->at[0] != end) {
if (lex_at_end(lex)) {
lex_error(token, "invalid include directive, reached end of file");
return false;
}
if (lex->at[0] == '\n') {
lex_error(token, "invalid include directive, reached end of line");
return false;
}
lex_advance(lex);
}
lex_advance(lex);
} else if (s8_are_equal(token->string, s8("if"))) {
token->kind = lex_kind_preproc_if;
} else if (s8_are_equal(token->string, s8("endif"))) {
token->kind = lex_kind_preproc_endif;
} else if (s8_are_equal(token->string, s8("error"))) {
token->kind = lex_kind_preproc_error;
lex_eat_macro_whitespace(lex);
token->str = lex->at;
lex_eat_until(lex, '\n');
} else if (s8_are_equal(token->string, s8("else"))) {
token->kind = lex_kind_preproc_else;
} else if (s8_are_equal(token->string, s8("elif"))) {
token->kind = lex_kind_preproc_elif;
} else if (s8_are_equal(token->string, s8("pragma"))) {
token->kind = lex_kind_preproc_pragma;
} else if (s8_are_equal(token->string, s8("undef"))) {
token->kind = lex_kind_preproc_undef;
} else {
return false;
}
return true;
}
#define LEX_CASE3(C1, K1, C2, K2, C3, K3) \
case C1: { \
token->kind = K1; \
if (lex_match(lex, C2)) { \
lex_advance(lex); \
token->kind = K2; \
} else if (lex_match(lex, C3)) { \
lex_advance(lex); \
token->kind = K3; \
} \
} break
fn void lex_token_ex(lexer_t *lex, lex_t *token) {
lex_eat_whitespace(lex);
*token = (lex_t){.str = lex->at, .file = lex->file, .line = lex->line, .column = lex->column};
lex_advance(lex);
switch (token->str[0]) {
case '\0': token->kind = lex_kind_eof; break;
case '{': token->kind = lex_kind_open_brace; break;
case '}': token->kind = lex_kind_close_brace; break;
case '(': token->kind = lex_kind_open_paren; break;
case ')': token->kind = lex_kind_close_paren; break;
case '[': token->kind = lex_kind_open_bracket; break;
case ']': token->kind = lex_kind_close_bracket; break;
case '~': token->kind = lex_kind_bit_negation; break;
case ';': token->kind = lex_kind_semicolon; break;
case ':': token->kind = lex_kind_colon; break;
case ',': token->kind = lex_kind_comma; break;
case '@': token->kind = lex_kind_tag; break;
case '?': token->kind = lex_kind_question; break;
case '\\': token->kind = lex_kind_escape; break;
case '"': lex_eat_string(lex, token); break;
case '`': lex_eat_string(lex, token); break;
case '\'': lex_eat_string(lex, token); break;
LEX_CASE3('^', lex_kind_bit_xor, '=', lex_kind_bit_xor_assign, /*ignored option*/'=', lex_kind_bit_xor_assign);
LEX_CASE3('=', lex_kind_assign, '=', lex_kind_equals, /*ignored option*/'=', lex_kind_equals);
LEX_CASE3('!', lex_kind_negation, '=', lex_kind_not_equals, /*ignored option*/'=', lex_kind_not_equals);
LEX_CASE3('%', lex_kind_modulo, '=', lex_kind_modulo_assign, /*ignored option*/'=', lex_kind_modulo_assign);
LEX_CASE3('*', lex_kind_multiply, '=', lex_kind_multiply_assign, /*ignored option*/'=', lex_kind_multiply_assign);
LEX_CASE3('+', lex_kind_plus, '+', lex_kind_increment, '=', lex_kind_plus_assign);
LEX_CASE3('-', lex_kind_minus, '-', lex_kind_decrement, '=', lex_kind_minus_assign);
LEX_CASE3('&', lex_kind_bit_and, '&', lex_kind_and, '=', lex_kind_bit_and_assign);
LEX_CASE3('|', lex_kind_bit_or, '|', lex_kind_or, '=', lex_kind_bit_or_assign);
case '.': {
token->kind = lex_kind_dot;
if (lex->at[0] == '.' && lex->at[1] == '.') {
lex_advance(lex);
lex_advance(lex);
token->kind = lex_kind_three_dots;
}
} break;
case '/': {
token->kind = lex_kind_divide;
if (lex_match(lex, '/')) {
token->kind = lex_kind_comment;
lex_eat_until(lex, '\n');
} else if (lex_match(lex, '*')) {
token->kind = lex_kind_comment;
for (;;) {
if (lex->at[0] == '*' && lex->at[1] == '/') {
break;
}
if (lex->at[0] == 0) {
lex_error(token, "unclosed block comment");
return;
}
lex_advance(lex);
}
lex_advance(lex);
lex_advance(lex);
} else if (lex_match(lex, '=')) {
token->kind = lex_kind_divide_assign;
}
} break;
case '>': {
token->kind = lex_kind_greater;
if (lex_match(lex, '=')) {
token->kind = lex_kind_greater_or_equal;
} else if (lex_match(lex, '>')) {
token->kind = lex_kind_bit_right_shift;
if (lex_match(lex, '=')) {
token->kind = lex_kind_bit_right_shift_assign;
}
}
} break;
case '<': {
token->kind = lex_kind_lesser;
if (lex_match(lex, '=')) {
token->kind = lex_kind_lesser_or_equal;
} else if (lex_match(lex, '<')) {
token->kind = lex_kind_bit_left_shift;
if (lex_match(lex, '=')) {
token->kind = lex_kind_bit_left_shift_assign;
}
}
} break;
case '#': {
if (lex_match(lex, '#')) {
token->kind = lex_kind_preproc_concat;
} else {
b32 inside_macro = lex_macro(lex, token);
if (inside_macro) {
lex->inside_macro = true;
} else {
if (!lex->inside_macro) {
lex_error(token, "invalid preprocessor directive");
return;
}
token->kind = lex_kind_preproc_stringify;
token->str = lex->at;
// this is slighly wrong, first letter can't be number
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
}
}
} break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': {
lex_eat_number(lex, token);
} break;
case 'A': case 'a': case 'B': case 'b': case 'C': case 'c':
case 'D': case 'd': case 'E': case 'e': case 'F': case 'f':
case 'G': case 'g': case 'H': case 'h': case 'I': case 'i':
case 'J': case 'j': case 'K': case 'k': case 'L': case 'l':
case 'M': case 'm': case 'N': case 'n': case 'O': case 'o':
case 'P': case 'p': case 'Q': case 'q': case 'R': case 'r':
case 'S': case 's': case 'T': case 't': case 'U': case 'u':
case 'V': case 'v': case 'W': case 'w': case 'X': case 'x':
case 'Y': case 'y': case 'Z': case 'z': case '_': {
token->kind = lex_kind_ident;
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
} break;
default: {
lex_error(token, "found invalid character in the token stream");
}
}
token->len = (i32)(lex->at - token->str);
if (token->kind == lex_kind_integer) {
s8_t string_to_lex = token->string;
if (token->suffix != lex_suffix_none) {
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
s8_t prefix = s8("lex_suffix_");
string_to_lex.len -= string_value.len - prefix.len;
}
token->integer = u64_from_s8(string_to_lex, 10);
} else if (token->kind == lex_kind_real) {
s8_t string_to_lex = token->string;
if (token->suffix != lex_suffix_none) {
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
s8_t prefix = s8("lex_suffix_");
string_to_lex.len -= string_value.len - prefix.len;
}
token->real = f64_from_s8(string_to_lex);
} else if (token->kind == lex_kind_string) {
token->str += 1;
token->len -= 2;
} else if (token->kind == lex_kind_preproc_include) {
token->len -= 1;
}
if (lex->inside_macro) token->inside_macro = true;
}
fn lex_t lex_token(lexer_t *lex) {
lex_t result = {0};
lex_token_ex(lex, &result);
return result;
}
fn lex_array_t lex_tokens(ma_arena_t *arena, char *file_name, s8_t stream) {
usize align = arena->align;
arena->align = 0;
lex_array_t token_array = {0};
lexer_t l = lex_make(stream, file_name);
for (;;) {
lex_t *token = ma_push_type(arena, lex_t);
if (token_array.data == NULL) {
token_array.data = token;
}
token_array.len += 1;
do {
lex_token_ex(&l, token);
} while (token->kind == lex_kind_comment);
if (token->kind == lex_kind_eof) break;
}
arena->align = align;
return token_array;
}
gb_read_only s8_t lex_kind_simple_strings[] = {
#define X(KIND, STR, SIMPLE) s8_const(SIMPLE),
LEX_KIND_XLIST
#undef X
};
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind) {
assert_expr(kind >= 0 && kind < lex_kind_count);
return lex_kind_simple_strings[kind];
}
gb_read_only s8_t lex_kind_strings[] = {
#define X(KIND, STR, SIMPLE) s8_const(STR),
LEX_KIND_XLIST
#undef X
};
fn s8_t lex_kind_to_s8(lex_kind_t kind) {
assert(kind >= 0 && kind < lex_kind_count);
return lex_kind_strings[kind];
}
fn lex_t *parser_next(parser_t *par) {
lex_t *result = par->at;
if (result->kind != lex_kind_eof) par->at += 1;
return result;
}
fn lex_t *parser_match(parser_t *par, lex_kind_t kind) {
if (par->at->kind == kind) {
return parser_next(par);
} else {
return NULL;
}
}
fn lex_t *parser_matchi(parser_t *par, s8_t str) {
if (par->at->kind == lex_kind_ident && s8_are_equal(par->at->string, str)) {
return parser_next(par);
} else {
return NULL;
}
}
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch();
b8 p = tcx->log.print_file_and_line;
tcx->log.print_file_and_line = false;
S8_FMT(scratch.arena, str, str8);
if (print_only_file) {
fatalf("%s: error: %.*s", token->file, s8_fmtspec(str8));
} else {
fatalf("%s(%d): error: %.*s", token->file, token->line, s8_fmtspec(str8));
}
tcx->log.print_file_and_line = p;
ma_end_scratch(scratch);
}
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind) {
lex_t *token = parser_match(par, kind);
if (!token) parser_panicf(par->print_only_file, par->at, "expected token kind: %s, got instead: %s", lex_kind_to_s8(kind).str, lex_kind_to_s8(par->at->kind).str);
return token;
}
fn lex_t *parser_expecti(parser_t *par, s8_t ident) {
lex_t *token = parser_matchi(par, ident);
if (!token) parser_panicf(par->print_only_file, par->at, "expected identifier: '%.*s'", s8_fmtspec(ident));
return token;
}
fn void parser_eat_until(parser_t *par, lex_kind_t kind) {
while (par->at->kind != kind && par->at->kind != lex_kind_eof) {
parser_next(par);
}
}
fn void parser_eat_including(parser_t *par, lex_kind_t kind) {
parser_eat_until(par, kind);
parser_next(par);
}
-182
View File
@@ -1,182 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_string.h"
#include "core_arena.h"
#include "core_type_info.h"
typedef enum lex_kind_t {
#define LEX_KIND_XLIST\
X(lex_kind_eof , "end of file" , "---" )\
X(lex_kind_error , "error" , "---" )\
X(lex_kind_integer , "integer" , "---" )\
X(lex_kind_real , "real" , "---" )\
X(lex_kind_ident , "identifier" , "---" )\
X(lex_kind_string , "string" , "---" )\
X(lex_kind_comment , "comment" , "---" )\
X(lex_kind_open_brace , "'{' open brace" , "{" )\
X(lex_kind_close_brace , "'}' close brace" , "}" )\
X(lex_kind_open_paren , "'(' open parenthesis" , "(" )\
X(lex_kind_close_paren , "')' close parenthesis" , ")" )\
X(lex_kind_open_bracket , "'[' open bracket" , "[" )\
X(lex_kind_close_bracket , "']' close bracket" , "]" )\
X(lex_kind_plus , "'+' plus" , "+" )\
X(lex_kind_minus , "'-' minus" , "-" )\
X(lex_kind_divide , "'/' division sign" , "/" )\
X(lex_kind_multiply , "'*' multiplication sign" , "*" )\
X(lex_kind_modulo , "'%' modulo" , "%" )\
X(lex_kind_or , "'||' logical or" , "||" )\
X(lex_kind_and , "'&&' logical and" , "&&" )\
X(lex_kind_negation , "'!' logical negation" , "!" )\
X(lex_kind_bit_negation , "'~' bit negation" , "~" )\
X(lex_kind_bit_left_shift , "'<<' bit left shift" , "<<" )\
X(lex_kind_bit_right_shift , "'>>' bit right shift" , ">>" )\
X(lex_kind_bit_or , "'|' bit or" , "|" )\
X(lex_kind_bit_and , "'&' bit and" , "&" )\
X(lex_kind_bit_xor , "'^' bit xor" , "^" )\
X(lex_kind_decrement , "'--' decrement" , "--" )\
X(lex_kind_increment , "'++' increment" , "++" )\
X(lex_kind_post_decrement , "'--' post decrement" , "--" )\
X(lex_kind_post_increment , "'++' post increment" , "++" )\
X(lex_kind_assign , "'=' assignment" , "=" )\
X(lex_kind_divide_assign , "'/=' divide assignment" , "/=" )\
X(lex_kind_multiply_assign , "'*=' multiply assignment" , "*=" )\
X(lex_kind_plus_assign , "'+=' plus assignment" , "+=" )\
X(lex_kind_minus_assign , "'-=' minus assignment" , "-=" )\
X(lex_kind_modulo_assign , "'%=' modulo assignment" , "%=" )\
X(lex_kind_bit_and_assign , "'&=' bit and assignment" , "&=" )\
X(lex_kind_bit_or_assign , "'|=' bit or assignment" , "|=" )\
X(lex_kind_bit_xor_assign , "'^=' bit xor assignment" , "^=" )\
X(lex_kind_bit_left_shift_assign , "'<<=' bit left shift assignment" , "<<=" )\
X(lex_kind_bit_right_shift_assign , "'>>=' bit right shift assignment" , ">>=" )\
X(lex_kind_equals , "'==' equals sign" , "==" )\
X(lex_kind_not_equals , "'!=' not equals sign" , "!=" )\
X(lex_kind_lesser , "'<' lesser then" , "<" )\
X(lex_kind_greater , "'>' greater then" , ">" )\
X(lex_kind_lesser_or_equal , "'<=' lesser then or equal" , "<=" )\
X(lex_kind_greater_or_equal , "'>=' greater then or equal" , ">=" )\
X(lex_kind_comma , "',' comma" , "," )\
X(lex_kind_dot , "'.' dot" , "." )\
X(lex_kind_three_dots , "'...' three dots" , "..." )\
X(lex_kind_semicolon , "';' semicolon" , ";" )\
X(lex_kind_colon , "':' colon" , ":" )\
X(lex_kind_arrow , "'->' arrow" , "->" )\
X(lex_kind_question , "'?' question mark" , "?" )\
X(lex_kind_tag , "'@' tag sign" , "@" )\
X(lex_kind_escape , "'\\' escape" , "\\" )\
X(lex_kind_preproc_null , "preproc_null" , "---" )\
X(lex_kind_preproc_define , "preproc_define" , "---" )\
X(lex_kind_preproc_ifdef , "preproc_ifdef" , "---" )\
X(lex_kind_preproc_ifndef , "preproc_ifndef" , "---" )\
X(lex_kind_preproc_include , "preproc_include" , "---" )\
X(lex_kind_preproc_endif , "preproc_endif" , "---" )\
X(lex_kind_preproc_if , "preproc_if" , "---" )\
X(lex_kind_preproc_pragma , "preproc_pragma" , "---" )\
X(lex_kind_preproc_error , "preproc_error" , "---" )\
X(lex_kind_preproc_else , "preproc_else" , "---" )\
X(lex_kind_preproc_elif , "preproc_elif" , "---" )\
X(lex_kind_preproc_undef , "preproc_undef" , "---" )\
X(lex_kind_preproc_concat , "preproc_concat" , "---" )\
X(lex_kind_preproc_stringify , "preproc_stringify" , "---" )\
#define X(KIND, STR, SIMPLE) KIND,
LEX_KIND_XLIST
#undef X
lex_kind_count,
} lex_kind_t;
typedef enum lex_suffix_t {
#define LEX_SUFFIX_XLIST\
X(lex_suffix_none) \
X(lex_suffix_f) \
X(lex_suffix_d) \
X(lex_suffix_u) \
X(lex_suffix_ul) \
X(lex_suffix_ull) \
X(lex_suffix_l) \
X(lex_suffix_ll) \
#define X(KIND) KIND,
LEX_SUFFIX_XLIST
#undef X
lex_suffix_count,
} lex_suffix_t;
typedef struct lex_t lex_t;
struct lex_t {
lex_kind_t kind;
lex_suffix_t suffix;
struct {
b8 inside_macro: 1;
b8 system_include: 1;
};
union {
struct {char *str; i64 len;};
s8_t string;
};
i32 line;
i32 column;
char *file;
union {
u64 integer;
f64 real;
char *error;
};
};
typedef struct lexer_t lexer_t;
struct lexer_t {
char *at;
char *end;
char *file;
i32 line;
i32 column;
b8 inside_macro;
};
typedef struct lex_array_t lex_array_t;
struct lex_array_t {
lex_t *data;
i32 len;
};
fn lex_array_t lex_tokens(ma_arena_t *arena, char *filename, s8_t stream);
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind);
fn s8_t lex_kind_to_s8(lex_kind_t kind);
typedef struct parser_t parser_t;
struct parser_t {
ma_arena_t *arena;
lex_t *at;
b8 print_only_file;
};
#define parser_make(ARENA, TOKEN) &(parser_t){.arena = ARENA, .at = TOKEN}
fn lex_t *parser_next(parser_t *par);
fn lex_t *parser_match(parser_t *par, lex_kind_t kind);
fn lex_t *parser_matchi(parser_t *par, s8_t str);
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind);
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...);
fn void parser_eat_until(parser_t *par, lex_kind_t kind);
fn void parser_eat_including(parser_t *par, lex_kind_t kind);
static gb_read_only lex_t lex_null;
static gb_read_only type_member_t members__lex_kind_t[] = {
#define X(KIND, STR, SIMPLE) {.name = s8_const("lex_kind_" #KIND), .value = KIND},
LEX_KIND_XLIST
#undef X
};
static DEFINE_ENUM(lex_kind_t);
static gb_read_only type_member_t members__lex_suffix_t[] = {
#define X(KIND) {.name = s8_const(#KIND), .value = KIND},
LEX_SUFFIX_XLIST
#undef X
};
static DEFINE_ENUM(lex_suffix_t);
-42
View File
@@ -1,42 +0,0 @@
#include "core_log.h"
#include "core_ctx.h"
#include "core_platform.h"
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, str, string);
tcx->log.log_proc(level, file_and_line, string);
ma_end_scratch(scratch);
}
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string) {
ma_temp_t scratch = ma_begin_scratch();
char *colon = ": ";
if (tcx->log.print_file_and_line == false) {
file_and_line.len = 0;
colon = "";
}
switch(level) {
case log_level_debug:
case log_level_info: {
os_console_log(s8_printf(scratch.arena, "%.*s\n", s8_fmtspec(string)).str);
} break;
case log_level_warning: {
os_console_log(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
if (tcx->log.break_on_warning) debug_break();
} break;
case log_level_error: {
os_console_log(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
if (tcx->log.break_on_error) debug_break();
} break;
case log_level_fatal: {
os_error_box(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
if (tcx->log.break_on_fatal) debug_break();
} break;
default_is_invalid;
}
ma_end_scratch(scratch);
}
-30
View File
@@ -1,30 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_string.h"
typedef enum {
log_level_debug,
log_level_info,
log_level_warning,
log_level_error,
log_level_fatal,
} log_level_t;
typedef struct logger_t logger_t;
struct logger_t {
void (*log_proc)(log_level_t level, s8_t file_and_line, s8_t string);
void *user_data;
b8 break_on_fatal;
b8 break_on_error;
b8 break_on_warning;
b8 print_file_and_line;
};
///////////////////////////////
// main api
#define debugf(...) log_basef(log_level_debug, S8_FILE_AND_LINE, __VA_ARGS__)
#define errorf(...) log_basef(log_level_error, S8_FILE_AND_LINE, __VA_ARGS__)
#define fatalf(...) (log_basef(log_level_fatal, S8_FILE_AND_LINE, __VA_ARGS__), 0)
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string);
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
-555
View File
@@ -1,555 +0,0 @@
#include "core_math.h"
#include "core_intrin.h"
/*
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* also https://gist.github.com/ciembor/1494530
* alpha is ignored
*/
fn v3f32_t v3f32_rgb_to_hsl(v3f32_t color) {
v3f32_t result;
f32 max = MAX(MAX(color.r, color.g), color.b);
f32 min = MIN(MIN(color.r, color.g), color.b);
result.h = result.s = result.l = (max + min) / 2.f;
if (max == min) {
result.h = result.s = 0.f; // achromatic
} else {
f32 d = max - min;
result.s = (result.l > 0.5f) ? d / (2.f - max - min) : d / (max + min);
if (max == color.r) {
result.h = (color.g - color.b) / d + (color.g < color.b ? 6.f : 0.f);
} else if (max == color.g) {
result.h = (color.b - color.r) / d + 2.f;
} else if (max == color.b) {
result.h = (color.r - color.g) / d + 4.f;
}
result.h /= 6.f;
}
return result;
}
/*
* Converts an HUE to r, g or b.
* returns f32 in the set [0, 1].
*/
fn f32 f32_hue_to_rgb(f32 p, f32 q, f32 t) {
if (t < 0.f)
t += 1.f;
if (t > 1.f)
t -= 1.f;
if (t < 1.f / 6.f)
return p + (q - p) * 6.f * t;
if (t < 1.f / 2.f)
return q;
if (t < 2.f / 3.f)
return p + (q - p) * (2.f / 3.f - t) * 6.f;
return p;
}
fn v3f32_t v3f32_hsl_to_rgb(v3f32_t color) {
v3f32_t result;
if (0 == color.s) {
result.r = result.g = result.b = color.l; // achromatic
} else {
f32 q = color.l < 0.5f ? color.l * (1.f + color.s)
: color.l + color.s - color.l * color.s;
f32 p = 2.f * color.l - q;
result.r = f32_hue_to_rgb(p, q, color.h + 1.f / 3.f);
result.g = f32_hue_to_rgb(p, q, color.h);
result.b = f32_hue_to_rgb(p, q, color.h - 1.f / 3.f);
}
return result;
}
fn v4f32_t v4f32_rgba_to_hsla(v4f32_t rgba) {
v3f32_t result = v3f32_rgb_to_hsl(rgba.xyz);
return (v4f32_t){result.r, result.g, result.b, rgba.a};
}
fn v4f32_t v4f32_hsla_to_rgba(v4f32_t color) {
v3f32_t result = v3f32_hsl_to_rgb(color.xyz);
return (v4f32_t){result.r, result.g, result.b, color.a};
}
/*
https://git.musl-libc.org/cgit/musl/tree/src/math
https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
*/
fn f64 f64_clamp01(f64 a) { return CLAMP(a, 0, 1); }
fn f64 f64_lerp(f64 a, f64 b, f64 t) { return (1 - t) * a + t * b; }
fn f64 f64_smooth_step(f64 t) { return t*t*(3-2*t); }
fn f64 f64_ease_in_quint(f64 x) { return x * x * x * x * x; }
fn f64 f64_ease_in_cubic(f64 x) { return x * x * x; }
fn f64 f64_ping_pong(f64 x) { return 1.0 - f64_abs(1.0 - f64_mod(x,2)); }
fn f32 f32_clamp01(f32 a) { return CLAMP(a, 0, 1); }
fn f32 f32_lerp(f32 a, f32 b, f32 t) { return (1 - t) * a + t * b; }
fn f32 f32_smooth_step(f32 t) { return t*t*(3-2*t); }
fn f32 f32_ease_in_quint(f32 x) { return x * x * x * x * x; }
fn f32 f32_ease_in_cubic(f32 x) { return x * x * x; }
fn f32 f32_ping_pong(f32 x) { return 1.0f - f32_abs(1.0f - f32_mod(x,2)); }
fn v4f32_t v4f32_lerp(v4f32_t a, v4f32_t b, f32 t) {
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), f32_lerp(a.w, b.w, t)};
}
fn v4f32_t v4f32_lerp_noa(v4f32_t a, v4f32_t b, f32 t) {
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), a.w};
}
fn f64 _Sine(f64 x) {
// Calculates sin(x) for x in [0, pi/4].
f64 x2 = x * x;
return x * (U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFC5555555555540) + x2 * (U64_TO_F64(0x3F8111111110ED80) + x2 * (U64_TO_F64(0xBF2A01A019AE6000)
+ x2 * (U64_TO_F64(0x3EC71DE349280000) + x2 * (U64_TO_F64(0xBE5AE5DC48000000) + x2 * U64_TO_F64(0x3DE5D68200000000)))))));
}
fn f32 _SineFloat(f32 x) {
// Calculates sin(x) for x in [0, pi/4].
f32 x2 = x * x;
return x * (U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBE2AAAA0) + x2 * (U32_TO_F32(0x3C0882C0) + x2 * U32_TO_F32(0xB94C6000))));
}
fn f64 _ArcSine(f64 x) {
// Calculates arcsin(x) for x in [0, 0.5].
f64 x2 = x * x;
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE6) + x2 * (U64_TO_F64(0x3FC555555555FE00) + x2 * (U64_TO_F64(0x3FB333333292DF90) + x2 * (U64_TO_F64(0x3FA6DB6DFD3693A0)
+ x2 * (U64_TO_F64(0x3F9F1C608DE51900) + x2 * (U64_TO_F64(0x3F96EA0659B9A080) + x2 * (U64_TO_F64(0x3F91B4ABF1029100)
+ x2 * (U64_TO_F64(0x3F8DA8DAF31ECD00) + x2 * (U64_TO_F64(0x3F81C01FD5000C00) + x2 * (U64_TO_F64(0x3F94BDA038CF6B00)
+ x2 * (U64_TO_F64(0xBF8E849CA75B1E00) + x2 * U64_TO_F64(0x3FA146C2D37F2C60))))))))))));
}
fn f32 _ArcSineFloat(f32 x) {
// Calculates arcsin(x) for x in [0, 0.5].
f32 x2 = x * x;
return x * (U32_TO_F32(0x3F800004) + x2 * (U32_TO_F32(0x3E2AA130) + x2 * (U32_TO_F32(0x3D9B2C28) + x2 * (U32_TO_F32(0x3D1C1800) + x2 * U32_TO_F32(0x3D5A97C0)))));
}
fn f64 _ArcTangent(f64 x) {
// Calculates arctan(x) for x in [0, 0.5].
f64 x2 = x * x;
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFF8) + x2 * (U64_TO_F64(0xBFD5555555553B44) + x2 * (U64_TO_F64(0x3FC9999999803988) + x2 * (U64_TO_F64(0xBFC249248C882E80)
+ x2 * (U64_TO_F64(0x3FBC71C5A4E4C220) + x2 * (U64_TO_F64(0xBFB745B3B75243F0) + x2 * (U64_TO_F64(0x3FB3AFAE9A2939E0)
+ x2 * (U64_TO_F64(0xBFB1030C4A4A1B90) + x2 * (U64_TO_F64(0x3FAD6F65C35579A0) + x2 * (U64_TO_F64(0xBFA805BCFDAFEDC0)
+ x2 * (U64_TO_F64(0x3F9FC6B5E115F2C0) + x2 * U64_TO_F64(0xBF87DCA5AB25BF80))))))))))));
}
fn f32 _ArcTangentFloat(f32 x) {
// Calculates arctan(x) for x in [0, 0.5].
f32 x2 = x * x;
return x * (U32_TO_F32(0x3F7FFFF8) + x2 * (U32_TO_F32(0xBEAAA53C) + x2 * (U32_TO_F32(0x3E4BC990) + x2 * (U32_TO_F32(0xBE084A60) + x2 * U32_TO_F32(0x3D8864B0)))));
}
fn f64 _Cosine(f64 x) {
// Calculates cos(x) for x in [0, pi/4].
f64 x2 = x * x;
return U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFDFFFFFFFFFFFA0) + x2 * (U64_TO_F64(0x3FA555555554F7C0) + x2 * (U64_TO_F64(0xBF56C16C16475C00)
+ x2 * (U64_TO_F64(0x3EFA019F87490000) + x2 * (U64_TO_F64(0xBE927DF66B000000) + x2 * U64_TO_F64(0x3E21B949E0000000))))));
}
fn f32 _CosineFloat(f32 x) {
// Calculates cos(x) for x in [0, pi/4].
f32 x2 = x * x;
return U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBEFFFFDA) + x2 * (U32_TO_F32(0x3D2A9F60) + x2 * U32_TO_F32(0xBAB22C00)));
}
fn f64 _Tangent(f64 x) {
// Calculates tan(x) for x in [0, pi/4].
f64 x2 = x * x;
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE8) + x2 * (U64_TO_F64(0x3FD5555555558000) + x2 * (U64_TO_F64(0x3FC1111110FACF90) + x2 * (U64_TO_F64(0x3FABA1BA266BFD20)
+ x2 * (U64_TO_F64(0x3F9664F30E56E580) + x2 * (U64_TO_F64(0x3F822703B08BDC00) + x2 * (U64_TO_F64(0x3F6D698D2E4A4C00)
+ x2 * (U64_TO_F64(0x3F57FF4F23EA4400) + x2 * (U64_TO_F64(0x3F424F3BEC845800) + x2 * (U64_TO_F64(0x3F34C78CA9F61000)
+ x2 * (U64_TO_F64(0xBF042089F8510000) + x2 * (U64_TO_F64(0x3F29D7372D3A8000) + x2 * (U64_TO_F64(0xBF19D1C5EF6F0000)
+ x2 * (U64_TO_F64(0x3F0980BDF11E8000)))))))))))))));
}
fn f32 _TangentFloat(f32 x) {
// Calculates tan(x) for x in [0, pi/4].
f32 x2 = x * x;
return x * (U32_TO_F32(0x3F800001) + x2 * (U32_TO_F32(0x3EAAA9AA) + x2 * (U32_TO_F32(0x3E08ABA8) + x2 * (U32_TO_F32(0x3D58EC90)
+ x2 * (U32_TO_F32(0x3CD24840) + x2 * (U32_TO_F32(0x3AC3CA00) + x2 * U32_TO_F32(0x3C272F00)))))));
}
fn f64 f64_sin(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = true;
}
// x in 0, infty
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
// x in 0, 2*pi
if (x < F64_PI / 2) {
} else if (x < F64_PI) {
x = F64_PI - x;
} else if (x < 3 * F64_PI / 2) {
x = x - F64_PI;
negate = !negate;
} else {
x = F64_PI * 2 - x;
negate = !negate;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Sine(x) : _Cosine(F64_PI / 2 - x);
return negate ? -y : y;
}
fn f32 f32_sin(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = true;
}
// x in 0, infty
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
// x in 0, 2*pi
if (x < F32_PI / 2) {
} else if (x < F32_PI) {
x = F32_PI - x;
} else if (x < 3 * F32_PI / 2) {
x = x - F32_PI;
negate = !negate;
} else {
x = F32_PI * 2 - x;
negate = !negate;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _SineFloat(x) : _CosineFloat(F32_PI / 2 - x);
return negate ? -y : y;
}
fn f64 f64_cos(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
}
// x in 0, infty
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
// x in 0, 2*pi
if (x < F64_PI / 2) {
} else if (x < F64_PI) {
x = F64_PI - x;
negate = !negate;
} else if (x < 3 * F64_PI / 2) {
x = x - F64_PI;
negate = !negate;
} else {
x = F64_PI * 2 - x;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Cosine(x) : _Sine(F64_PI / 2 - x);
return negate ? -y : y;
}
fn f32 f32_cos(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
}
// x in 0, infty
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
// x in 0, 2*pi
if (x < F32_PI / 2) {
} else if (x < F32_PI) {
x = F32_PI - x;
negate = !negate;
} else if (x < 3 * F32_PI / 2) {
x = x - F32_PI;
negate = !negate;
} else {
x = F32_PI * 2 - x;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _CosineFloat(x) : _SineFloat(F32_PI / 2 - x);
return negate ? -y : y;
}
fn f64 f64_tan(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = !negate;
}
// x in 0, infty
x -= F64_PI * f64_floor(x / F64_PI);
// x in 0, pi
if (x > F64_PI / 2) {
x = F64_PI - x;
negate = !negate;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Tangent(x) : (1.0 / _Tangent(F64_PI / 2 - x));
return negate ? -y : y;
}
fn f32 f32_tan(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = !negate;
}
// x in 0, infty
x -= F32_PI * f32_floor(x / F32_PI);
// x in 0, pi
if (x > F32_PI / 2) {
x = F32_PI - x;
negate = !negate;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _TangentFloat(x) : (1.0f / _TangentFloat(F32_PI / 2 - x));
return negate ? -y : y;
}
fn f64 f64_asin(f64 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
f64 y;
if (x < 0.5) {
y = _ArcSine(x);
} else {
y = F64_PI / 2 - 2 * _ArcSine(f64_sqrt(0.5 - 0.5 * x));
}
return negate ? -y : y;
}
fn f32 f32_asin(f32 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
f32 y;
if (x < 0.5) {
y = _ArcSineFloat(x);
} else {
y = F32_PI / 2 - 2 * _ArcSineFloat(f32_sqrt(0.5f - 0.5f * x));
}
return negate ? -y : y;
}
fn f64 f64_acos(f64 x) {
return f64_asin(-x) + F64_PI / 2;
}
fn f32 f32_acos(f32 x) {
return f32_asin(-x) + F32_PI / 2;
}
fn f64 f64_atan(f64 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
b32 reciprocalTaken = false;
if (x > 1) {
x = 1 / x;
reciprocalTaken = true;
}
f64 y;
if (x < 0.5) {
y = _ArcTangent(x);
} else {
y = 0.463647609000806116 + _ArcTangent((2 * x - 1) / (2 + x));
}
if (reciprocalTaken) {
y = F64_PI / 2 - y;
}
return negate ? -y : y;
}
fn f32 f32_atan(f32 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
b32 reciprocalTaken = false;
if (x > 1) {
x = 1 / x;
reciprocalTaken = true;
}
f32 y;
if (x < 0.5f) {
y = _ArcTangentFloat(x);
} else {
y = 0.463647609000806116f + _ArcTangentFloat((2 * x - 1) / (2 + x));
}
if (reciprocalTaken) {
y = F32_PI / 2 - y;
}
return negate ? -y : y;
}
fn f64 f64_atan2(f64 y, f64 x) {
if (x == 0) return y > 0 ? F64_PI / 2 : -F64_PI / 2;
else if (x > 0) return f64_atan(y / x);
else if (y >= 0) return F64_PI + f64_atan(y / x);
else return -F64_PI + f64_atan(y / x);
}
fn f32 f32_atan2(f32 y, f32 x) {
if (x == 0) return y > 0 ? F32_PI / 2 : -F32_PI / 2;
else if (x > 0) return f32_atan(y / x);
else if (y >= 0) return F32_PI + f32_atan(y / x);
else return -F32_PI + f32_atan(y / x);
}
fn b32 f32_are_equal(f32 a, f32 b) {
f32 diff = f32_abs(a - b);
b32 result = diff <= 0.00001f;
return result;
}
fn b32 f64_are_equal(f64 a, f64 b) {
f64 diff = f64_abs(a - b);
b32 result = diff <= 0.00001;
return result;
}
fn f32 f32_ease_out_bounce(f32 x) {
f32 n1 = 7.5625f;
f32 d1 = 2.75f;
if (x < 1.f / d1) {
return n1 * x * x;
} else if (x < 2.f / d1) {
return n1 * (x -= 1.5f / d1) * x + 0.75f;
} else if (x < 2.5f / d1) {
return n1 * (x -= 2.25f / d1) * x + 0.9375f;
} else {
return n1 * (x -= 2.625f / d1) * x + 0.984375f;
}
}
fn f32 f32_ease_out_elastic(f32 x) {
f32 c4 = (2 * F32_PI) / 3;
return x == 0.f
? 0
: x == 1.f
? 1
: f32_pow(2.f, -10.f * x) * f32_sin((x * 10.f - 0.75f) * c4) + 1.f;
}
fn f32 f32_ease_out_cubic(f32 x) {
return 1.f - f32_pow(1.f - x, 3.f);
}
fn f32 f32_ease_out_n(f32 x, f32 n) {
return 1.f - f32_pow(1.f - x, n);
}
fn r2f32_t r2f32_lerp(r2f32_t a, r2f32_t b, f32 t) {
r2f32_t result = { .min = {f32_lerp(a.min.x, b.min.x, t), f32_lerp(a.min.y, b.min.y, t)}, .max = {f32_lerp(a.max.x, b.max.x, t), f32_lerp(a.max.y, b.max.y, t)} };
return result;
}
-959
View File
@@ -1,959 +0,0 @@
#include "core_math.h"
#include "core_intrin.h"
fn_inline v2f32_t v2f32(f32 x, f32 y) { return (v2f32_t){ x, y }; }
gb_read_only v2f32_t v2f32_null = {0};
fn_inline b32 v2f32_is_null(v2f32_t a) { return memory_equal(&a, &v2f32_null, sizeof(a)); }
fn_inline b32 v2f32_are_equal(v2f32_t a, v2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v2f32_t v2f32_add(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x + b.x, a.y + b.y }; }
fn_inline v2f32_t v2f32_adds(v2f32_t a, f32 b) { return (v2f32_t){ a.x + b, a.y + b }; }
fn_inline v2f32_t v2f32_sub(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x - b.x, a.y - b.y }; }
fn_inline v2f32_t v2f32_subs(v2f32_t a, f32 b) { return (v2f32_t){ a.x - b, a.y - b }; }
fn_inline v2f32_t v2f32_mul(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x * b.x, a.y * b.y }; }
fn_inline v2f32_t v2f32_muls(v2f32_t a, f32 b) { return (v2f32_t){ a.x * b, a.y * b }; }
fn_inline v2f32_t v2f32_div(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x / b.x, a.y / b.y }; }
fn_inline v2f32_t v2f32_divs(v2f32_t a, f32 b) { return (v2f32_t){ a.x / b, a.y / b }; }
fn_inline v3f32_t v3f32(f32 x, f32 y, f32 z) { return (v3f32_t){ x, y, z }; }
gb_read_only v3f32_t v3f32_null = {0};
fn_inline b32 v3f32_is_null(v3f32_t a) { return memory_equal(&a, &v3f32_null, sizeof(a)); }
fn_inline b32 v3f32_are_equal(v3f32_t a, v3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v3f32_t v3f32_add(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
fn_inline v3f32_t v3f32_adds(v3f32_t a, f32 b) { return (v3f32_t){ a.x + b, a.y + b, a.z + b }; }
fn_inline v3f32_t v3f32_sub(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
fn_inline v3f32_t v3f32_subs(v3f32_t a, f32 b) { return (v3f32_t){ a.x - b, a.y - b, a.z - b }; }
fn_inline v3f32_t v3f32_mul(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
fn_inline v3f32_t v3f32_muls(v3f32_t a, f32 b) { return (v3f32_t){ a.x * b, a.y * b, a.z * b }; }
fn_inline v3f32_t v3f32_div(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
fn_inline v3f32_t v3f32_divs(v3f32_t a, f32 b) { return (v3f32_t){ a.x / b, a.y / b, a.z / b }; }
fn_inline v4f32_t v4f32(f32 x, f32 y, f32 z, f32 w) { return (v4f32_t){ x, y, z, w }; }
gb_read_only v4f32_t v4f32_null = {0};
fn_inline b32 v4f32_is_null(v4f32_t a) { return memory_equal(&a, &v4f32_null, sizeof(a)); }
fn_inline b32 v4f32_are_equal(v4f32_t a, v4f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v4f32_t v4f32_add(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
fn_inline v4f32_t v4f32_adds(v4f32_t a, f32 b) { return (v4f32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
fn_inline v4f32_t v4f32_sub(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
fn_inline v4f32_t v4f32_subs(v4f32_t a, f32 b) { return (v4f32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
fn_inline v4f32_t v4f32_mul(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
fn_inline v4f32_t v4f32_muls(v4f32_t a, f32 b) { return (v4f32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
fn_inline v4f32_t v4f32_div(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
fn_inline v4f32_t v4f32_divs(v4f32_t a, f32 b) { return (v4f32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
fn_inline r2f32_t r2f32(f32 x0, f32 y0, f32 x1, f32 y1) { return (r2f32_t){ x0, y0, x1, y1 }; }
gb_read_only r2f32_t r2f32_null = {0};
fn_inline b32 r2f32_is_null(r2f32_t a) { return memory_equal(&a, &r2f32_null, sizeof(a)); }
fn_inline b32 r2f32_are_equal(r2f32_t a, r2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r2f32_t r2f32_add(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
fn_inline r2f32_t r2f32_adds(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
fn_inline r2f32_t r2f32_sub(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
fn_inline r2f32_t r2f32_subs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
fn_inline r2f32_t r2f32_mul(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
fn_inline r2f32_t r2f32_muls(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
fn_inline r2f32_t r2f32_div(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
fn_inline r2f32_t r2f32_divs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
fn_inline r3f32_t r3f32(f32 x0, f32 y0, f32 z0, f32 x1, f32 y1, f32 z1) { return (r3f32_t){ x0, y0, z0, x1, y1, z1 }; }
gb_read_only r3f32_t r3f32_null = {0};
fn_inline b32 r3f32_is_null(r3f32_t a) { return memory_equal(&a, &r3f32_null, sizeof(a)); }
fn_inline b32 r3f32_are_equal(r3f32_t a, r3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r3f32_t r3f32_add(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
fn_inline r3f32_t r3f32_adds(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
fn_inline r3f32_t r3f32_sub(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
fn_inline r3f32_t r3f32_subs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
fn_inline r3f32_t r3f32_mul(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
fn_inline r3f32_t r3f32_muls(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
fn_inline r3f32_t r3f32_div(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
fn_inline r3f32_t r3f32_divs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
fn_inline v2f64_t v2f64(f64 x, f64 y) { return (v2f64_t){ x, y }; }
gb_read_only v2f64_t v2f64_null = {0};
fn_inline b32 v2f64_is_null(v2f64_t a) { return memory_equal(&a, &v2f64_null, sizeof(a)); }
fn_inline b32 v2f64_are_equal(v2f64_t a, v2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v2f64_t v2f64_add(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x + b.x, a.y + b.y }; }
fn_inline v2f64_t v2f64_adds(v2f64_t a, f64 b) { return (v2f64_t){ a.x + b, a.y + b }; }
fn_inline v2f64_t v2f64_sub(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x - b.x, a.y - b.y }; }
fn_inline v2f64_t v2f64_subs(v2f64_t a, f64 b) { return (v2f64_t){ a.x - b, a.y - b }; }
fn_inline v2f64_t v2f64_mul(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x * b.x, a.y * b.y }; }
fn_inline v2f64_t v2f64_muls(v2f64_t a, f64 b) { return (v2f64_t){ a.x * b, a.y * b }; }
fn_inline v2f64_t v2f64_div(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x / b.x, a.y / b.y }; }
fn_inline v2f64_t v2f64_divs(v2f64_t a, f64 b) { return (v2f64_t){ a.x / b, a.y / b }; }
fn_inline v3f64_t v3f64(f64 x, f64 y, f64 z) { return (v3f64_t){ x, y, z }; }
gb_read_only v3f64_t v3f64_null = {0};
fn_inline b32 v3f64_is_null(v3f64_t a) { return memory_equal(&a, &v3f64_null, sizeof(a)); }
fn_inline b32 v3f64_are_equal(v3f64_t a, v3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v3f64_t v3f64_add(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
fn_inline v3f64_t v3f64_adds(v3f64_t a, f64 b) { return (v3f64_t){ a.x + b, a.y + b, a.z + b }; }
fn_inline v3f64_t v3f64_sub(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
fn_inline v3f64_t v3f64_subs(v3f64_t a, f64 b) { return (v3f64_t){ a.x - b, a.y - b, a.z - b }; }
fn_inline v3f64_t v3f64_mul(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
fn_inline v3f64_t v3f64_muls(v3f64_t a, f64 b) { return (v3f64_t){ a.x * b, a.y * b, a.z * b }; }
fn_inline v3f64_t v3f64_div(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
fn_inline v3f64_t v3f64_divs(v3f64_t a, f64 b) { return (v3f64_t){ a.x / b, a.y / b, a.z / b }; }
fn_inline v4f64_t v4f64(f64 x, f64 y, f64 z, f64 w) { return (v4f64_t){ x, y, z, w }; }
gb_read_only v4f64_t v4f64_null = {0};
fn_inline b32 v4f64_is_null(v4f64_t a) { return memory_equal(&a, &v4f64_null, sizeof(a)); }
fn_inline b32 v4f64_are_equal(v4f64_t a, v4f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v4f64_t v4f64_add(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
fn_inline v4f64_t v4f64_adds(v4f64_t a, f64 b) { return (v4f64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
fn_inline v4f64_t v4f64_sub(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
fn_inline v4f64_t v4f64_subs(v4f64_t a, f64 b) { return (v4f64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
fn_inline v4f64_t v4f64_mul(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
fn_inline v4f64_t v4f64_muls(v4f64_t a, f64 b) { return (v4f64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
fn_inline v4f64_t v4f64_div(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
fn_inline v4f64_t v4f64_divs(v4f64_t a, f64 b) { return (v4f64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
fn_inline r2f64_t r2f64(f64 x0, f64 y0, f64 x1, f64 y1) { return (r2f64_t){ x0, y0, x1, y1 }; }
gb_read_only r2f64_t r2f64_null = {0};
fn_inline b32 r2f64_is_null(r2f64_t a) { return memory_equal(&a, &r2f64_null, sizeof(a)); }
fn_inline b32 r2f64_are_equal(r2f64_t a, r2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r2f64_t r2f64_add(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
fn_inline r2f64_t r2f64_adds(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
fn_inline r2f64_t r2f64_sub(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
fn_inline r2f64_t r2f64_subs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
fn_inline r2f64_t r2f64_mul(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
fn_inline r2f64_t r2f64_muls(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
fn_inline r2f64_t r2f64_div(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
fn_inline r2f64_t r2f64_divs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
fn_inline r3f64_t r3f64(f64 x0, f64 y0, f64 z0, f64 x1, f64 y1, f64 z1) { return (r3f64_t){ x0, y0, z0, x1, y1, z1 }; }
gb_read_only r3f64_t r3f64_null = {0};
fn_inline b32 r3f64_is_null(r3f64_t a) { return memory_equal(&a, &r3f64_null, sizeof(a)); }
fn_inline b32 r3f64_are_equal(r3f64_t a, r3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r3f64_t r3f64_add(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
fn_inline r3f64_t r3f64_adds(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
fn_inline r3f64_t r3f64_sub(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
fn_inline r3f64_t r3f64_subs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
fn_inline r3f64_t r3f64_mul(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
fn_inline r3f64_t r3f64_muls(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
fn_inline r3f64_t r3f64_div(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
fn_inline r3f64_t r3f64_divs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
fn_inline v2i32_t v2i32(i32 x, i32 y) { return (v2i32_t){ x, y }; }
gb_read_only v2i32_t v2i32_null = {0};
fn_inline b32 v2i32_is_null(v2i32_t a) { return memory_equal(&a, &v2i32_null, sizeof(a)); }
fn_inline b32 v2i32_are_equal(v2i32_t a, v2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v2i32_t v2i32_add(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x + b.x, a.y + b.y }; }
fn_inline v2i32_t v2i32_adds(v2i32_t a, i32 b) { return (v2i32_t){ a.x + b, a.y + b }; }
fn_inline v2i32_t v2i32_sub(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x - b.x, a.y - b.y }; }
fn_inline v2i32_t v2i32_subs(v2i32_t a, i32 b) { return (v2i32_t){ a.x - b, a.y - b }; }
fn_inline v2i32_t v2i32_mul(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x * b.x, a.y * b.y }; }
fn_inline v2i32_t v2i32_muls(v2i32_t a, i32 b) { return (v2i32_t){ a.x * b, a.y * b }; }
fn_inline v2i32_t v2i32_div(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x / b.x, a.y / b.y }; }
fn_inline v2i32_t v2i32_divs(v2i32_t a, i32 b) { return (v2i32_t){ a.x / b, a.y / b }; }
fn_inline v3i32_t v3i32(i32 x, i32 y, i32 z) { return (v3i32_t){ x, y, z }; }
gb_read_only v3i32_t v3i32_null = {0};
fn_inline b32 v3i32_is_null(v3i32_t a) { return memory_equal(&a, &v3i32_null, sizeof(a)); }
fn_inline b32 v3i32_are_equal(v3i32_t a, v3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v3i32_t v3i32_add(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
fn_inline v3i32_t v3i32_adds(v3i32_t a, i32 b) { return (v3i32_t){ a.x + b, a.y + b, a.z + b }; }
fn_inline v3i32_t v3i32_sub(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
fn_inline v3i32_t v3i32_subs(v3i32_t a, i32 b) { return (v3i32_t){ a.x - b, a.y - b, a.z - b }; }
fn_inline v3i32_t v3i32_mul(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
fn_inline v3i32_t v3i32_muls(v3i32_t a, i32 b) { return (v3i32_t){ a.x * b, a.y * b, a.z * b }; }
fn_inline v3i32_t v3i32_div(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
fn_inline v3i32_t v3i32_divs(v3i32_t a, i32 b) { return (v3i32_t){ a.x / b, a.y / b, a.z / b }; }
fn_inline v4i32_t v4i32(i32 x, i32 y, i32 z, i32 w) { return (v4i32_t){ x, y, z, w }; }
gb_read_only v4i32_t v4i32_null = {0};
fn_inline b32 v4i32_is_null(v4i32_t a) { return memory_equal(&a, &v4i32_null, sizeof(a)); }
fn_inline b32 v4i32_are_equal(v4i32_t a, v4i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v4i32_t v4i32_add(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
fn_inline v4i32_t v4i32_adds(v4i32_t a, i32 b) { return (v4i32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
fn_inline v4i32_t v4i32_sub(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
fn_inline v4i32_t v4i32_subs(v4i32_t a, i32 b) { return (v4i32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
fn_inline v4i32_t v4i32_mul(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
fn_inline v4i32_t v4i32_muls(v4i32_t a, i32 b) { return (v4i32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
fn_inline v4i32_t v4i32_div(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
fn_inline v4i32_t v4i32_divs(v4i32_t a, i32 b) { return (v4i32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
fn_inline r2i32_t r2i32(i32 x0, i32 y0, i32 x1, i32 y1) { return (r2i32_t){ x0, y0, x1, y1 }; }
gb_read_only r2i32_t r2i32_null = {0};
fn_inline b32 r2i32_is_null(r2i32_t a) { return memory_equal(&a, &r2i32_null, sizeof(a)); }
fn_inline b32 r2i32_are_equal(r2i32_t a, r2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r2i32_t r2i32_add(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
fn_inline r2i32_t r2i32_adds(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
fn_inline r2i32_t r2i32_sub(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
fn_inline r2i32_t r2i32_subs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
fn_inline r2i32_t r2i32_mul(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
fn_inline r2i32_t r2i32_muls(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
fn_inline r2i32_t r2i32_div(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
fn_inline r2i32_t r2i32_divs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
fn_inline r3i32_t r3i32(i32 x0, i32 y0, i32 z0, i32 x1, i32 y1, i32 z1) { return (r3i32_t){ x0, y0, z0, x1, y1, z1 }; }
gb_read_only r3i32_t r3i32_null = {0};
fn_inline b32 r3i32_is_null(r3i32_t a) { return memory_equal(&a, &r3i32_null, sizeof(a)); }
fn_inline b32 r3i32_are_equal(r3i32_t a, r3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r3i32_t r3i32_add(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
fn_inline r3i32_t r3i32_adds(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
fn_inline r3i32_t r3i32_sub(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
fn_inline r3i32_t r3i32_subs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
fn_inline r3i32_t r3i32_mul(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
fn_inline r3i32_t r3i32_muls(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
fn_inline r3i32_t r3i32_div(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
fn_inline r3i32_t r3i32_divs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
fn_inline v2i64_t v2i64(i64 x, i64 y) { return (v2i64_t){ x, y }; }
gb_read_only v2i64_t v2i64_null = {0};
fn_inline b32 v2i64_is_null(v2i64_t a) { return memory_equal(&a, &v2i64_null, sizeof(a)); }
fn_inline b32 v2i64_are_equal(v2i64_t a, v2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v2i64_t v2i64_add(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x + b.x, a.y + b.y }; }
fn_inline v2i64_t v2i64_adds(v2i64_t a, i64 b) { return (v2i64_t){ a.x + b, a.y + b }; }
fn_inline v2i64_t v2i64_sub(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x - b.x, a.y - b.y }; }
fn_inline v2i64_t v2i64_subs(v2i64_t a, i64 b) { return (v2i64_t){ a.x - b, a.y - b }; }
fn_inline v2i64_t v2i64_mul(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x * b.x, a.y * b.y }; }
fn_inline v2i64_t v2i64_muls(v2i64_t a, i64 b) { return (v2i64_t){ a.x * b, a.y * b }; }
fn_inline v2i64_t v2i64_div(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x / b.x, a.y / b.y }; }
fn_inline v2i64_t v2i64_divs(v2i64_t a, i64 b) { return (v2i64_t){ a.x / b, a.y / b }; }
fn_inline v3i64_t v3i64(i64 x, i64 y, i64 z) { return (v3i64_t){ x, y, z }; }
gb_read_only v3i64_t v3i64_null = {0};
fn_inline b32 v3i64_is_null(v3i64_t a) { return memory_equal(&a, &v3i64_null, sizeof(a)); }
fn_inline b32 v3i64_are_equal(v3i64_t a, v3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v3i64_t v3i64_add(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
fn_inline v3i64_t v3i64_adds(v3i64_t a, i64 b) { return (v3i64_t){ a.x + b, a.y + b, a.z + b }; }
fn_inline v3i64_t v3i64_sub(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
fn_inline v3i64_t v3i64_subs(v3i64_t a, i64 b) { return (v3i64_t){ a.x - b, a.y - b, a.z - b }; }
fn_inline v3i64_t v3i64_mul(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
fn_inline v3i64_t v3i64_muls(v3i64_t a, i64 b) { return (v3i64_t){ a.x * b, a.y * b, a.z * b }; }
fn_inline v3i64_t v3i64_div(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
fn_inline v3i64_t v3i64_divs(v3i64_t a, i64 b) { return (v3i64_t){ a.x / b, a.y / b, a.z / b }; }
fn_inline v4i64_t v4i64(i64 x, i64 y, i64 z, i64 w) { return (v4i64_t){ x, y, z, w }; }
gb_read_only v4i64_t v4i64_null = {0};
fn_inline b32 v4i64_is_null(v4i64_t a) { return memory_equal(&a, &v4i64_null, sizeof(a)); }
fn_inline b32 v4i64_are_equal(v4i64_t a, v4i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline v4i64_t v4i64_add(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
fn_inline v4i64_t v4i64_adds(v4i64_t a, i64 b) { return (v4i64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
fn_inline v4i64_t v4i64_sub(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
fn_inline v4i64_t v4i64_subs(v4i64_t a, i64 b) { return (v4i64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
fn_inline v4i64_t v4i64_mul(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
fn_inline v4i64_t v4i64_muls(v4i64_t a, i64 b) { return (v4i64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
fn_inline v4i64_t v4i64_div(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
fn_inline v4i64_t v4i64_divs(v4i64_t a, i64 b) { return (v4i64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
fn_inline r2i64_t r2i64(i64 x0, i64 y0, i64 x1, i64 y1) { return (r2i64_t){ x0, y0, x1, y1 }; }
gb_read_only r2i64_t r2i64_null = {0};
fn_inline b32 r2i64_is_null(r2i64_t a) { return memory_equal(&a, &r2i64_null, sizeof(a)); }
fn_inline b32 r2i64_are_equal(r2i64_t a, r2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r2i64_t r2i64_add(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
fn_inline r2i64_t r2i64_adds(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
fn_inline r2i64_t r2i64_sub(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
fn_inline r2i64_t r2i64_subs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
fn_inline r2i64_t r2i64_mul(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
fn_inline r2i64_t r2i64_muls(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
fn_inline r2i64_t r2i64_div(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
fn_inline r2i64_t r2i64_divs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
fn_inline r3i64_t r3i64(i64 x0, i64 y0, i64 z0, i64 x1, i64 y1, i64 z1) { return (r3i64_t){ x0, y0, z0, x1, y1, z1 }; }
gb_read_only r3i64_t r3i64_null = {0};
fn_inline b32 r3i64_is_null(r3i64_t a) { return memory_equal(&a, &r3i64_null, sizeof(a)); }
fn_inline b32 r3i64_are_equal(r3i64_t a, r3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
fn_inline r3i64_t r3i64_add(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
fn_inline r3i64_t r3i64_adds(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
fn_inline r3i64_t r3i64_sub(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
fn_inline r3i64_t r3i64_subs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
fn_inline r3i64_t r3i64_mul(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
fn_inline r3i64_t r3i64_muls(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
fn_inline r3i64_t r3i64_div(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
fn_inline r3i64_t r3i64_divs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
fn_inline r2f32_t r2f32_min_dim(v2f32_t pos, v2f32_t size) { return (r2f32_t){ pos, v2f32_add(pos, size) }; }
fn_inline r2f32_t r2f32_center_half_dim(v2f32_t center, v2f32_t halfdim) { return (r2f32_t){ v2f32_sub(center, halfdim), v2f32_add(center, halfdim) }; }
fn_inline r3f32_t r3f32_min_dim(v3f32_t pos, v3f32_t size) { return (r3f32_t){ pos, v3f32_add(pos, size) }; }
fn_inline r3f32_t r3f32_center_half_dim(v3f32_t center, v3f32_t halfdim) { return (r3f32_t){ v3f32_sub(center, halfdim), v3f32_add(center, halfdim) }; }
fn_inline r2f64_t r2f64_min_dim(v2f64_t pos, v2f64_t size) { return (r2f64_t){ pos, v2f64_add(pos, size) }; }
fn_inline r2f64_t r2f64_center_half_dim(v2f64_t center, v2f64_t halfdim) { return (r2f64_t){ v2f64_sub(center, halfdim), v2f64_add(center, halfdim) }; }
fn_inline r3f64_t r3f64_min_dim(v3f64_t pos, v3f64_t size) { return (r3f64_t){ pos, v3f64_add(pos, size) }; }
fn_inline r3f64_t r3f64_center_half_dim(v3f64_t center, v3f64_t halfdim) { return (r3f64_t){ v3f64_sub(center, halfdim), v3f64_add(center, halfdim) }; }
fn_inline r2i32_t r2i32_min_dim(v2i32_t pos, v2i32_t size) { return (r2i32_t){ pos, v2i32_add(pos, size) }; }
fn_inline r2i32_t r2i32_center_half_dim(v2i32_t center, v2i32_t halfdim) { return (r2i32_t){ v2i32_sub(center, halfdim), v2i32_add(center, halfdim) }; }
fn_inline r3i32_t r3i32_min_dim(v3i32_t pos, v3i32_t size) { return (r3i32_t){ pos, v3i32_add(pos, size) }; }
fn_inline r3i32_t r3i32_center_half_dim(v3i32_t center, v3i32_t halfdim) { return (r3i32_t){ v3i32_sub(center, halfdim), v3i32_add(center, halfdim) }; }
fn_inline r2i64_t r2i64_min_dim(v2i64_t pos, v2i64_t size) { return (r2i64_t){ pos, v2i64_add(pos, size) }; }
fn_inline r2i64_t r2i64_center_half_dim(v2i64_t center, v2i64_t halfdim) { return (r2i64_t){ v2i64_sub(center, halfdim), v2i64_add(center, halfdim) }; }
fn_inline r3i64_t r3i64_min_dim(v3i64_t pos, v3i64_t size) { return (r3i64_t){ pos, v3i64_add(pos, size) }; }
fn_inline r3i64_t r3i64_center_half_dim(v3i64_t center, v3i64_t halfdim) { return (r3i64_t){ v3i64_sub(center, halfdim), v3i64_add(center, halfdim) }; }
fn r2f32_t r2f32_cut_left(r2f32_t *r, f32 value) {
f32 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f32_t r2f32_cut_right(r2f32_t *r, f32 value) {
f32 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f32_t r2f32_cut_top(r2f32_t *r, f32 value) { /* Y is down */
f32 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f32_t r2f32_cut_bottom(r2f32_t *r, f32 value) { /* Y is down */
f32 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f32_t r2f32_cut_left_no_squash(r2f32_t *r, f32 value) {
f32 minx = r->min.x;
r->min.x = r->min.x + value;
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f32_t r2f32_cut_right_no_squash(r2f32_t *r, f32 value) {
f32 maxx = r->max.x;
r->max.x = r->max.x - value;
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f32_t r2f32_cut_top_no_squash(r2f32_t *r, f32 value) { /* Y is down */
f32 miny = r->min.y;
r->min.y = r->min.y + value;
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f32_t r2f32_cut_bottom_no_squash(r2f32_t *r, f32 value) { /* Y is down */
f32 maxy = r->max.y;
r->max.y = r->max.y - value;
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f32_t r2f32_add_left(r2f32_t *r, f32 value) {
r2f32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
r->min.x -= value;
return result;
}
fn r2f32_t r2f32_add_right(r2f32_t *r, f32 value) {
r2f32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
r->max.x += value;
return result;
}
fn r2f32_t r2f32_add_top(r2f32_t *r, f32 value) {
r2f32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
r->min.y -= value;
return result;
}
fn r2f32_t r2f32_add_bottom(r2f32_t *r, f32 value) {
r2f32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
r->max.y += value;
return result;
}
// get past left
fn r2f32_t r2f32_getp_left(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
fn r2f32_t r2f32_getp_right(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
fn r2f32_t r2f32_getp_bottom(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
fn r2f32_t r2f32_getp_top(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
fn r2f32_t r2f32_get_left(const r2f32_t *r, f32 value) {
f32 minx = r->min.x;
r2f32_t result = (r2f32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
fn r2f32_t r2f32_get_right(const r2f32_t *r, f32 value) {
f32 maxx = r->max.x;
r2f32_t result = (r2f32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f32_t r2f32_get_top(const r2f32_t *r, f32 value) { /* Y is down */
f32 miny = r->min.y;
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
fn r2f32_t r2f32_get_bottom(const r2f32_t *r, f32 value) { /* Y is down */
f32 maxy = r->max.y;
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn_inline r2f32_t r2f32_expand(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_sub(rect.min, value), v2f32_add(rect.max, value) }; }
fn_inline r2f32_t r2f32_shrink(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_add(rect.min, value), v2f32_sub(rect.max, value) }; }
fn_inline r2f32_t r2f32_shrinks(r2f32_t rect, f32 value) { return (r2f32_t){ v2f32_adds(rect.min, value), v2f32_subs(rect.max, value) }; }
fn_inline v2f32_t r2f32_size(r2f32_t r) { return (v2f32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
fn_inline v2f32_t r2f32_get_mid(r2f32_t r) { return v2f32_add(r.min, v2f32_divs(r2f32_size(r), 2)); }
fn_inline b32 r2f32_contains(r2f32_t rec, v2f32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
fn_inline r2f32_t r2f32_intersect(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
fn_inline r2f32_t r2f32_union(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
fn_inline f32 r1f32_size(r1f32_t a) { return a.max - a.min; }
fn_inline r1f32_t r1f32(f32 min, f32 max) { return (r1f32_t){min,max}; }
fn_inline r1f32_t r1f32_auto(f32 a, f32 b) { return (r1f32_t){MIN(a,b),MAX(a,b)}; }
fn_inline r1f32_t r1f32s(f32 a) { return (r1f32_t){a,a}; }
fn_inline r1f32_t r1f32_clamp(r1f32_t a, f32 min, f32 max) { return (r1f32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
fn_inline b32 r1f32_contains(r1f32_t rec, f32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
fn_inline b32 r1f32_are_equal(r1f32_t a, r1f32_t b) { return a.min == b.min && a.max == b.max; }
gb_read_only r1f32_t r1f32_null;
fn b32 r1f32_overlap(r1f32_t a, r1f32_t b) {
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
fn v2f32_t v2f32_clamps(v2f32_t v, f32 min, f32 max) {
v2f32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
return result;
}
fn v2f32_t v2f32_clamp(v2f32_t v, v2f32_t min, v2f32_t max) {
v2f32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
return result;
}
fn r2f32_t r2f32_fix(r2f32_t n) {
r2f32_t result = {
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
};
return result;
}
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = r->min.x + value;
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = r->max.x - value;
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = r->min.y + value;
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = r->max.y - value;
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
r->min.x -= value;
return result;
}
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
r->max.x += value;
return result;
}
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
r->min.y -= value;
return result;
}
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
r->max.y += value;
return result;
}
// get past left
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
gb_read_only r1f64_t r1f64_null;
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
return result;
}
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
return result;
}
fn r2f64_t r2f64_fix(r2f64_t n) {
r2f64_t result = {
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
};
return result;
}
fn r2i32_t r2i32_cut_left(r2i32_t *r, i32 value) {
i32 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2i32_t r2i32_cut_right(r2i32_t *r, i32 value) {
i32 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i32_t r2i32_cut_top(r2i32_t *r, i32 value) { /* Y is down */
i32 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2i32_t r2i32_cut_bottom(r2i32_t *r, i32 value) { /* Y is down */
i32 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2i32_t r2i32_cut_left_no_squash(r2i32_t *r, i32 value) {
i32 minx = r->min.x;
r->min.x = r->min.x + value;
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2i32_t r2i32_cut_right_no_squash(r2i32_t *r, i32 value) {
i32 maxx = r->max.x;
r->max.x = r->max.x - value;
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i32_t r2i32_cut_top_no_squash(r2i32_t *r, i32 value) { /* Y is down */
i32 miny = r->min.y;
r->min.y = r->min.y + value;
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2i32_t r2i32_cut_bottom_no_squash(r2i32_t *r, i32 value) { /* Y is down */
i32 maxy = r->max.y;
r->max.y = r->max.y - value;
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2i32_t r2i32_add_left(r2i32_t *r, i32 value) {
r2i32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
r->min.x -= value;
return result;
}
fn r2i32_t r2i32_add_right(r2i32_t *r, i32 value) {
r2i32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
r->max.x += value;
return result;
}
fn r2i32_t r2i32_add_top(r2i32_t *r, i32 value) {
r2i32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
r->min.y -= value;
return result;
}
fn r2i32_t r2i32_add_bottom(r2i32_t *r, i32 value) {
r2i32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
r->max.y += value;
return result;
}
// get past left
fn r2i32_t r2i32_getp_left(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
fn r2i32_t r2i32_getp_right(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
fn r2i32_t r2i32_getp_bottom(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
fn r2i32_t r2i32_getp_top(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
fn r2i32_t r2i32_get_left(const r2i32_t *r, i32 value) {
i32 minx = r->min.x;
r2i32_t result = (r2i32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
fn r2i32_t r2i32_get_right(const r2i32_t *r, i32 value) {
i32 maxx = r->max.x;
r2i32_t result = (r2i32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i32_t r2i32_get_top(const r2i32_t *r, i32 value) { /* Y is down */
i32 miny = r->min.y;
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
fn r2i32_t r2i32_get_bottom(const r2i32_t *r, i32 value) { /* Y is down */
i32 maxy = r->max.y;
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn_inline r2i32_t r2i32_expand(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_sub(rect.min, value), v2i32_add(rect.max, value) }; }
fn_inline r2i32_t r2i32_shrink(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_add(rect.min, value), v2i32_sub(rect.max, value) }; }
fn_inline r2i32_t r2i32_shrinks(r2i32_t rect, i32 value) { return (r2i32_t){ v2i32_adds(rect.min, value), v2i32_subs(rect.max, value) }; }
fn_inline v2i32_t r2i32_size(r2i32_t r) { return (v2i32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
fn_inline v2i32_t r2i32_get_mid(r2i32_t r) { return v2i32_add(r.min, v2i32_divs(r2i32_size(r), 2)); }
fn_inline b32 r2i32_contains(r2i32_t rec, v2i32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
fn_inline r2i32_t r2i32_intersect(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
fn_inline r2i32_t r2i32_union(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
fn_inline i32 r1i32_size(r1i32_t a) { return a.max - a.min; }
fn_inline r1i32_t r1i32(i32 min, i32 max) { return (r1i32_t){min,max}; }
fn_inline r1i32_t r1i32_auto(i32 a, i32 b) { return (r1i32_t){MIN(a,b),MAX(a,b)}; }
fn_inline r1i32_t r1i32s(i32 a) { return (r1i32_t){a,a}; }
fn_inline r1i32_t r1i32_clamp(r1i32_t a, i32 min, i32 max) { return (r1i32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
fn_inline b32 r1i32_contains(r1i32_t rec, i32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
fn_inline b32 r1i32_are_equal(r1i32_t a, r1i32_t b) { return a.min == b.min && a.max == b.max; }
gb_read_only r1i32_t r1i32_null;
fn b32 r1i32_overlap(r1i32_t a, r1i32_t b) {
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
fn v2i32_t v2i32_clamps(v2i32_t v, i32 min, i32 max) {
v2i32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
return result;
}
fn v2i32_t v2i32_clamp(v2i32_t v, v2i32_t min, v2i32_t max) {
v2i32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
return result;
}
fn r2i32_t r2i32_fix(r2i32_t n) {
r2i32_t result = {
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
};
return result;
}
fn r2i64_t r2i64_cut_left(r2i64_t *r, i64 value) {
i64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2i64_t r2i64_cut_right(r2i64_t *r, i64 value) {
i64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i64_t r2i64_cut_top(r2i64_t *r, i64 value) { /* Y is down */
i64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2i64_t r2i64_cut_bottom(r2i64_t *r, i64 value) { /* Y is down */
i64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2i64_t r2i64_cut_left_no_squash(r2i64_t *r, i64 value) {
i64 minx = r->min.x;
r->min.x = r->min.x + value;
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2i64_t r2i64_cut_right_no_squash(r2i64_t *r, i64 value) {
i64 maxx = r->max.x;
r->max.x = r->max.x - value;
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i64_t r2i64_cut_top_no_squash(r2i64_t *r, i64 value) { /* Y is down */
i64 miny = r->min.y;
r->min.y = r->min.y + value;
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2i64_t r2i64_cut_bottom_no_squash(r2i64_t *r, i64 value) { /* Y is down */
i64 maxy = r->max.y;
r->max.y = r->max.y - value;
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2i64_t r2i64_add_left(r2i64_t *r, i64 value) {
r2i64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
r->min.x -= value;
return result;
}
fn r2i64_t r2i64_add_right(r2i64_t *r, i64 value) {
r2i64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
r->max.x += value;
return result;
}
fn r2i64_t r2i64_add_top(r2i64_t *r, i64 value) {
r2i64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
r->min.y -= value;
return result;
}
fn r2i64_t r2i64_add_bottom(r2i64_t *r, i64 value) {
r2i64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
r->max.y += value;
return result;
}
// get past left
fn r2i64_t r2i64_getp_left(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
fn r2i64_t r2i64_getp_right(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
fn r2i64_t r2i64_getp_bottom(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
fn r2i64_t r2i64_getp_top(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
fn r2i64_t r2i64_get_left(const r2i64_t *r, i64 value) {
i64 minx = r->min.x;
r2i64_t result = (r2i64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
fn r2i64_t r2i64_get_right(const r2i64_t *r, i64 value) {
i64 maxx = r->max.x;
r2i64_t result = (r2i64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2i64_t r2i64_get_top(const r2i64_t *r, i64 value) { /* Y is down */
i64 miny = r->min.y;
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
fn r2i64_t r2i64_get_bottom(const r2i64_t *r, i64 value) { /* Y is down */
i64 maxy = r->max.y;
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn_inline r2i64_t r2i64_expand(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_sub(rect.min, value), v2i64_add(rect.max, value) }; }
fn_inline r2i64_t r2i64_shrink(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_add(rect.min, value), v2i64_sub(rect.max, value) }; }
fn_inline r2i64_t r2i64_shrinks(r2i64_t rect, i64 value) { return (r2i64_t){ v2i64_adds(rect.min, value), v2i64_subs(rect.max, value) }; }
fn_inline v2i64_t r2i64_size(r2i64_t r) { return (v2i64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
fn_inline v2i64_t r2i64_get_mid(r2i64_t r) { return v2i64_add(r.min, v2i64_divs(r2i64_size(r), 2)); }
fn_inline b32 r2i64_contains(r2i64_t rec, v2i64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
fn_inline r2i64_t r2i64_intersect(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
fn_inline r2i64_t r2i64_union(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
fn_inline i64 r1i64_size(r1i64_t a) { return a.max - a.min; }
fn_inline r1i64_t r1i64(i64 min, i64 max) { return (r1i64_t){min,max}; }
fn_inline r1i64_t r1i64_auto(i64 a, i64 b) { return (r1i64_t){MIN(a,b),MAX(a,b)}; }
fn_inline r1i64_t r1i64s(i64 a) { return (r1i64_t){a,a}; }
fn_inline r1i64_t r1i64_clamp(r1i64_t a, i64 min, i64 max) { return (r1i64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
fn_inline b32 r1i64_contains(r1i64_t rec, i64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
fn_inline b32 r1i64_are_equal(r1i64_t a, r1i64_t b) { return a.min == b.min && a.max == b.max; }
gb_read_only r1i64_t r1i64_null;
fn b32 r1i64_overlap(r1i64_t a, r1i64_t b) {
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
fn v2i64_t v2i64_clamps(v2i64_t v, i64 min, i64 max) {
v2i64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
return result;
}
fn v2i64_t v2i64_clamp(v2i64_t v, v2i64_t min, v2i64_t max) {
v2i64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
return result;
}
fn r2i64_t r2i64_fix(r2i64_t n) {
r2i64_t result = {
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
};
return result;
}
fn_inline v2f64_t v2f32_to_v2f64(v2f32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
fn_inline v3f64_t v3f32_to_v3f64(v3f32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
fn_inline v4f64_t v4f32_to_v4f64(v4f32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
fn_inline r2f64_t r2f32_to_r2f64(r2f32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
fn_inline r3f64_t r3f32_to_r3f64(r3f32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
fn_inline v2i32_t v2f32_to_v2i32(v2f32_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
fn_inline v3i32_t v3f32_to_v3i32(v3f32_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
fn_inline v4i32_t v4f32_to_v4i32(v4f32_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
fn_inline r2i32_t r2f32_to_r2i32(r2f32_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
fn_inline r3i32_t r3f32_to_r3i32(r3f32_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
fn_inline v2i64_t v2f32_to_v2i64(v2f32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
fn_inline v3i64_t v3f32_to_v3i64(v3f32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
fn_inline v4i64_t v4f32_to_v4i64(v4f32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
fn_inline r2i64_t r2f32_to_r2i64(r2f32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
fn_inline r3i64_t r3f32_to_r3i64(r3f32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
fn_inline v2f32_t v2f64_to_v2f32(v2f64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
fn_inline v3f32_t v3f64_to_v3f32(v3f64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
fn_inline v4f32_t v4f64_to_v4f32(v4f64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
fn_inline r2f32_t r2f64_to_r2f32(r2f64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
fn_inline r3f32_t r3f64_to_r3f32(r3f64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
fn_inline v2i32_t v2f64_to_v2i32(v2f64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
fn_inline v3i32_t v3f64_to_v3i32(v3f64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
fn_inline v4i32_t v4f64_to_v4i32(v4f64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
fn_inline r2i32_t r2f64_to_r2i32(r2f64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
fn_inline r3i32_t r3f64_to_r3i32(r3f64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
fn_inline v2i64_t v2f64_to_v2i64(v2f64_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
fn_inline v3i64_t v3f64_to_v3i64(v3f64_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
fn_inline v4i64_t v4f64_to_v4i64(v4f64_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
fn_inline r2i64_t r2f64_to_r2i64(r2f64_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
fn_inline r3i64_t r3f64_to_r3i64(r3f64_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
fn_inline v2f32_t v2i32_to_v2f32(v2i32_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
fn_inline v3f32_t v3i32_to_v3f32(v3i32_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
fn_inline v4f32_t v4i32_to_v4f32(v4i32_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
fn_inline r2f32_t r2i32_to_r2f32(r2i32_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
fn_inline r3f32_t r3i32_to_r3f32(r3i32_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
fn_inline v2f64_t v2i32_to_v2f64(v2i32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
fn_inline v3f64_t v3i32_to_v3f64(v3i32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
fn_inline v4f64_t v4i32_to_v4f64(v4i32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
fn_inline r2f64_t r2i32_to_r2f64(r2i32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
fn_inline r3f64_t r3i32_to_r3f64(r3i32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
fn_inline v2i64_t v2i32_to_v2i64(v2i32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
fn_inline v3i64_t v3i32_to_v3i64(v3i32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
fn_inline v4i64_t v4i32_to_v4i64(v4i32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
fn_inline r2i64_t r2i32_to_r2i64(r2i32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
fn_inline r3i64_t r3i32_to_r3i64(r3i32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
fn_inline v2f32_t v2i64_to_v2f32(v2i64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
fn_inline v3f32_t v3i64_to_v3f32(v3i64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
fn_inline v4f32_t v4i64_to_v4f32(v4i64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
fn_inline r2f32_t r2i64_to_r2f32(r2i64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
fn_inline r3f32_t r3i64_to_r3f32(r3i64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
fn_inline v2f64_t v2i64_to_v2f64(v2i64_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
fn_inline v3f64_t v3i64_to_v3f64(v3i64_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
fn_inline v4f64_t v4i64_to_v4f64(v4i64_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
fn_inline r2f64_t r2i64_to_r2f64(r2i64_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
fn_inline r3f64_t r3i64_to_r3f64(r3i64_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
fn_inline v2i32_t v2i64_to_v2i32(v2i64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
fn_inline v3i32_t v3i64_to_v3i32(v3i64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
fn_inline v4i32_t v4i64_to_v4i32(v4i64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
fn_inline r2i32_t r2i64_to_r2i32(r2i64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
fn_inline r3i32_t r3i64_to_r3i32(r3i64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
fn_inline r2f32_t r2f32_add_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_add(a.min, b), v2f32_add(a.max, b) }; }
fn_inline r2f32_t r2f32_sub_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_sub(a.min, b), v2f32_sub(a.max, b) }; }
fn_inline r2f32_t r2f32_mul_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_mul(a.min, b), v2f32_mul(a.max, b) }; }
fn_inline r2f32_t r2f32_div_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_div(a.min, b), v2f32_div(a.max, b) }; }
fn_inline r2f64_t r2f64_add_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_add(a.min, b), v2f64_add(a.max, b) }; }
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
fn_inline r2f64_t r2f64_mul_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_mul(a.min, b), v2f64_mul(a.max, b) }; }
fn_inline r2f64_t r2f64_div_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_div(a.min, b), v2f64_div(a.max, b) }; }
fn_inline r2i32_t r2i32_add_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_add(a.min, b), v2i32_add(a.max, b) }; }
fn_inline r2i32_t r2i32_sub_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_sub(a.min, b), v2i32_sub(a.max, b) }; }
fn_inline r2i32_t r2i32_mul_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_mul(a.min, b), v2i32_mul(a.max, b) }; }
fn_inline r2i32_t r2i32_div_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_div(a.min, b), v2i32_div(a.max, b) }; }
fn_inline r2i64_t r2i64_add_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_add(a.min, b), v2i64_add(a.max, b) }; }
fn_inline r2i64_t r2i64_sub_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_sub(a.min, b), v2i64_sub(a.max, b) }; }
fn_inline r2i64_t r2i64_mul_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_mul(a.min, b), v2i64_mul(a.max, b) }; }
fn_inline r2i64_t r2i64_div_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_div(a.min, b), v2i64_div(a.max, b) }; }
fn f32 f32_safe_ratio(f32 a, f32 b, f32 if0) {
f32 result = if0;
if (b != 0.0) {
result = a / b;
}
return result;
}
fn_inline f32 f32_safe_ratio0(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
fn_inline f32 f32_safe_ratio1(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
f64 result = if0;
if (b != 0.0) {
result = a / b;
}
return result;
}
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
-215
View File
@@ -1,215 +0,0 @@
#pragma once
#include "core_basic.h"
typedef union v2f32_t v2f32_t;
union v2f32_t {
struct { f32 x, y; };
f32 e[2];
};
typedef union v3f32_t v3f32_t;
union v3f32_t {
struct { f32 x, y, z; };
struct { v2f32_t xy; };
struct { f32 _x0; v2f32_t zw; };
struct { f32 r, g, b; };
struct { f32 h, s, l; };
f32 e[3];
};
typedef union v4f32_t v4f32_t;
union v4f32_t {
struct { f32 x, y, z, w; };
struct { v2f32_t xy; v2f32_t zw; };
struct { v3f32_t xyz; };
struct { f32 _x0; f32 yzw; };
struct { f32 r, g, b, a; };
struct { f32 h, s, l, _a; };
f32 e[4];
};
typedef union r1f32_t r1f32_t;
union r1f32_t {
struct { f32 min, max; };
struct { f32 x0, x1; };
f32 e[2];
};
typedef union r2f32_t r2f32_t;
union r2f32_t {
struct { v2f32_t min, max; };
struct { f32 x0, y0, x1, y1; };
v4f32_t e4;
f32 e[4];
};
typedef union r3f32_t r3f32_t;
union r3f32_t {
struct { v3f32_t min, max; };
struct { f32 x0, y0, z0, x1, y1, z1; };
f32 e[6];
};
typedef union v2f64_t v2f64_t;
union v2f64_t {
struct { f64 x, y; };
f64 e[2];
};
typedef union v3f64_t v3f64_t;
union v3f64_t {
struct { f64 x, y, z; };
struct { v2f64_t xy; };
struct { f64 _x0; v2f64_t zw; };
struct { f64 r, g, b; };
struct { f64 h, s, l; };
f64 e[3];
};
typedef union v4f64_t v4f64_t;
union v4f64_t {
struct { f64 x, y, z, w; };
struct { v2f64_t xy; v2f64_t zw; };
struct { v3f64_t xyz; };
struct { f64 _x0; f64 yzw; };
struct { f64 r, g, b, a; };
struct { f64 h, s, l, _a; };
f64 e[4];
};
typedef union r1f64_t r1f64_t;
union r1f64_t {
struct { f64 min, max; };
struct { f64 x0, x1; };
f64 e[2];
};
typedef union r2f64_t r2f64_t;
union r2f64_t {
struct { v2f64_t min, max; };
struct { f64 x0, y0, x1, y1; };
v4f64_t e4;
f64 e[4];
};
typedef union r3f64_t r3f64_t;
union r3f64_t {
struct { v3f64_t min, max; };
struct { f64 x0, y0, z0, x1, y1, z1; };
f64 e[6];
};
typedef union v2i32_t v2i32_t;
union v2i32_t {
struct { i32 x, y; };
i32 e[2];
};
typedef union v3i32_t v3i32_t;
union v3i32_t {
struct { i32 x, y, z; };
struct { v2i32_t xy; };
struct { i32 _x0; v2i32_t zw; };
struct { i32 r, g, b; };
struct { i32 h, s, l; };
i32 e[3];
};
typedef union v4i32_t v4i32_t;
union v4i32_t {
struct { i32 x, y, z, w; };
struct { v2i32_t xy; v2i32_t zw; };
struct { v3i32_t xyz; };
struct { i32 _x0; i32 yzw; };
struct { i32 r, g, b, a; };
struct { i32 h, s, l, _a; };
i32 e[4];
};
typedef union r1i32_t r1i32_t;
union r1i32_t {
struct { i32 min, max; };
struct { i32 x0, x1; };
i32 e[2];
};
typedef union r2i32_t r2i32_t;
union r2i32_t {
struct { v2i32_t min, max; };
struct { i32 x0, y0, x1, y1; };
v4i32_t e4;
i32 e[4];
};
typedef union r3i32_t r3i32_t;
union r3i32_t {
struct { v3i32_t min, max; };
struct { i32 x0, y0, z0, x1, y1, z1; };
i32 e[6];
};
typedef union v2i64_t v2i64_t;
union v2i64_t {
struct { i64 x, y; };
i64 e[2];
};
typedef union v3i64_t v3i64_t;
union v3i64_t {
struct { i64 x, y, z; };
struct { v2i64_t xy; };
struct { i64 _x0; v2i64_t zw; };
struct { i64 r, g, b; };
struct { i64 h, s, l; };
i64 e[3];
};
typedef union v4i64_t v4i64_t;
union v4i64_t {
struct { i64 x, y, z, w; };
struct { v2i64_t xy; v2i64_t zw; };
struct { v3i64_t xyz; };
struct { i64 _x0; i64 yzw; };
struct { i64 r, g, b, a; };
struct { i64 h, s, l, _a; };
i64 e[4];
};
typedef union r1i64_t r1i64_t;
union r1i64_t {
struct { i64 min, max; };
struct { i64 x0, x1; };
i64 e[2];
};
typedef union r2i64_t r2i64_t;
union r2i64_t {
struct { v2i64_t min, max; };
struct { i64 x0, y0, x1, y1; };
v4i64_t e4;
i64 e[4];
};
typedef union r3i64_t r3i64_t;
union r3i64_t {
struct { v3i64_t min, max; };
struct { i64 x0, y0, z0, x1, y1, z1; };
i64 e[6];
};
#define F64_PI (3.1415926535897932384626433832795028841971693994)
#define F64_DEG2RAD (F64_PI / 180.0); // @Usage: degree * DEG2RAD = radians;
#define F64_RAD2DEG (180.0 / F64_PI);
#define F32_PI ((f32)F64_PI)
#define v4f32_const_rgba255(r, g, b, a) { (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
#define v4f32_rgba255(r, g, b, a) (v4f32_t){ (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
static gb_read_only v4f32_t white_color = v4f32_const_rgba255(255, 255, 255, 255);
static gb_read_only v4f32_t black_color = v4f32_const_rgba255(0, 0, 0, 255);
static gb_read_only v4f32_t magenta_color = v4f32_const_rgba255(255, 0, 255, 255);
static gb_read_only v4f32_t red_color = v4f32_const_rgba255(255, 0, 0, 255);
static gb_read_only v4f32_t blue_color = v4f32_const_rgba255(0, 0, 255, 255);
-406
View File
@@ -1,406 +0,0 @@
import sys
op_idx = 0
opname_idx = 1
symbols = [
["+", "add"],
["-", "sub"],
["*", "mul"],
["/", "div"],
]
basic_types = [
"f32",
"f64",
"i32",
"i64",
]
name_idx = 0
member_idx = 1
vec_types = [
["v2", ["x", "y"]],
["v3", ["x", "y", "z"]],
["v4", ["x", "y", "z", "w"]],
]
rect_types = [
["r2", ["x0", "y0", "x1", "y1"]],
["r3", ["x0", "y0", "z0", "x1", "y1", "z1"]],
]
struct_types = vec_types + rect_types
# fd = open("core_math.gen.h", "w")
# sys.stdout = fd
# print("// auto generated using:", __file__)
# for bt in basic_types:
# s = """
# typedef union v2f64_t v2f64_t;
# union v2f64_t {
# struct { f64 x, y; };
# f64 e[2];
# };
# typedef union v3f64_t v3f64_t;
# union v3f64_t {
# struct { f64 x, y, z; };
# struct { v2f64_t xy; };
# struct { f64 _x0; v2f64_t zw; };
# struct { f64 r, g, b; };
# struct { f64 h, s, l; };
# f64 e[3];
# };
# typedef union v4f64_t v4f64_t;
# union v4f64_t {
# struct { f64 x, y, z, w; };
# struct { v2f64_t xy; v2f64_t zw; };
# struct { v3f64_t xyz; };
# struct { f64 _x0; f64 yzw; };
# struct { f64 r, g, b, a; };
# struct { f64 h, s, l, _a; };
# f64 e[4];
# };
# typedef union r1f64_t r1f64_t;
# union r1f64_t {
# struct { f64 min, max; };
# struct { f64 x0, x1; };
# f64 e[2];
# };
# typedef union r2f64_t r2f64_t;
# union r2f64_t {
# struct { v2f64_t min, max; };
# struct { f64 x0, y0, x1, y1; };
# v4f64_t e4;
# f64 e[4];
# };
# typedef union r3f64_t r3f64_t;
# union r3f64_t {
# struct { v3f64_t min, max; };
# struct { f64 x0, y0, z0, x1, y1, z1; };
# f64 e[6];
# };
#
#
# type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
# .members = (type_member_t[]){
# {s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
# {s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
# }
# };
# type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
# .members = (type_member_t[]){
# {s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
# {s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
# {s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
# }
# };
# type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
# .members = (type_member_t[]){
# {s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
# {s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
# {s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
# {s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
# }
# };
# type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
# .members = (type_member_t[]){
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
# {s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
# {s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
# }
# };
# type_member_t members__r2f64_t[] = {
# {s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
# {s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
# {s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
# {s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
# };
# DEFINE_STRUCT(r2f64_t);
# type_member_t members__r1f64_t[] = {
# {s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
# {s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
# };
# DEFINE_STRUCT(r1f64_t);
# """
# s = s.replace("f64", bt)
# print(s)
fd = open("core_math.gen.c", "w", newline = "\n", encoding = "utf-8")
sys.stdout = fd
for basic_type in basic_types:
for st in struct_types:
type = f"{st[name_idx]}{basic_type}"
typedef = f"{type}_t"
members = st[member_idx]
def members_as_func_params(members, basic_type):
result = ""
for i, m in enumerate(members):
result += f"{basic_type} {m}"
if i != len(members) - 1:
result += ", "
return result
print(f"""fn_inline {type}_t {type}({members_as_func_params(members, basic_type)}) {{ return ({type}_t){{ {members_as_func_params(members, "")} }}; }}""")
print(f"""gb_read_only {type}_t {type}_null = {{0}};""")
print(f"""fn_inline b32 {type}_is_null({type}_t a) {{ return memory_equal(&a, &{type}_null, sizeof(a)); }}""")
print(f"""fn_inline b32 {type}_are_equal({type}_t a, {type}_t b) {{ return memory_equal(&a, &b, sizeof(a)); }}""")
for sym in symbols:
op = sym[op_idx]
opname = sym[opname_idx]
def op_str(members, op, skip_right = False):
result = ""
for i in range(len(members)):
mem = members[i]
if skip_right:
result += f"a.{mem} {op} b"
else:
result += f"a.{mem} {op} b.{mem}"
if i != len(members) - 1:
result += ", "
return result
print(f"fn_inline {type}_t {type}_{opname}({type}_t a, {type}_t b) {{ return ({type}_t){{ {op_str(members, op)} }}; }}")
print(f"fn_inline {type}_t {type}_{opname}s({type}_t a, {basic_type} b) {{ return ({type}_t){{ {op_str(members, op, skip_right = True)} }}; }}")
for basic_type in basic_types:
for i in range(len(rect_types)):
vec_type = vec_types[i]
rect_type = rect_types[i]
vec_name = vec_type[name_idx] + basic_type
vec_members = vec_type[member_idx]
rect_name = rect_type[name_idx] + basic_type
rect_members = rect_type[member_idx]
print(f"fn_inline {rect_name}_t {rect_name}_min_dim({vec_name}_t pos, {vec_name}_t size) {{ return ({rect_name}_t){{ pos, {vec_name}_add(pos, size) }}; }}")
print(f"fn_inline {rect_name}_t {rect_name}_center_half_dim({vec_name}_t center, {vec_name}_t halfdim) {{ return ({rect_name}_t){{ {vec_name}_sub(center, halfdim), {vec_name}_add(center, halfdim) }}; }}")
for basic_type in basic_types:
s = """
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = r->min.x + value;
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = r->max.x - value;
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = r->min.y + value;
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
return result;
}
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = r->max.y - value;
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
r->min.x -= value;
return result;
}
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
r->max.x += value;
return result;
}
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
r->min.y -= value;
return result;
}
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
r->max.y += value;
return result;
}
// get past left
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
gb_read_only r1f64_t r1f64_null;
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
return r1 || r2;
}
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
return result;
}
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
return result;
}
fn r2f64_t r2f64_fix(r2f64_t n) {
r2f64_t result = {
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
};
return result;
}
""".strip()
s = s.replace("f64", basic_type)
print(s)
for at in basic_types:
for bt in basic_types:
if at == bt: continue
for st in struct_types:
atype = f"{st[name_idx]}{at}"
btype = f"{st[name_idx]}{bt}"
members = st[member_idx]
def cast_members(members, type):
result = ""
for i in range(len(members)):
result += f"({type})v.{members[i]}"
if i != len(members) - 1:
result += ", "
return result
print(f"fn_inline {btype}_t {atype}_to_{btype}({atype}_t v) {{ return ({btype}_t){{ {cast_members(members, bt)} }}; }}")
#######
# generate r2f64_sub_v2f64 for +-*/ and types
for bt in basic_types:
for sym in symbols:
word_op = sym[1]
s = """
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
""".strip()
s = s.replace("f64", bt)
s = s.replace("sub", word_op)
print(s)
for bt in ["f32", "f64"]:
s = """
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
f64 result = if0;
if (b != 0.0) {
result = a / b;
}
return result;
}
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
""".strip()
s = s.replace("f64", bt)
print(s)
-613
View File
@@ -1,613 +0,0 @@
#include "core_platform.h"
#include "core_ctx.h"
#include "stb_sprintf.h"
#if PLATFORM_WASM && PLATFORM_EMSCRIPTEN == 0
#define gb_wasm_export __attribute__((visibility("default")))
#define fn_export __attribute__((visibility("default")))
#define fn_wasm_import
fn_wasm_import void wasm_alert(isize ptr, i32 len);
fn_wasm_import f64 wasm_parse_float(isize str, i32 len);
fn_wasm_import void wasm_write_to_console(isize str, i32 len);
fn_wasm_import void wasm_trap(void);
extern char __heap_base;
fn void *os_vmem_reserve(usize size) {
unused(size);
return NULL;
}
fn b32 os_vmem_commit(void *p, usize size) {
unused(p);
unused(size);
return false;
}
fn b32 os_vmem_release(void *p) {
unused(p);
return true;
}
fn b32 os_vmem_decommit(void *p, usize size) {
unused(p);
unused(size);
return true;
}
fn void os_error_box(char *str) {
wasm_alert((isize)str, str_len(str));
}
fn void os_console_log(char *str) {
s8_t string = s8_from_char(str);
if (s8_ends_with(string, s8("\n"))) {
string = s8_chop(string, 1);
}
wasm_write_to_console((isize)string.str, (i32)string.len);
}
fn f64 os_parse_float(char *str) {
return wasm_parse_float((isize)str, str_len((char *)str));
}
fn void os_core_small_init(ma_arena_t *arena) {
tcx = ma_push_type(arena, thread_ctx_t);
tcx->log.break_on_error = true;
tcx->log.break_on_fatal = true;
tcx->log.break_on_warning = true;
tcx->log.print_file_and_line = true;
tcx->log.log_proc = default_log_proc;
}
fn void os_core_init(void) {
ma_arena_t perm = {0};
isize page_size = kib(64);
isize page_count = __builtin_wasm_memory_size(0);
u8 *memory = (u8 *)&__heap_base;
usize memory_size = page_count * (page_size) - (isize)memory;
perm.data = memory;
perm.commit = perm.reserve = memory_size;
os_core_small_init(&perm);
tcx->perm = perm;
ma_push_arena_ex(&tcx->perm, &tcx->temp, mib(64));
ma_push_arena_ex(&tcx->perm, &tcx->scratch[0], mib(2));
ma_push_arena_ex(&tcx->perm, &tcx->scratch[1], kib(256));
ma_push_arena_ex(&tcx->perm, &tcx->scratch[2], kib(64));
debugf("memory size = %lld", memory_size);
}
#elif PLATFORM_WINDOWS
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "DbgHelp.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Ole32.lib")
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <DbgHelp.h>
#include <TlHelp32.h>
#include <Shlobj.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
typedef struct b_stacktrace_tag* b_stacktrace_handle;
/*
Returns a stack-trace handle from the point of view of the caller which
can be expanded to a string via b_stacktrace_to_string.
The handle is allocated with `malloc` and needs to be freed with `free`
*/
fn b_stacktrace_handle b_stacktrace_get();
/*
Converts a stack-trace handle to a human-readable string.
The string is allocated with `malloc` and needs to be freed with `free`
*/
fn char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
/*
Returns a human-readable stack-trace string from the point of view of the
caller.
The string is allocated with `malloc` and needs to be freed with `free`
*/
fn char* b_stacktrace_get_string(void);
/* version */
typedef struct print_buf {
char* buf;
int pos;
int size;
} print_buf;
static print_buf buf_init(void) {
print_buf ret = {
(char*) malloc(1024),
0,
1024
};
return ret;
}
static void buf_printf(print_buf* b, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
const int len = stbsp_vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args);
const int new_end = b->pos + len;
if (new_end > b->size) {
while (new_end > b->size) b->size *= 2;
b->buf = (char*)realloc(b->buf, b->size);
}
va_start(args, fmt);
b->pos += stbsp_vsnprintf(b->buf + b->pos, len, fmt, args);
va_end(args);
}
char* b_stacktrace_get_string(void) {
b_stacktrace_handle h = b_stacktrace_get();
char* ret = b_stacktrace_to_string(h);
free(h);
return ret;
}
#define B_STACKTRACE_MAX_DEPTH 1024
#define B_STACKTRACE_ERROR_FLAG ((DWORD64)1 << 63)
typedef struct b_stacktrace_entry {
DWORD64 AddrPC_Offset;
DWORD64 AddrReturn_Offset;
} b_stacktrace_entry;
static int SymInitialize_called = 0;
b_stacktrace_handle b_stacktrace_get(void) {
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context;
STACKFRAME64 frame; /* in/out stackframe */
DWORD imageType;
b_stacktrace_entry* ret = (b_stacktrace_entry*)malloc(B_STACKTRACE_MAX_DEPTH * sizeof(b_stacktrace_entry));
int i = 0;
if (!SymInitialize_called) {
SymInitialize(process, NULL, TRUE);
SymInitialize_called = 1;
}
RtlCaptureContext(&context);
memset(&frame, 0, sizeof(frame));
#ifdef _M_IX86
imageType = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = context.Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Esp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
imageType = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = context.Rip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Rsp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Rsp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
imageType = IMAGE_FILE_MACHINE_IA64;
frame.AddrPC.Offset = context.StIIP;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.IntSp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrBStore.Offset = context.RsBSP;
frame.AddrBStore.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.IntSp;
frame.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif
while (1) {
b_stacktrace_entry* cur = ret + i++;
if (i == B_STACKTRACE_MAX_DEPTH) {
cur->AddrPC_Offset = 0;
cur->AddrReturn_Offset = 0;
break;
}
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
cur->AddrPC_Offset = frame.AddrPC.Offset;
cur->AddrReturn_Offset = B_STACKTRACE_ERROR_FLAG; /* mark error */
cur->AddrReturn_Offset |= GetLastError();
break;
}
cur->AddrPC_Offset = frame.AddrPC.Offset;
cur->AddrReturn_Offset = frame.AddrReturn.Offset;
if (frame.AddrReturn.Offset == 0) {
break;
}
}
return (b_stacktrace_handle)(ret);
}
char* b_stacktrace_to_string(b_stacktrace_handle h) {
const b_stacktrace_entry* entries = (b_stacktrace_entry*)h;
int i = 0;
HANDLE process = GetCurrentProcess();
print_buf out = buf_init();
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + 1024);
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol->MaxNameLength = 1024;
while (1) {
IMAGEHLP_LINE64 lineData;
DWORD lineOffset = 0;
DWORD64 symOffset = 0;
const b_stacktrace_entry* cur = entries + i++;
if (cur->AddrReturn_Offset & B_STACKTRACE_ERROR_FLAG) {
DWORD error = cur->AddrReturn_Offset & 0xFFFFFFFF;
buf_printf(&out, "StackWalk64 error: %d @ %p\n", error, cur->AddrPC_Offset);
break;
}
if (cur->AddrPC_Offset == cur->AddrReturn_Offset) {
buf_printf(&out, "Stack overflow @ %p\n", cur->AddrPC_Offset);
break;
}
SymGetLineFromAddr64(process, cur->AddrPC_Offset, &lineOffset, &lineData);
buf_printf(&out, "%s(%d): ", lineData.FileName, lineData.LineNumber);
if (SymGetSymFromAddr64(process, cur->AddrPC_Offset, &symOffset, symbol)) {
buf_printf(&out, "%s\n", symbol->Name);
}
else {
buf_printf(&out, " Unkown symbol @ %p\n", cur->AddrPC_Offset);
}
if (cur->AddrReturn_Offset == 0) {
break;
}
}
free(symbol);
return out.buf;
}
fn void *os_vmem_reserve(usize size) {
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
fn b32 os_vmem_commit(void *p, usize size) {
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
return result ? true : false;
}
fn b32 os_vmem_release(void *p) {
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
return result ? true : false;
}
fn b32 os_vmem_decommit(void *p, usize size) {
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
return result ? true : false;
}
fn void os_error_box(char *str) {
OutputDebugStringA(str);
fprintf(stderr, "%s", str);
fflush(stderr);
MessageBoxA(NULL, str, "fatal error", MB_OK);
}
fn void os_console_log(char *str) {
OutputDebugStringA(str);
fputs(str, stdout);
fflush(stdout);
}
fn f64 os_parse_float(char *str) {
return strtod(str, NULL);
}
fn void os_win32_crash_handler(int signal) {
printf("signal: %d\n", signal);
puts(b_stacktrace_get_string());
exit(1);
}
fn void os_win32_register_crash_handler() {
signal(SIGSEGV, os_win32_crash_handler);
signal(SIGABRT, os_win32_crash_handler);
}
fn void os_core_small_init(ma_arena_t *arena) {
tcx = ma_push_type(arena, thread_ctx_t);
tcx->log.break_on_error = true;
tcx->log.break_on_fatal = true;
tcx->log.break_on_warning = true;
tcx->log.print_file_and_line = true;
tcx->log.log_proc = default_log_proc;
os_win32_register_crash_handler();
}
fn void os_core_init(void) {
ma_arena_t perm = {0};
os_core_small_init(&perm);
tcx->perm = perm;
}
#elif PLATFORM_POSIX
#if defined(__linux__) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#if !PLATFORM_EMSCRIPTEN
#include <execinfo.h>
#include <ucontext.h>
#endif
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mman.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>
fn void *os_vmem_reserve(usize size) {
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
return result == MAP_FAILED ? NULL : result;
}
fn b32 os_vmem_commit(void *ptr, usize size) {
mprotect(ptr, size, PROT_READ|PROT_WRITE);
return true;
}
fn b32 os_vmem_release(void *ptr) {
int result = munmap(ptr, 0);
return result == 0 ? true : false;
}
fn b32 os_vmem_decommit(void *ptr, usize size) {
madvise(ptr, size, MADV_DONTNEED);
mprotect(ptr, size, PROT_NONE);
return true;
}
fn void os_error_box(char *str) {
fprintf(stderr, "%s", str);
fflush(stderr);
}
fn void os_console_log(char *str) {
fputs(str, stdout);
fflush(stdout);
}
fn f64 os_parse_float(char *str) {
return strtod(str, NULL);
}
#if !PLATFORM_EMSCRIPTEN
typedef struct b_stacktrace_tag* b_stacktrace_handle;
b_stacktrace_handle b_stacktrace_get();
int b_stacktrace_depth(b_stacktrace_handle stacktrace);
char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
char* malloc_backtrace(void);
typedef struct print_buf {
char* buf;
int pos;
int size;
} print_buf;
static print_buf buf_init(void) {
print_buf ret = {
(char*) malloc(1024),
0,
1024
};
return ret;
}
static void buf_printf(print_buf* b, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
const int len = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args);
const int new_end = b->pos + len;
if (new_end > b->size) {
while (new_end > b->size) b->size *= 2;
b->buf = (char*)realloc(b->buf, b->size);
}
va_start(args, fmt);
b->pos += vsnprintf(b->buf + b->pos, len, fmt, args);
va_end(args);
}
char* malloc_backtrace(void) {
b_stacktrace_handle h = b_stacktrace_get();
char* ret = b_stacktrace_to_string(h);
free(h);
return ret;
}
#define B_STACKTRACE_MAX_DEPTH 1024
typedef struct b_stacktrace {
void* trace[B_STACKTRACE_MAX_DEPTH];
int trace_size;
} b_stacktrace;
b_stacktrace_handle b_stacktrace_get(void) {
b_stacktrace* ret = (b_stacktrace*)malloc(sizeof(b_stacktrace));
ret->trace_size = backtrace(ret->trace, B_STACKTRACE_MAX_DEPTH);
return (b_stacktrace_handle)(ret);
}
int b_stacktrace_depth(b_stacktrace_handle h) {
const b_stacktrace* stacktrace = (b_stacktrace*)h;
return stacktrace->trace_size;
}
char* b_stacktrace_to_string(b_stacktrace_handle h) {
const b_stacktrace* stacktrace = (b_stacktrace*)h;
char** messages = backtrace_symbols(stacktrace->trace, stacktrace->trace_size);
print_buf out = buf_init();
int i;
int skip_count = 5;
for (i = 0; i < stacktrace->trace_size; ++i) {
void* tracei = stacktrace->trace[i];
char* msg = messages[i];
if (i < skip_count) {
continue;
}
/* calculate load offset */
Dl_info info;
dladdr(tracei, &info);
if (info.dli_fbase == (void*)0x400000) {
/* address from executable, so don't offset */
info.dli_fbase = NULL;
}
while (*msg && *msg != '(') ++msg;
*msg = 0;
{
char cmd[1024];
char line[2048];
FILE* fp;
snprintf(cmd, 1024, "addr2line -e %s -f -C -p %p 2>/dev/null", messages[i], (void*)((char*)tracei - (char*)info.dli_fbase));
fp = popen(cmd, "r");
if (!fp) {
buf_printf(&out, "Failed to generate trace further...\n");
break;
}
while (fgets(line, sizeof(line), fp)) {
buf_printf(&out, " ");
if (strstr(line, "?? ")) {
/* just output address if nothing can be found */
buf_printf(&out, "%p\n", tracei);
}
else {
int len = strlen(line);
char *at = strstr(line, " at ");
if (at) {
char *function = line;
int function_len = at - line;
char *file = at + 4;
int file_len = strlen(file) - 1;
buf_printf(&out, " %.*s %.*s (%s)\n", file_len, file, function_len, function, messages[i]);
} else {
buf_printf(&out, " %.*s (%s)\n", len - 1, line, messages[i]);
}
}
}
pclose(fp);
}
}
free(messages);
return out.buf;
}
void print_backtrace(void) {
char *backtrace = malloc_backtrace();
puts(backtrace);
free(backtrace);
}
const char *signal_to_string(int signal) {
switch (signal) {
case SIGINT: return "SIGINT";
case SIGILL: return "SIGILL";
case SIGABRT: return "SIGABRT";
case SIGFPE: return "SIGFPE";
case SIGSEGV: return "SIGSEGV";
case SIGTERM: return "SIGTERM";
case SIGHUP: return "SIGALRM";
case SIGQUIT: return "SIGQUIT";
case SIGTRAP: return "SIGTRAP";
case SIGKILL: return "SIGKILL";
case SIGPIPE: return "SIGPIPE";
case SIGALRM: return "SIGHUP";
case SIGPOLL: return "SIGPOLL";
default: return "";
}
}
void backtrace_handle_signal(int signal, siginfo_t* info, void* context) {
(void)context; // unused
printf("Stack trace (%s/%d):", signal_to_string(signal), signal);
if (signal == SIGSEGV) {
printf(" at addr: %p", info->si_addr);
}
puts("");
print_backtrace();
exit(1);
}
void setup_backtrace() {
struct sigaction sa;
sa.sa_sigaction = backtrace_handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGTRAP, &sa, NULL);
}
#endif
fn void os_core_small_init(ma_arena_t *arena) {
tcx = ma_push_type(arena, thread_ctx_t);
tcx->log.break_on_error = true;
tcx->log.break_on_fatal = true;
tcx->log.break_on_warning = true;
tcx->log.print_file_and_line = true;
tcx->log.log_proc = default_log_proc;
#if !PLATFORM_EMSCRIPTEN
setup_backtrace();
#endif
}
fn void os_core_init(void) {
ma_arena_t perm = {0};
os_core_small_init(&perm);
tcx->perm = perm;
}
#endif
-30
View File
@@ -1,30 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_arena.h"
fn void os_error_box(char *str);
fn void os_console_log(char *str);
fn void *os_vmem_reserve(usize size);
fn b32 os_vmem_commit(void *p, usize size);
fn b32 os_vmem_release(void *p);
fn b32 os_vmem_decommit(void *p, usize size);
fn void os_core_init(void);
fn void os_core_small_init(ma_arena_t *arena);
fn f64 os_parse_float(char *str);
#if PLATFORM_DEBUG_ASSERT
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
#define assert(x) do { assert_expr(x); } while(0)
#define assert_ex(x, msg) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x " :: " #msg "\n"), debug_break()))
#else
#define assert_expr(x) (void)(x)
#define assert(x) do { (void)(x); } while(0)
#define assert_ex(x, msg) do { (void)(x); } while(0)
#endif
#define not_implemented assert(!"not implemented!")
#define invalid_codepath assert(!"invalid code path!")
#define default_is_invalid default: assert(!"invalid default case")
#define else_is_invalid else { assert(!"else was not expected to be executed!"); }
-557
View File
@@ -1,557 +0,0 @@
#include "core_string.h"
#include "core_intrin.h"
#include "core_platform.h"
#include "stb_sprintf.h"
fn i32 str_len(char *str) {
i32 i = 0;
while (str[i]) i += 1;
return i;
}
fn b32 str_eq(char *a, char *b) {
return s8_are_equal(s8_from_char(a), s8_from_char(b));
}
fn char char_to_lower_case(char a) {
if (a >= 'A' && a <= 'Z') a += 32;
return a;
}
fn char char_to_upper_case(char a) {
if (a >= 'a' && a <= 'z') a -= 32;
return a;
}
fn b32 char_is_whitespace(char w) {
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result;
}
fn b32 char_is_alphabetic(char a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
return result;
}
fn b32 char_is_ident(char a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
return result;
}
fn b32 char_is_digit(char a) {
b32 result = a >= '0' && a <= '9';
return result;
}
fn b32 char_is_alphanumeric(char a) {
b32 result = char_is_digit(a) || char_is_alphabetic(a);
return result;
}
fn b32 char_is_symbol(char w) {
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
return result;
}
fn b32 char_is_non_word(char w) {
b32 result = w != '_' && (char_is_symbol(w) || char_is_whitespace(w));
return result;
}
fn b32 char_is_word(char w) {
b32 result = !char_is_non_word(w);
return result;
}
fn s8_t s8_from_range(char *begin, char *end) {
assert(end >= begin);
intptr_t size = (intptr_t)end - (intptr_t)begin;
s8_t result = {begin, size};
return result;
}
fn s8_t s8_from_char(char *string) {
s8_t result;
result.str = (char *)string;
result.len = str_len(string);
return result;
}
fn s8_t s8_copy(ma_arena_t *ma, s8_t string) {
char *copy = (char *)ma_push_size(ma, sizeof(char) * (string.len + 1));
memory_copy(copy, string.str, string.len);
copy[string.len] = 0;
s8_t result = s8_make(copy, string.len);
return result;
}
fn s8_t s8_copy_char(ma_arena_t *ma, char *s) {
int64_t len = str_len(s);
char *copy = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
memory_copy(copy, s, len);
copy[len] = 0;
s8_t result = s8_make(copy, len);
return result;
}
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case) {
if (a.len != b.len) return false;
for (int64_t i = 0; i < a.len; i++) {
char A = a.str[i];
char B = b.str[i];
if (ignore_case) {
A = char_to_lower_case(A);
B = char_to_lower_case(B);
}
if (A != B)
return false;
}
return true;
}
fn b32 s8_are_equal(s8_t a, s8_t b) {
return s8_are_equal_ex(a, b, false);
}
fn s8_t s8_get_postfix(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
int64_t remain_len = string.len - len;
s8_t result = s8_make(string.str + remain_len, len);
return result;
}
fn s8_t s8_get_prefix(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
s8_t result = s8_make(string.str, len);
return result;
}
fn s8_t s8_chop(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
s8_t result = s8_make(string.str, string.len - len);
return result;
}
fn s8_t s8_skip(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
int64_t remain = string.len - len;
s8_t result = s8_make(string.str + len, remain);
return result;
}
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case) {
s8_t a_end = s8_get_postfix(a, end.len);
b32 result = s8_are_equal_ex(end, a_end, ignore_case);
return result;
}
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case) {
s8_t a_start = s8_get_prefix(a, start.len);
b32 result = s8_are_equal_ex(start, a_start, ignore_case);
return result;
}
fn b32 s8_ends_with(s8_t a, s8_t end) {
return s8_ends_with_ex(a, end, false);
}
fn b32 s8_starts_with(s8_t a, s8_t start) {
return s8_starts_with_ex(a, start, false);
}
fn void s8_normalize_path_unsafe(s8_t s) {
for (int64_t i = 0; i < s.len; i++) {
if (s.str[i] == '\\')
s.str[i] = '/';
}
}
fn b32 s8_is_pointer_inside(s8_t string, char *p) {
uintptr_t pointer = (uintptr_t)p;
uintptr_t start = (uintptr_t)string.str;
uintptr_t stop = start + (uintptr_t)string.len;
b32 result = pointer >= start && pointer < stop;
return result;
}
fn s8_t s8_cut_start(s8_t *in, i64 size) {
s8_t result = s8_get_prefix(*in, size);
*in = s8_skip(*in, result.len);
return result;
}
fn s8_t s8_cut_end(s8_t *in, i64 size) {
s8_t result = s8_get_postfix(*in, size);
*in = s8_chop(*in, result.len);
return result;
}
#if 0
s8_t s8_skip_to_p(s8_t string, char *p) {
if (s8_is_pointer_inside(string, p)) {
s8_t result = s8_make(p, p - string.str);
return result;
}
return string;
}
s8_t s8_skip_past(s8_t string, s8_t a) {
if (s8_is_pointer_inside(string, a.str)) {
s8_t on_p = s8_make(a.str, a.str - string.str);
s8_t result = s8_skip(on_p, a.len);
return result;
}
return string;
}
#endif
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index) {
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
if (first_index < 0) first_index = string.len + first_index;
assert(first_index < one_past_last_index);
assert(string.len > 0);
s8_t result = string;
if (string.len > 0) {
if (one_past_last_index > first_index) {
first_index = CLAMP_TOP(first_index, string.len - 1);
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
result.str += first_index;
result.len = one_past_last_index - first_index;
}
else {
result.len = 0;
}
}
return result;
}
fn s8_t s8_trim(s8_t string) {
if (string.len == 0)
return string;
int64_t whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!char_is_whitespace(string.str[whitespace_begin])) {
break;
}
}
int64_t whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
}
else {
string = s8_slice(string, whitespace_begin, whitespace_end);
}
return string;
}
fn s8_t s8_trim_end(s8_t string) {
int64_t whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
s8_t result = s8_get_prefix(string, whitespace_end);
return result;
}
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out) {
b32 ignore_case = flags & s8_seek_ignore_case ? true : false;
b32 result = false;
if (flags & s8_seek_match_find_last) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
s8_t substring = s8_slice(string, index, index + find.len);
if (s8_are_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = index;
result = true;
break;
}
}
}
else {
for (int64_t i = 0; i < string.len; i++) {
s8_t substring = s8_slice(string, i, i + find.len);
if (s8_are_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = i;
result = true;
break;
}
}
}
return result;
}
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag) {
int64_t result = -1;
s8_seek(string, find, flag, &result);
return result;
}
fn s8_t s8_chop_last_char(s8_t s, s8_t ch) {
s8_t result = s;
s8_seek(s, ch, s8_seek_match_find_last, &result.len);
return result;
}
fn s8_t s8_chop_last_slash(s8_t s) {
return s8_chop_last_char(s, s8("/"));
}
fn s8_t s8_chop_last_period(s8_t s) {
return s8_chop_last_char(s, s8("."));
}
fn s8_t s8_skip_to_last_char(s8_t s, s8_t ch) {
int64_t pos;
s8_t result = s;
if (s8_seek(s, ch, s8_seek_match_find_last, &pos)) {
result = s8_skip(result, pos + 1);
}
return result;
}
fn s8_t s8_skip_to_last_slash(s8_t s) {
return s8_skip_to_last_char(s, s8("/"));
}
fn s8_t s8_skip_to_last_period(s8_t s) {
return s8_skip_to_last_char(s, s8("."));
}
fn s8_t s8_get_name_no_ext(s8_t s) {
return s8_skip_to_last_slash(s8_chop_last_period(s));
}
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
s8_normalize_path_unsafe(copy);
return copy;
}
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char_to_lower_case(copy.str[i]);
}
return copy;
}
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char_to_upper_case(copy.str[i]);
}
return copy;
}
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1) {
va_list args2;
va_copy(args2, args1);
int64_t len = s8_vsnprintf(0, 0, str, args2);
va_end(args2);
char *result = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
s8_vsnprintf(result, (i32)(len + 1), str, args1);
s8_t res = s8_make(result, len);
return res;
}
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...) {
S8_FMT(ma, str, result);
return result;
}
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str) {
sb8_node_t *node = ma_push_type(ma, sb8_node_t);
node->string = str;
return node;
}
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string) {
assert(list->arena != NULL);
sb8_node_t *node = sb8_create_node(list->arena, string);
SLLQ_APPEND(list->first, list->last, node);
return node;
}
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...) {
S8_FMT(sb->arena, str, result);
sb8_append(sb, result);
return result;
}
fn void sb8_indent(sb8_t *sb) {
sb8_printf(sb, "\n%.*s", sb->indent*4, " ");
}
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...) {
S8_FMT(sb->arena, str, result);
sb8_indent(sb);
sb8_append(sb, result);
return result;
}
fn int64_t sb8_char_size(sb8_t *sb) {
int64_t result = 0;
for (sb8_node_t *it = sb->first; it; it = it->next) {
result += it->len;
}
return result;
}
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb) {
int64_t size = sb8_char_size(sb) + 1;
char *str = ma_push_size(arena, size);
s8_t result = {str, 0};
for (sb8_node_t *it = sb->first; it; it = it->next) {
memory_copy(result.str + result.len, it->str, it->len);
result.len += it->len;
}
result.str[result.len] = 0;
return result;
}
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
sb8_t result = (sb8_t){ma};
int64_t index = 0;
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
while (s8_seek(string, find, find_flag, &index)) {
s8_t before_match = s8_make(string.str, index);
if (flags & s8_split_cleanup) {
before_match = s8_trim(before_match);
if (before_match.len) {
sb8_append(&result, before_match);
}
} else {
sb8_append(&result, before_match);
}
if (flags & s8_split_inclusive) {
s8_t match = s8_make(string.str + index, find.len);
sb8_append(&result, match);
}
string = s8_skip(string, index + find.len);
}
if (string.len) sb8_append(&result, string);
return result;
}
fn u64 u64_from_hexchar(char c) {
switch (c) {
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
case 'a':
case 'A': return 10; break;
case 'b':
case 'B': return 11; break;
case 'c':
case 'C': return 12; break;
case 'd':
case 'D': return 13; break;
case 'e':
case 'E': return 14; break;
case 'f':
case 'F': return 15; break;
default: return 255;
}
}
fn u64 u64_from_s8(s8_t s, u64 base) {
assert(base >= 2 && base <= 16);
u64 acc = 0;
for (i64 i = 0; i < s.len; i++) {
u64 num = u64_from_hexchar(s.str[i]);
assert(num < base);
acc *= base;
acc += num;
}
return acc;
}
fn u64 u64_from_s8_loose(s8_t s, u64 base) {
assert(base >= 2 && base <= 16);
u64 acc = 0;
for (i64 i = 0; i < s.len; i++) {
u64 num = u64_from_hexchar(s.str[i]);
if (num >= base) {
break;
}
acc *= base;
acc += num;
}
return acc;
}
fn f64 f64_from_s8(s8_t string) {
ma_temp_t scratch = ma_begin_scratch();
s8_t num_string = s8_copy(scratch.arena, string);
f64 result = os_parse_float(num_string.str);
ma_end_scratch(scratch);
return result;
}
gb_read_only i64 s8_fuzzy_closer_word_begin = 5;
gb_read_only i64 s8_fuzzy_consecutive_multiplier = 3;
fn i64 s8_fuzzy_rate_string(s8_t string, s8_t with) {
if (with.len == 0) return 0;
i64 points = 0;
i64 consecutive = 0;
i64 with_i = 0;
for (i64 i = 0; i < string.len; i++) {
if (string.str[i] == with.str[with_i]) {
i64 closer_begin = CLAMP_BOT((i64)0, s8_fuzzy_closer_word_begin - i);
points += closer_begin;
consecutive++;
with_i += 1;
} else {
points += consecutive * s8_fuzzy_consecutive_multiplier;
consecutive = 0;
with_i = 0;
}
if (with_i >= with.len) with_i = 0;
}
points += consecutive * s8_fuzzy_consecutive_multiplier;
return points;
}
fn fuzzy_pair_t *s8_fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) {
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
for (i32 i = 0; i < len; i += 1) {
pairs[i].rating = s8_fuzzy_rate_string(array[i], needle);
pairs[i].index = i;
}
for (i32 i = 0; i < len - 1; i++) {
for (i32 j = 0; j < len - 1; j++) {
if (pairs[j].rating < pairs[j + 1].rating) {
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
}
}
}
return pairs;
}
-180
View File
@@ -1,180 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_arena.h"
typedef struct s8_t s8_t;
struct s8_t {
char *str;
int64_t len;
};
typedef struct sb8_node_t sb8_node_t;
struct sb8_node_t {
sb8_node_t *next;
union {
struct { char *str; int64_t len; };
s8_t string;
};
};
typedef struct sb8_t sb8_t;
struct sb8_t {
ma_arena_t *arena;
sb8_node_t *first;
sb8_node_t *last;
// WARNING: remember to update typeinfo after editing this
i32 indent;
};
typedef i32 s8_seek_t;
enum {
s8_seek_none = 0,
s8_seek_ignore_case = 1,
s8_seek_match_find_last = 2,
};
typedef i32 s8_split_t;
enum {
s8_split_none = 0,
s8_split_ignore_case = 1,
s8_split_inclusive = 2,
s8_split_cleanup = 4,
};
enum { s8_ignore_case = 1 };
//
// char and char string operations
fn i32 str_len(char *str);
fn b32 str_eq(char *a, char *b);
fn char char_to_lower_case(char a);
fn char char_to_upper_case(char a);
fn b32 char_is_whitespace(char w);
fn b32 char_is_alphabetic(char a);
fn b32 char_is_ident(char a);
fn b32 char_is_digit(char a);
fn b32 char_is_alphanumeric(char a);
fn u64 u64_from_hexchar(char c);
fn u64 u64_from_s8(s8_t s, u64 base);
fn f64 f64_from_s8(s8_t string);
//
// string8 constructors
#define s8_make(str,len) (s8_t){str, len}
#define s8_null (s8_t){0}
#define s8_invalid s8("<INVALID>")
#define s8(string) (s8_t){(char *)string, sizeof(string) - 1}
#define s8_const(string) { string, sizeof(string) - 1 }
#define s8_struct(DATA) (s8_t){.str = (char *)&(DATA), .len = sizeof(DATA)}
#define s8_array(DATA) (s8_t){.str = (char *)(DATA), .len = lengthof(DATA)}
#define s8_array_lit(DATA) {.str = (char *)(DATA), .len = lengthof(DATA)}
fn s8_t s8_from_range(char *begin, char *end);
fn s8_t s8_from_char(char *string);
fn s8_t s8_copy(ma_arena_t *ma, s8_t string);
//
// conditional
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case);
fn b32 s8_are_equal(s8_t a, s8_t b);
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case);
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case);
fn b32 s8_ends_with(s8_t a, s8_t end);
fn b32 s8_starts_with(s8_t a, s8_t start);
fn b32 s8_is_pointer_inside(s8_t string, char *p);// @todo: maybe more general?
//
// search
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out);
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag);
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags);
//
// string view transforms
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index);
fn s8_t s8_get_postfix(s8_t string, int64_t len);
fn s8_t s8_get_prefix(s8_t string, int64_t len);
fn s8_t s8_chop(s8_t string, int64_t len);
fn s8_t s8_skip(s8_t string, int64_t len);
fn s8_t s8_chop_last_slash(s8_t s);
fn s8_t s8_chop_last_period(s8_t s);
fn s8_t s8_skip_to_last_slash(s8_t s);
fn s8_t s8_skip_to_last_period(s8_t s);
fn s8_t s8_get_name_no_ext(s8_t s);
fn s8_t s8_trim(s8_t string);
fn s8_t s8_trim_end(s8_t string);
fn s8_t s8_cut_start(s8_t *in, i64 size);
fn s8_t s8_cut_end(s8_t *in, i64 size);
//
// formatting
fn void s8_normalize_path_unsafe(s8_t s);
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s);
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s);
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s);
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1);
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...);
//
// string builder
#define sb8(ARENA) &(sb8_t){.arena = arena}
#define sb8_serial_begin(ARENA) &(sb8_t){.arena = ARENA}
#define sb8_serial_end(ARENA, SB) sb8_merge(ARENA, SB)
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...);
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string);
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str);
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb);
fn void sb8_indent(sb8_t *sb);
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...);
fn int64_t sb8_char_size(sb8_t *sb);
#if 0
sb8_t *sbin_write_begin(ma_arena_t *arena);
s8_t sbin_write_end(sb8_t *sb);
void *sbin_write_data(sb8_t *sb, void *p, i64 size);
void *sbin_write_size(sb8_t *sb, i64 size);
void *sbin_write_u64(sb8_t *sb, u64 value);
void *sbin_write_u32(sb8_t *sb, u32 value);
void *sbin_write_u16(sb8_t *sb, u16 value);
void *sbin_write_u8(sb8_t *sb, u8 value);
s8_t *sbin_write_s8(sb8_t *sb, s8_t string);
char *sbin_write_str(sb8_t *sb, char *string);
stream_t sbin_read_begin(void *p, i64 size);
void sbin_read_end(stream_t *stream);
void *sbin_read_data(stream_t *stream, i64 size);
#endif
//
// other
#define s8_fmtspec(string) (int)(string).len, (string).str
#define S8_CODE(...) s8(#__VA_ARGS__)
#define S8_FILE s8(__FILE__)
#define S8_FILE_AND_LINE s8(FILE_AND_LINE)
#define S8_FMT(ma, str, result) \
va_list args1; \
va_start(args1, str); \
s8_t result = s8_vfmt(ma, str, args1); \
va_end(args1)
#if PLATFORM_TCC
#define s8_vsnprintf vsnprintf
#else
#define s8_vsnprintf stbsp_vsnprintf
#endif
#define STR_FMT(buff, str) \
va_list args1; \
va_start(args1, str); \
i32 len = s8_vsnprintf(buff, sizeof(buff), str, args1); \
va_end(args1)
typedef struct fuzzy_pair_t fuzzy_pair_t;
struct fuzzy_pair_t {
i64 index;
i64 rating;
};
-622
View File
@@ -1,622 +0,0 @@
#include "core_string16.h"
#include "core_platform.h"
#include "core_intrin.h"
#include "core_unicode.h"
#include "core_ctx.h"
fn i64 str16_len(u16 *string) {
i64 len = 0;
while (*string++ != 0)
len++;
return len;
}
fn u16 char16_to_lower_case(u16 a) {
if (a >= 'A' && a <= 'Z') a += 32;
return a;
}
fn u16 char16_to_upper_case(u16 a) {
if (a >= 'a' && a <= 'z') a -= 32;
return a;
}
fn b32 char16_is_whitespace(u16 w) {
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result;
}
fn b32 char16_is_alphabetic(u16 a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
return result;
}
fn b32 char16_is_ident(u16 a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
return result;
}
fn b32 char16_is_digit(u16 a) {
b32 result = a >= '0' && a <= '9';
return result;
}
fn b32 char16_is_symbol(u16 w) {
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
return result;
}
fn b32 char16_is_non_word(u16 w) {
b32 result = w != '_' && (char16_is_symbol(w) || char16_is_whitespace(w));
return result;
}
fn b32 char16_is_word(u16 w) {
b32 result = !char16_is_non_word(w);
return result;
}
fn b32 char16_is_alphanumeric(u16 a) {
b32 result = char16_is_digit(a) || char16_is_alphabetic(a);
return result;
}
fn s16_t s16_from_range(u16 *begin, u16 *end) {
assert_expr(end >= begin);
intptr_t size = (intptr_t)end - (intptr_t)begin;
s16_t result = {begin, size / 2};
return result;
}
fn s16_t s16_from_str16(u16 *string) {
s16_t result;
result.str = string;
result.len = str16_len(string);
return result;
}
fn s16_t s16_copy(ma_arena_t *ma, s16_t string) {
i64 byte_size = sizeof(u16) * string.len;
u16 *copy = (u16 *)ma_push_size(ma, byte_size + sizeof(u16));
memory_copy(copy, string.str, byte_size);
copy[string.len] = 0;
s16_t result = s16_make(copy, string.len);
return result;
}
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s) {
return s16_copy(ma, s16_make(s, str16_len(s)));
}
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case) {
if (a.len != b.len) return false;
for (i64 i = 0; i < a.len; i++) {
u16 A = a.str[i];
u16 B = b.str[i];
if (ignore_case) {
A = char16_to_lower_case(A);
B = char16_to_lower_case(B);
}
if (A != B)
return false;
}
return true;
}
fn b32 s16_are_equal(s16_t a, s16_t b) {
return s16_are_equal_ex(a, b, false);
}
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string) {
u16 *buffer = ma_push_array(ma, u16, string.len + 1);
i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len);
assert(len <= string.len); // @todo: verify
return (s16_t){buffer, len};
}
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string) {
i64 buffer_size = (string.len + 1) * 2;
char *buffer = ma_push_array(ma, char, buffer_size);
i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len);
assert(len < buffer_size);
return (s8_t){buffer, len};
}
fn s16_t s16_get_postfix(s16_t string, i64 len) {
len = CLAMP_TOP(len, string.len);
i64 remain_len = string.len - len;
s16_t result = s16_make(string.str + remain_len, len);
return result;
}
fn s16_t s16_get_prefix(s16_t string, i64 len) {
len = CLAMP_TOP(len, string.len);
s16_t result = s16_make(string.str, len);
return result;
}
fn s16_t s16_chop(s16_t string, i64 len) {
len = CLAMP_TOP(len, string.len);
s16_t result = s16_make(string.str, string.len - len);
return result;
}
fn s16_t s16_skip(s16_t string, i64 len) {
len = CLAMP_TOP(len, string.len);
i64 remain = string.len - len;
s16_t result = s16_make(string.str + len, remain);
return result;
}
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case) {
s16_t a_end = s16_get_postfix(a, end.len);
b32 result = s16_are_equal_ex(end, a_end, ignore_case);
return result;
}
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case) {
s16_t a_start = s16_get_prefix(a, start.len);
b32 result = s16_are_equal_ex(start, a_start, ignore_case);
return result;
}
fn b32 s16_ends_with(s16_t a, s16_t end) {
return s16_ends_with_ex(a, end, false);
}
fn b32 s16_starts_with(s16_t a, s16_t start) {
return s16_ends_with_ex(a, start, false);
}
fn void s16_normalize_path_unsafe(s16_t s) {
for (i64 i = 0; i < s.len; i++) {
if (s.str[i] == '\\')
s.str[i] = '/';
}
}
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s) {
s16_t copy = s16_copy(ma, s);
s16_normalize_path_unsafe(copy);
return copy;
}
fn b32 s16_is_pointer_inside(s16_t string, u16 *p) {
uintptr_t pointer = (uintptr_t)p;
uintptr_t start = (uintptr_t)string.str;
uintptr_t stop = start + (uintptr_t)string.len * sizeof(u16);
b32 result = pointer >= start && pointer < stop;
return result;
}
fn s16_t s16_cut_start(s16_t *in, i64 size) {
s16_t result = s16_get_prefix(*in, size);
*in = s16_skip(*in, result.len);
return result;
}
fn s16_t s16_cut_end(s16_t *in, i64 size) {
s16_t result = s16_get_postfix(*in, size);
*in = s16_chop(*in, result.len);
return result;
}
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index) {
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
if (first_index < 0) first_index = string.len + first_index;
assert(first_index < one_past_last_index);
assert(string.len > 0);
s16_t result = string;
if (string.len > 0) {
if (one_past_last_index > first_index) {
first_index = CLAMP_TOP(first_index, string.len - 1);
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
result.str += first_index;
result.len = one_past_last_index - first_index;
}
else {
result.len = 0;
}
}
return result;
}
fn s16_t s16_trim(s16_t string) {
if (string.len == 0)
return string;
i64 whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!char16_is_whitespace(string.str[whitespace_begin])) {
break;
}
}
i64 whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
}
else {
string = s16_slice(string, whitespace_begin, whitespace_end);
}
return string;
}
fn s16_t s16_trim_end(s16_t string) {
i64 whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
s16_t result = s16_get_prefix(string, whitespace_end);
return result;
}
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out) {
b32 ignore_case = flags & s16_seek_ignore_case ? true : false;
b32 result = false;
if (flags & s16_seek_match_find_last) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
s16_t substring = s16_slice(string, index, index + find.len);
if (s16_are_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = index;
result = true;
break;
}
}
}
else {
for (int64_t i = 0; i < string.len; i++) {
s16_t substring = s16_slice(string, i, i + find.len);
if (s16_are_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = i;
result = true;
break;
}
}
}
return result;
}
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag) {
int64_t result = -1;
s16_seek(string, find, flag, &result);
return result;
}
fn s16_t s16_chop_last_char(s16_t s, s16_t ch) {
s16_t result = s;
s16_seek(s, ch, s16_seek_match_find_last, &result.len);
return result;
}
// fn s16_t s16_chop_last_slash(s16_t s) {
// return s16_chop_last_char(s, s16("/"));
// }
// fn s16_t s16_chop_last_period(s16_t s) {
// return s16_chop_last_char(s, s16("."));
// }
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch) {
int64_t pos;
s16_t result = s;
if (s16_seek(s, ch, s16_seek_match_find_last, &pos)) {
result = s16_skip(result, pos + 1);
}
return result;
}
// fn s16_t s16_skip_to_last_slash(s16_t s) {
// return s16_skip_to_last_char(s, s16("/"));
// }
// fn s16_t s16_skip_to_last_period(s16_t s) {
// return s16_skip_to_last_char(s, s16("."));
// }
// fn s16_t s16_get_name_no_ext(s16_t s) {
// return s16_skip_to_last_slash(s16_chop_last_period(s));
// }
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s) {
s16_t copy = s16_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char16_to_lower_case(copy.str[i]);
}
return copy;
}
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s) {
s16_t copy = s16_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char16_to_upper_case(copy.str[i]);
}
return copy;
}
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch1(ma);
S8_FMT(scratch.arena, str, result);
s16_t result16 = s16_from_s8(ma, result);
ma_end_scratch(scratch);
return result16;
}
fn u64 u64_from_s16(s16_t s, u64 base) {
assert(base >= 2 && base <= 16);
u64 acc = 0;
for (i64 i = 0; i < s.len; i++) {
u64 num = u64_from_hexchar((char)s.str[i]);
assert(num < base);
acc *= base;
acc += num;
}
return acc;
}
fn f64 f64_from_s16(s16_t string) {
ma_temp_t scratch = ma_begin_scratch();
s8_t num_string = s8_from_s16(scratch.arena, string);
f64 result = os_parse_float(num_string.str);
ma_end_scratch(scratch);
return result;
}
gb_read_only i64 s16_fuzzy_closer_word_begin = 5;
gb_read_only i64 s16_fuzzy_consecutive_multiplier = 3;
fn i64 s16_fuzzy_rate(s16_t string, s16_t with) {
if (with.len == 0) return 0;
i64 points = 0;
i64 consecutive = 0;
i64 with_i = 0;
for (i64 i = 0; i < string.len; i++) {
if (string.str[i] == with.str[with_i]) {
i64 closer_begin = CLAMP_BOT((i64)0, s16_fuzzy_closer_word_begin - i);
points += closer_begin;
consecutive++;
with_i += 1;
} else {
points += consecutive * s16_fuzzy_consecutive_multiplier;
consecutive = 0;
with_i = 0;
}
if (with_i >= with.len) with_i = 0;
}
points += consecutive * s16_fuzzy_consecutive_multiplier;
return points;
}
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len) {
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
for (i32 i = 0; i < len; i += 1) {
pairs[i].rating = s16_fuzzy_rate(array[i], needle);
pairs[i].index = i;
}
for (i32 i = 0; i < len - 1; i++) {
for (i32 j = 0; j < len - 1; j++) {
if (pairs[j].rating < pairs[j + 1].rating) {
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
}
}
}
return pairs;
}
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str) {
sb16_node_t *node = ma_push_type(ma, sb16_node_t);
node->string = str;
return node;
}
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string) {
assert(list->arena != NULL);
sb16_node_t *node = sb16_create_node(list->arena, string);
SLLQ_APPEND(list->first, list->last, node);
return node;
}
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
S8_FMT(scratch.arena, str, result);
s16_t result16 = s16_from_s8(sb->arena, result);
sb16_append(sb, result16);
ma_end_scratch(scratch);
return result16;
}
fn void sb16_indent(sb16_t *sb) {
sb16_printf(sb, "\n%.*s", sb->indent*4, " ");
}
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
S8_FMT(scratch.arena, str, result);
s16_t result16 = s16_from_s8(sb->arena, result);
sb16_indent(sb);
sb16_append(sb, result16);
ma_end_scratch(scratch);
return result16;
}
fn int64_t sb16_char_size(sb16_t *sb) {
int64_t result = 0;
for (sb16_node_t *it = sb->first; it; it = it->next) {
result += it->len;
}
return result;
}
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb) {
int64_t size = sb16_char_size(sb) + 1;
i64 byte_size = size * sizeof(u16);
u16 *str = ma_push_size(arena, byte_size);
s16_t result = {str, 0};
for (sb16_node_t *it = sb->first; it; it = it->next) {
memory_copy(result.str + result.len, it->str, it->len * sizeof(u16));
result.len += it->len;
}
result.str[result.len] = 0;
return result;
}
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags) {
sb16_t result = (sb16_t){ma};
int64_t index = 0;
s16_seek_t find_flag = flags & s16_split_ignore_case ? s16_seek_ignore_case : s16_seek_none;
while (s16_seek(string, find, find_flag, &index)) {
s16_t before_match = s16_make(string.str, index);
sb16_append(&result, before_match);
if (flags & s16_split_inclusive) {
s16_t match = s16_make(string.str + index, find.len);
sb16_append(&result, match);
}
string = s16_skip(string, index + find.len);
}
if (string.len) sb16_append(&result, string);
return result;
}
fn s16_t s16_copy_ex(alo_t ma, s16_t string) {
i64 byte_size = sizeof(u16) * string.len;
u16 *copy = (u16 *)alloc_size(ma, byte_size + sizeof(u16));
memory_copy(copy, string.str, byte_size);
copy[string.len] = 0;
s16_t result = s16_make(copy, string.len);
return result;
}
#if 0
fn_test void test_string16(void) {
ma_temp_t scratch = ma_begin_scratch();
// string16 lit basic tests
{
s16_t a = s16("memes");
assert(a.len == 5);
assert(a.str[0] == char16('m'));
assert(a.str[4] == char16('s'));
s16_t b = s16("not memes");
s16_t c = s16("MEMES");
assert(s16_are_equal(a, b) == false);
assert(s16_are_equal(a, a) == true);
assert(s16_are_equal_ex(a, c, true) == true);
}
{
assert(char16_to_upper_case('a') == char16('A'));
assert(char16_to_upper_case('a') == 'A');
assert(char16_to_upper_case(char16('a')) == 'A');
assert(char16_is_digit('3'));
}
{
s16_t a = s16_from_str16(str16("memes"));
assert(a.len == 5);
assert(s16_are_equal(a, s16("memes")) == true);
s16_t b = s16_copy(scratch.arena, a);
assert(a.str != b.str);
assert(b.len == a.len);
assert(s16_are_equal(a, b));
s16_t c = s16_from_range(a.str, a.str + a.len);
assert(s16_are_equal(a, c));
}
{
s16_t a = s16("thing itself");
assert(s16_starts_with_ex(a, s16("thing"), false));
assert(!s16_starts_with_ex(a, s16("thing itself and"), false));
assert(!s16_starts_with_ex(a, s16("thing itself "), false));
assert(s16_starts_with_ex(a, s16("THING"), true));
assert(!s16_starts_with_ex(a, s16("a"), false));
assert(s16_ends_with_ex(a, s16("itself"), false));
assert(s16_ends_with_ex(a, s16("thing itself"), false));
assert(!s16_ends_with_ex(a, s16("thing itselfa"), false));
s16_t b = s16("memes");
assert(s16_is_pointer_inside(b, b.str));
assert(s16_is_pointer_inside(b, b.str + 4));
assert(!s16_is_pointer_inside(b, b.str + 5));
}
{
s16_t a = s16("C:\\Program Files\\Memes");
u16 memes[256] = {0};
memory_copy(memes, a.str, a.len * 2 + 2);
s16_t b = s16_make(memes, a.len);
s16_normalize_path_unsafe(b);
assert(b.str[2] == '/');
}
{
s16_t a = s16(" thing ");
s16_t b = s16_trim(a);
assert(s16_are_equal(b, s16("thing")));
}
{
s16_t a = s16_printf(scratch.arena, "%d", 432);
assert(s16_are_equal(a, s16("432")));
assert(f64_from_s16(s16("432.0")) == 432.0);
assert(u64_from_s16(s16("432"), 10) == 432);
}
{
sb16_t *list = sb16_serial_begin(scratch.arena);
sb16_printf(list, "%d ", 987);
sb16_printf(list, "ter ");
sb16_printf(list, "|");
s16_t string = sb16_serial_end(scratch.arena, list);
assert(s16_are_equal(string, s16("987 ter |")));
}
{
s16_t a = s16("A|B|dek|mek|vek|");
sb16_t b = s16_split(scratch.arena, a, s16("|"), s16_split_none);
assert(s16_are_equal(b.first->string, s16("A")));
assert(s16_are_equal(b.first->next->string, s16("B")));
assert(s16_are_equal(b.first->next->next->string, s16("dek")));
assert(s16_are_equal(b.first->next->next->next->string, s16("mek")));
assert(s16_are_equal(b.first->next->next->next->next->string, s16("vek")));
assert(b.first->next->next->next->next->next == NULL);
}
{
s16_t a = s16_to_upper_case(scratch.arena, s16("thing Meme"));
assert(s16_are_equal(a, s16("THING MEME")));
a = s16_to_lower_case(scratch.arena, s16("THING Meme"));
assert(s16_are_equal(a, s16("thing meme")));
}
{
s16_t a = s16("C:/thing/itself");
assert(s16_are_equal(s16_chop_last_slash(a), s16("C:/thing")));
}
ma_end_scratch(scratch);
}
#endif
-128
View File
@@ -1,128 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_arena.h"
#include "core_string.h"
typedef struct s16_t s16_t;
struct s16_t {
u16 *str;
i64 len;
};
typedef struct sb16_node_t sb16_node_t;
struct sb16_node_t {
sb16_node_t *next;
union {
struct { u16 *str; int64_t len; };
s16_t string;
};
};
typedef struct sb16_t sb16_t;
struct sb16_t {
ma_arena_t *arena;
sb16_node_t *first;
sb16_node_t *last;
// WARNING: remember to update typeinfo after editing this
i32 indent;
};
typedef i32 s16_seek_t;
enum {
s16_seek_none = 0,
s16_seek_ignore_case = 1,
s16_seek_match_find_last = 2,
};
typedef i32 s16_split_t;
enum {
s16_split_none = 0,
s16_split_ignore_case = 1,
s16_split_inclusive = 2,
};
enum { s16_ignore_case = 1 };
typedef struct s32_t s32_t;
struct s32_t {
u32 *str;
i64 len;
};
#define s16_make(str,len) (s16_t){str, len}
#define s16(str) (s16_t){(u16 *)u##str, lengthof(str) - 1}
#define s16_const(string) { (u16 *)u##string, lengthof(string) - 1 }
#define s16_invalid s16_lit("<INVALID>")
#define s16_null (s16_t){0}
#define str16(str) ((u16 *)u##str)
#define char16(str) ((u16)u##str)
#define sb16(ARENA) &(sb16_t){.arena = arena}
#define sb16_serial_begin(ARENA) &(sb16_t){.arena = ARENA}
#define sb16_serial_end(ARENA, SB) sb16_merge(ARENA, SB)
fn i64 str16_len(u16 *string);
fn u16 char16_to_lower_case(u16 a);
fn u16 char16_to_upper_case(u16 a);
fn b32 char16_is_whitespace(u16 w);
fn b32 char16_is_alphabetic(u16 a);
fn b32 char16_is_ident(u16 a);
fn b32 char16_is_digit(u16 a);
fn b32 char16_is_symbol(u16 w);
fn b32 char16_is_non_word(u16 w);
fn b32 char16_is_word(u16 w);
fn b32 char16_is_alphanumeric(u16 a);
fn s16_t s16_from_range(u16 *begin, u16 *end);
fn s16_t s16_from_str16(u16 *string);
fn s16_t s16_copy(ma_arena_t *ma, s16_t string);
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s);
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case);
fn b32 s16_are_equal(s16_t a, s16_t b);
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string);
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string);
fn s16_t s16_get_postfix(s16_t string, i64 len);
fn s16_t s16_get_prefix(s16_t string, i64 len);
fn s16_t s16_chop(s16_t string, i64 len);
fn s16_t s16_skip(s16_t string, i64 len);
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case);
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case);
fn b32 s16_ends_with(s16_t a, s16_t end);
fn b32 s16_starts_with(s16_t a, s16_t start);
fn void s16_normalize_path_unsafe(s16_t s);
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s);
fn b32 s16_is_pointer_inside(s16_t string, u16 *p);
fn s16_t s16_cut_start(s16_t *in, i64 size);
fn s16_t s16_cut_end(s16_t *in, i64 size);
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index);
fn s16_t s16_trim(s16_t string);
fn s16_t s16_trim_end(s16_t string);
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out);
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag);
fn s16_t s16_chop_last_char(s16_t s, s16_t ch);
fn s16_t s16_chop_last_slash(s16_t s);
fn s16_t s16_chop_last_period(s16_t s);
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch);
fn s16_t s16_skip_to_last_slash(s16_t s);
fn s16_t s16_skip_to_last_period(s16_t s);
fn s16_t s16_get_name_no_ext(s16_t s);
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s);
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s);
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...);
fn u64 u64_from_s16(s16_t s, u64 base);
fn f64 f64_from_s16(s16_t string);
fn i64 s16_fuzzy_rate(s16_t string, s16_t with);
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len);
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str);
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string);
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...);
fn void sb16_indent(sb16_t *sb);
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...);
fn int64_t sb16_char_size(sb16_t *sb);
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb);
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags);
fn s16_t s16_copy_ex(alo_t ma, s16_t string);
fn_test void test_string16(void);
-466
View File
@@ -1,466 +0,0 @@
#include "core_type_info.h"
#include "core_platform.h"
#include "core_log.h"
#include "core_lexer.h"
fn s8_t ti_enum_value_to_name(i64 value, type_t *type) {
assert(type->kind == type_kind_enum);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (value == it->value) {
return it->name;
}
}
return s8("invalid");
}
fn i64 ti_enum_name_to_value(s8_t name, type_t *type) {
assert(type->kind == type_kind_enum);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (s8_are_equal(it->name, name)) {
return it->value;
}
}
return -1;
}
fn i64 ti_enum_read_value(void *p, type_t *type) {
assert(type->kind == type_kind_enum);
i64 value = 0;
if (type->size == 1) {
value = *(i8 *)p;
} else if (type->size == 2) {
value = *(i16 *)p;
} else if (type->size == 4) {
value = *(i32 *)p;
} else if (type->size == 8) {
value = *(i64 *)p;
} else {
fatalf("invalid size of enum: %d", type->size);
}
return value;
}
fn void ti_enum_write_value(void *p, i64 value, type_t *type) {
assert(type->kind == type_kind_enum);
if (type->size == 1) {
*(i8 *)p = (i8)value;
} else if (type->size == 2) {
*(i16 *)p = (i16)value;
} else if (type->size == 4) {
*(i32 *)p = (i32)value;
} else if (type->size == 8) {
*(i64 *)p = (i64)value;
} else {
fatalf("invalid size of enum: %d", type->size);
}
}
fn i64 ti_enum_next_value(i64 value, type_t *type) {
assert(type->kind == type_kind_enum);
i32 next_i = 0;
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (value == it->value) {
if (i + 1 < type->count) {
next_i = i + 1;
break;
}
}
}
type_member_t *tm = type->members + next_i;
return tm->value;
}
fn type_member_t *ti_get_member(s8_t name, type_t *type) {
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (s8_are_equal(it->name, name)) {
return it;
}
}
return NULL;
}
fn void *ti_extract_member(void *p, type_member_t *tm) {
u8 *p8 = (u8 *)p;
u8 *result = p8 + tm->offset;
return result;
}
fn void *ti_extract_array_idx(void *p, type_t *type, i32 idx) {
assert(idx < type->count);
u8 *p8 = (u8 *)p;
u8 *result = p8 + type->base->size * idx;
return result;
}
fn void ti__serial_data_ex(sb8_t *sb, void *p, type_t *type) {
assert(type->kind != type_kind_invalid);
switch(type->kind) {
case type_kind_i8: {
i8 n = *(i8 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i16: {
i16 n = *(i16 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i32: {
i32 n = *(i32 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i64: {
i64 n = *(i64 *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_u8: {
u8 n = *(u8 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u16: {
u16 n = *(u16 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u32: {
u32 n = *(u32 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u64: {
u64 n = *(u64 *)p;
sb8_printf(sb, "%llu", (unsigned long long)n);
return;
} break;
case type_kind_b8: {
b8 n = *(b8 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b16: {
b16 n = *(b16 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b32: {
b32 n = *(b32 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b64: {
b64 n = *(b64 *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_f32: {
f32 n = *(f32 *)p;
sb8_printf(sb, "%f", n);
return;
} break;
case type_kind_f64: {
f64 n = *(f64 *)p;
sb8_printf(sb, "%f", n);
return;
} break;
case type_kind_isize: {
isize n = *(isize *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_usize: {
usize n = *(usize *)p;
sb8_printf(sb, "%llu", (unsigned long long)n);
return;
} break;
case type_kind_int: {
int n = *(int *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_char: {
char n = *(char *)p;
sb8_printf(sb, "%c", n);
return;
} break;
}
if (type == &type__s8_t) {
s8_t n = *(s8_t *)p;
sb8_printf(sb, "\"%.*s\"", s8_fmtspec(n));
return;
}
if (type->kind == type_kind_pointer) {
sb8_printf(sb, "0x%x", p);
return;
}
if (type->kind == type_kind_enum) {
i64 value = ti_enum_read_value(p, type);
s8_t s = ti_enum_value_to_name(value, type);
sb8_append(sb, s);
return;
}
if (type->kind == type_kind_array) {
sb8_printf(sb, "{");
sb->indent += 1;
for (i32 i = 0; i < type->count; i += 1) {
void *mem_p = ti_extract_array_idx(p, type, i);
sb8_indent(sb);
ti__serial_data_ex(sb, mem_p, type->base);
sb8_printf(sb, ",");
}
sb->indent -= 1;
sb8_stmtf(sb, "}");
return;
}
if (type->kind == type_kind_struct) {
sb8_printf(sb, "{");
sb->indent += 1;
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *mem = type->members + i;
void *mem_p = ti_extract_member(p, mem);
sb8_indent(sb);
sb8_printf(sb, "%.*s: ", s8_fmtspec(mem->name));
ti__serial_data_ex(sb, mem_p, mem->type);
sb8_printf(sb, ",");
}
sb->indent -= 1;
sb8_stmtf(sb, "}");
return;
}
fatalf("can't serialize: unhandled type");
}
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type) {
ma_temp_t scratch = ma_begin_scratch1(arena);
sb8_t *sb = sb8_serial_begin(scratch.arena);
ti__serial_data_ex(sb, p, type);
s8_t string = sb8_serial_end(arena, sb);
ma_end_scratch(scratch);
return string;
}
fn i64 ti__parser_match_i64(parser_t *par) {
i64 minus = 1;
if (parser_match(par, lex_kind_minus)) {
minus = -1;
}
lex_t *token = parser_expect(par, lex_kind_integer);
i64 result = (i64)token->integer * minus;
return result;
}
fn void ti__deserial_data_ex(ma_arena_t *arena, parser_t *par, void *p, type_t *type) {
switch(type->kind) {
case type_kind_i8: {
i8 *n = (i8 *)p;
n[0] = (i8)ti__parser_match_i64(par);
return;
} break;
case type_kind_i16: {
i16 *n = (i16 *)p;
n[0] = (i16)ti__parser_match_i64(par);
return;
} break;
case type_kind_i32: {
i32 *n = (i32 *)p;
n[0] = (i32)ti__parser_match_i64(par);
return;
} break;
case type_kind_i64: {
i64 *n = (i64 *)p;
n[0] = (i64)ti__parser_match_i64(par);
return;
} break;
case type_kind_b8: {
b8 *n = (b8 *)p;
n[0] = (b8)ti__parser_match_i64(par);
return;
} break;
case type_kind_b16: {
b16 *n = (b16 *)p;
n[0] = (b16)ti__parser_match_i64(par);
return;
} break;
case type_kind_b32: {
b32 *n = (b32 *)p;
n[0] = (b32)ti__parser_match_i64(par);
return;
} break;
case type_kind_b64: {
b64 *n = (b64 *)p;
n[0] = (b64)ti__parser_match_i64(par);
return;
} break;
case type_kind_u8: {
lex_t *token = parser_expect(par, lex_kind_integer);
u8 *n = (u8 *)p;
n[0] = (u8)token->integer;
return;
} break;
case type_kind_u16: {
lex_t *token = parser_expect(par, lex_kind_integer);
u16 *n = (u16 *)p;
n[0] = (u16)token->integer;
return;
} break;
case type_kind_u32: {
lex_t *token = parser_expect(par, lex_kind_integer);
u32 *n = (u32 *)p;
n[0] = (u32)token->integer;
return;
} break;
case type_kind_u64: {
lex_t *token = parser_expect(par, lex_kind_integer);
u64 *n = (u64 *)p;
n[0] = (u64)token->integer;
return;
} break;
case type_kind_f32: {
lex_t *token = parser_expect(par, lex_kind_real);
f32 *n = (f32 *)p;
n[0] = (f32)token->real;
return;
} break;
case type_kind_f64: {
lex_t *token = parser_expect(par, lex_kind_real);
f64 *n = (f64 *)p;
n[0] = token->real;
return;
} break;
case type_kind_isize: {
isize *n = (isize *)p;
n[0] = (isize)ti__parser_match_i64(par);
return;
} break;
case type_kind_usize: {
lex_t *token = parser_expect(par, lex_kind_integer);
usize *n = (usize *)p;
n[0] = (usize)token->integer;
return;
} break;
case type_kind_int: {
int *n = (int *)p;
n[0] = (int)ti__parser_match_i64(par);
return;
} break;
case type_kind_char: {
char *n = (char *)p;
n[0] = (char)ti__parser_match_i64(par);
return;
} break;
}
if (type == &type__s8_t) {
lex_t *token = parser_expect(par, lex_kind_string);
s8_t *n = (s8_t *)p;
n[0] = s8_copy(arena, token->string);
return;
}
if (type->kind == type_kind_enum) {
lex_t *token = parser_expect(par, lex_kind_ident);
i64 value = ti_enum_name_to_value(token->string, type);
if (value == -1) {
fatalf("invalid enum value: %.*s", s8_fmtspec(token->string));
}
ti_enum_write_value(p, value, type);
return;
}
if (type->kind == type_kind_struct) {
#if 0
parser_expect(par, lex_kind_open_brace);
while (!parser_match(par, lex_kind_close_brace)) {
lex_t *ident = parser_expect(par, lex_kind_ident);
parser_expect(par, lex_kind_colon);
type_member_t *mem = ti_get_member(type, ident->string);
if (mem) {
u8 *mem_p = p8 + mem->offset;
ti__deserial_data_ex(arena, par, mem_p, mem->type);
} else {
debugf("deserial - skipping field: %.*s", s8_fmtspec(ident->string));
parser_eat_until(par, lex_kind_comma);
}
parser_expect(par, lex_kind_comma);
}
#else // strict
parser_expect(par, lex_kind_open_brace);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *mem = type->members + i;
void *memp = ti_extract_member(p, mem);
lex_t *ident = parser_expect(par, lex_kind_ident);
parser_expect(par, lex_kind_colon);
expect (s8_are_equal(ident->string, mem->name)) fatalf("expected identifier: %.*s, got instead %.*s", s8_fmtspec(mem->name), s8_fmtspec(ident->string));
ti__deserial_data_ex(arena, par, memp, mem->type);
parser_expect(par, lex_kind_comma);
}
parser_expect(par, lex_kind_close_brace);
#endif
}
if (type->kind == type_kind_array) {
parser_expect(par, lex_kind_open_brace);
for (i32 i = 0; i < type->count; i += 1) {
void *memp = ti_extract_array_idx(p, type, i);
ti__deserial_data_ex(arena, par, memp, type->base);
parser_expect(par, lex_kind_comma);
}
parser_expect(par, lex_kind_close_brace);
}
}
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type) {
void *p = ma_push_size(arena, type->size);
ma_temp_t scratch = ma_begin_scratch();
lex_array_t tokens = lex_tokens(scratch.arena, "data serializing", data);
parser_t *par = parser_make(scratch.arena, tokens.data);
ti__deserial_data_ex(arena, par, p, type);
ma_end_scratch(scratch);
return p;
}
fn b32 ti_is_basic(type_t *type) {
b32 result = type->kind >= type_kind_first_basic && type->kind <= type_kind_last_basic;
return result;
}
fn b32 ti_has_type_name(type_t *type) {
b32 result = ti_is_basic(type) || type->kind == type_kind_struct || type->kind == type_kind_enum || type->kind == type_kind_union;
return result;
}
fn s8_t ti_serial_type(ma_arena_t *arena, type_t *type) {
if (ti_has_type_name(type)) {
return type->name;
} else if (type->kind == type_kind_pointer) {
s8_t name = ti_serial_type(arena, type->base);
return s8_printf(arena, "%.*s*", s8_fmtspec(name));
} else if (type->kind == type_kind_array) {
s8_t name = ti_serial_type(arena, type->base);
return s8_printf(arena, "%.*s[%d]", s8_fmtspec(name), type->count);
} else_is_invalid;
return s8_invalid;
}
-364
View File
@@ -1,364 +0,0 @@
#pragma once
#include "core_basic.h"
#include "core_arena.h"
#include "core_string.h"
#include "core_string16.h"
#include "core_math.h"
typedef int type_kind_t;
enum {
type_kind_invalid,
type_kind_i8,
type_kind_i16,
type_kind_i32,
type_kind_i64,
type_kind_b8,
type_kind_b16,
type_kind_b32,
type_kind_b64,
type_kind_u8,
type_kind_u16,
type_kind_u32,
type_kind_u64,
type_kind_f32,
type_kind_f64,
type_kind_isize,
type_kind_usize,
type_kind_int,
type_kind_char,
type_kind_void,
type_kind_pointer,
type_kind_array,
type_kind_struct,
type_kind_union,
type_kind_enum,
type_kind_first_basic = type_kind_i8,
type_kind_last_basic = type_kind_void,
};
typedef struct type_t type_t;
struct type_t {
type_kind_t kind;
s8_t name;
i32 size;
i32 count;
struct type_member_t *members;
type_t *base;
};
typedef struct type_member_t type_member_t;
struct type_member_t {
s8_t name;
type_t *type;
i64 value;
u64 offset;
b8 dont_serialize;
};
typedef struct mt_tweak_t mt_tweak_t;
struct mt_tweak_t {
type_t *type;
s8_t name;
void *ptr;
f32 min, max;
};
#define mt_embed_file(name, path)
#define mt_tweak_f32(name, default, min, max)
#define mt_tweak_color(name, ...)
#define mt_tweak_b32(name, default)
//
// serialization to string
#define ti_deserial_data(ARENA, DATA, TYPE) (TYPE *)ti__deserial_data(ARENA, DATA, type(TYPE))
#define ti_serial_data(ARENA, DATA, TYPE) ti__serial_data(ARENA, DATA, type(TYPE))
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type);
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type);
//
// utilities
fn s8_t ti_enum_value_to_name(i64 value, type_t *type);
fn i64 ti_enum_name_to_value(s8_t name, type_t *type);
fn type_member_t *ti_get_member(s8_t name, type_t *type);
//
// core type info data
#define type(X) (&type__##X)
#define DEFINE_ENUM(x) type_t type__##x = {type_kind_enum, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
#define DEFINE_STRUCT(x) type_t type__##x = {type_kind_struct, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
#define POINTER(x) (type_t){type_kind_pointer, s8_const(#x "*"), sizeof(void *), .base = &type__##x}
static gb_read_only type_t type__i8 = {type_kind_i8, s8_const("i8"), sizeof(i8)};
static gb_read_only type_t type__i16 = {type_kind_i16, s8_const("i16"), sizeof(i16)};
static gb_read_only type_t type__i32 = {type_kind_i32, s8_const("i32"), sizeof(i32)};
static gb_read_only type_t type__i64 = {type_kind_i64, s8_const("i64"), sizeof(i64)};
static gb_read_only type_t type__u8 = {type_kind_u8, s8_const("u8"), sizeof(u8)};
static gb_read_only type_t type__u16 = {type_kind_u16, s8_const("u16"), sizeof(u16)};
static gb_read_only type_t type__u32 = {type_kind_u32, s8_const("u32"), sizeof(u32)};
static gb_read_only type_t type__u64 = {type_kind_u64, s8_const("u64"), sizeof(u64)};
static gb_read_only type_t type__b8 = {type_kind_b8, s8_const("b8"), sizeof(b8)};
static gb_read_only type_t type__b16 = {type_kind_b16, s8_const("b16"), sizeof(b16)};
static gb_read_only type_t type__b32 = {type_kind_b32, s8_const("b32"), sizeof(b32)};
static gb_read_only type_t type__b64 = {type_kind_b64, s8_const("b64"), sizeof(b64)};
static gb_read_only type_t type__f32 = {type_kind_f32, s8_const("f32"), sizeof(f32)};
static gb_read_only type_t type__f64 = {type_kind_f64, s8_const("f64"), sizeof(f64)};
static gb_read_only type_t type__isize = {type_kind_isize, s8_const("isize"), sizeof(isize)};
static gb_read_only type_t type__usize = {type_kind_usize, s8_const("usize"), sizeof(usize)};
static gb_read_only type_t type__int = {type_kind_int, s8_const("int"), sizeof(int)};
static gb_read_only type_t type__char = {type_kind_char, s8_const("char"), sizeof(char)};
static gb_read_only type_t type__void = {type_kind_void, s8_const("void")};
static gb_read_only type_t type__s8_t = { type_kind_struct, s8_const("s8_t"), sizeof(s8_t), .count = 2,
.members = (type_member_t[]){
{s8_const("str"), &POINTER(char), .offset = offsetof(s8_t, str)},
{s8_const("len"), &type__i64, .offset = offsetof(s8_t, len)},
}
};
static gb_read_only type_t type__s16_t = { type_kind_struct, s8_const("s16_t"), sizeof(s16_t), .count = 2,
.members = (type_member_t[]){
{s8_const("str"), &POINTER(u16), .offset = offsetof(s16_t, str)},
{s8_const("len"), &type__i64, .offset = offsetof(s16_t, len)},
}
};
static gb_read_only type_t type__s32_t = { type_kind_struct, s8_const("s32_t"), sizeof(s32_t), .count = 2,
.members = (type_member_t[]){
{s8_const("str"), &POINTER(u32), .offset = offsetof(s32_t, str)},
{s8_const("len"), &type__i64, .offset = offsetof(s32_t, len)},
}
};
static gb_read_only type_t type__ma_arena_t = { type_kind_struct, s8_const("ma_arena_t"), sizeof(ma_arena_t), .count = 6,
.members = (type_member_t[]){
{s8_const("data"), &POINTER(u8), .offset = offsetof(ma_arena_t, data)},
{s8_const("len"), &type__usize, .offset = offsetof(ma_arena_t, len)},
{s8_const("base_len"), &type__usize, .offset = offsetof(ma_arena_t, base_len)},
{s8_const("reserve"), &type__usize, .offset = offsetof(ma_arena_t, reserve)},
{s8_const("commit"), &type__usize, .offset = offsetof(ma_arena_t, commit)},
{s8_const("align"), &type__usize, .offset = offsetof(ma_arena_t, align)},
}
};
static gb_read_only type_t type__sb8_node_t = {type_kind_struct, s8_const("sb8_node_t"), sizeof(sb8_t), .count = 2,
.members = (type_member_t[]){
{s8_const("next"), &POINTER(sb8_node_t), .offset = offsetof(sb8_node_t, next)},
{s8_const("string"), &type__s8_t, .offset = offsetof(sb8_node_t, string)},
}
};
static gb_read_only type_t type__sb8_t = { type_kind_struct, s8_const("sb8_t"), sizeof(sb8_t), .count = 4,
.members = (type_member_t[]){
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(sb8_t, arena)},
{s8_const("first"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, first)},
{s8_const("last"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, last)},
{s8_const("indent"), &type__i32, .offset = offsetof(sb8_t, indent)},
}
};
static gb_read_only type_t type__ma_temp_t = { type_kind_struct, s8_const("ma_temp_t"), sizeof(ma_temp_t), .count = 2,
.members = (type_member_t[]){
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(ma_temp_t, arena)},
{s8_const("len"), &type__usize, .offset = offsetof(ma_temp_t, len)},
}
};
static gb_read_only type_t type__v2f32_t = { type_kind_struct, s8_const("v2f32_t"), sizeof(v2f32_t), .count = 2,
.members = (type_member_t[]){
{s8_const("x"), &type__f32, .offset = offsetof(v2f32_t, x)},
{s8_const("y"), &type__f32, .offset = offsetof(v2f32_t, y)},
}
};
static gb_read_only type_t type__v3f32_t = { type_kind_struct, s8_const("v3f32_t"), sizeof(v3f32_t), .count = 3,
.members = (type_member_t[]){
{s8_const("x"), &type__f32, .offset = offsetof(v3f32_t, x)},
{s8_const("y"), &type__f32, .offset = offsetof(v3f32_t, y)},
{s8_const("z"), &type__f32, .offset = offsetof(v3f32_t, z)},
}
};
static gb_read_only type_t type__v4f32_t = { type_kind_struct, s8_const("v4f32_t"), sizeof(v4f32_t), .count = 4,
.members = (type_member_t[]){
{s8_const("x"), &type__f32, .offset = offsetof(v4f32_t, x)},
{s8_const("y"), &type__f32, .offset = offsetof(v4f32_t, y)},
{s8_const("z"), &type__f32, .offset = offsetof(v4f32_t, z)},
{s8_const("w"), &type__f32, .offset = offsetof(v4f32_t, w)},
}
};
static gb_read_only type_t type__r3f32_t = { type_kind_struct, s8_const("r3f32_t"), sizeof(r3f32_t), .count = 6,
.members = (type_member_t[]){
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, x0)},
{s8_const("y0"), &type__f32, .offset = offsetof(r3f32_t, y0)},
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, z0)},
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, x1)},
{s8_const("y1"), &type__f32, .offset = offsetof(r3f32_t, y1)},
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, z1)},
}
};
static gb_read_only type_member_t members__r2f32_t[] = {
{s8_const("x0"), &type__f32, .offset = offsetof(r2f32_t, x0)},
{s8_const("y0"), &type__f32, .offset = offsetof(r2f32_t, y0)},
{s8_const("x1"), &type__f32, .offset = offsetof(r2f32_t, x1)},
{s8_const("y1"), &type__f32, .offset = offsetof(r2f32_t, y1)},
};
static gb_read_only DEFINE_STRUCT(r2f32_t);
static gb_read_only type_member_t members__r1f32_t[] = {
{s8_const("x0"), &type__f32, .offset = offsetof(r1f32_t, x0)},
{s8_const("x1"), &type__f32, .offset = offsetof(r1f32_t, x1)},
};
static gb_read_only DEFINE_STRUCT(r1f32_t);
static gb_read_only type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
.members = (type_member_t[]){
{s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
{s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
}
};
static gb_read_only type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
.members = (type_member_t[]){
{s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
{s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
{s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
}
};
static gb_read_only type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
.members = (type_member_t[]){
{s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
{s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
{s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
{s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
}
};
static gb_read_only type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
.members = (type_member_t[]){
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
{s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
{s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
}
};
static gb_read_only type_member_t members__r2f64_t[] = {
{s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
{s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
{s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
{s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
};
static gb_read_only DEFINE_STRUCT(r2f64_t);
static gb_read_only type_member_t members__r1f64_t[] = {
{s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
{s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
};
static gb_read_only DEFINE_STRUCT(r1f64_t);
static gb_read_only type_t type__v2i32_t = { type_kind_struct, s8_const("v2i32_t"), sizeof(v2i32_t), .count = 2,
.members = (type_member_t[]){
{s8_const("x"), &type__i32, .offset = offsetof(v2i32_t, x)},
{s8_const("y"), &type__i32, .offset = offsetof(v2i32_t, y)},
}
};
static gb_read_only type_t type__v3i32_t = { type_kind_struct, s8_const("v3i32_t"), sizeof(v3i32_t), .count = 3,
.members = (type_member_t[]){
{s8_const("x"), &type__i32, .offset = offsetof(v3i32_t, x)},
{s8_const("y"), &type__i32, .offset = offsetof(v3i32_t, y)},
{s8_const("z"), &type__i32, .offset = offsetof(v3i32_t, z)},
}
};
static gb_read_only type_t type__v4i32_t = { type_kind_struct, s8_const("v4i32_t"), sizeof(v4i32_t), .count = 4,
.members = (type_member_t[]){
{s8_const("x"), &type__i32, .offset = offsetof(v4i32_t, x)},
{s8_const("y"), &type__i32, .offset = offsetof(v4i32_t, y)},
{s8_const("z"), &type__i32, .offset = offsetof(v4i32_t, z)},
{s8_const("w"), &type__i32, .offset = offsetof(v4i32_t, w)},
}
};
static gb_read_only type_t type__r3i32_t = { type_kind_struct, s8_const("r3i32_t"), sizeof(r3i32_t), .count = 6,
.members = (type_member_t[]){
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, x0)},
{s8_const("y0"), &type__i32, .offset = offsetof(r3i32_t, y0)},
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, z0)},
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, x1)},
{s8_const("y1"), &type__i32, .offset = offsetof(r3i32_t, y1)},
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, z1)},
}
};
static gb_read_only type_member_t members__r2i32_t[] = {
{s8_const("x0"), &type__i32, .offset = offsetof(r2i32_t, x0)},
{s8_const("y0"), &type__i32, .offset = offsetof(r2i32_t, y0)},
{s8_const("x1"), &type__i32, .offset = offsetof(r2i32_t, x1)},
{s8_const("y1"), &type__i32, .offset = offsetof(r2i32_t, y1)},
};
static gb_read_only DEFINE_STRUCT(r2i32_t);
static gb_read_only type_member_t members__r1i32_t[] = {
{s8_const("x0"), &type__i32, .offset = offsetof(r1i32_t, x0)},
{s8_const("x1"), &type__i32, .offset = offsetof(r1i32_t, x1)},
};
static gb_read_only DEFINE_STRUCT(r1i32_t);
static gb_read_only type_t type__v2i64_t = { type_kind_struct, s8_const("v2i64_t"), sizeof(v2i64_t), .count = 2,
.members = (type_member_t[]){
{s8_const("x"), &type__i64, .offset = offsetof(v2i64_t, x)},
{s8_const("y"), &type__i64, .offset = offsetof(v2i64_t, y)},
}
};
static gb_read_only type_t type__v3i64_t = { type_kind_struct, s8_const("v3i64_t"), sizeof(v3i64_t), .count = 3,
.members = (type_member_t[]){
{s8_const("x"), &type__i64, .offset = offsetof(v3i64_t, x)},
{s8_const("y"), &type__i64, .offset = offsetof(v3i64_t, y)},
{s8_const("z"), &type__i64, .offset = offsetof(v3i64_t, z)},
}
};
static gb_read_only type_t type__v4i64_t = { type_kind_struct, s8_const("v4i64_t"), sizeof(v4i64_t), .count = 4,
.members = (type_member_t[]){
{s8_const("x"), &type__i64, .offset = offsetof(v4i64_t, x)},
{s8_const("y"), &type__i64, .offset = offsetof(v4i64_t, y)},
{s8_const("z"), &type__i64, .offset = offsetof(v4i64_t, z)},
{s8_const("w"), &type__i64, .offset = offsetof(v4i64_t, w)},
}
};
static gb_read_only type_t type__r3i64_t = { type_kind_struct, s8_const("r3i64_t"), sizeof(r3i64_t), .count = 6,
.members = (type_member_t[]){
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, x0)},
{s8_const("y0"), &type__i64, .offset = offsetof(r3i64_t, y0)},
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, z0)},
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, x1)},
{s8_const("y1"), &type__i64, .offset = offsetof(r3i64_t, y1)},
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, z1)},
}
};
static gb_read_only type_member_t members__r2i64_t[] = {
{s8_const("x0"), &type__i64, .offset = offsetof(r2i64_t, x0)},
{s8_const("y0"), &type__i64, .offset = offsetof(r2i64_t, y0)},
{s8_const("x1"), &type__i64, .offset = offsetof(r2i64_t, x1)},
{s8_const("y1"), &type__i64, .offset = offsetof(r2i64_t, y1)},
};
static gb_read_only DEFINE_STRUCT(r2i64_t);
static gb_read_only type_member_t members__r1i64_t[] = {
{s8_const("x0"), &type__i64, .offset = offsetof(r1i64_t, x0)},
{s8_const("x1"), &type__i64, .offset = offsetof(r1i64_t, x1)},
};
static gb_read_only DEFINE_STRUCT(r1i64_t);
-199
View File
@@ -1,199 +0,0 @@
#include "core_unicode.h"
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance) {
utf32_result_t result = {0};
if (max_advance >= 1) {
result.advance = 1;
result.out_str = c[0];
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
if (max_advance >= 2) {
result.out_str = 0x10000;
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
result.advance = 2;
} else {
result.error = 2;
}
}
}
else {
result.error = 1;
}
return result;
}
fn utf8_result_t utf32_to_utf8(uint32_t codepoint) {
utf8_result_t result = {0};
if (codepoint <= 0x7F) {
result.len = 1;
result.out_str[0] = (char)codepoint;
}
else if (codepoint <= 0x7FF) {
result.len = 2;
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
result.out_str[1] = 0x80 | (0x3f & codepoint);
}
else if (codepoint <= 0xFFFF) { // 16 bit word
result.len = 3;
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
}
else if (codepoint <= 0x10FFFF) { // 21 bit word
result.len = 4;
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
}
else {
result.error = 1;
}
return result;
}
fn utf32_result_t utf8_to_utf32(char *c, int max_advance) {
utf32_result_t result = {0};
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
if (max_advance >= 1) {
result.out_str = c[0];
result.advance = 1;
}
else result.error = 1;
}
else if ((c[0] & 0xe0) == 0xc0) {
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
if (max_advance >= 2) {
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
result.advance = 2;
}
else result.error = 2;
}
else result.error = 2;
}
else if ((c[0] & 0xf0) == 0xe0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
if (max_advance >= 3) {
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
result.advance = 3;
}
else result.error = 3;
}
else result.error = 3;
}
else if ((c[0] & 0xf8) == 0xf0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
if (max_advance >= 4) {
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
result.advance = 4;
}
else result.error = 4;
}
else result.error = 4;
}
else result.error = 4;
return result;
}
fn utf16_result_t utf32_to_utf16(uint32_t codepoint) {
utf16_result_t result = {0};
if (codepoint < 0x10000) {
result.out_str[0] = (uint16_t)codepoint;
result.out_str[1] = 0;
result.len = 1;
}
else if (codepoint <= 0x10FFFF) {
uint32_t code = (codepoint - 0x10000);
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
result.len = 2;
}
else {
result.error = 1;
}
return result;
}
#define UTF__HANDLE_DECODE_ERROR(question_mark) \
{ \
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
break; \
}
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen && in[i];) {
utf32_result_t decode = utf16_to_utf32((uint16_t *)(in + i), (int)(inlen - i));
if (!decode.error) {
i += decode.advance;
utf8_result_t encode = utf32_to_utf8(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
}
else UTF__HANDLE_DECODE_ERROR('?');
}
else UTF__HANDLE_DECODE_ERROR('?');
}
buffer[outlen] = 0;
return outlen;
}
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen;) {
utf32_result_t decode = utf8_to_utf32(in + i, (int)(inlen - i));
if (!decode.error) {
i += decode.advance;
utf16_result_t encode = utf32_to_utf16(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
}
else UTF__HANDLE_DECODE_ERROR(0x003f);
}
else UTF__HANDLE_DECODE_ERROR(0x003f);
}
buffer[outlen] = 0;
return outlen;
}
fn void utf8_advance(utf8_iter_t *iter) {
iter->i += iter->utf8_codepoint_byte_size;
utf32_result_t r = utf8_to_utf32(iter->str + iter->i, iter->len - iter->i);
if (r.error) {
iter->item = 0;
return;
}
iter->utf8_codepoint_byte_size = r.advance;
iter->item = r.out_str;
}
// @todo: s8_t, change name
fn utf8_iter_t utf8_iterate_ex(char *str, int len) {
utf8_iter_t result = {str, len};
if (len) utf8_advance(&result);
return result;
}
fn utf8_iter_t utf8_iterate(char *str) {
int length = 0;
while (str[length]) length += 1;
return utf8_iterate_ex(str, length);
}
-56
View File
@@ -1,56 +0,0 @@
#pragma once
#include "core_basic.h"
typedef struct utf32_result_t utf32_result_t;
struct utf32_result_t {
uint32_t out_str;
int advance;
int error;
};
typedef struct utf16_result_t utf16_result_t;
struct utf16_result_t {
uint16_t out_str[2];
int len;
int error;
};
typedef struct utf8_result_t utf8_result_t;
struct utf8_result_t {
uint8_t out_str[4];
int len;
int error;
};
typedef struct utf8_iter_t utf8_iter_t;
struct utf8_iter_t {
char *str;
int len;
int utf8_codepoint_byte_size;
int i;
uint32_t item;
};
//
// codepoint conversions
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance);
fn utf8_result_t utf32_to_utf8(uint32_t codepoint);
fn utf32_result_t utf8_to_utf32(char *c, int max_advance);
fn utf16_result_t utf32_to_utf16(uint32_t codepoint);
//
// widestring / string conversions
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen);
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
//
// codepoint iterator
fn utf8_iter_t utf8_iterate(char *str);
fn utf8_iter_t utf8_iterate_ex(char *str, int len);
fn void utf8_advance(utf8_iter_t *iter);
/* example:
for (utf8_iter_t iter = utf8_iterate(string); iter.item; utf8_advance(&iter)) {
u32 codepoint = iter.item;
}
*/
-3
View File
@@ -1,3 +0,0 @@
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#undef STB_SPRINTF_IMPLEMENTATION
File diff suppressed because it is too large Load Diff
+1819
View File
File diff suppressed because it is too large Load Diff
+3655
View File
File diff suppressed because it is too large Load Diff
+311
View File
@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */
+2023
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
+5077
View File
File diff suppressed because it is too large Load Diff
-654
View File
@@ -1,654 +0,0 @@
#include "os.h"
#include "core/core_string16.h"
#include "core/core_platform.h"
#include "core/core_log.h"
///////////////////////////////////
#if PLATFORM_WINDOWS
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <DbgHelp.h>
#include <TlHelp32.h>
#include <Shlobj.h>
///////////////////////////////
fn os_date_t os_local_time(void) {
SYSTEMTIME lt;
GetLocalTime(&lt);
os_date_t result = {0};
result.ms = lt.wMilliseconds;
result.sec = lt.wSecond;
result.min = lt.wMinute;
result.hour = lt.wHour;
result.day = lt.wDay;
result.month = lt.wMonth;
result.year = lt.wYear;
return result;
}
fn os_date_t os_universal_time(void) {
SYSTEMTIME lt;
GetSystemTime(&lt);
os_date_t result = {0};
result.ms = lt.wMilliseconds;
result.sec = lt.wSecond;
result.min = lt.wMinute;
result.hour = lt.wHour;
result.day = lt.wDay;
result.month = lt.wMonth;
result.year = lt.wYear;
return result;
}
static int64_t win32_counts_per_second;
fn f64 os_seconds(void) {
if (win32_counts_per_second == 0) {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
win32_counts_per_second = freq.QuadPart;
}
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
f64 result = (f64)time.QuadPart / (f64)win32_counts_per_second;
return result;
}
// @todo: revise these conversions
fn f64 os_get_microseconds(void) {
f64 secs = os_seconds();
f64 result = secs * 1000000.0;
return result;
}
fn f64 os_milliseconds(void) {
f64 secs = os_seconds();
f64 result = secs * 1000.0;
return result;
}
fn void os_sleep(u32 milliseconds) {
Sleep(milliseconds);
}
///////////////////////////////
// files
fn b32 os_copy(s8_t from, s8_t to, b32 overwrite) {
BOOL fail_if_exists = true;
if (overwrite) fail_if_exists = false;
ma_temp_t scratch = ma_begin_scratch();
s16_t from16 = s16_from_s8(scratch.arena, from);
s16_t to16 = s16_from_s8(scratch.arena, to);
BOOL success = CopyFileW(from16.str, to16.str, fail_if_exists);
ma_end_scratch(scratch);
return success ? true : false;
}
fn b32 os_delete(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
BOOL success = DeleteFileW(path16.str);
ma_end_scratch(scratch);
return success ? true : false;
}
fn os_mkdir_t os_mkdir(s8_t path) {
os_mkdir_t result = os_mkdir_success;
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
BOOL success = CreateDirectoryW(path16.str, NULL);
if (success == 0) {
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS) result = os_mkdir_file_exists;
else if (error == ERROR_PATH_NOT_FOUND) result = os_mkdir_path_not_found;
else result = os_mkdir_other_error;
}
ma_end_scratch(scratch);
return result;
}
fn os_write_t os_write(s8_t path, s8_t content) {
os_write_t result = os_write_other_error;
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
HANDLE handle = CreateFileW(path16.str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) {
assert_expr(content.len == (DWORD)content.len);
DWORD bytes_written = 0;
BOOL error = WriteFile(handle, content.str, (DWORD)content.len, &bytes_written, NULL);
if (error == TRUE) {
if (bytes_written == content.len) {
result = os_write_success;
}
}
CloseHandle(handle);
} else result = os_write_path_not_found;
ma_end_scratch(scratch);
return result;
}
// @todo: improve to return error codes
fn s8_t os_read(ma_arena_t *arena, s8_t path) {
s8_t result = {0};
ma_temp_t scratch = ma_begin_scratch1(arena);
s16_t path16 = s16_from_s8(scratch.arena, path);
HANDLE handle = CreateFileW(path16.str, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER file_size;
if (GetFileSizeEx(handle, &file_size)) {
if (file_size.QuadPart != 0) {
result.len = file_size.QuadPart;
result.str = ma_push_array(arena, char, result.len + 1);
assert(result.len == (i64)(DWORD)result.len);
DWORD read;
if (ReadFile(handle, result.str, (DWORD)result.len, &read, NULL)) { // @todo: can only read 32 byte size files?
if (read == result.len) {
result.str[result.len] = 0;
}
}
}
}
CloseHandle(handle);
}
ma_end_scratch(scratch);
return result;
}
typedef struct w32_file_iter_t w32_file_iter_t;
struct w32_file_iter_t {
HANDLE handle;
WIN32_FIND_DATAW data;
};
fn void os_advance(os_iter_t *it) {
while (FindNextFileW(it->w32->handle, &it->w32->data) != 0) {
WIN32_FIND_DATAW *data = &it->w32->data;
// Skip '.' and '..'
if (data->cFileName[0] == '.' && data->cFileName[1] == '.' && data->cFileName[2] == 0) continue;
if (data->cFileName[0] == '.' && data->cFileName[1] == 0) continue;
it->is_directory = data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
it->name = s8_from_s16(it->arena, s16_make(data->cFileName, str16_len(data->cFileName)));
char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
it->rel = s8_printf(it->arena, "%.*s%s%.*s", s8_fmtspec(it->path), separator, s8_fmtspec(it->name));
it->abs = os_abs(it->arena, it->rel);
it->is_valid = true;
s8_normalize_path_unsafe(it->rel);
s8_normalize_path_unsafe(it->abs);
return;
}
it->is_valid = false;
DWORD error = GetLastError();
assert(error == ERROR_NO_MORE_FILES);
FindClose(it->w32->handle);
}
fn os_iter_t *os_iter(ma_arena_t *arena, s8_t path) {
os_iter_t *it = ma_push_type(arena, os_iter_t);
it->w32 = ma_push_type(arena, w32_file_iter_t);
it->arena = arena;
it->path = path;
it->is_valid = true;
ma_temp_t scratch = ma_begin_scratch1(arena);
s8_t mod_path = s8_printf(scratch.arena, "%.*s\\*", s8_fmtspec(path));
s16_t mod_path16 = s16_from_s8(scratch.arena, mod_path);
it->w32->handle = FindFirstFileW(mod_path16.str, &it->w32->data);
if (it->w32->handle == INVALID_HANDLE_VALUE) {
it->is_valid = false;
}
if (it->is_valid) {
assert(it->w32->data.cFileName[0] == '.' && it->w32->data.cFileName[1] == 0);
os_advance(it);
}
ma_end_scratch(scratch);
return it;
}
fn i64 os_mod_time(s8_t file) {
WIN32_FIND_DATAW data;
ma_temp_t scratch = ma_begin_scratch();
s16_t wpath = s16_from_s8(scratch.arena, file);
HANDLE handle = FindFirstFileW(wpath.str, &data);
i64 result = -1;
if (handle != INVALID_HANDLE_VALUE) {
FindClose(handle);
FILETIME time = data.ftLastWriteTime;
result = (i64)time.dwHighDateTime << 32 | time.dwLowDateTime;
}
ma_end_scratch(scratch);
return result;
}
fn s8_t os_abs(ma_arena_t *arena, s8_t rel) {
const int buffer_size = 2048;
ma_temp_t scratch = ma_begin_scratch1(arena);
s16_t rel16 = s16_from_s8(scratch.arena, rel);
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
DWORD written = GetFullPathNameW(rel16.str, buffer_size, buffer, 0);
assert(written != 0);
assert((i64)written < (i64)buffer_size);
s8_t result = s8_from_s16(arena, s16_make(buffer, written));
ma_end_scratch(scratch);
return result;
}
fn s8_t os_exe(ma_arena_t *arena) {
const int buffer_size = 2048;
ma_temp_t scratch = ma_begin_scratch1(arena);
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
DWORD wsize = GetModuleFileNameW(0, buffer, buffer_size);
assert(wsize != 0);
s8_t result = s8_from_s16(arena, s16_make(buffer, wsize));
s8_normalize_path_unsafe(result);
ma_end_scratch(scratch);
return result;
}
fn s8_t os_exe_dir(ma_arena_t *arena) {
ma_temp_t scratch = ma_begin_scratch1(arena);
s8_t exe = os_exe(scratch.arena);
s8_t path = s8_chop_last_slash(exe);
s8_t result = s8_printf(arena, "%.*s", s8_fmtspec(path));
ma_end_scratch(scratch);
return result;
}
fn b32 os_is_dir(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
DWORD dwAttrib = GetFileAttributesW(path16.str);
ma_end_scratch(scratch);
return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}
fn b32 os_is_file(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
DWORD dwAttrib = GetFileAttributesW(path16.str);
ma_end_scratch(scratch);
b32 is_file = (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0;
return dwAttrib != INVALID_FILE_ATTRIBUTES && is_file;
}
fn b32 os_is_abs(s8_t path) {
b32 result = path.len > 3 && char_is_alphabetic(path.str[0]) && path.str[1] == ':' && path.str[2] == '/';
return result;
}
fn b32 os_exists(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
DWORD attribs = GetFileAttributesW(path16.str);
ma_end_scratch(scratch);
return attribs == INVALID_FILE_ATTRIBUTES ? false : true;
}
fn s8_t os_cwd(ma_arena_t *arena) {
ma_temp_t scratch = ma_begin_scratch1(arena);
const u32 buffer_size = 1024;
wchar_t *buffer = ma_push_array(scratch.arena, wchar_t, buffer_size);
DWORD wsize = GetCurrentDirectoryW(buffer_size, buffer);
assert(wsize != 0);
assert(wsize <= buffer_size);
s8_t path = s8_from_s16(scratch.arena, s16_make(buffer, wsize));
s8_normalize_path_unsafe(path);
s8_t result = s8_printf(arena, "%.*s", s8_fmtspec(path));
ma_end_scratch(scratch);
return result;
}
fn void os_set_cwd(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s16_t path16 = s16_from_s8(scratch.arena, path);
SetCurrentDirectoryW(path16.str);
ma_end_scratch(scratch);
}
///////////////////////////////
// threading
typedef struct w32_thread_t w32_thread_t;
struct w32_thread_t {
HANDLE handle;
DWORD id;
};
fn os_thread_t os_thread_create(ma_arena_t *arena, os_thread_fn_t *func, void *user_data) {
assert(func);
LPSECURITY_ATTRIBUTES security_attribs = NULL;
SIZE_T stack_size = 0;
DWORD creation_flags = 0;
DWORD thread_id = 0;
HANDLE thread_handle = CreateThread(security_attribs, stack_size, (LPTHREAD_START_ROUTINE)func, user_data, creation_flags, &thread_id);
if (thread_handle == NULL) {
debugf("%s.CreatedThread failed: %d", __FUNCTION__, GetLastError());
return (os_thread_t){.exited = true};
}
os_thread_t result = {0};
result.w32 = ma_push_type(arena, w32_thread_t);
result.w32->handle = thread_handle;
result.w32->id = thread_id;
return result;
}
fn i32 os_thread_join(os_thread_t *thread) {
DWORD return_value_indicates_event = WaitForSingleObject(thread->w32->handle, INFINITE);
if (return_value_indicates_event != WAIT_OBJECT_0) {
debugf("%s.WaitForSingleObject failed: %d", __FUNCTION__, GetLastError());
}
DWORD exit_code = 0;
BOOL if_fails_then_zero = GetExitCodeThread(thread->w32->handle, &exit_code);
if (if_fails_then_zero == 0) {
debugf("%s.GetExitCodeThread failed: %d", __FUNCTION__, GetLastError());
} else {
thread->exit_code = exit_code;
}
CloseHandle(thread->w32->handle);
thread->exited = true;
return thread->exit_code;
}
// @todo:
// This will probably create 16 arenas or more XD
// fn i32 os__thread_log(void *data) {
// os_core_init();
// debugf("testing");
// return 0;
// }
// fn void os_test_threads(void) {
// os_thread_t threads[16];
// ma_temp_t scratch = ma_begin_scratch();
// for (int i = 0; i < lengthof(threads); i += 1) {
// threads[i] = os_thread_create(scratch.arena, os__thread_log, NULL);
// }
// for (int i = 0; i < lengthof(threads); i += 1) {
// os_thread_join(&threads[i]);
// }
// ma_end_scratch(scratch);
// }
fn s8_t os_appdata(ma_arena_t *arena, s8_t name) {
assert(name.len != 0);
assert(name.str);
assert(arena);
wchar_t *out_path = NULL;
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &out_path);
if (!SUCCEEDED(hr)) {
debugf("%s.SHGetKnownFolderPath failed with hr: %d", __FUNCTION__, hr);
return s8_null;
}
s16_t appdata_path = s16_from_str16((u16 *)out_path);
ma_temp_t scratch = ma_begin_scratch1(arena);
s8_t tmp = s8_from_s16(scratch.arena, appdata_path);
s8_normalize_path_unsafe(tmp);
s8_t path = s8_printf(arena, "%.*s/%.*s", s8_fmtspec(tmp), s8_fmtspec(name));
os_mkdir_t mkdir_status = os_mkdir(path);
if (mkdir_status != os_mkdir_success && mkdir_status != os_mkdir_file_exists) {
debugf("%s.os_mkdir failed with status: %d, for: %.*s", __FUNCTION__, mkdir_status, s8_fmtspec(path));
path = s8_null;
}
CoTaskMemFree(out_path);
ma_end_scratch(scratch);
return path;
}
///////////////////////////////////
#elif PLATFORM_POSIX
///////////////////////////////////
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
fn os_date_t os_local_time(void) {
os_date_t result = {0};
time_t t = time(NULL);
struct tm *lt = localtime(&t);
result.sec = lt->tm_sec;
result.min = lt->tm_min;
result.hour = lt->tm_hour;
result.day = lt->tm_mday;
result.month = lt->tm_mon;
result.year = lt->tm_year;
return result;
}
fn os_date_t os_universal_time(void) {
os_date_t result = {0};
time_t t = time(NULL);
struct tm u = {0};
gmtime_r(&t, &u);
result.sec = u.tm_sec;
result.min = u.tm_min;
result.hour = u.tm_hour;
result.day = u.tm_mday;
result.month = u.tm_mon;
result.year = u.tm_year;
return result;
}
fn f64 os_get_microseconds(void) {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
u64 result = t.tv_sec*million(1) + (t.tv_nsec/thousand(1));
return (f64)result;
}
fn f64 os_get_milliseconds(void) {
u64 micros = os_get_microseconds();
f64 result = (f64)micros / 1000.0;
return result;
}
fn s8_t os_exe(ma_arena_t *arena) {
const i32 buffer_size = 2048;
ma_temp_t temp = ma_begin_scratch1(arena);
char *buffer = ma_push_array(arena, char, buffer_size);
ssize_t size = readlink("/proc/self/exe", buffer, buffer_size);
assert(size < buffer_size); // @todo:?
assert(size != -1);
s8_t string = s8_copy(arena, s8_make(buffer, size));
ma_end_scratch(temp);
return string;
}
fn s8_t os_exe_dir(ma_arena_t *arena) {
ma_temp_t temp = ma_begin_scratch1(arena);
s8_t exe = os_exe(temp.arena);
s8_t dir = s8_chop_last_slash(exe);
s8_t result = s8_copy(arena, dir);
ma_end_scratch(temp);
return result;
}
fn s8_t os_cwd(ma_arena_t *arena) {
const i32 buffer_size = 2048;
ma_temp_t temp = ma_begin_scratch1(arena);
char *buffer = ma_push_array(arena, char, buffer_size);
char *ok = getcwd(buffer, buffer_size);
assert(ok);
s8_t result = s8_copy(arena, s8_from_char(buffer));
ma_end_scratch(temp);
return result;
}
fn void os_set_cwd(s8_t path) {
ma_temp_t temp = ma_begin_scratch();
chdir(s8_copy(temp.arena, path).str);
ma_end_scratch(temp);
}
fn b32 os_exists(s8_t path) {
ma_temp_t temp = ma_begin_scratch();
s8_t copy = s8_copy(temp.arena, path);
int ok = access(copy.str, F_OK);
ma_end_scratch(temp);
return ok == 0 ? true : false;
}
fn b32 os_is_dir(s8_t path) {
b32 result = false;
ma_temp_t temp = ma_begin_scratch();
s8_t copy = s8_copy(temp.arena, path);
DIR *dir = opendir(copy.str);
if (dir) {
result = true;
closedir(dir);
}
ma_end_scratch(temp);
return result;
}
fn b32 os_is_file(s8_t path) {
ma_temp_t temp = ma_begin_scratch();
s8_t copy = s8_copy(temp.arena, path);
struct stat path_stat;
stat(copy.str, &path_stat);
ma_end_scratch(temp);
b32 result = S_ISREG(path_stat.st_mode);
return result;
}
fn b32 os_is_abs(s8_t path) {
b32 result = path.len && path.str[0] == '/';
return result;
}
fn s8_t os_abs(ma_arena_t *arena, s8_t path) {
ma_temp_t temp = ma_begin_scratch1(arena);
s8_t null_term_path = s8_copy(temp.arena, path);
char buffer[PATH_MAX];
char *resolved_path = realpath(null_term_path.str, buffer);
s8_t result = s8_copy(arena, s8_from_char(resolved_path));
ma_end_scratch(temp);
return result;
}
fn s8_t os_read(ma_arena_t *arena, s8_t path) {
s8_t result = {0};
ma_temp_t temp = ma_begin_scratch1(arena);
s8_t copy_path = s8_copy(temp.arena, path);
FILE *fd = fopen(copy_path.str, "rb");
if (fd) {
fseek(fd, 0, SEEK_END);
long size = ftell(fd);
fseek(fd, 0, SEEK_SET);
char *string = malloc(size + 1);
fread(string, size, 1, fd);
fclose(fd);
result = s8_make(string, size);
result.str[result.len] = 0;
}
ma_end_scratch(temp);
return result;
}
fn os_write_t os_write(s8_t path, s8_t content) {
os_write_t result = os_write_path_not_found;
ma_temp_t scratch = ma_begin_scratch();
s8_t copy_path = s8_copy(scratch.arena, path);
FILE *fd = fopen(copy_path.str, "w");
if (fd) {
size_t size_written = fwrite(content.str, 1, content.len, fd);
assert((int64_t)size_written == content.len);
fclose(fd);
result = os_write_success;
}
ma_end_scratch(scratch);
return result;
}
fn b32 os_copy(s8_t src_path, s8_t dst_path, b32 overwrite) {
if (overwrite == false && os_exists(dst_path)) {
return 0;
}
ma_temp_t temp = ma_begin_scratch();
s8_t src_data = os_read(temp.arena, src_path);
os_write_t write_result = os_write(dst_path, src_data);
b32 result = write_result == os_write_success;
ma_end_scratch(temp);
return result;
}
fn b32 os_delete(s8_t path) {
ma_temp_t scratch = ma_begin_scratch();
s8_t copy_path = s8_copy(scratch.arena, path);
int rc = unlink(copy_path.str);
ma_end_scratch(scratch);
return (b32)(rc == 0);
}
fn void os_advance(os_iter_t *it) {
struct dirent *file = NULL;
while ((file = readdir((DIR *)it->unix_dir)) != NULL) {
if (file->d_name[0] == '.' && file->d_name[1] == '.' && file->d_name[2] == 0) {
continue;
}
if (file->d_name[0] == '.' && file->d_name[1] == 0) {
continue;
}
it->is_directory = file->d_type == DT_DIR;
it->name = s8_copy(it->arena, s8_from_char(file->d_name));
const char *separator = it->path.str[it->path.len - 1] == '/' ? "" : "/";
it->rel = s8_printf(it->arena, "%.*s%s%s", s8_fmtspec(it->path), separator, file->d_name);
it->abs = os_abs(it->arena, it->rel);
it->is_valid = true;
return;
}
it->is_valid = false;
closedir((DIR *)it->unix_dir);
}
fn os_iter_t *os_iter(ma_arena_t *arena, s8_t path) {
os_iter_t *it = ma_push_type(arena, os_iter_t);
it->arena = arena;
it->path = s8_copy(arena, path);
it->unix_dir = opendir(s8_copy(arena, it->path).str);
if (it->unix_dir) {
it->is_valid = true;
os_advance(it);
}
return it;
}
///////////////////////////////////
#endif // PLATFORM_POSIX
///////////////////////////////////
fn s8_t os_format_date(ma_arena_t *arena, os_date_t date) {
s8_t result = s8_printf(arena, "%04u-%02u-%02u %02u:%02u:%02u.%03u", date.year, date.month, date.day, date.hour, date.min, date.sec, date.ms);
return result;
}
#if PLATFORM_WINDOWS || PLATFORM_POSIX
fn int os_systemf(const char *string, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, string, result);
int error_code = system(result.str);
ma_end_scratch(scratch);
return error_code;
}
#endif
-90
View File
@@ -1,90 +0,0 @@
#pragma once
#include "core/core_basic.h"
#include "core/core_string.h"
typedef struct os_date_t os_date_t;
struct os_date_t {
u16 ms;
u16 sec;
u16 min;
u16 hour;
u16 day;
u16 month;
u16 year;
};
typedef struct os_iter_t os_iter_t;
struct os_iter_t {
s8_t abs;
s8_t rel;
s8_t name;
b8 is_directory;
b8 is_valid;
s8_t path;
ma_arena_t *arena;
union {
struct w32_file_iter_t *w32;
void *platform;
void *unix_dir;
};
};
typedef enum {
os_mkdir_success,
os_mkdir_file_exists,
os_mkdir_path_not_found,
os_mkdir_other_error,
} os_mkdir_t;
typedef enum {
os_write_success,
os_write_path_not_found,
os_write_other_error,
} os_write_t;
fn os_date_t os_local_time(void);
fn os_date_t os_universal_time(void);
fn s8_t os_format_date(ma_arena_t *arena, os_date_t date);
fn f64 os_seconds(void);
fn f64 os_milliseconds(void);
fn f64 os_get_microseconds(void);
fn b32 os_copy(s8_t from, s8_t to, b32 overwrite);
fn b32 os_delete(s8_t path);
fn os_mkdir_t os_mkdir(s8_t path);
fn os_write_t os_write(s8_t path, s8_t content);
fn s8_t os_read(ma_arena_t *arena, s8_t path);
fn void os_advance(os_iter_t *it);
fn os_iter_t *os_iter(ma_arena_t *arena, s8_t path);
fn i64 os_mod_time(s8_t file);
fn s8_t os_abs(ma_arena_t *arena, s8_t rel);
fn s8_t os_exe(ma_arena_t *arena);
fn s8_t os_exe_dir(ma_arena_t *arena);
fn b32 os_is_dir(s8_t path);
fn b32 os_is_file(s8_t path);
fn b32 os_is_abs(s8_t path);
fn b32 os_exists(s8_t path);
fn s8_t os_cwd(ma_arena_t *arena);
fn void os_set_cwd(s8_t new_cwd);
fn s8_t os_appdata(ma_arena_t *arena, s8_t name);
typedef i32 os_thread_fn_t(void *user_data);
typedef struct os_thread_t os_thread_t;
struct os_thread_t {
b32 exited;
i32 exit_code;
union {
struct w32_thread_t *w32;
void *ptr;
};
};
fn os_thread_t os_thread_create(ma_arena_t *arena, os_thread_fn_t *func, void *user_data);
fn i32 os_thread_wait_for_exit(os_thread_t *thread);
+165
View File
@@ -0,0 +1,165 @@
struct Glyph {
Vec2 size;
Vec2 offset;
float xadvance;
float left_side_bearing;
Rect2 atlas_bounding_box;
};
struct Font {
Array<Glyph> glyphs;
uint32_t first_char, last_char;
uint32_t texture_id;
float size;
float descent;
float ascent;
float line_gap;
Int line_spacing;
Int char_spacing;
Rect2 white_texture_bounding_box;
};
struct Atlas {
uint8_t *bitmap;
Vec2I size;
Vec2 inverse_size;
int xcursor;
int ycursor;
int32_t biggest_height;
Rect2 white_texture_bounding_box;
uint32_t texture_id;
};
Atlas CreateAtlas(Allocator allocator, Vec2I size) {
Atlas result = {};
result.size = size;
result.inverse_size.x = 1.f / (float)result.size.x;
result.inverse_size.y = 1.f / (float)result.size.y;
result.bitmap = AllocArray(allocator, uint8_t, size.x * size.y);
// Add a whitebox first for rectangle rendering
for (int y = 0; y < 16; y++) {
for (int x = 0; x < 16; x++) {
uint8_t *dst = result.bitmap + x + y * result.size.x;
*dst = 0xff;
}
}
result.white_texture_bounding_box = {
{ 2.f * result.inverse_size.x, 2.f / (float)result.size.y},
{14.f * result.inverse_size.x, 14.f / (float)result.size.y}
};
result.xcursor += 16;
result.biggest_height += 16;
return result;
}
Rect2 PackBitmap(Atlas *atlas, uint8_t *bitmap, int width, int height) {
// Packing into a texture atlas
// @Inefficient The algorithm is a simplest thing I had in mind, first we advance
// through the atlas in X packing consecutive glyphs. After we get to the end of the row
// we advance to the next row by the Y size of the biggest packed glyph. If we get to the
// end of atlas and fail to pack everything the app panics.
int spacing = 4;
if (atlas->xcursor + width > atlas->size.x) {
if (atlas->ycursor + height < atlas->size.y) {
atlas->xcursor = 0;
atlas->ycursor += atlas->biggest_height + spacing;
} else {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Font loading error!", "Error while packing a font into atlas. Atlas size for this font scale is a bit too small", NULL);
}
}
uint8_t *src = bitmap;
for (int y = atlas->ycursor; y < atlas->ycursor + height; y += 1) {
for (int x = atlas->xcursor; x < atlas->xcursor + width; x += 1) {
uint8_t *dst = atlas->bitmap + x + y * atlas->size.x;
*dst = *src++;
}
}
Vec2 size = {(float)width * atlas->inverse_size.x, (float)height * atlas->inverse_size.y};
Vec2 pos = {(float)atlas->xcursor * atlas->inverse_size.x, (float)atlas->ycursor * atlas->inverse_size.y};
Rect2 result = {pos.x, pos.y, pos.x + size.x, pos.y + size.y};
atlas->xcursor += width + spacing;
if (height > atlas->biggest_height) {
atlas->biggest_height = height;
}
return result;
}
Glyph *GetGlyph(Font *font, uint32_t codepoint) {
bool is_in_range = codepoint >= font->first_char && codepoint <= font->last_char;
if (is_in_range) {
uint32_t index = codepoint - font->first_char;
return &font->glyphs[index];
} else {
uint32_t index = '?' - font->first_char;
return &font->glyphs[index];
}
}
Font CreateFont(Atlas *atlas, int32_t size, String path) {
Allocator allocator = GetSystemAllocator();
Scratch scratch;
Font result = {};
result.glyphs.allocator = allocator;
String file = ReadFile(scratch, path);
if (file.len == 0) {
file = BakedInFont;
Assert(file.len != 0);
}
stbtt_fontinfo stb_font;
int success = stbtt_InitFont(&stb_font, (const unsigned char *)file.data, 0);
if (!success) {
return result;
}
float scale = stbtt_ScaleForPixelHeight(&stb_font, (float)size);
// float em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, (float)size);
int ascent, descent, line_gap;
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &line_gap);
result.ascent = (float)ascent * scale;
result.descent = (float)descent * scale;
result.line_gap = (float)line_gap * scale;
result.size = (float)size;
result.first_char = ' ';
result.last_char = '~';
result.white_texture_bounding_box = atlas->white_texture_bounding_box;
int glyph_count = result.last_char - result.first_char + 1; // + 1 because it's '<=' not '<'
Reserve(&result.glyphs, glyph_count);
for (uint32_t ascii_symbol = result.first_char; ascii_symbol <= result.last_char; ascii_symbol++) {
int width, height, xoff, yoff;
uint8_t *bitmap = (uint8_t *)stbtt_GetCodepointBitmap(&stb_font, 0, scale, ascii_symbol, &width, &height, &xoff, &yoff);
defer { stbtt_FreeBitmap(bitmap, 0); };
int xadvance, left_side_bearing;
stbtt_GetCodepointHMetrics(&stb_font, ascii_symbol, &xadvance, &left_side_bearing);
Glyph glyph = {};
glyph.atlas_bounding_box = PackBitmap(atlas, bitmap, width, height);
glyph.size = {(float)width, (float)height};
glyph.offset = {(float)xoff, (float)yoff};
glyph.xadvance = (float)xadvance * scale;
glyph.left_side_bearing = (float)left_side_bearing * scale;
Add(&result.glyphs, glyph);
}
Glyph *g = GetGlyph(&result, '_');
result.char_spacing = (Int)g->xadvance ? (Int)g->xadvance : (Int)g->size.x;
result.line_spacing = (Int)(result.ascent - result.descent + result.line_gap);
return result;
}
File diff suppressed because it is too large Load Diff
+404
View File
@@ -0,0 +1,404 @@
struct Vertex2D {
Vec2 pos;
Vec2 tex;
Color color;
};
struct VertexNode2D {
VertexNode2D *next;
int count;
Vertex2D vertices[1024 * 16];
Rect2 scissor;
};
struct VertexList2D {
VertexNode2D *first;
VertexNode2D *last;
};
struct Shader {
GLuint program; // linked program (vertex+fragment)
GLint uni_invHalf; // uniform location for inv half-screen size
GLint uni_texture; // sampler location
};
VertexList2D Vertices;
int64_t TotalVertexCount;
unsigned VBO, VAO;
Shader Shader2D;
BlockArena RenderArena;
Rect2 CurrentScissor;
Font PrimaryFont;
Font SecondaryFont;
// ---------- shaders (ES3 / WebGL2) ----------
static const char *glsl_vshader_es3 = R"==(#version 300 es
precision highp float;
uniform vec2 U_InvHalfScreenSize; // same meaning as before
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec2 aTex;
layout(location = 2) in vec4 aColor; // normalized unsigned byte will map to 0..1 if we use normalized=true
out vec2 vUV;
out vec4 vColor;
void main() {
vec2 pos = aPos * U_InvHalfScreenSize;
pos.y = 2.0 - pos.y; // invert Y the same way you had
pos -= vec2(1.0, 1.0);
gl_Position = vec4(pos, 0.0, 1.0);
vUV = aTex;
vColor = aColor; // already 0..1
}
)==";
static const char *glsl_fshader_es3 = R"==(#version 300 es
precision mediump float;
in vec2 vUV;
in vec4 vColor;
uniform sampler2D S_Texture;
out vec4 OutColor;
void main() {
float a = texture(S_Texture, vUV).r;
vec4 c = vColor;
c.a *= a;
OutColor = c;
}
)==";
void ReportWarningf(const char *fmt, ...);
void GLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) {
ReportWarningf("OpenGL message: %s", message);
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL error", message, NULL);
}
}
// ---------- helper: compile/link ----------
static GLuint CompileShaderSrc(GLenum kind, const char *src) {
GLuint s = glCreateShader(kind);
glShaderSource(s, 1, &src, NULL);
glCompileShader(s);
GLint ok = 0;
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
if (!ok) {
char buf[1024];
glGetShaderInfoLog(s, sizeof(buf), NULL, buf);
SDL_Log("%s", buf);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
(kind == GL_VERTEX_SHADER ? "Vertex shader compile error" : "Fragment shader compile error"),
buf, NULL);
}
return s;
}
Shader CreateShaderES3(const char *vsrc, const char *fsrc) {
Shader out = {};
GLuint vs = CompileShaderSrc(GL_VERTEX_SHADER, vsrc);
GLuint fs = CompileShaderSrc(GL_FRAGMENT_SHADER, fsrc);
GLuint prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
// Bind attribute locations to match layout locations (optional because we use layout(location=...))
// glBindAttribLocation(prog, 0, "aPos");
// glBindAttribLocation(prog, 1, "aTex");
// glBindAttribLocation(prog, 2, "aColor");
glLinkProgram(prog);
GLint linked = 0;
glGetProgramiv(prog, GL_LINK_STATUS, &linked);
if (!linked) {
char buf[1024];
glGetProgramInfoLog(prog, sizeof(buf), NULL, buf);
SDL_Log("%s", buf);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Program link error", buf, NULL);
}
// We can detach/delete shaders after linking
glDetachShader(prog, vs);
glDetachShader(prog, fs);
glDeleteShader(vs);
glDeleteShader(fs);
out.program = prog;
out.uni_invHalf = glGetUniformLocation(prog, "U_InvHalfScreenSize");
out.uni_texture = glGetUniformLocation(prog, "S_Texture");
return out;
}
// ---------- InitRender for ES3 ----------
void InitRender() {
#if !OS_WASM
glDebugMessageCallback(&GLDebugCallback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
#endif
// Create VBO (non-DSA path)
glGenBuffers(1, &VBO);
// reserve buffer big enough for one VertexNode2D->vertices array (same as original intent)
GLsizeiptr vbo_size = (GLsizeiptr) (Lengthof(((VertexNode2D*)0)->vertices) * sizeof(Vertex2D));
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vbo_size, NULL, GL_DYNAMIC_DRAW); // NULL initial, dynamic usage
// Create and setup VAO
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// attribute 0 : pos (vec2, floats)
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, pos));
// attribute 1 : tex (vec2)
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, tex));
// attribute 2 : color (vec4) -- stored as 4 unsigned bytes; we want normalized floats 0..1
glEnableVertexAttribArray(2);
// Using normalized GL_TRUE to map 0..255 -> 0..1 directly in shader
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D), (const void*)offsetof(Vertex2D, color));
// Unbind VAO and VBO
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Create shader program (ES3)
Shader2D = CreateShaderES3(glsl_vshader_es3, glsl_fshader_es3);
// other initializations like fonts will be done elsewhere (ReloadFont)
}
void BeginFrameRender(float wx, float wy) {
Release(&RenderArena);
TotalVertexCount = 0;
Vertices.first = NULL;
Vertices.last = NULL;
CurrentScissor = Rect0Size(wx, wy);
}
// ---------- EndFrameRender for ES3 ----------
void EndFrameRender(float wx, float wy, Color color) {
ProfileFunction();
glEnable(GL_BLEND);
glEnable(GL_SCISSOR_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glViewport(0, 0, (GLsizei)wx, (GLsizei)wy);
glScissor(0, 0, (GLsizei)wx, (GLsizei)wy);
glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Use program and set uniforms
glUseProgram(Shader2D.program);
float xinverse = 1.f / (wx / 2.f);
float yinverse = 1.f / (wy / 2.f);
// set uniform (U_InvHalfScreenSize)
if (Shader2D.uni_invHalf >= 0) {
glUniform2f(Shader2D.uni_invHalf, xinverse, yinverse);
}
// set sampler to texture unit 0
if (Shader2D.uni_texture >= 0) {
glUniform1i(Shader2D.uni_texture, 0);
}
glBindVertexArray(VAO);
for (VertexNode2D *it = Vertices.first; it; it = it->next) {
Rect2 rect = it->scissor;
GLint x = (GLint)rect.min.x;
GLint y = (GLint)rect.min.y;
GLsizei w = (GLsizei)(rect.max.x - x);
GLsizei h = (GLsizei)(rect.max.y - y);
// convert scissor Y to OpenGL bottom-left origin like before
glScissor(x, (GLint)wy - (GLint)rect.max.y, w, h);
// upload vertex data into VBO at offset 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, it->count * sizeof(Vertex2D), it->vertices);
// bind texture unit 0 and the font texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, PrimaryFont.texture_id);
// draw
glDrawArrays(GL_TRIANGLES, 0, it->count);
// unbind VBO (optional)
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
glUseProgram(0);
}
VertexNode2D *AllocVertexNode2D(Allocator allocator, VertexList2D *list) {
VertexNode2D *node = AllocType(allocator, VertexNode2D);
SLL_QUEUE_ADD(list->first, list->last, node);
return node;
}
void SetScissor(Rect2 rect) {
CurrentScissor = rect;
VertexNode2D *node = Vertices.last;
if (!node) {
node = AllocVertexNode2D(RenderArena, &Vertices);
node->scissor = rect;
return;
}
if (node->scissor != rect && node->count == 0) {
node->scissor = rect;
return;
}
if (node->scissor != rect) {
node = AllocVertexNode2D(RenderArena, &Vertices);
node->scissor = rect;
return;
}
}
void SetScissor(Rect2I rect) { SetScissor(ToRect2(rect)); }
Vertex2D *AllocVertex2D(Allocator allocator, VertexList2D *list, int count) {
VertexNode2D *node = list->last;
if (node == 0 || node->count + count > Lengthof(node->vertices)) {
node = AllocVertexNode2D(allocator, list);
node->scissor = CurrentScissor;
}
TotalVertexCount += count;
Vertex2D *result = node->vertices + node->count;
node->count += count;
return result;
}
void PushVertex2D(Allocator allocator, VertexList2D *list, Vertex2D *vertices, int count) {
Vertex2D *result = AllocVertex2D(allocator, list, count);
for (int i = 0; i < count; i += 1) result[i] = vertices[i];
}
void PushQuad2D(Allocator arena, VertexList2D *list, Rect2 rect, Rect2 tex, Color color, float rotation = 0.f, Vec2 rotation_point = {}) {
Vertex2D *v = AllocVertex2D(arena, list, 6);
v[0] = { {rect.min.x, rect.max.y}, { tex.min.x, tex.max.y}, color };
v[1] = { {rect.max.x, rect.max.y}, { tex.max.x, tex.max.y}, color };
v[2] = { {rect.min.x, rect.min.y}, { tex.min.x, tex.min.y}, color };
v[3] = { {rect.min.x, rect.min.y}, { tex.min.x, tex.min.y}, color };
v[4] = { {rect.max.x, rect.max.y}, { tex.max.x, tex.max.y}, color };
v[5] = { {rect.max.x, rect.min.y}, { tex.max.x, tex.min.y}, color };
if (rotation != 0.f) {
float s = sinf(rotation);
float c = cosf(rotation);
for (int i = 0; i < 6; i += 1) {
v[i].pos -= rotation_point;
v[i].pos = {v[i].pos.x * c + v[i].pos.y * (-s), v[i].pos.x * s + v[i].pos.y * c};
v[i].pos += rotation_point;
}
}
}
void DrawRect(Rect2 rect, Color color) {
PushQuad2D(RenderArena, &Vertices, rect, PrimaryFont.white_texture_bounding_box, color);
}
void DrawRect(Rect2I rect, Color color) {
PushQuad2D(RenderArena, &Vertices, ToRect2(rect), PrimaryFont.white_texture_bounding_box, color);
}
void DrawRectOutline(Rect2 rect, Color color, float thickness = 2) {
Rect2 a = CutLeft(&rect, thickness);
Rect2 b = CutRight(&rect, thickness);
Rect2 c = CutTop(&rect, thickness);
Rect2 d = CutBottom(&rect, thickness);
PushQuad2D(RenderArena, &Vertices, a, PrimaryFont.white_texture_bounding_box, color);
PushQuad2D(RenderArena, &Vertices, b, PrimaryFont.white_texture_bounding_box, color);
PushQuad2D(RenderArena, &Vertices, c, PrimaryFont.white_texture_bounding_box, color);
PushQuad2D(RenderArena, &Vertices, d, PrimaryFont.white_texture_bounding_box, color);
}
void DrawRectOutline(Rect2I rect, Color color, Int thickness = 2) {
DrawRectOutline(ToRect2(rect), color, (float)thickness);
}
Vec2 DrawString(Font *font, String16 string, Vec2 pos, Color color, bool draw = true) {
pos.y += font->line_spacing + font->descent; // TODO: descent?
Vec2 original_pos = pos;
For(string) {
Glyph *g = GetGlyph(font, it);
Rect2 rect = Rect2FromSize(pos + g->offset, g->size);
if (draw && it != '\n' && it != ' ' && it != '\t') {
PushQuad2D(RenderArena, &Vertices, rect, g->atlas_bounding_box, color);
}
pos.x += g->xadvance;
}
Vec2 result = {pos.x - original_pos.x, font->size};
return result;
}
void DrawCircle(Vec2 pos, float radius, Color color) {
const int segment_count = 16;
const int vertex_count = segment_count * 3;
Vec2 points[segment_count + 1];
for (int i = 0; i < Lengthof(points); i += 1) {
float radians = 2.0f * PI32 * float(i) / float(segment_count);
float x = radius * cosf(radians);
float y = radius * sinf(radians);
points[i] = {x, y};
}
points[segment_count] = points[0]; // wrap around
Vertex2D *vertices = AllocVertex2D(RenderArena, &Vertices, vertex_count);
int point_i = 0;
int segment_i = 0;
for (; segment_i < vertex_count; segment_i += 3, point_i += 1) {
Rect2 tex = PrimaryFont.white_texture_bounding_box;
Vertex2D *it = vertices + segment_i;
it[0].color = color;
it[1].color = color;
it[2].color = color;
it[0].tex = {tex.min.x, tex.max.y};
it[1].tex = {tex.max.x, tex.max.y};
it[2].tex = {tex.min.x, tex.min.y};
it[0].pos = {pos + points[point_i]};
it[1].pos = {pos + points[point_i + 1]};
it[2].pos = {pos};
}
}
GLuint UploadAtlas(Atlas *atlas) {
GLuint tex = 0;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y, 0, GL_RED, GL_UNSIGNED_BYTE, atlas->bitmap);
glBindTexture(GL_TEXTURE_2D, 0);
atlas->texture_id = tex;
return tex;
}
void ReloadFont(String path, U32 size) {
if (PrimaryFont.texture_id) {
glDeleteTextures(1, &PrimaryFont.texture_id);
Dealloc(&PrimaryFont.glyphs);
PrimaryFont = {};
}
Scratch scratch;
Atlas atlas = CreateAtlas(scratch, {2048, 2048});
PrimaryFont = CreateFont(&atlas, (uint32_t)ClampBottom(2u, (U32)size), path);
SecondaryFont = CreateFont(&atlas, 12, path);
SecondaryFont.texture_id = PrimaryFont.texture_id = UploadAtlas(&atlas);
}
Binary file not shown.
-213
View File
@@ -1,213 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;padding:0;}
canvas{display:block;width:100%;height:100%;}
</style>
</head>
<body>
<canvas id="glcanvas"></canvas>
<script>
CANVAS = null;
GL = null;
class wglRender {
constructor() {
const VERTEX_SRC = `#version 300 es
precision mediump float;
in vec2 a_position;
out vec2 v_texCoord;
void main() {
v_texCoord = (a_position + 1.0) * 0.5; // [0,1]
v_texCoord.y = (1.0 - v_texCoord.y); // Flip the Y to get the standard memory behavior
gl_Position = vec4(a_position, 0.0, 1.0);
}`;
const FRAGMENT_SRC = `#version 300 es
precision mediump float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 outColor;
void main() {
vec4 c = texture(u_texture, v_texCoord);
outColor = c;
}`;
CANVAS = document.getElementById('glcanvas');
GL = CANVAS.getContext('webgl2');
if (!GL) { alert('WebGL 2 not supported'); return; }
const vs = this.createShader(GL.VERTEX_SHADER, VERTEX_SRC);
const fs = this.createShader(GL.FRAGMENT_SHADER, FRAGMENT_SRC);
this.program = this.createProgram(vs, fs);
this.posLoc = GL.getAttribLocation(this.program, 'a_position');
this.texLoc = GL.getUniformLocation(this.program, 'u_texture');
// Fullscreen quad
const quad = new Float32Array([
-1, -1, // bottom left
1, -1, // bottom right
-1, 1, // top left
-1, 1, // top left
1, -1, // bottom right
1, 1 // top right
]);
this.vao = GL.createVertexArray();
GL.bindVertexArray(this.vao);
this.vbo = GL.createBuffer();
GL.bindBuffer(GL.ARRAY_BUFFER, this.vbo);
GL.bufferData(GL.ARRAY_BUFFER, quad, GL.STATIC_DRAW);
GL.enableVertexAttribArray(this.posLoc);
GL.vertexAttribPointer(this.posLoc, 2, GL.FLOAT, false, 0, 0);
}
render() {
GL.useProgram(this.program);
GL.bindVertexArray(this.vao);
GL.activeTexture(GL.TEXTURE0);
GL.bindTexture(GL.TEXTURE_2D, this.texture);
GL.uniform1i(this.texLoc, 0);
GL.drawArrays(GL.TRIANGLES, 0, 6);
}
updateTextureSize(wasm) {
const dpr = window.devicePixelRatio || 1;
const w = Math.floor(CANVAS.clientWidth * dpr);
const h = Math.floor(CANVAS.clientHeight * dpr);
if (w !== this.w || h !== this.h) {
CANVAS.width = w;
CANVAS.height = h;
GL.viewport(0, 0, w, h);
this.w = w;
this.h = h;
if (this.texture) {
GL.deleteTexture(this.texture);
}
const rawPtr = wasm.exports.update(w, h, window.devicePixelRatio || 1.0);
const pixels = wasm.getU8View(rawPtr, w*h*4);
{
this.texture = GL.createTexture();
GL.bindTexture(GL.TEXTURE_2D, this.texture);
// Allocate an empty texture of the canvas size
GL.texImage2D(
GL.TEXTURE_2D, 0, GL.RGBA8,
w, h, 0,
GL.RGBA, GL.UNSIGNED_BYTE, pixels
);
// Set parameters no filtering needed for empty data
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
}
// GL.activeTexture(GL.TEXTURE0);
// GL.bindTexture(GL.TEXTURE_2D, this.texture);
// GL.texSubImage2D(GL.TEXTURE_2D, 0, 0, 0, w, h, GL.RGBA, GL.UNSIGNED_BYTE,pixels);
}
}
createShader(type, src) {
const sh = GL.createShader(type);
GL.shaderSource(sh, src);
GL.compileShader(sh);
if (!GL.getShaderParameter(sh, GL.COMPILE_STATUS)) {
console.error('Shader compile error:', GL.getShaderInfoLog(sh));
GL.deleteShader(sh);
return null;
}
return sh;
}
createProgram(vs, fs) {
const prg = GL.createProgram();
GL.attachShader(prg, vs);
GL.attachShader(prg, fs);
GL.linkProgram(prg);
if (!GL.getProgramParameter(prg, GL.LINK_STATUS)) {
console.error('Program link error:', GL.getProgramInfoLog(prg));
GL.deleteProgram(prg);
return null;
}
return prg;
}
}
class WASMMemory {
constructor(wasm_memory) {
this.mem = wasm_memory;
this.u8 = new Uint8Array(this.mem.buffer);
this.data_view = new DataView(this.mem.buffer);
this.utf8decoder = new TextDecoder("utf-8");
this.utf8encoder = new TextEncoder("utf-8");
this.exports = null;
}
decodeString(str, len) {
const arr = this.u8.subarray(str, str+len);
const text = this.utf8decoder.decode(arr);
return text;
}
getU8View(p, len) {
const arr = this.u8.subarray(p, p+len);
return arr;
}
getView(p, len) {
const res = new DataView(this.mem.buffer, p, p+len);
return res;
}
encodeString(ptr, ptr_len, string) {
const bytes = this.utf8encoder.encode(string);
let i = 0;
for (; i < bytes.length && i < (ptr_len-1); i += 1) {
this.u8[ptr + i] = bytes[i];
}
this.u8[ptr + i] = 0;
}
}
async function WASMInit(name) {
const request = await fetch(name);
const mem = new WASMMemory(new WebAssembly['Memory']({ initial: 2000, maximum: 65536 }));
const binary = await request.arrayBuffer();
const import_table = {
memory: mem.mem,
wasm_parse_float: (str, len) => { return parseFloat(mem.decodeString(str, len)); },
wasm_alert: (str, len) => { alert(mem.decodeString(str,len)); },
wasm_trap: () => { debugger; },
wasm_write_to_console: (str, len) => { console.log(mem.decodeString(str, len)); },
};
const program = await WebAssembly['instantiate'](binary, { "env": import_table });
const instance = program['instance'];
const export_table = instance['exports'];
mem.exports = export_table;
return mem;
}
(async () => {
const render = new wglRender();
const wasm = await WASMInit("main.wasm");
wasm.exports.init();
function frameLoop() {
render.updateTextureSize(wasm);
render.render();
requestAnimationFrame(frameLoop);
}
requestAnimationFrame(frameLoop);
})();
</script>
</body>
</html>
-212
View File
@@ -1,212 +0,0 @@
#include "core/core.h"
#include "core/core.c"
#define STB_TRUETYPE_IMPLEMENTATION
#define STBTT_ifloor(x) ((i32)f64_floor(x))
#define STBTT_iceil(x) ((i32)f64_ceil(x))
#define STBTT_sqrt(x) (f64_sqrt(x))
#define STBTT_fmod(x,y) (f64_mod(x,y))
#define STBTT_pow(x,y) (f64_pow(x,y))
#define STBTT_cos(x) (f64_cos(x))
#define STBTT_acos(x) (f64_acos(x))
#define STBTT_fabs(x) (f64_abs(x))
#define STBTT_malloc(x,u) ((void)u,ma_push_size(&tcx->temp,x))
#define STBTT_free(x,u) ((void)x,(void)u)
#define STBTT_assert(x) assert(x)
#define STBTT_strlen(x) str_len(x)
#define STBTT_memcpy memory_copy
#define STBTT_memset memory_set
#include "vendor/stb/stb_truetype.h"
#include "fira_code.c"
typedef struct bitmap_t bitmap_t;
struct bitmap_t {
u32 *data;
i32 x, y;
};
typedef struct glyph_t glyph_t;
struct glyph_t {
bitmap_t bitmap;
i32 xoff, yoff;
i32 left_side_bearing, xadvance;
r2f32_t tex;
};
typedef struct font_t font_t;
struct font_t {
glyph_t glyphs[256];
bitmap_t atlas;
i32 ascent, descent, line_gap, size;
f32 scale;
i32 height;
};
fn font_t create_font(i32 size) {
font_t font = {0};
font.size = size;
stbtt_fontinfo stb_font;
i32 rc = stbtt_InitFont(&stb_font, main_font_data, 0);
assert_expr(rc != 0);
font.scale = stbtt_ScaleForPixelHeight(&stb_font, (f32)font.size);
stbtt_GetFontVMetrics(&stb_font, &font.ascent, &font.descent, &font.line_gap);
font.height = f32_round((font.ascent - font.descent) + font.line_gap) * font.scale;
for (i32 c = 0; c < 256; c += 1) {
glyph_t *glyph = font.glyphs + c;
u8 *temp_data = (u8 *)stbtt_GetCodepointBitmap(&stb_font, 0, font.scale, c, &glyph->bitmap.x, &glyph->bitmap.y, &glyph->xoff, &glyph->yoff);
glyph->bitmap.data = ma_push_array(&tcx->temp, u32, glyph->bitmap.x * glyph->bitmap.y);
for (i32 y = 0; y < glyph->bitmap.y; y += 1) {
for (i32 x = 0; x < glyph->bitmap.x; x += 1) {
glyph->bitmap.data[x + y * glyph->bitmap.x] = temp_data[x + y * glyph->bitmap.x] << 24;
}
}
stbtt_GetCodepointHMetrics(&stb_font, c, &glyph->xadvance, &glyph->left_side_bearing);
}
return font;
}
fn font_t create_font_atlas(i32 size) {
stbtt_fontinfo stb_font;
i32 rc = stbtt_InitFont(&stb_font, main_font_data, 0);
assert_expr(rc != 0);
font_t font = { 0 };
font.size = size;
font.atlas.x = 512;
font.atlas.y = 512;
font.atlas.data = ma_push_array(&tcx->temp, u32, font.atlas.x * font.atlas.y);
font.scale = stbtt_ScaleForPixelHeight(&stb_font, (f32)font.size);
stbtt_GetFontVMetrics(&stb_font, &font.ascent, &font.descent, &font.line_gap);
i32 xiter = 2;
i32 yiter = 2;
i32 max_yiter_for_row = 0;
for (i32 c = ' '; c < '~'; c += 1) {
glyph_t *glyph = font.glyphs + (c - ' ');
u8 *temp_data = (u8 *)stbtt_GetCodepointBitmap(&stb_font, 0, font.scale, c, &glyph->bitmap.x, &glyph->bitmap.y, &glyph->xoff, &glyph->yoff);
if (xiter + glyph->bitmap.x >= font.atlas.x) {
xiter = 0;
yiter += max_yiter_for_row + 2;
}
glyph->tex.min.x = (f32)xiter / (f32)font.atlas.x;
glyph->tex.min.y = (f32)yiter / (f32)font.atlas.y;
glyph->tex.max.x = (f32)(xiter + glyph->bitmap.x)/ (f32)font.atlas.x;
glyph->tex.max.y = (f32)(yiter + glyph->bitmap.y)/ (f32)font.atlas.y;
max_yiter_for_row = MAX(max_yiter_for_row, glyph->bitmap.y);
for (i32 y = 0; y < glyph->bitmap.y; y += 1) {
for (i32 x = 0; x < glyph->bitmap.x; x += 1) {
font.atlas.data[(xiter + x) + (yiter + y)*font.atlas.x] = temp_data[x + y * glyph->bitmap.x] << 24;
}
}
xiter += glyph->bitmap.x + 2;
}
return font;
}
fn_export void init(void) {
os_core_init();
}
fn void draw_bitmap(bitmap_t *canvas, bitmap_t *bitmap, i32 x, i32 y) {
i32 x0 = x;
i32 y0 = y;
i32 x1 = x + bitmap->x;
i32 y1 = y + bitmap->y;
i32 cx0 = CLAMP(x0, 0, canvas->x);
i32 cy0 = CLAMP(y0, 0, canvas->y);
i32 cx1 = CLAMP(x1, 0, canvas->x);
i32 cy1 = CLAMP(y1, 0, canvas->y);
if (cx0 >= cx1 || cy0 >= cy1) {
return;
}
i32 sx_off = cx0 - x0;
i32 sy_off = cy0 - y0;
i32 sy = sy_off;
for (i32 y = cy0; y < cy1; y += 1) {
i32 sx = sx_off;
for (i32 x = cx0; x < cx1; x += 1) {
canvas->data[x + y * canvas->x] = bitmap->data[sx + sy * bitmap->x];
//canvas->data[x + y * canvas->x] = blend_pixel_u32(canvas->data[x + y * canvas->x], bitmap->data[sx + sy * bitmap->x]);
sx += 1;
}
sy += 1;
}
}
fn void draw_rect(bitmap_t *canvas, i32 x, i32 y, i32 w, i32 h, u32 color) {
i32 x0 = x;
i32 y0 = y;
i32 x1 = x + w;
i32 y1 = y + h;
i32 cx0 = CLAMP(x0, 0, canvas->x);
i32 cy0 = CLAMP(y0, 0, canvas->y);
i32 cx1 = CLAMP(x1, 0, canvas->x);
i32 cy1 = CLAMP(y1, 0, canvas->y);
if (cx0 >= cx1 || cy0 >= cy1) {
return;
}
i32 sx_off = cx0 - x0;
i32 sy_off = cy0 - y0;
for (i32 y = cy0; y < cy1; y += 1) {
for (i32 x = cx0; x < cx1; x += 1) {
canvas->data[x + y * canvas->x] = color;
//canvas->data[x + y * canvas->x] = blend_pixel_u32(canvas->data[x + y * canvas->x], color);
}
}
}
fn v2i32_t draw_string(bitmap_t *canvas, font_t *font, i32 ix, i32 iy, b32 draw, char *string) {
i32 xiter = 0;
v2i32_t R = {0};
for (char *it = string; *it; it += 1) {
glyph_t *g = font->glyphs + (*it);
i32 curr_xiter = xiter;
xiter += g->xadvance * font->scale;
R.x = xiter;
R.y = MAX(R.y, g->bitmap.y);
if (!draw) {
continue;
}
draw_bitmap(canvas, &g->bitmap, curr_xiter + g->xoff + ix, g->yoff + font->ascent*font->scale + iy);
}
return R;
}
fn_export u32 *update(i32 width, i32 height, f32 dpr) {
ma_set0(&tcx->temp);
u32 *pixels = ma_push_array(&tcx->temp, u32, width * height);
bitmap_t canvas = {pixels, width, height};
font_t font = create_font_atlas(60);
draw_bitmap(&canvas, &font.atlas, 0, 0);
for (i32 i = 0; i < lengthof(font.glyphs); i += 1) {
glyph_t *g = &font.glyphs[i];
i32 x = g->tex.min.x * font.atlas.x;
i32 y = g->tex.min.y * font.atlas.y;
i32 w = (g->tex.max.x - g->tex.min.x) * font.atlas.x;
i32 h = (g->tex.max.y - g->tex.min.y) * font.atlas.y;
//draw_rect(&canvas, x, y, w, h, 0xFF0000FF);
}
//bitmap_t canvas = {pixels, width, height};
//font_t font = create_font(60);
//v2i32_t size = draw_string(&canvas, &font, 200, 500, false, "Hello world (stb)");
//draw_string(&canvas, &font, (width-size.x)/2, height - size.y*2, true, "Hello world (stb)");
return pixels;
}
+160
View File
@@ -0,0 +1,160 @@
String TestDir;
BlockArena TestArena;
void AddCtrlPress(SDL_Keycode key) {
Event event = {};
event.key = key;
event.ctrl = 1;
event.xwindow = 1280;
event.ywindow = 720;
Add(&EventPlayback, event);
}
void AddText(String string) {
Event event = {};
event.kind = EVENT_TEXT_INPUT;
event.xwindow = 1280;
event.ywindow = 720;
event.text = Copy(SysAllocator, string).data;
Add(&EventPlayback, event);
}
void Wait(mco_coro *co) {
Add(&EventPlayback, {EVENT_KIND_INVALID});
for (Event *event = CoYield(co); event->kind != EVENT_KIND_INVALID; event = CoYield(co)) {
}
}
void PlayTestOpen(mco_coro *co) {
// Open file, move a little, then open again and verify the caret didn't move
// String basic_env_cpp = Format(SysAllocator, "%S/test_env", TestDir);
// AddCtrlPress(SDLK_P);
// Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720});
// AddCtrlPress(SDLK_Q);
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_PERIOD; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_PERIOD; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_F; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_S; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "s"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_R; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "r"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_C; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "c"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_LCTRL; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_Q; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_LCTRL; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_F; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_T; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "t"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_E; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "e"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_S; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "s"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_T; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "t"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_LCTRL; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_Q; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_LCTRL; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_F; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_T; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "t"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_E; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "e"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_S; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_TEXT_INPUT; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.text = "s"; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_ESCAPE; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_LCTRL; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// {Event ev = {};ev.kind = EVENT_KEY_PRESS; ev.key = SDLK_Q; ev.xwindow = 1910; ev.ywindow = 2040; ev.xmouse = 581; ev.ymouse = 952; ev.ctrl = 1; Add(&EventPlayback, ev);}
// Wait(co);
// {
// BSet main = GetActiveMainSet();
// Assert(main.buffer->name == basic_env_cpp);
// Assert(main.view->carets[0].range.min == 0);
// Assert(main.view->carets[0].range.max == 0);
// Int line = PosToLine(main.buffer, main.view->carets[0].range.min);
// Assert(line == 0);
// }
// AddCtrlPress(SDLK_DOWN);
// AddCtrlPress(SDLK_DOWN);
// AddCtrlPress(SDLK_DOWN);
// Wait(co);
// Range range = {};
// {
// BSet main = GetActiveMainSet();
// Assert(main.view->carets[0].range.min > 0);
// Assert(main.view->carets[0].range.max > 0);
// range = main.view->carets[0].range;
// }
// AddCtrlPress(SDLK_P);
// Add(&EventPlayback, {EVENT_KEY_PRESS, SDLK_UP, 1280, 720});
// AddCtrlPress(SDLK_Q);
// Wait(co);
// Int buffer_len = 0;
// {
// BSet main = GetActiveMainSet();
// Assert(main.buffer->name == basic_env_cpp);
// Assert(main.view->carets[0].range.min == range.min);
// Assert(main.view->carets[0].range.max == range.max);
// buffer_len = main.buffer->len;
// }
// AddText(Format(SysAllocator, "%S:20", basic_env_cpp));
// AddCtrlPress(SDLK_Q);
// Wait(co);
// {
// BSet main = GetActiveMainSet();
// Int pos = main.view->carets[0].range.min;
// Int line = PosToLine(main.buffer, pos);
// Assert(line == 19);
// Assert(main.buffer->name == basic_env_cpp);
// Assert(main.buffer->len != buffer_len);
// Assert(main.buffer->dirty);
// }
// AddCtrlPress(SDLK_Z);
// AddCtrlPress(SDLK_PAGEUP);
// Wait(co);
// {
// BSet main = GetActiveMainSet();
// Assert(main.buffer->len == buffer_len);
// Assert(main.view->carets[0].range.min == 0);
// Assert(main.view->carets[0].range.max == 0);
// }
ReportConsolef("%s DONE", __FUNCTION__);
}
void Test(mco_coro *co) {
Wait(co); // First phase starts immediately but stuff is not initialized so Open acts weird
Open(TestDir);
PlayTestOpen(co);
Release(&TestArena);
// Add(&EventPlayback, {EVENT_QUIT});
}
void InitTests() {
WaitForEvents = false;
TestDir = Format(TestArena, "%S/test_env", GetExeDir(TestArena));
CoRemove("Test");
CoData *data = CoAdd(Test);
data->dont_wait_until_resolved = true;
CoResume(data);
}
-181
View File
@@ -1,181 +0,0 @@
#include "core/core.h"
#include "os/os.h"
#include "core/core.c"
#include "os/os.c"
fn void os_test(void) {
ma_temp_t scratch = ma_begin_scratch();
os_date_t local_time = os_local_time();
os_date_t universal_time = os_universal_time();
unused(universal_time); unused(local_time);
s8_t exe_dir = os_exe_dir(&tcx->temp);
assert(exe_dir.str[exe_dir.len - 1] != '/');
s8_t exe = os_exe(&tcx->temp);
s8_t cwd = os_cwd(&tcx->temp);
assert(cwd.str[cwd.len - 1] != '/');
assert(os_is_dir(exe_dir));
assert(os_is_file(exe));
assert(os_is_dir(cwd));
assert(os_exists(exe_dir));
assert(os_exists(exe));
assert(os_exists(cwd));
assert(os_is_abs(exe_dir));
assert(os_is_abs(exe));
assert(os_is_abs(cwd));
assert(!os_is_abs(s8("../path/")));
s8_t file = os_read(&tcx->temp, s8("../.gitignore"));
assert(file.str != 0);
assert(file.len != 0);
// TEST os_copy
{
b32 a = os_copy(s8("../.gitignore"), s8(".gitignore_copy_test"), true);
assert(a);
s8_t gitignore_copy = os_read(scratch.arena, s8(".gitignore_copy_test"));
s8_t gitignore = os_read(scratch.arena, s8("../.gitignore"));
assert(s8_are_equal(gitignore, gitignore_copy));
os_delete(s8(".gitignore_copy_test"));
}
// TEST os_iter
{
b32 found_gitignore = false;
b32 found_src = false;
for (os_iter_t *iter = os_iter(scratch.arena, s8("../")); iter->is_valid; os_advance(iter)) {
assert(os_is_abs(iter->abs));
assert(!os_is_abs(iter->rel));
if (s8_ends_with(iter->rel, s8(".gitignore"))) {
found_gitignore = true;
assert(os_is_file(iter->rel));
}
if (s8_ends_with(iter->rel, s8("src"))) {
found_src = true;
assert(os_is_dir(iter->rel));
}
if (os_is_dir(iter->abs)) {
assert(iter->abs.str[iter->abs.len - 1] != '/');
}
}
assert(found_src);
assert(found_gitignore);
}
#if PLATFORM_WINDOWS
s8_t path = os_appdata(scratch.arena, s8("testing"));
assert(path.str[path.len - 1] != '/');
assert(s8_starts_with(path, s8("C:/")));
assert(s8_ends_with(path, s8("/testing")));
#endif
ma_end_scratch(scratch);
}
fn void test_s8(void) {
ma_arena_t *arena = ma_create(ma_default_reserve_size);
{
ma_temp_t temp = ma_begin_temp(arena);
sb8_t *sb = &(sb8_t){arena};
s8_t memes = s8("memes");
sb8_printf(sb, "%.*s", s8_fmtspec(memes));
assert(sb->first == sb->last);
assert(sb->first->len == 5);
assert(s8_are_equal(sb->first->string, memes));
sb8_printf(sb, "%s", "things are going fine");
s8_t string = sb8_merge(temp.arena, sb);
assert(s8_are_equal(string, s8("memesthings are going fine")));
ma_end_temp(temp);
}
{
s8_t str = s8("thing|another|");
sb8_t sb = s8_split(arena, str, s8("|"), s8_split_none);
assert(s8_are_equal(sb.first->string, s8("thing")));
assert(s8_are_equal(sb.first->next->string, s8("another")));
assert(sb.first->next->next == NULL);
}
{
s8_t str = s8("thing|another|");
sb8_t sb = s8_split(arena, str, s8("|"), s8_split_inclusive);
assert(s8_are_equal(sb.first->string, s8("thing")));
assert(s8_are_equal(sb.first->next->string, s8("|")));
assert(s8_are_equal(sb.first->next->next->string, s8("another")));
assert(s8_are_equal(sb.first->next->next->next->string, s8("|")));
assert(sb.first->next->next->next->next == NULL);
}
{
s8_t str = s8("aabaaBaa");
sb8_t sb = s8_split(arena, str, s8("b"), s8_split_inclusive | s8_split_ignore_case);
assert(s8_are_equal(sb.first->string, s8("aa")));
assert(s8_are_equal(sb.first->next->string, s8("b")));
assert(s8_are_equal(sb.first->next->next->string, s8("aa")));
assert(s8_are_equal(sb.first->next->next->next->string, s8("B")));
assert(s8_are_equal(sb.first->next->next->next->next->string, s8("aa")));
assert(sb.first->next->next->next->next->next == NULL);
}
{
s8_t str = s8("aabaaBaa");
sb8_t sb = s8_split(arena, str, s8("b"), s8_split_inclusive);
assert(s8_are_equal(sb.first->string, s8("aa")));
assert(s8_are_equal(sb.first->next->string, s8("b")));
assert(s8_are_equal(sb.first->next->next->string, s8("aaBaa")));
}
{
s8_t s = s8("0123456789");
assert(s8_are_equal(s8_slice(s, 0, 4), s8("0123")));
assert(s8_are_equal(s8_slice(s, -2, -1), s8("89")));
assert(s8_are_equal(s8_slice(s, -2, 10), s8("89")));
assert(s8_are_equal(s8_slice(s, 8, 10), s8("89")));
}
{
s8_t s = s8(" a \n");
s = s8_trim(s);
assert(s8_are_equal(s, s8("a")));
}
{
s8_t s = s8("C:/memes/the_thing.c");
s8_t ss = s8_get_name_no_ext(s);
assert(s8_are_equal(ss, s8("the_thing")));
}
{
s8_t s = s8_printf(arena, "%d%sv%s", 32, "|", ">");
assert(s8_are_equal(s, s8("32|v>")));
}
{
s8_t s0 = s8("0123456789");
s8_t s1 = s8_cut_start(&s0, 2);
assert(s8_are_equal(s0, s8("23456789")));
assert(s8_are_equal(s1, s8("01")));
}
ma_destroy(arena);
}
int main() {
os_core_init();
test_s8();
os_test();
debugf("Testing OK");
return 0;
}
File diff suppressed because it is too large Load Diff
+252
View File
@@ -0,0 +1,252 @@
View *GetViewForFixingWhenBufferCommand(Buffer *buffer, bool *is_active = NULL) {
View *view = NULL;
if (is_active) {
*is_active = false;
}
BSet active = GetBSet(ActiveWindowID);
if (active.buffer->id == buffer->id) {
if (is_active) {
*is_active = true;
}
return active.view;
}
For(Views) {
if (it->active_buffer != buffer->id) {
continue;
}
view = it;
break;
}
if (!view) {
view = CreateView(buffer->id);
}
return view;
}
void ReplaceWithoutMovingCarets(Buffer *buffer, Range range, String16 string) {
View *view = GetViewForFixingWhenBufferCommand(buffer);
Array<Caret> carets = Copy(GetSystemAllocator(), view->carets);
Scratch scratch;
SelectRange(view, range);
ReplaceEx(scratch, view, string);
Dealloc(&view->carets);
view->carets = carets;
}
// @todo: revamp interface since it scrolls ALL VIEWS??? or maybe not??
void Append(View *view, String16 string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
struct ViewInfo {
View *view;
Array<Caret> carets;
bool scroll_to_end;
};
Array<ViewInfo> view_info = {scratch};
ForItem(it_view, Views) {
if (it_view->active_buffer != buffer->id) {
continue;
}
ViewInfo vi = {it_view};
if (scroll_to_end_if_cursor_on_last_line) {
Int line = PosToLine(buffer, GetFront(it_view->carets[0]));
if (line == buffer->line_starts.len - 1) {
vi.scroll_to_end = true;
}
}
if (!vi.scroll_to_end) {
vi.carets = Copy(GetSystemAllocator(), it_view->carets);
}
Add(&view_info, vi);
}
SelectRange(view, GetBufferEndAsRange(buffer));
Replace(view, string);
For (view_info) {
if (it.scroll_to_end) {
it.view->carets[0] = MakeCaret(GetBufferEndAsRange(buffer).min);
} else {
Dealloc(&it.view->carets);
it.view->carets = it.carets;
}
}
}
void Append(View *view, String string, bool scroll_to_end_if_cursor_on_last_line) {
Scratch scratch;
String16 string16 = ToString16(scratch, string);
Append(view, string16, scroll_to_end_if_cursor_on_last_line);
}
void Appendf(View *view, const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
Append(view, string, true);
}
void ReportErrorf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
if (BreakOnError) {
BREAK();
}
Appendf(LogView, "%S\n", string);
ShowUIMessagef("%S", string);
}
void ReportConsolef(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
Appendf(LogView, "%S\n", string);
}
void ReportWarningf(const char *fmt, ...) {
ErrorCount += 1;
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
if (BreakOnError) {
BREAK();
}
Appendf(LogView, "%S\n", string);
}
void CMD_CenterView() {
CenterView(PrimaryWindowID);
} RegisterCommand(CMD_CenterView, "", "");
void TrimWhitespace(Buffer *buffer, bool trim_lines_with_caret) {
Scratch scratch;
bool is_active_view = false;
View *view = GetViewForFixingWhenBufferCommand(buffer, &is_active_view);
if (!is_active_view && !trim_lines_with_caret) {
trim_lines_with_caret = true;
}
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
Array<Range> lines_to_skip_triming = {};
if (!trim_lines_with_caret) {
lines_to_skip_triming = GetSelectedLinesSorted(scratch, view);
}
for (Int i = 0; i < buffer->line_starts.len; i += 1) {
Int range_index = FindRangeByPos(&lines_to_skip_triming, i);
if (range_index != -1) continue;
Range range = GetLineRangeWithoutNL(buffer, i);
Int whitespace_end = range.max;
for (; whitespace_end > range.min; whitespace_end -= 1) {
U16 w = buffer->data[whitespace_end - 1];
bool is_whitespace = w == ' ' || w == '\t' || w == '\v' || w == '\r';
if (!is_whitespace) break;
}
Range whitespace_range = {whitespace_end, range.max};
AddEdit(&edits, whitespace_range, u"");
}
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
view->update_scroll = false;
}
void ApplyFormattingTool(Buffer *buffer, String tool) {
Scratch scratch;
String string = AllocCharString(scratch, buffer);
ExecResult exec_result = ExecAndWait(scratch, tool, GetDirectory(buffer), string);
String16 string16 = {exec_result.buffer->str, exec_result.buffer->len};
if (exec_result.exit_code == 0) {
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), string16);
} else {
Append(LogView, string16, true);
}
}
void SaveAll() {
For(Buffers) {
// NOTE: file_mod_time is only set when buffer got read or written to disk already so should be saved
if (it->file_mod_time && it->dirty) {
SaveBuffer(it);
}
}
}
// @todo: plugin_languages ? and then branch out language_cpp ...
void CMD_FormatSelection() {
Scratch scratch;
BSet primary = GetBSet(PrimaryWindowID);
String tool = "";
if (EndsWith(primary.buffer->name, ".c") || EndsWith(primary.buffer->name, ".cpp") || EndsWith(primary.buffer->name, ".h") || EndsWith(primary.buffer->name, ".hpp")) {
tool = "clang-format";
} else if (EndsWith(primary.buffer->name, ".go")) {
tool = "gofmt";
} else {
return;
}
Array<Edit> edits = BeginEdit(scratch, primary.buffer, primary.view->carets);
MergeCarets(primary.buffer, &primary.view->carets);
For (primary.view->carets) {
String input_string = ToString(scratch, GetString(primary.buffer, it.range));
ExecResult exec_result = ExecAndWait(scratch, tool, GetDirectory(primary.buffer), input_string);
String16 string16 = {exec_result.buffer->str, exec_result.buffer->len};
AddEdit(&edits, it.range, string16);
}
EndEdit(primary.buffer, &edits, &primary.view->carets, KILL_SELECTION);
} RegisterCommand(CMD_FormatSelection, "", "");
void CMD_KillProcess() {
BSet main = GetBSet(PrimaryWindowID);
KillProcess(main.view);
} RegisterCommand(CMD_KillProcess, "", "Kill process in the last active primary window");
void CMD_MakeFontLarger() {
FontSize += 1;
ReloadFont(PathToFont, (U32)FontSize);
} RegisterCommand(CMD_MakeFontLarger, "ctrl-equals", "Increase the font size");
void CMD_MakeFontSmaller() {
if (FontSize > 4) {
FontSize -= 1;
ReloadFont(PathToFont, (U32)FontSize);
}
} RegisterCommand(CMD_MakeFontSmaller, "ctrl-minus", "Decrease the font size");
void CMD_ToggleFullscreen() {
if (IsInFullscreen) {
SDL_SetWindowSize(SDLWindow, FullScreenSizeX, FullScreenSizeY);
SDL_SetWindowPosition(SDLWindow, FullScreenPositionX, FullScreenPositionY);
} else {
SDL_GetWindowSize(SDLWindow, &FullScreenSizeX, &FullScreenSizeY);
SDL_GetWindowPosition(SDLWindow, &FullScreenPositionX, &FullScreenPositionY);
SDL_DisplayID display = SDL_GetDisplayForWindow(SDLWindow);
const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(display);
SDL_SetWindowSize(SDLWindow, dm->w, dm->h);
SDL_SetWindowPosition(SDLWindow, 0, 0);
}
IsInFullscreen = !IsInFullscreen;
} RegisterCommand(CMD_ToggleFullscreen, "f11", "Switches between the fullscreen and non-fulscreen mode");
void CMD_OpenLogs() {
ErrorCount = 0;
Open(LogBuffer->name);
} RegisterCommand(CMD_OpenLogs, "", "Opens the text editor logs and clear error counter");
void CMD_Errors() {
CMD_OpenLogs();
} RegisterCommand(CMD_Errors, "", "Opens the text editor logs and clear error counter");
+105
View File
@@ -0,0 +1,105 @@
#if OS_WASM
EM_ASYNC_JS(void, _SetClipboardText, (const char* c_str), {
const type = "text/plain";
const clipboardItemData = {
[type]: UTF8ToString(c_str),
};
const clipboardItem = new ClipboardItem(clipboardItemData);
await navigator.clipboard.write([clipboardItem]);
})
EM_ASYNC_JS(const char *, GetClipboardText, (), {
const text = await navigator.clipboard.readText();
return stringToNewUTF8(text);
})
#define FreeClipboardText free
#else
#define FreeClipboardText SDL_free
#define GetClipboardText SDL_GetClipboardText
#define _SetClipboardText SDL_SetClipboardText
#endif
void FreeClipboardGlobals() {
Release(&ClipboardArena);
SavedClipboardString = {};
SavedClipboardCarets = {};
SavedClipboardCarets.allocator = ClipboardArena;
}
void SaveStringInClipboard(String16 string) {
Scratch scratch;
FreeClipboardGlobals();
SavedClipboardString = Copy16(ClipboardArena, string);
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
}
void ClipboardCopy(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
// First, if there is no selection - select the entire line
For(view->carets) {
if (GetSize(it.range) == 0) {
Int line = PosToLine(buffer, it.range.min);
Range line_range = GetLineRange(buffer, line);
it.range = line_range;
}
}
FreeClipboardGlobals();
Reserve(&SavedClipboardCarets, view->carets.len);
For(view->carets) {
String16 string = GetString(buffer, it.range);
String16 copy = Copy16(ClipboardArena, string);
Add(&SavedClipboardCarets, copy);
}
// @todo: maybe only add new line if there is no new line at the end, experiment with it
SavedClipboardString = Merge(ClipboardArena, SavedClipboardCarets, u"\n");
_SetClipboardText(ToString(scratch, SavedClipboardString).data);
}
void ClipboardPaste(View *view) {
Scratch scratch;
Buffer *buffer = GetBuffer(view->active_buffer);
const char *text = GetClipboardText();
defer { FreeClipboardText((void *)text); };
String16 string = ToUnixString16(scratch, text);
// Regular paste
if (string != SavedClipboardString || SavedClipboardCarets.len != view->carets.len) {
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
For(view->carets) AddEdit(&edits, it.range, string);
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
return;
}
// Multicursor paste
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
MergeCarets(buffer, &view->carets);
for (int64_t i = 0; i < view->carets.len; i += 1) {
String16 string = SavedClipboardCarets[i];
Caret &it = view->carets[i];
AddEdit(&edits, it.range, string);
}
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
}
void CMD_Paste() {
BSet active = GetBSet(ActiveWindowID);
ClipboardPaste(active.view);
} RegisterCommand(CMD_Paste, "ctrl-v", "Paste the content of system clipboard at caret");
void CMD_Copy() {
BSet active = GetBSet(ActiveWindowID);
ClipboardCopy(active.view);
} RegisterCommand(CMD_Copy, "ctrl-c", "Copy currently selected content to system clipboard");
void CMD_Cut() {
BSet active = GetBSet(ActiveWindowID);
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
ClipboardCopy(active.view);
Replace(active.view, u"");
} RegisterCommand(CMD_Cut, "ctrl-x", "Copy and delete currently selected content to system clipboard");
+285
View File
@@ -0,0 +1,285 @@
struct Lexer {
Allocator allocator;
char *at;
char *start;
char *end;
char *name;
int line, column;
};
enum TriggerKind {
TriggerKind_Error,
TriggerKind_Key,
TriggerKind_Mouse,
TriggerKind_Binary,
TriggerKind_CatchAll,
};
struct Trigger {
TriggerKind kind;
Trigger *left;
Trigger *right;
SDL_Keycode key;
struct {
EventKind event_kind : 8;
U32 ctrl : 1;
U32 alt : 1;
U32 shift : 1;
};
};
struct CachedTrigger {
Trigger *trigger;
String key;
};
Array<CachedTrigger> CachedTriggers;
void Advance(Lexer *lex) {
if (lex->at < lex->end) {
if (lex->at[0] == '\n') {
lex->line += 1;
lex->column = 0;
} else {
lex->column += 1;
}
lex->at += 1;
}
}
void Advance(Lexer *lex, int n) {
for (int i = 0; i < n; i += 1) Advance(lex);
}
char At(Lexer *lex) {
if (lex->at < lex->end) {
return lex->at[0];
}
return 0;
}
String AsString(Lexer *lex) {
String result = {lex->at, lex->end - lex->at};
return result;
}
void EatWhitespace(Lexer *lex) {
while (At(lex) != '\n' && IsWhitespace(At(lex))) {
Advance(lex);
}
}
Trigger *TriggerBinary(Lexer *lex, Trigger *left, Trigger *right, int key) {
Trigger *result = AllocType(lex->allocator, Trigger);
result->kind = TriggerKind_Binary;
result->key = key;
result->left = left;
result->right = right;
return result;
}
Trigger *ParseKeyAtom(Lexer *lex) {
Trigger *result = AllocType(lex->allocator, Trigger);
result->kind = TriggerKind_Key;
EatWhitespace(lex);
for (;;) {
String lex_string = AsString(lex);
if (StartsWith(lex_string, "ctrl")) {
result->ctrl = true;
Advance(lex, 4);
} else if (StartsWith(lex_string, "shift")) {
result->shift = true;
Advance(lex, 5);
} else if (StartsWith(lex_string, "alt")) {
result->alt = true;
Advance(lex, 3);
} else if (IsAlphanumeric(At(lex))) {
char *start = lex->at;
while (IsAlphanumeric(At(lex))) {
Advance(lex);
}
String a = {start, lex->at - start};
Advance(lex);
bool found = false;
for (int i = 0; !found && i < Lengthof(MouseConversionTable); i += 1) {
if (a == MouseConversionTable[i].string) {
result->event_kind = MouseConversionTable[i].value;
result->kind = TriggerKind_Mouse;
found = true;
}
}
for (int i = 0; !found && i < Lengthof(SDLKeycodeConversionTable); i += 1) {
if (a == SDLKeycodeConversionTable[i].string) {
result->key = SDLKeycodeConversionTable[i].value;
found = true;
}
}
if (!found) {
result->kind = TriggerKind_Error;
ReportErrorf("%s:%d:%d: Failed to parse key trigger, unexpected identifier: '%d'", lex->name, lex->line, lex->column, result->key);
return result;
}
} else {
result->kind = TriggerKind_Error;
ReportErrorf("%s:%d:%d: Failed to parse key trigger, unexpected character: '%c'", lex->name, lex->line, lex->column, At(lex));
return result;
}
if (At(lex) == '-') {
Advance(lex);
} else {
break;
}
}
return result;
}
Trigger *ParseKeyChord(Lexer *lex) {
Trigger *left = ParseKeyAtom(lex);
EatWhitespace(lex);
while (IsAlphanumeric(At(lex))) {
left = TriggerBinary(lex, left, ParseKeyChord(lex), ' ');
EatWhitespace(lex);
}
return left;
}
Trigger *ParseKeyOr(Lexer *lex) {
Trigger *left = ParseKeyChord(lex);
EatWhitespace(lex);
while (At(lex) == '|') {
Advance(lex);
left = TriggerBinary(lex, left, ParseKeyOr(lex), '|');
EatWhitespace(lex);
}
return left;
}
Trigger *ParseKeyCatchAll(Lexer *lex) {
String string = AsString(lex);
if (string == "catch_all") {
Trigger *result = AllocType(lex->allocator, Trigger);
result->kind = TriggerKind_CatchAll;
return result;
} else {
return ParseKeyOr(lex);
}
}
Trigger *ParseKey(Allocator allocator, String key, char *debug_name) {
Lexer lex = {allocator, key.data, key.data, key.data + key.len, debug_name};
Trigger *result = ParseKeyCatchAll(&lex);
return result;
}
Trigger *ParseKeyCached(String key) {
key = Trim(key);
if (key.len == 0) {
return NULL;
}
For (CachedTriggers) {
if (it.key == key) {
return it.trigger;
}
}
Allocator allocator = GetSystemAllocator();
Trigger *result = ParseKey(allocator, key, key.data);
if (!result) {
return NULL;
}
Add(&CachedTriggers, {result, key});
return result;
}
bool MatchEvent(Trigger *trigger, Event *event) {
if (trigger->kind == TriggerKind_Key) {
if (trigger->key == event->key && trigger->ctrl == event->ctrl && trigger->alt == event->alt && trigger->shift == event->shift) {
return true;
}
} else if (trigger->kind == TriggerKind_Mouse) {
if (trigger->event_kind == event->kind) {
return true;
}
} else if (trigger->kind == TriggerKind_Binary) {
if (trigger->key == ' ') {
return false;
} else if (trigger->key == '|') {
bool ok = MatchEvent(trigger->left, event);
if (ok) return ok;
ok = MatchEvent(trigger->right, event);
if (ok) return ok;
} ElseInvalidCodepath();
} else if (trigger->kind == TriggerKind_CatchAll) {
if (event->kind == EVENT_MOUSE_LEFT || event->kind == EVENT_MOUSE_RIGHT || event->kind == EVENT_MOUSE_MIDDLE || event->kind == EVENT_MOUSE_X1 || event->kind == EVENT_MOUSE_X2 || event->kind == EVENT_KEY_PRESS || event->kind == EVENT_TEXT_INPUT) {
return true;
}
} else {
return false;
}
return false;
}
void TestParser() {
Scratch scratch;
{
char *cmd = "ctrl-b";
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
Trigger *trigger = ParseKeyCatchAll(&base_lex);
Assert(trigger->kind == TriggerKind_Key);
Assert(trigger->key == SDLK_B);
Assert(trigger->ctrl);
Assert(trigger->shift == 0);
}
{
char *cmd = "ctrl-b shift-ctrl-a";
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
Trigger *trigger = ParseKeyCatchAll(&base_lex);
Assert(trigger->kind == TriggerKind_Binary);
Assert(trigger->key == ' ');
Assert(trigger->left->kind == TriggerKind_Key);
Assert(trigger->left->key == SDLK_B);
Assert(trigger->left->ctrl);
Assert(trigger->left->shift == 0);
Assert(trigger->right->kind == TriggerKind_Key);
Assert(trigger->right->key == SDLK_A);
Assert(trigger->right->ctrl);
Assert(trigger->right->shift);
}
{
char *cmd = "ctrl-b shift-ctrl-a | ctrl-c | ctrl-d";
Lexer base_lex = {scratch, cmd, cmd, cmd + strlen(cmd), "keybinding"};
Trigger *trigger = ParseKeyCatchAll(&base_lex);
Assert(trigger->kind == TriggerKind_Binary);
Assert(trigger->key == '|');
Assert(trigger->left->kind == TriggerKind_Binary);
Assert(trigger->left->key == ' ');
Assert(trigger->right->kind == TriggerKind_Binary);
Assert(trigger->right->key == '|');
Event event = {};
event.kind = EVENT_KEY_PRESS;
event.key = SDLK_D;
event.ctrl = 1;
bool ok = MatchEvent(trigger, &event);
Assert(ok);
event.key = SDLK_F1;
ok = MatchEvent(trigger, &event);
Assert(ok == 0);
event.ctrl = 1;
event.shift = 1;
event.key = SDLK_A;
ok = MatchEvent(trigger, &event);
Assert(!ok);
}
} RegisterFunction(&TestFunctions, TestParser);
+91
View File
@@ -0,0 +1,91 @@
typedef void CoroutineProc(mco_coro *co);
CoData *CoCurr = NULL;
void CoDestroy(CoData *n) {
mco_destroy(n->co);
Release(&n->arena);
}
void CoRemove(String name) {
IterRemove(ActiveCoroutines) {
IterRemovePrepare(ActiveCoroutines);
if (it.name == name) {
CoDestroy(&it);
remove_item = true;
}
}
}
#define CoAdd(x) CoAddEx(x, #x)
CoData *CoAddEx(CoroutineProc *proc, String name) {
mco_desc desc = mco_desc_init(proc, 0);
mco_coro *coro = NULL;
mco_result ok = mco_create(&coro, &desc);
if (ok != MCO_SUCCESS) {
ReportWarningf("failed to create coroutine %d", ok);
return NULL;
}
Add(&ActiveCoroutines, {coro, name});
return GetLast(ActiveCoroutines);
}
void CoResume(CoData *dat) {
CoData *prev_curr = CoCurr;
CoCurr = dat;
mco_result ok = mco_resume(dat->co);
Assert(ok == MCO_SUCCESS);
CoCurr = prev_curr;
}
void CoUpdate(Event *event) {
ProfileFunction();
double start = GetTimeSeconds();
for (;ActiveCoroutines.len;) {
IterRemove(ActiveCoroutines) {
IterRemovePrepare(ActiveCoroutines);
ProfileScopeEx(it.name);
mco_state status = mco_status(it.co);
if (status == MCO_DEAD) {
CoDestroy(&it);
remove_item = true;
} else {
mco_push(it.co, &event, sizeof(Event *));
CoCurr = &it;
mco_result ok = mco_resume(it.co);
if (ok != MCO_SUCCESS) {
ReportWarningf("failed to resume coroutine %d", ok);
CoDestroy(&it);
remove_item = true;
}
}
}
#if DEBUG_BUILD
//:CoroutineLeakCheck
// Make sure we don't leak scratch arenas between coroutine boundaries.
// it leads to memory corruption! If you hit Assert here make sure you
// don't leak the scratch arena.
for (int i = 0; i < Lengthof(ScratchArenas); i += 1) {
Assert(ScratchArenas[i].refs == 0);
}
#endif
double took = GetTimeSeconds() - start;
if (took > (0.016666 / 3.0)) {
break;
}
}
}
Event *CoYield(mco_coro *co) {
mco_result ok = mco_yield(co);
Assert(ok == MCO_SUCCESS);
Event *event = NULL;
ok = mco_pop(co, &event, sizeof(Event *));
Assert(ok == MCO_SUCCESS);
return event;
}
+312
View File
@@ -0,0 +1,312 @@
Vec2I GetCellSize(Window *window) {
Vec2I result = {(Int)window->font->char_spacing, (Int)window->font->line_spacing};
return result;
}
Rect2I GetVisibleCells(Window *window) {
ProfileFunction();
View *view = GetView(window->active_view);
Vec2I size = GetSize(window->document_rect);
Int _cx = size.x / window->font->char_spacing;
Int _cy = size.y / window->font->line_spacing;
Int cx = _cx + 1;
Int cy = _cy + 2;
Vec2I pos = {SafeDivide(view->scroll.x, window->font->char_spacing), SafeDivide(view->scroll.y, window->font->line_spacing)};
Int x = pos.x;
Int y = pos.y;
Rect2I result = {x, y, x + cx, y + cy};
return result;
}
Scroller ComputeScrollerRect(Window *window) {
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Vec2I size = GetSize(window->scrollbar_rect);
Rect2I vis = GetVisibleCells(window);
Int line_count = buffer->line_starts.len + GetSize(vis).y - 1;
double begin = (double)vis.min.y / (double)line_count;
double end = (double)vis.max.y / (double)line_count;
Rect2 rect = {
{(float)window->scrollbar_rect.min.x, (float)window->scrollbar_rect.min.y + (float)((double)size.y * begin)},
{(float)window->scrollbar_rect.max.x, (float)window->scrollbar_rect.min.y + (float)((double)size.y * end)},
};
Scroller result = {rect, begin, end, line_count};
return result;
}
void DrawVisibleText(Window *window, Color tint) {
ProfileFunction();
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Rect2I visible = GetVisibleCells(window);
for (Int line_index = visible.min.y; line_index < visible.max.y && line_index >= 0 && line_index < buffer->line_starts.len; line_index += 1) {
String16 line_string = GetLineString(buffer, line_index);
Vec2I pos = Vec2I{visible.min.x, line_index} * Vec2I{(Int)window->font->char_spacing, (Int)window->font->line_spacing} - view->scroll + window->document_rect.min;
float text_offset_x = 0;
for (Int col_index = visible.min.x; col_index < visible.max.x && col_index >= 0 && col_index < line_string.len; col_index += 1) {
int codepoint = line_string[col_index];
Glyph *g = GetGlyph(window->font, codepoint);
Vec2 p = ToVec2(pos);
p.y += window->font->line_spacing + window->font->descent;
p.x += text_offset_x;
Rect2 rect = Rect2FromSize(p + g->offset, g->size);
if (codepoint != '\n' && codepoint != '\r' && codepoint != ' ' && codepoint != '\t') {
PushQuad2D(RenderArena, &Vertices, rect, g->atlas_bounding_box, tint);
}
text_offset_x += window->font->char_spacing;
}
}
}
Vec2I XYToWorldPos(Window *window, XY xy) {
Vec2I result = {xy.col * (Int)window->font->char_spacing, xy.line * (Int)window->font->line_spacing};
return result;
}
Rect2I XYToRect(Window *window, XY xy) {
Rect2I result = Rect2IFromSize(XYToWorldPos(window, xy), GetCellSize(window));
return result;
}
void DrawCaret(Window *window, XY xy, float size, Color color) {
View *view = GetView(window->active_view);
Rect2I _rect = XYToRect(window, xy);
Rect2I rect = CutLeft(&_rect, (Int)(size * (float)window->font->char_spacing));
Rect2I scrolled_rect = rect - view->scroll + window->document_rect.min;
DrawRect(ToRect2(scrolled_rect), color);
}
void DrawUnderline(Window *window, View *view, Buffer *buffer, Range range, Color color, Int size = 1) {
XY xy_min = PosToXY(buffer, range.min);
XY xy_max = PosToXY(buffer, range.max);
// @todo: maybe consider underlining multiple lines but then we would need to consider
// optimizing and so on
if (xy_min.line != xy_max.line) return;
Vec2I min = {xy_min.col * window->font->char_spacing, (xy_min.line + 1) * window->font->line_spacing - size};
Vec2I max = {xy_max.col * window->font->char_spacing, (xy_max.line + 1) * window->font->line_spacing};
Rect2I rect = {min, max};
Rect2I scrolled_rect = rect - view->scroll + window->document_rect.min;
DrawRectOutline(scrolled_rect, color);
}
void DrawWindow(Window *window, Event &event) {
ProfileFunction();
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Rect2 screen_rect = Rect0Size(event.xwindow, event.ywindow);
SetScissor(screen_rect);
bool is_active = window->id == ActiveWindowID;
bool active_layed_out_doc = window->id == PrimaryWindowID;
Color color_whitespace_during_selection = SelectedWhitespaceColor;
Color color_background = BackgroundColor;
Color color_line_highlight = LineHighlightColor;
Color color_selection = SelectionColor;
Color color_main_caret = PrimaryCaretColor;
Color color_sub_caret = SecondaryCaretColor;
Color color_text_line_numbers = LineNumberTextColor;
Color color_text = TextColor;
if (window->secondary_window_style) {
color_background = SecondaryWindowStyle_BackgroundColor;
color_selection = SecondaryWindowStyle_SelectionColor;
color_text = SecondaryWindowStyle_TextColor;
color_line_highlight = SecondaryWindowStyle_LineHighlightColor;
}
DrawRect(window->total_rect, color_background);
Rect2I combined_document_line_number = window->document_rect;
if (DrawLineNumbers && window->draw_line_numbers) {
combined_document_line_number.min.x = window->line_numbers_rect.min.x;
}
SetScissor(combined_document_line_number);
BeginProfileScope(draw_caret_selection);
Rect2I visible = GetVisibleCells(window);
For(view->carets) {
XY min = PosToXY(buffer, it.range.min);
XY max = PosToXY(buffer, it.range.max);
if (visible.min.y > max.line) continue;
if (visible.max.y < min.line) continue;
if (GetSize(it.range)) {
//
// Draw selection
for (Int line = visible.min.y; line <= visible.max.y && line >= 0 && line < buffer->line_starts.len; line += 1) {
String16 line_string = GetLineString(buffer, line);
for (Int col = visible.min.x; col < visible.max.x && col >= 0 && col < line_string.len; col += 1) {
bool a = line > min.line && line < max.line;
bool b = min.line != max.line && (line == min.line && col >= min.col);
bool c = min.line != max.line && (line == max.line && col < max.col);
bool d = min.line == max.line && line == max.line && col >= min.col && col < max.col;
if (!(a || b || c || d)) continue;
Vec2I pos = {col * window->font->char_spacing, line * window->font->line_spacing};
pos -= view->scroll;
pos += window->document_rect.min;
Rect2 rect = Rect2FromSize({(float)pos.x, (float)pos.y}, {(float)window->font->char_spacing, (float)window->font->line_spacing});
DrawRect(rect, color_selection);
}
}
// Draw the little artifacts signaling whitespace
// @copypaste
Glyph *xglyph = GetGlyph(window->font, 'x');
for (Int line = visible.min.y; line <= visible.max.y && line >= 0 && line < buffer->line_starts.len; line += 1) {
String16 line_string = GetLineString(buffer, line);
for (Int col = visible.min.x; col < visible.max.x && col >= 0 && col < line_string.len; col += 1) {
bool a = line > min.line && line < max.line;
bool b = min.line != max.line && (line == min.line && col >= min.col);
bool c = min.line != max.line && (line == max.line && col < max.col);
bool d = min.line == max.line && line == max.line && col >= min.col && col < max.col;
if (!(a || b || c || d)) continue;
if (line_string[col] == ' ' || line_string[col] == '\t' || line_string[col] == '\n' || line_string[col] == '\r') {
Vec2I pos = {col * window->font->char_spacing, line * window->font->line_spacing};
Vec2I scrolled_pos = pos - view->scroll + window->document_rect.min;
Vec2 circle_pos = {scrolled_pos.x + (float)window->font->char_spacing / 2.f, (float)scrolled_pos.y + xglyph->size.y};
float circle_size = window->font->size / 16.f;
DrawCircle(circle_pos, circle_size, color_whitespace_during_selection);
}
}
}
} else if (window->draw_line_highlight) {
//
// Draw highlight
Int front = GetFront(it);
XY fxy = PosToXY(buffer, front);
Vec2I pos = XYToWorldPos(window, XYLine(fxy.line));
Vec2I scrolled_pos = pos - view->scroll + window->document_rect.min;
Rect2 rect = {
{(float)window->total_rect.min.x, (float)scrolled_pos.y},
{(float)window->total_rect.max.x, (float)scrolled_pos.y + (float)window->font->line_spacing}
};
DrawRect(rect, color_line_highlight);
}
}
// Underline word under mouse cursor
Caret caret = view->carets[0];
Vec2I mouse = MouseVec2I();
bool mouse_in_document = AreOverlapping(mouse, window->document_rect);
if (mouse_in_document) {
View *view = GetView(window->active_view);
Buffer *buffer = GetBuffer(view->active_buffer);
Int p = ScreenSpaceToBufferPosErrorOutOfBounds(window, view, buffer, mouse);
if (p != -1) {
Range range = EncloseLoadWord(buffer, p);
if (InBounds(caret.range, p)) range = caret.range;
DrawUnderline(window, view, buffer, range, MouseUnderlineColor, 2);
}
}
if (event.ctrl) {
if (is_active) {
if (GetSize(caret.range) == 0) {
Range range = EncloseLoadWord(buffer, caret.range.min);
DrawUnderline(window, view, buffer, range, CaretUnderlineColor);
} else {
DrawUnderline(window, view, buffer, caret.range, CaretUnderlineColor);
}
}
}
EndProfileScope();
DrawVisibleText(window, color_text);
// Draw caret "|" markings
if (is_active) {
ProfileScope(DrawCarets);
For(view->carets) {
Int front = GetFront(it);
XY fxy = PosToXY(buffer, front);
if (fxy.col >= visible.min.x && fxy.col < visible.max.x && fxy.line >= visible.min.y && fxy.line <= visible.max.y) {
bool main_caret = &it == &view->carets.data[0];
DrawCaret(window, fxy, 0.3f, main_caret ? color_main_caret : color_sub_caret);
}
}
}
// Draw line numbers
if (DrawLineNumbers && window->draw_line_numbers) {
ProfileScope(DrawLineNumbers);
Scratch scratch;
SetScissor(window->line_numbers_rect);
Rect2I vlines = GetVisibleCells(window);
for (Int line = vlines.min.y; line <= visible.max.y && line >= 0 && line < buffer->line_starts.len; line += 1) {
Vec2I pos = {0, line * window->font->line_spacing};
pos.y -= view->scroll.y;
pos += window->line_numbers_rect.min;
String s = Format(scratch, "%lld", (long long)line + 1ll);
String16 string = ToString16(scratch, s);
float x = window->font->char_spacing * (float)string.len;
Vec2 p = ToVec2(pos);
float rectx = (float)GetSize(window->line_numbers_rect).x;
p.x += (rectx - x) / 2.f;
if (x > rectx) p.x = (float)window->line_numbers_rect.min.x;
DrawString(window->font, string, p, color_text_line_numbers);
}
}
#if PLUGIN_SEARCH_WINDOW
if (SearchWindowID == window->id) {
SetScissor(window->line_numbers_rect);
DrawString(window->font, u"Find: ", ToVec2(window->line_numbers_rect.min), color_text_line_numbers);
}
#endif
// Draw scrollbar
if (DrawScrollbar && window->draw_scrollbar) {
ProfileScope(DrawScrollbar);
SetScissor(window->scrollbar_rect);
DrawRect(window->scrollbar_rect, ScrollbarBackgroundColor);
Scroller scroller = ComputeScrollerRect(window);
Rect2 rect = Shrink(scroller.rect, 2);
Color color = ScrollerColor;
if (ScrollbarSelected.id == window->id.id) color = ScrollerSelectedColor;
DrawRect(rect, color);
}
// color the floating object to make it stand out
if (window->z >= 1) {
ProfileScope(ColorFloating);
SetScissor(window->total_rect);
DrawRect(window->total_rect, {255, 255, 255, 25});
}
if (window->secondary_window_style) {
SetScissor(window->total_rect);
Rect2I rect = window->total_rect;
DrawRect(CutTop(&rect, 1), SecondaryWindowStyle_OutlineColor);
}
// darken the inactive windows
if (!is_active && !active_layed_out_doc) {
ProfileScope(DarkenInactiveRect);
SetScissor(screen_rect);
DrawRect(window->total_rect, InactiveWindowColor);
}
// Draw resizer rect
if (GetSize(window->resizer_rect).x > 0){
Rect2I rect = window->resizer_rect;
SetScissor(window->resizer_rect);
DrawRect(rect, ResizerBackgroundColor);
DrawRect(CutRight(&rect, 1), ResizerOutlineColor);
}
}
+515
View File
@@ -0,0 +1,515 @@
const char *SDLKeycodeToName(SDL_Keycode keycode) {
switch(keycode) {
case SDLK_UNKNOWN: return "SDLK_UNKNOWN"; break;
case SDLK_RETURN: return "SDLK_RETURN"; break;
case SDLK_ESCAPE: return "SDLK_ESCAPE"; break;
case SDLK_BACKSPACE: return "SDLK_BACKSPACE"; break;
case SDLK_TAB: return "SDLK_TAB"; break;
case SDLK_SPACE: return "SDLK_SPACE"; break;
case SDLK_EXCLAIM: return "SDLK_EXCLAIM"; break;
case SDLK_DBLAPOSTROPHE: return "SDLK_DBLAPOSTROPHE"; break;
case SDLK_HASH: return "SDLK_HASH"; break;
case SDLK_DOLLAR: return "SDLK_DOLLAR"; break;
case SDLK_PERCENT: return "SDLK_PERCENT"; break;
case SDLK_AMPERSAND: return "SDLK_AMPERSAND"; break;
case SDLK_APOSTROPHE: return "SDLK_APOSTROPHE"; break;
case SDLK_LEFTPAREN: return "SDLK_LEFTPAREN"; break;
case SDLK_RIGHTPAREN: return "SDLK_RIGHTPAREN"; break;
case SDLK_ASTERISK: return "SDLK_ASTERISK"; break;
case SDLK_PLUS: return "SDLK_PLUS"; break;
case SDLK_COMMA: return "SDLK_COMMA"; break;
case SDLK_MINUS: return "SDLK_MINUS"; break;
case SDLK_PERIOD: return "SDLK_PERIOD"; break;
case SDLK_SLASH: return "SDLK_SLASH"; break;
case SDLK_0: return "SDLK_0"; break;
case SDLK_1: return "SDLK_1"; break;
case SDLK_2: return "SDLK_2"; break;
case SDLK_3: return "SDLK_3"; break;
case SDLK_4: return "SDLK_4"; break;
case SDLK_5: return "SDLK_5"; break;
case SDLK_6: return "SDLK_6"; break;
case SDLK_7: return "SDLK_7"; break;
case SDLK_8: return "SDLK_8"; break;
case SDLK_9: return "SDLK_9"; break;
case SDLK_COLON: return "SDLK_COLON"; break;
case SDLK_SEMICOLON: return "SDLK_SEMICOLON"; break;
case SDLK_LESS: return "SDLK_LESS"; break;
case SDLK_EQUALS: return "SDLK_EQUALS"; break;
case SDLK_GREATER: return "SDLK_GREATER"; break;
case SDLK_QUESTION: return "SDLK_QUESTION"; break;
case SDLK_AT: return "SDLK_AT"; break;
case SDLK_LEFTBRACKET: return "SDLK_LEFTBRACKET"; break;
case SDLK_BACKSLASH: return "SDLK_BACKSLASH"; break;
case SDLK_RIGHTBRACKET: return "SDLK_RIGHTBRACKET"; break;
case SDLK_CARET: return "SDLK_CARET"; break;
case SDLK_UNDERSCORE: return "SDLK_UNDERSCORE"; break;
case SDLK_GRAVE: return "SDLK_GRAVE"; break;
case SDLK_A: return "SDLK_A"; break;
case SDLK_B: return "SDLK_B"; break;
case SDLK_C: return "SDLK_C"; break;
case SDLK_D: return "SDLK_D"; break;
case SDLK_E: return "SDLK_E"; break;
case SDLK_F: return "SDLK_F"; break;
case SDLK_G: return "SDLK_G"; break;
case SDLK_H: return "SDLK_H"; break;
case SDLK_I: return "SDLK_I"; break;
case SDLK_J: return "SDLK_J"; break;
case SDLK_K: return "SDLK_K"; break;
case SDLK_L: return "SDLK_L"; break;
case SDLK_M: return "SDLK_M"; break;
case SDLK_N: return "SDLK_N"; break;
case SDLK_O: return "SDLK_O"; break;
case SDLK_P: return "SDLK_P"; break;
case SDLK_Q: return "SDLK_Q"; break;
case SDLK_R: return "SDLK_R"; break;
case SDLK_S: return "SDLK_S"; break;
case SDLK_T: return "SDLK_T"; break;
case SDLK_U: return "SDLK_U"; break;
case SDLK_V: return "SDLK_V"; break;
case SDLK_W: return "SDLK_W"; break;
case SDLK_X: return "SDLK_X"; break;
case SDLK_Y: return "SDLK_Y"; break;
case SDLK_Z: return "SDLK_Z"; break;
case SDLK_LEFTBRACE: return "SDLK_LEFTBRACE"; break;
case SDLK_PIPE: return "SDLK_PIPE"; break;
case SDLK_RIGHTBRACE: return "SDLK_RIGHTBRACE"; break;
case SDLK_TILDE: return "SDLK_TILDE"; break;
case SDLK_DELETE: return "SDLK_DELETE"; break;
case SDLK_PLUSMINUS: return "SDLK_PLUSMINUS"; break;
case SDLK_CAPSLOCK: return "SDLK_CAPSLOCK"; break;
case SDLK_F1: return "SDLK_F1"; break;
case SDLK_F2: return "SDLK_F2"; break;
case SDLK_F3: return "SDLK_F3"; break;
case SDLK_F4: return "SDLK_F4"; break;
case SDLK_F5: return "SDLK_F5"; break;
case SDLK_F6: return "SDLK_F6"; break;
case SDLK_F7: return "SDLK_F7"; break;
case SDLK_F8: return "SDLK_F8"; break;
case SDLK_F9: return "SDLK_F9"; break;
case SDLK_F10: return "SDLK_F10"; break;
case SDLK_F11: return "SDLK_F11"; break;
case SDLK_F12: return "SDLK_F12"; break;
case SDLK_PRINTSCREEN: return "SDLK_PRINTSCREEN"; break;
case SDLK_SCROLLLOCK: return "SDLK_SCROLLLOCK"; break;
case SDLK_PAUSE: return "SDLK_PAUSE"; break;
case SDLK_INSERT: return "SDLK_INSERT"; break;
case SDLK_HOME: return "SDLK_HOME"; break;
case SDLK_PAGEUP: return "SDLK_PAGEUP"; break;
case SDLK_END: return "SDLK_END"; break;
case SDLK_PAGEDOWN: return "SDLK_PAGEDOWN"; break;
case SDLK_RIGHT: return "SDLK_RIGHT"; break;
case SDLK_LEFT: return "SDLK_LEFT"; break;
case SDLK_DOWN: return "SDLK_DOWN"; break;
case SDLK_UP: return "SDLK_UP"; break;
case SDLK_NUMLOCKCLEAR: return "SDLK_NUMLOCKCLEAR"; break;
case SDLK_KP_DIVIDE: return "SDLK_KP_DIVIDE"; break;
case SDLK_KP_MULTIPLY: return "SDLK_KP_MULTIPLY"; break;
case SDLK_KP_MINUS: return "SDLK_KP_MINUS"; break;
case SDLK_KP_PLUS: return "SDLK_KP_PLUS"; break;
case SDLK_KP_ENTER: return "SDLK_KP_ENTER"; break;
case SDLK_KP_1: return "SDLK_KP_1"; break;
case SDLK_KP_2: return "SDLK_KP_2"; break;
case SDLK_KP_3: return "SDLK_KP_3"; break;
case SDLK_KP_4: return "SDLK_KP_4"; break;
case SDLK_KP_5: return "SDLK_KP_5"; break;
case SDLK_KP_6: return "SDLK_KP_6"; break;
case SDLK_KP_7: return "SDLK_KP_7"; break;
case SDLK_KP_8: return "SDLK_KP_8"; break;
case SDLK_KP_9: return "SDLK_KP_9"; break;
case SDLK_KP_0: return "SDLK_KP_0"; break;
case SDLK_KP_PERIOD: return "SDLK_KP_PERIOD"; break;
case SDLK_APPLICATION: return "SDLK_APPLICATION"; break;
case SDLK_POWER: return "SDLK_POWER"; break;
case SDLK_KP_EQUALS: return "SDLK_KP_EQUALS"; break;
case SDLK_F13: return "SDLK_F13"; break;
case SDLK_F14: return "SDLK_F14"; break;
case SDLK_F15: return "SDLK_F15"; break;
case SDLK_F16: return "SDLK_F16"; break;
case SDLK_F17: return "SDLK_F17"; break;
case SDLK_F18: return "SDLK_F18"; break;
case SDLK_F19: return "SDLK_F19"; break;
case SDLK_F20: return "SDLK_F20"; break;
case SDLK_F21: return "SDLK_F21"; break;
case SDLK_F22: return "SDLK_F22"; break;
case SDLK_F23: return "SDLK_F23"; break;
case SDLK_F24: return "SDLK_F24"; break;
case SDLK_EXECUTE: return "SDLK_EXECUTE"; break;
case SDLK_HELP: return "SDLK_HELP"; break;
case SDLK_MENU: return "SDLK_MENU"; break;
case SDLK_SELECT: return "SDLK_SELECT"; break;
case SDLK_STOP: return "SDLK_STOP"; break;
case SDLK_AGAIN: return "SDLK_AGAIN"; break;
case SDLK_UNDO: return "SDLK_UNDO"; break;
case SDLK_CUT: return "SDLK_CUT"; break;
case SDLK_COPY: return "SDLK_COPY"; break;
case SDLK_PASTE: return "SDLK_PASTE"; break;
case SDLK_FIND: return "SDLK_FIND"; break;
case SDLK_MUTE: return "SDLK_MUTE"; break;
case SDLK_VOLUMEUP: return "SDLK_VOLUMEUP"; break;
case SDLK_VOLUMEDOWN: return "SDLK_VOLUMEDOWN"; break;
case SDLK_KP_COMMA: return "SDLK_KP_COMMA"; break;
case SDLK_KP_EQUALSAS400: return "SDLK_KP_EQUALSAS400"; break;
case SDLK_ALTERASE: return "SDLK_ALTERASE"; break;
case SDLK_SYSREQ: return "SDLK_SYSREQ"; break;
case SDLK_CANCEL: return "SDLK_CANCEL"; break;
case SDLK_CLEAR: return "SDLK_CLEAR"; break;
case SDLK_PRIOR: return "SDLK_PRIOR"; break;
case SDLK_RETURN2: return "SDLK_RETURN2"; break;
case SDLK_SEPARATOR: return "SDLK_SEPARATOR"; break;
case SDLK_OUT: return "SDLK_OUT"; break;
case SDLK_OPER: return "SDLK_OPER"; break;
case SDLK_CLEARAGAIN: return "SDLK_CLEARAGAIN"; break;
case SDLK_CRSEL: return "SDLK_CRSEL"; break;
case SDLK_EXSEL: return "SDLK_EXSEL"; break;
case SDLK_KP_00: return "SDLK_KP_00"; break;
case SDLK_KP_000: return "SDLK_KP_000"; break;
case SDLK_THOUSANDSSEPARATOR: return "SDLK_THOUSANDSSEPARATOR"; break;
case SDLK_DECIMALSEPARATOR: return "SDLK_DECIMALSEPARATOR"; break;
case SDLK_CURRENCYUNIT: return "SDLK_CURRENCYUNIT"; break;
case SDLK_CURRENCYSUBUNIT: return "SDLK_CURRENCYSUBUNIT"; break;
case SDLK_KP_LEFTPAREN: return "SDLK_KP_LEFTPAREN"; break;
case SDLK_KP_RIGHTPAREN: return "SDLK_KP_RIGHTPAREN"; break;
case SDLK_KP_LEFTBRACE: return "SDLK_KP_LEFTBRACE"; break;
case SDLK_KP_RIGHTBRACE: return "SDLK_KP_RIGHTBRACE"; break;
case SDLK_KP_TAB: return "SDLK_KP_TAB"; break;
case SDLK_KP_BACKSPACE: return "SDLK_KP_BACKSPACE"; break;
case SDLK_KP_A: return "SDLK_KP_A"; break;
case SDLK_KP_B: return "SDLK_KP_B"; break;
case SDLK_KP_C: return "SDLK_KP_C"; break;
case SDLK_KP_D: return "SDLK_KP_D"; break;
case SDLK_KP_E: return "SDLK_KP_E"; break;
case SDLK_KP_F: return "SDLK_KP_F"; break;
case SDLK_KP_XOR: return "SDLK_KP_XOR"; break;
case SDLK_KP_POWER: return "SDLK_KP_POWER"; break;
case SDLK_KP_PERCENT: return "SDLK_KP_PERCENT"; break;
case SDLK_KP_LESS: return "SDLK_KP_LESS"; break;
case SDLK_KP_GREATER: return "SDLK_KP_GREATER"; break;
case SDLK_KP_AMPERSAND: return "SDLK_KP_AMPERSAND"; break;
case SDLK_KP_DBLAMPERSAND: return "SDLK_KP_DBLAMPERSAND"; break;
case SDLK_KP_VERTICALBAR: return "SDLK_KP_VERTICALBAR"; break;
case SDLK_KP_DBLVERTICALBAR: return "SDLK_KP_DBLVERTICALBAR"; break;
case SDLK_KP_COLON: return "SDLK_KP_COLON"; break;
case SDLK_KP_HASH: return "SDLK_KP_HASH"; break;
case SDLK_KP_SPACE: return "SDLK_KP_SPACE"; break;
case SDLK_KP_AT: return "SDLK_KP_AT"; break;
case SDLK_KP_EXCLAM: return "SDLK_KP_EXCLAM"; break;
case SDLK_KP_MEMSTORE: return "SDLK_KP_MEMSTORE"; break;
case SDLK_KP_MEMRECALL: return "SDLK_KP_MEMRECALL"; break;
case SDLK_KP_MEMCLEAR: return "SDLK_KP_MEMCLEAR"; break;
case SDLK_KP_MEMADD: return "SDLK_KP_MEMADD"; break;
case SDLK_KP_MEMSUBTRACT: return "SDLK_KP_MEMSUBTRACT"; break;
case SDLK_KP_MEMMULTIPLY: return "SDLK_KP_MEMMULTIPLY"; break;
case SDLK_KP_MEMDIVIDE: return "SDLK_KP_MEMDIVIDE"; break;
case SDLK_KP_PLUSMINUS: return "SDLK_KP_PLUSMINUS"; break;
case SDLK_KP_CLEAR: return "SDLK_KP_CLEAR"; break;
case SDLK_KP_CLEARENTRY: return "SDLK_KP_CLEARENTRY"; break;
case SDLK_KP_BINARY: return "SDLK_KP_BINARY"; break;
case SDLK_KP_OCTAL: return "SDLK_KP_OCTAL"; break;
case SDLK_KP_DECIMAL: return "SDLK_KP_DECIMAL"; break;
case SDLK_KP_HEXADECIMAL: return "SDLK_KP_HEXADECIMAL"; break;
case SDLK_LCTRL: return "SDLK_LCTRL"; break;
case SDLK_LSHIFT: return "SDLK_LSHIFT"; break;
case SDLK_LALT: return "SDLK_LALT"; break;
case SDLK_LGUI: return "SDLK_LGUI"; break;
case SDLK_RCTRL: return "SDLK_RCTRL"; break;
case SDLK_RSHIFT: return "SDLK_RSHIFT"; break;
case SDLK_RALT: return "SDLK_RALT"; break;
case SDLK_RGUI: return "SDLK_RGUI"; break;
case SDLK_MODE: return "SDLK_MODE"; break;
case SDLK_SLEEP: return "SDLK_SLEEP"; break;
case SDLK_WAKE: return "SDLK_WAKE"; break;
case SDLK_CHANNEL_INCREMENT: return "SDLK_CHANNEL_INCREMENT"; break;
case SDLK_CHANNEL_DECREMENT: return "SDLK_CHANNEL_DECREMENT"; break;
case SDLK_MEDIA_PLAY: return "SDLK_MEDIA_PLAY"; break;
case SDLK_MEDIA_PAUSE: return "SDLK_MEDIA_PAUSE"; break;
case SDLK_MEDIA_RECORD: return "SDLK_MEDIA_RECORD"; break;
case SDLK_MEDIA_FAST_FORWARD: return "SDLK_MEDIA_FAST_FORWARD"; break;
case SDLK_MEDIA_REWIND: return "SDLK_MEDIA_REWIND"; break;
case SDLK_MEDIA_NEXT_TRACK: return "SDLK_MEDIA_NEXT_TRACK"; break;
case SDLK_MEDIA_PREVIOUS_TRACK: return "SDLK_MEDIA_PREVIOUS_TRACK"; break;
case SDLK_MEDIA_STOP: return "SDLK_MEDIA_STOP"; break;
case SDLK_MEDIA_EJECT: return "SDLK_MEDIA_EJECT"; break;
case SDLK_MEDIA_PLAY_PAUSE: return "SDLK_MEDIA_PLAY_PAUSE"; break;
case SDLK_MEDIA_SELECT: return "SDLK_MEDIA_SELECT"; break;
case SDLK_AC_NEW: return "SDLK_AC_NEW"; break;
case SDLK_AC_OPEN: return "SDLK_AC_OPEN"; break;
case SDLK_AC_CLOSE: return "SDLK_AC_CLOSE"; break;
case SDLK_AC_EXIT: return "SDLK_AC_EXIT"; break;
case SDLK_AC_SAVE: return "SDLK_AC_SAVE"; break;
case SDLK_AC_PRINT: return "SDLK_AC_PRINT"; break;
case SDLK_AC_PROPERTIES: return "SDLK_AC_PROPERTIES"; break;
case SDLK_AC_SEARCH: return "SDLK_AC_SEARCH"; break;
case SDLK_AC_HOME: return "SDLK_AC_HOME"; break;
case SDLK_AC_BACK: return "SDLK_AC_BACK"; break;
case SDLK_AC_FORWARD: return "SDLK_AC_FORWARD"; break;
case SDLK_AC_STOP: return "SDLK_AC_STOP"; break;
case SDLK_AC_REFRESH: return "SDLK_AC_REFRESH"; break;
case SDLK_AC_BOOKMARKS: return "SDLK_AC_BOOKMARKS"; break;
case SDLK_SOFTLEFT: return "SDLK_SOFTLEFT"; break;
case SDLK_SOFTRIGHT: return "SDLK_SOFTRIGHT"; break;
case SDLK_CALL: return "SDLK_CALL"; break;
case SDLK_ENDCALL: return "SDLK_ENDCALL"; break;
case SDLK_LEFT_TAB: return "SDLK_LEFT_TAB"; break;
case SDLK_LEVEL5_SHIFT: return "SDLK_LEVEL5_SHIFT"; break;
case SDLK_MULTI_KEY_COMPOSE: return "SDLK_MULTI_KEY_COMPOSE"; break;
case SDLK_LMETA: return "SDLK_LMETA"; break;
case SDLK_RMETA: return "SDLK_RMETA"; break;
case SDLK_LHYPER: return "SDLK_LHYPER"; break;
case SDLK_RHYPER: return "SDLK_RHYPER"; break;
default: return "SDLK_INVALID";
}
}
struct { String string; EventKind value; } MouseConversionTable[] = {
{"mousex1", EVENT_MOUSE_X1},
{"mousex2", EVENT_MOUSE_X2},
{"mouseleft", EVENT_MOUSE_LEFT},
{"mouseright", EVENT_MOUSE_RIGHT},
{"mousemiddle", EVENT_MOUSE_MIDDLE},
};
struct { String string; SDL_Keycode value; } SDLKeycodeConversionTable[] = {
{"enter", SDLK_RETURN},
{"escape", SDLK_ESCAPE},
{"backspace", SDLK_BACKSPACE},
{"tab", SDLK_TAB},
{"space", SDLK_SPACE},
{"minus", SDLK_MINUS},
{"period", SDLK_PERIOD},
{"slash", SDLK_SLASH},
{"0", SDLK_0},
{"1", SDLK_1},
{"2", SDLK_2},
{"3", SDLK_3},
{"4", SDLK_4},
{"5", SDLK_5},
{"6", SDLK_6},
{"7", SDLK_7},
{"8", SDLK_8},
{"9", SDLK_9},
{"semicolon", SDLK_SEMICOLON},
{"less", SDLK_LESS},
{"equals", SDLK_EQUALS},
{"greater", SDLK_GREATER},
{"leftbracket", SDLK_LEFTBRACKET},
{"backslash", SDLK_BACKSLASH},
{"rightbracket", SDLK_RIGHTBRACKET},
{"grave", SDLK_GRAVE},
{"a", SDLK_A},
{"b", SDLK_B},
{"c", SDLK_C},
{"d", SDLK_D},
{"e", SDLK_E},
{"f", SDLK_F},
{"g", SDLK_G},
{"h", SDLK_H},
{"i", SDLK_I},
{"j", SDLK_J},
{"k", SDLK_K},
{"l", SDLK_L},
{"m", SDLK_M},
{"n", SDLK_N},
{"o", SDLK_O},
{"p", SDLK_P},
{"q", SDLK_Q},
{"r", SDLK_R},
{"s", SDLK_S},
{"t", SDLK_T},
{"u", SDLK_U},
{"v", SDLK_V},
{"w", SDLK_W},
{"x", SDLK_X},
{"y", SDLK_Y},
{"z", SDLK_Z},
{"delete", SDLK_DELETE},
{"capslock", SDLK_CAPSLOCK},
{"f1", SDLK_F1},
{"f2", SDLK_F2},
{"f3", SDLK_F3},
{"f4", SDLK_F4},
{"f5", SDLK_F5},
{"f6", SDLK_F6},
{"f7", SDLK_F7},
{"f8", SDLK_F8},
{"f9", SDLK_F9},
{"f10", SDLK_F10},
{"f11", SDLK_F11},
{"f12", SDLK_F12},
{"insert", SDLK_INSERT},
{"home", SDLK_HOME},
{"pageup", SDLK_PAGEUP},
{"end", SDLK_END},
{"pagedown", SDLK_PAGEDOWN},
{"right", SDLK_RIGHT},
{"left", SDLK_LEFT},
{"down", SDLK_DOWN},
{"up", SDLK_UP},
};
void FillEventWithBasicData(Event *event) {
SDL_Keymod mod = SDL_GetModState();
event->shift = (mod & SDL_KMOD_SHIFT) != 0;
event->ctrl = (mod & SDL_KMOD_CTRL) != 0;
event->alt = (mod & SDL_KMOD_ALT) != 0;
event->super = (mod & SDL_KMOD_GUI) != 0;
float xmouse, ymouse;
SDL_GetMouseState(&xmouse, &ymouse);
event->xmouse = (int16_t)roundf(DPIScale * xmouse);
event->ymouse = (int16_t)roundf(DPIScale * ymouse);
int xwindow, ywindow;
SDL_GetWindowSizeInPixels(SDLWindow, &xwindow, &ywindow);
event->xwindow = xwindow;
event->ywindow = ywindow;
event->text = "";
}
Event TranslateSDLEvent(SDL_Event *input_event) {
ProfileFunction();
Event event = {};
FillEventWithBasicData(&event);
switch (input_event->type) {
case SDL_EVENT_QUIT: {
event.kind = EVENT_QUIT;
} break;
case SDL_EVENT_KEY_DOWN: {
event.kind = EVENT_KEY_PRESS;
SDL_KeyboardEvent &key = input_event->key;
event.key = key.key;
} break;
case SDL_EVENT_TEXT_INPUT: {
event.kind = EVENT_TEXT_INPUT;
SDL_TextInputEvent &b = input_event->text;
String string = b.text;
event.text = Intern(&GlobalInternTable, string).data;
} break;
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)roundf(DPIScale * b.x);
event.ymouse = (int16_t)roundf(DPIScale * b.y);
event.clicks = b.clicks;
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2;
} else {
event.kind = EVENT_NONE;
event.clicks = 0;
}
} break;
case SDL_EVENT_MOUSE_BUTTON_UP: {
SDL_MouseButtonEvent &b = input_event->button;
event.xmouse = (int16_t)roundf(DPIScale * b.x);
event.ymouse = (int16_t)roundf(DPIScale * b.y);
if (b.button == SDL_BUTTON_LEFT) {
event.kind = EVENT_MOUSE_LEFT_UP;
} else if (b.button == SDL_BUTTON_RIGHT) {
event.kind = EVENT_MOUSE_RIGHT_UP;
} else if (b.button == SDL_BUTTON_MIDDLE) {
event.kind = EVENT_MOUSE_MIDDLE_UP;
} else if (b.button == SDL_BUTTON_X1) {
event.kind = EVENT_MOUSE_X1_UP;
} else if (b.button == SDL_BUTTON_X2) {
event.kind = EVENT_MOUSE_X2_UP;
} else {
event.kind = EVENT_NONE;
}
} break;
case SDL_EVENT_MOUSE_WHEEL: {
event.kind = EVENT_MOUSE_WHEEL;
SDL_MouseWheelEvent &b = input_event->wheel;
event.xmouse = (int16_t)roundf(DPIScale * b.mouse_x);
event.ymouse = (int16_t)roundf(DPIScale * b.mouse_y);
event.xwheel = b.x;
event.ywheel = b.y;
} break;
case SDL_EVENT_MOUSE_MOTION: {
event.kind = EVENT_UPDATE;
} break;
case SDL_EVENT_DROP_FILE: {
event.kind = EVENT_DROP_FILE;
SDL_DropEvent &b = input_event->drop;
String string = b.data;
event.text = Intern(&GlobalInternTable, string).data;
} break;
default: {
};
}
return event;
}
inline void AddEvent(Array<Event> *events, Event ev) {
bool any_special_modifiers = (ev.ctrl || ev.alt || ev.super);
if (ev.kind == EVENT_TEXT_INPUT && any_special_modifiers) {
return;
}
if (ev.kind == EVENT_KEY_PRESS && !any_special_modifiers && ev.key >= SDLK_A && ev.key <= SDLK_Z) {
if (ev.key != SDLK_RETURN) {
return;
}
}
if (ev.kind == EVENT_NONE) {
return;
}
Add(events, ev);
}
void GetEventsForFrame(Array<Event> *events) {
ProfileFunction();
For (EventPlayback) {
Add(events, it);
}
SDL_Event event;
if (WaitForEventsState) {
SDL_WaitEvent(&event);
Event ev = TranslateSDLEvent(&event);
AddEvent(events, ev);
}
while (SDL_PollEvent(&event)) {
Event ev = TranslateSDLEvent(&event);
AddEvent(events, ev);
}
if (events->len == 0) {
Event event = {};
FillEventWithBasicData(&event);
event.kind = EVENT_UPDATE;
Add(events, event);
}
Assert(events->len);
}
#define Press(KEY) (event.key == KEY)
#define CtrlPress(KEY) (event.key == KEY && event.ctrl)
#define ShiftPress(KEY) (event.key == KEY && event.shift)
#define AltPress(KEY) (event.key == KEY && event.alt)
#define CtrlShiftPress(KEY) (event.key == KEY && event.ctrl && event.shift)
#define CtrlAltPress(KEY) (event.key == KEY && event.ctrl && event.alt)
#define AltShiftPress(KEY) (event.key == KEY && event.shift && event.alt)
#define MouseVec2() Vec2 { (float)event.xmouse, (float)event.ymouse }
#define MouseVec2I() Vec2I { (Int) event.xmouse, (Int)event.ymouse }
#define Mouse(x) (event.kind == EVENT_MOUSE_##x)
#define MousePress() (Mouse(LEFT) || Mouse(RIGHT) || Mouse(MIDDLE))
#define MouseUp() (Mouse(LEFT_UP) || Mouse(RIGHT_UP) || Mouse(MIDDLE_UP))
+160
View File
@@ -0,0 +1,160 @@
float NewFuzzyRate(String16 s, String16 p) {
float score = 0;
// try to do this: https://github.com/junegunn/fzf/blob/master/src/algo/algo.go
return score;
}
float FuzzyRate(String16 s, String16 p) {
float score = 0;
for (Int outer_pi = 0; outer_pi < p.len; outer_pi += 1) {
String16 pit = Skip(p, outer_pi);
if (IsWhitespace(At(pit, 0))) {
continue;
}
float matching = 0;
for (Int outer_si = 0; outer_si < s.len; outer_si += 1) {
String16 sit = Skip(s, outer_si);
if (IsWhitespace(At(sit, 0))) {
continue;
}
Int si = 0;
Int pi = 0;
for (;si < sit.len && pi < pit.len;) {
while (si < sit.len && IsWhitespace(sit[si])) si += 1;
while (pi < pit.len && IsWhitespace(pit[pi])) pi += 1;
if (pi >= pit.len) break;
if (si >= sit.len) break;
if (ToLowerCase(sit[si]) == ToLowerCase(pit[pi])) {
matching += 1.0f;
} else {
break;
}
si += 1;
pi += 1;
}
}
score += matching;
}
score = score / (float)s.len;
return score;
}
inline bool MergeSortCompare(FuzzyPair *a, FuzzyPair *b) {
bool result = a->rating > b->rating;
return result;
}
Array<FuzzyPair> FuzzySearchLines(Allocator allocator, Buffer *buffer, Int line_min, Int line_max, String16 needle) {
ProfileFunction();
if (line_min < 0 || line_min >= buffer->line_starts.len) return {};
if (line_max < 0 || line_min > buffer->line_starts.len) return {};
Array<FuzzyPair> ratings = {allocator};
Reserve(&ratings, line_max - line_min + 4);
for (Int i = line_min; i < line_max; i += 1) {
String16 s = GetLineStringWithoutNL(buffer, i);
Int idx = 0;
if (Seek(s, u"||>", &idx, SeekFlag_None)) {
s = GetPrefix(s, idx);
} else if (Seek(s, u"<||", &idx, SeekFlag_None)) {
s = GetPrefix(s, idx);
}
s = Trim(s);
float rating = FuzzyRate(s, needle);
Add(&ratings, {(int32_t)i, rating});
}
Array<FuzzyPair> temp = Copy(allocator, ratings);
MergeSort(ratings.len, ratings.data, temp.data);
return ratings;
}
void UpdateFuzzySearchView() {
ProfileFunction();
Scratch scratch;
BSet active = GetBSet(ActiveWindowID);
String16 line_string = GetLineStringWithoutNL(active.buffer, 0);
uint64_t hash = HashBytes(line_string.data, line_string.len * sizeof(char16_t));
if (active.view->prev_search_line_hash != hash) {
active.view->prev_search_line_hash = hash;
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 1, active.buffer->line_starts.len, line_string);
Buffer *scratch_buff = CreateScratchBuffer(scratch, active.buffer->cap);
RawAppend(scratch_buff, line_string);
For (IterateInReverse(&ratings)) {
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
if (s.len == 0) continue;
RawAppend(scratch_buff, u"\n");
RawAppend(scratch_buff, s);
}
Caret caret = active.view->carets[0];
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
SelectEntireBuffer(active.view);
Replace(active.view, GetString(scratch_buff));
active.view->carets[0] = caret;
}
}
String16 FetchFuzzyViewLoadLine(View *view) {
Buffer *buffer = GetBuffer(view->active_buffer);
Range range = view->carets[0].range;
String16 string = GetString(buffer, range);
Int line = PosToLine(buffer, range.min);
if (GetSize(range) == 0 || line == 0) {
if (line == 0) {
line = ClampTop(1ll, buffer->line_starts.len - 1ll);
}
string = GetLineStringWithoutNL(buffer, line);
Int idx = 0;
String16 delim = u"||>";
if (Seek(string, delim, &idx, SeekFlag_None)) {
string = Skip(string, idx + delim.len);
}
}
return string;
}
void CMD_OpenLoadWord() {
Scratch scratch;
BSet active = GetBSet(ActiveWindowID);
For (active.view->carets) {
Range range = it.range;
if (GetSize(range) == 0) {
range = EncloseLoadWord(active.buffer, GetFront(it));
}
String16 load_word = GetString(active.buffer, range);
Open(load_word);
}
} RegisterCommand(CMD_OpenLoadWord, "ctrl-q | f12", "Open a link under the caret (file link, url, command) or open the selection");
void CMD_OpenForFuzzyView() {
BSet active = GetBSet(ActiveWindowID);
BSet main = GetBSet(PrimaryWindowID);
NextActiveWindowID = main.window->id;
if (active.view->carets.len == 1 && GetSize(active.view->carets[0].range) == 0) {
String16 string = FetchFuzzyViewLoadLine(active.view);
Open(string);
} else {
CMD_OpenLoadWord();
}
}
void CMD_OpenAndSetGotoNext() {
BSet active = GetBSet(ActiveWindowID);
BSet main = GetBSet(PrimaryWindowID);
NextActiveWindowID = main.window->id;
String16 string = FetchFuzzyViewLoadLine(active.view);
main.window->active_goto_list = active.view->id;
main.window->goto_list_pos = active.view->carets[0].range.min;
Open(string);
}
void SetFuzzy(View *view) {
AddCommand(&view->commands, "Open", OpenKeySet, CMD_OpenForFuzzyView);
view->update_hook = UpdateFuzzySearchView;
}
+188
View File
@@ -0,0 +1,188 @@
SDL_Window *SDLWindow;
bool IsInFullscreen;
int FullScreenSizeX, FullScreenSizeY;
int FullScreenPositionX, FullScreenPositionY;
bool Testing = false;
bool AppIsRunning = true;
bool WaitForEventsState = true;
bool RunGCThisFrame;
bool SearchCaseSensitive = false;
bool SearchWordBoundary = false;
bool BreakOnError = false;
Int ErrorCount;
Allocator SysAllocator = {SystemAllocatorProc};
String ConfigDir;
float DPIScale = 1.0f;
// @WARNING: be careful about using this, should only be used for debugging
// the problem with this is that we want events to be reproducible.
// We eat as many events as we can in a frame, we abstract the frame and so on.
// Dont use it
Int FrameID;
WindowID WindowIDs;
ViewID ViewIDs;
Int BufferIDs;
Array<Window *> Windows;
Array<View *> Views;
Array<Buffer *> Buffers;
View *LogView;
Buffer *LogBuffer;
BufferID NullBufferID;
ViewID NullViewID;
WindowID NullWindowID;
#if PLUGIN_SEARCH_WINDOW
WindowID SearchWindowID;
ViewID SearchViewID;
BufferID SearchBufferID;
#endif
Trigger *EscapeKey;
Trigger *EnterKey;
Trigger *OpenKeySet;
Trigger *EnterOrEscapeKeySet;
Trigger *AltEnterKeySet;
Trigger *ShiftEnterKeySet;
WindowID NextActiveWindowID;
WindowID ActiveWindowID;
WindowID PrimaryWindowID;
WindowID ScrollbarSelected = {-1};
WindowID DocumentSelected = {-1};
WindowID ResizerSelected = {-1};
WindowID ResizerHover = {-1};
Caret DocumentAnchor;
Vec2I MouseMiddleAnchor;
RandomSeed UniqueBufferNameSeed = {};
Array<Event> EventPlayback;
BlockArena Perm;
// clipboard
BlockArena ClipboardArena;
String16 SavedClipboardString;
Array<String16> SavedClipboardCarets = {SysAllocator};
struct InternTable {
HashTable<String> strings; // general allocator
BlockArena arena;
};
String Intern(InternTable *table, String string) {
String *value = table->strings.get(string);
if (!value) {
String copy = Copy(table->arena, string);
table->strings.put(copy, copy);
return copy;
}
return *value;
}
// We use the intern table to optimize for space, I don't want to worry about freeing
// buffer names and event text data so let it all accumulate and interning will at least
// optimize worst offenders (like event text)
InternTable GlobalInternTable;
Array<Command> GlobalCommands;
Array<FunctionData> TestFunctions;
Array<Variable> Variables;
Array<Process> ActiveProcesses = {};
Array<String> ProcessEnviroment = {};
struct CoData { mco_coro *co; String name; BlockArena arena; bool dont_wait_until_resolved; void *user_ctx; };
Array<CoData> ActiveCoroutines;
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
Color GruvboxDark0 = {0x28, 0x28, 0x28, 0xff};
Color GruvboxDark0Soft = {0x32, 0x30, 0x2f, 0xff};
Color GruvboxDark1 = {0x3c, 0x38, 0x36, 0xff};
Color GruvboxDark2 = {0x50, 0x49, 0x45, 0xff};
Color GruvboxDark3 = {0x66, 0x5c, 0x54, 0xff};
Color GruvboxDark4 = {0x7c, 0x6f, 0x64, 0xff};
Color GruvboxGray245 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxGray244 = {0x92, 0x83, 0x74, 0xff};
Color GruvboxLight0Hard = {0xf9, 0xf5, 0xd7, 0xff};
Color GruvboxLight0 = {0xfb, 0xf1, 0xc7, 0xff};
Color GruvboxLight0Soft = {0xf2, 0xe5, 0xbc, 0xff};
Color GruvboxLight1 = {0xeb, 0xdb, 0xb2, 0xff};
Color GruvboxLight2 = {0xd5, 0xc4, 0xa1, 0xff};
Color GruvboxLight3 = {0xbd, 0xae, 0x93, 0xff};
Color GruvboxLight4 = {0xa8, 0x99, 0x84, 0xff};
Color GruvboxBrightRed = {0xfb, 0x49, 0x34, 0xff};
Color GruvboxBrightGreen = {0xb8, 0xbb, 0x26, 0xff};
Color GruvboxBrightYellow = {0xfa, 0xbd, 0x2f, 0xff};
Color GruvboxBrightBlue = {0x83, 0xa5, 0x98, 0xff};
Color GruvboxBrightPurple = {0xd3, 0x86, 0x9b, 0xff};
Color GruvboxBrightAqua = {0x8e, 0xc0, 0x7c, 0xff};
Color GruvboxBrightOrange = {0xfe, 0x80, 0x19, 0xff};
Color GruvboxNeutralRed = {0xcc, 0x24, 0x1d, 0xff};
Color GruvboxNeutralGreen = {0x98, 0x97, 0x1a, 0xff};
Color GruvboxNeutralYellow = {0xd7, 0x99, 0x21, 0xff};
Color GruvboxNeutralBlue = {0x45, 0x85, 0x88, 0xff};
Color GruvboxNeutralPurple = {0xb1, 0x62, 0x86, 0xff};
Color GruvboxNeutralAqua = {0x68, 0x9d, 0x6a, 0xff};
Color GruvboxNeutralOrange = {0xd6, 0x5d, 0x0e, 0xff};
Color GruvboxFadedRed = {0x9d, 0x00, 0x06, 0xff};
Color GruvboxFadedGreen = {0x79, 0x74, 0x0e, 0xff};
Color GruvboxFadedYellow = {0xb5, 0x76, 0x14, 0xff};
Color GruvboxFadedBlue = {0x07, 0x66, 0x78, 0xff};
Color GruvboxFadedPurple = {0x8f, 0x3f, 0x71, 0xff};
Color GruvboxFadedAqua = {0x42, 0x7b, 0x58, 0xff};
Color GruvboxFadedOrange = {0xaf, 0x3a, 0x03, 0xff};
RegisterVariable(Color, TextColor, GruvboxDark0Hard);
RegisterVariable(Color, BackgroundColor, GruvboxLight0Hard);
RegisterVariable(Color, InactiveWindowColor, {0x00, 0x00, 0x00, 0x1F});
RegisterVariable(Color, LineNumberTextColor, GruvboxDark4);
RegisterVariable(Color, LineHighlightColor, GruvboxLight0Soft);
RegisterVariable(Color, PrimaryCaretColor, GruvboxDark0Hard);
RegisterVariable(Color, SecondaryCaretColor, GruvboxGray245);
RegisterVariable(Color, SelectionColor, GruvboxLight1);
RegisterVariable(Color, SelectedWhitespaceColor, GruvboxLight4);
RegisterVariable(Color, MouseUnderlineColor, GruvboxDark0Hard);
RegisterVariable(Color, CaretUnderlineColor, GruvboxGray245);
RegisterVariable(Color, ScrollbarBackgroundColor, GruvboxLight2);
RegisterVariable(Color, ScrollerColor, GruvboxLight1);
RegisterVariable(Color, ScrollerSelectedColor, GruvboxLight0Hard);
RegisterVariable(Color, SecondaryWindowStyle_TextColor, GruvboxDark0Hard);
RegisterVariable(Color, SecondaryWindowStyle_BackgroundColor, GruvboxLight0Hard);
RegisterVariable(Color, SecondaryWindowStyle_SelectionColor, GruvboxLight3);
RegisterVariable(Color, SecondaryWindowStyle_LineHighlightColor, GruvboxLight0Soft);
RegisterVariable(Color, SecondaryWindowStyle_OutlineColor, GruvboxLight3);
RegisterVariable(Color, ResizerBackgroundColor, GruvboxLight0Hard);
RegisterVariable(Color, ResizerOutlineColor, GruvboxLight3);
RegisterVariable(Int, WaitForEvents, 1);
RegisterVariable(Int, DrawLineNumbers, 1);
RegisterVariable(Int, DrawScrollbar, 1);
RegisterVariable(Int, IndentSize, 4);
RegisterVariable(String, IndentKindWhichIsTabsOrSpaces, "spaces");
RegisterVariable(Int, FontSize, 15);
RegisterVariable(String, PathToFont, "");
RegisterVariable(Float, UndoMergeTime, 0.3);
RegisterVariable(Float, JumpHistoryMergeTime, 0.3);
RegisterVariable(String, InternetBrowser, "firefox");
RegisterVariable(String, OpenCodePatterns, ".c .h .cpp .hpp .cc .cxx .rs .go .zig .py .lua .js .ts .jsx .tsx .java .kt .swift .cs .rb .php .html .css .scss .bat .sh .bash .zsh .sql .asm .s .cmake .make .json .yaml .toml .ini .txt .md .rst .Makefile .Dockerfile .gitignore .bashrc .zshrc");
RegisterVariable(String, OpenCodeExcludePatterns, "");
RegisterVariable(Int, TrimTrailingWhitespace, 1);
// PROJECT_MANAGEMENT
// Set at the beginning of the program to current directory
RegisterVariable(String, ProjectDirectory, "");
// PLUGIN_BUILD_WINDOW
RegisterVariable(String, Build1OnWindows, "build.bat");
RegisterVariable(String, Build1OnUnix, "sh build.sh");
RegisterVariable(String, Build2OnWindows, "build.bat release");
RegisterVariable(String, Build2OnUnix, "sh build.sh release");
// PLUGIN_LOAD_VCVARS
RegisterVariable(String, VCVarsPath, "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat");
// PLUGIN_REMEDYBG
RegisterVariable(String, BinaryUnderDebug, "");
RegisterVariable(String, RemedyBGPath, "remedybg.exe");
+24
View File
@@ -0,0 +1,24 @@
Hi! Welcome to my world, the world where text is all around and plentiful. I'm tee,
a simple text editor that hopefully will help you in your text journey!
Execute some of these using your mouse right button, hover over a
word like ":New" and click!
:New (ctrl-n) - create new text file
:OpenUpFolder (ctrl-o) - navigate directories
:ShowCommands (ctrl-shift-p) - open up the command lister
:ShowBufferList (ctrl-p) - open up a lister with open files
Alternatively you can open with your keyboard - ctrl-q / f12, try that also!
-----------------------------------------------------------------------------------------
Navigate to next parts of the guide by executing them like these commands you just played
with:
:GuideBigPicture
:GuideNavigation
:GuideProjects
:GuideBindings
:GuideConfig
+249
View File
@@ -0,0 +1,249 @@
void CMD_Redo() {
BSet active = GetBSet(ActiveWindowID);
RedoEdit(active.buffer, &active.view->carets);
} RegisterCommand(CMD_Redo, "ctrl-shift-z", "Redo after undoing changes to the buffer");
void CMD_Undo() {
BSet active = GetBSet(ActiveWindowID);
UndoEdit(active.buffer, &active.view->carets);
} RegisterCommand(CMD_Undo, "ctrl-z", "Undo last change you made to the buffer");
void CMD_EncloseLine() {
BSet active = GetBSet(ActiveWindowID);
EncloseLine(active.view);
} RegisterCommand(CMD_EncloseLine, "ctrl-l", "Select the entire line on which your caret is placed");
void CMD_SelectAll() {
BSet active = GetBSet(ActiveWindowID);
SelectEntireBuffer(active.view);
active.view->update_scroll = false;
} RegisterCommand(CMD_SelectAll, "ctrl-a", "Select the entire buffer");
void CMD_KillSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
KillSelectedLines(active.view);
} RegisterCommand(CMD_KillSelectedLines, "ctrl-shift-k", "Delete the selected lines, don't put to clipboard");
void CMD_IndentSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
IndentSelectedLines(active.view);
} RegisterCommand(CMD_IndentSelectedLines, "ctrl-rightbracket | tab", "");
void CMD_DedentSelectedLines() {
BSet active = GetBSet(ActiveWindowID);
IndentSelectedLines(active.view, true);
} RegisterCommand(CMD_DedentSelectedLines, "ctrl-leftbracket | shift-tab", "");
void CMD_DuplicateLineDown() {
BSet active = GetBSet(ActiveWindowID);
DuplicateLine(active.view, DIR_DOWN);
} RegisterCommand(CMD_DuplicateLineDown, "ctrl-alt-down", "");
void CMD_CreateCursorDown() {
BSet active = GetBSet(ActiveWindowID);
CreateCursorVertical(active.view, DIR_DOWN);
} RegisterCommand(CMD_CreateCursorDown, "alt-shift-down", "");
void CMD_SelectDownToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(CMD_SelectDownToEmptyLine, "ctrl-shift-down", "");
void CMD_MoveLineDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCaretsLine(active.view, DIR_DOWN);
} RegisterCommand(CMD_MoveLineDown, "alt-down", "");
void CMD_MoveDownToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, CTRL_PRESSED);
} RegisterCommand(CMD_MoveDownToEmptyLine, "ctrl-down", "");
void CMD_SelectDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN, false, SHIFT_PRESS);
} RegisterCommand(CMD_SelectDown, "shift-down", "");
void CMD_MoveDown() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_DOWN);
} RegisterCommand(CMD_MoveDown, "down", "");
void CMD_DuplicateLineUp() {
BSet active = GetBSet(ActiveWindowID);
DuplicateLine(active.view, DIR_UP);
} RegisterCommand(CMD_DuplicateLineUp, "ctrl-alt-up", "");
void CMD_CreateCursorUp() {
BSet active = GetBSet(ActiveWindowID);
CreateCursorVertical(active.view, DIR_UP);
} RegisterCommand(CMD_CreateCursorUp, "alt-shift-up", "");
void CMD_SelectUpToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(CMD_SelectUpToEmptyLine, "ctrl-shift-up", "");
void CMD_MoveLineUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCaretsLine(active.view, DIR_UP);
} RegisterCommand(CMD_MoveLineUp, "alt-up", "");
void CMD_MoveUpToEmptyLine() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, CTRL_PRESSED);
} RegisterCommand(CMD_MoveUpToEmptyLine, "ctrl-up", "");
void CMD_SelectUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP, false, SHIFT_PRESS);
} RegisterCommand(CMD_SelectUp, "shift-up", "");
void CMD_MoveUp() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_UP);
} RegisterCommand(CMD_MoveUp, "up", "");
void CMD_BoundarySelectLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(CMD_BoundarySelectLeft, "ctrl-shift-left", "");
void CMD_BoundaryMoveLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, CTRL_PRESSED);
} RegisterCommand(CMD_BoundaryMoveLeft, "ctrl-left", "");
void CMD_SelectLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT, false, SHIFT_PRESS);
} RegisterCommand(CMD_SelectLeft, "shift-left", "");
void CMD_MoveLeft() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_LEFT);
} RegisterCommand(CMD_MoveLeft, "left", "");
void CMD_BoundarySelectRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED, SHIFT_PRESS);
} RegisterCommand(CMD_BoundarySelectRight, "ctrl-shift-right", "");
void CMD_BoundaryMoveRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, CTRL_PRESSED);
} RegisterCommand(CMD_BoundaryMoveRight, "ctrl-right", "");
void CMD_SelectRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT, false, SHIFT_PRESS);
} RegisterCommand(CMD_SelectRight, "shift-right", "");
void CMD_MoveRight() {
BSet active = GetBSet(ActiveWindowID);
MoveCarets(active.view, DIR_RIGHT);
} RegisterCommand(CMD_MoveRight, "right", "");
void CMD_MoveUpAPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_UP);
} RegisterCommand(CMD_MoveUpAPage, "pageup", "");
void CMD_SelectUpPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_UP, SHIFT_PRESS);
} RegisterCommand(CMD_SelectUpPage, "shift-pageup", "");
void CMD_MoveToStart() {
BSet active = GetBSet(ActiveWindowID);
SelectRange(active.view, MakeRange(0));
} RegisterCommand(CMD_MoveToStart, "ctrl-pageup", "");
void CMD_SelectDownPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_DOWN, SHIFT_PRESS);
} RegisterCommand(CMD_SelectDownPage, "shift-pagedown", "");
void CMD_MoveToEnd() {
BSet active = GetBSet(ActiveWindowID);
SelectRange(active.view, MakeRange(active.buffer->len));
} RegisterCommand(CMD_MoveToEnd, "ctrl-pagedown", "");
void CMD_MoveDownPage() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorByPageSize(active.window, DIR_DOWN);
} RegisterCommand(CMD_MoveDownPage, "pagedown", "");
void CMD_SelectToLineStart() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_LEFT, SHIFT_PRESS);
} RegisterCommand(CMD_SelectToLineStart, "shift-home", "");
void CMD_MoveToLineStart() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_LEFT);
} RegisterCommand(CMD_MoveToLineStart, "home", "");
void CMD_MoveToLineEnd() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_RIGHT);
} RegisterCommand(CMD_MoveToLineEnd, "end", "");
void CMD_SelectToLineEnd() {
BSet active = GetBSet(ActiveWindowID);
MoveCursorToSide(active.view, DIR_RIGHT, SHIFT_PRESS);
} RegisterCommand(CMD_SelectToLineEnd, "shift-end", "");
void CMD_DeleteCharacter() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_LEFT);
} RegisterCommand(CMD_DeleteCharacter, "shift-backspace | backspace", "");
void CMD_DeleteBoundary() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_LEFT, SHIFT_PRESS);
} RegisterCommand(CMD_DeleteBoundary, "ctrl-backspace", "");
void CMD_DeleteForward() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_RIGHT);
} RegisterCommand(CMD_DeleteForward, "shift-delete | delete", "");
void CMD_DeleteForwardBoundary() {
BSet active = GetBSet(ActiveWindowID);
Delete(active.view, DIR_RIGHT, SHIFT_PRESS);
} RegisterCommand(CMD_DeleteForwardBoundary, "ctrl-delete", "");
void CMD_InsertNewLineUp() {
BSet active = GetBSet(ActiveWindowID);
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
MoveCursorToSide(active.view, DIR_LEFT);
IndentedNewLine(active.view);
MoveCarets(active.view, DIR_UP);
} RegisterCommand(CMD_InsertNewLineUp, "ctrl-shift-enter", "");
void CMD_InsertNewLineDown() {
BSet active = GetBSet(ActiveWindowID);
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
MoveCursorToSide(active.view, DIR_RIGHT);
IndentedNewLine(active.view);
} RegisterCommand(CMD_InsertNewLineDown, "ctrl-enter", "");
void CMD_NewLine() {
BSet active = GetBSet(ActiveWindowID);
IndentedNewLine(active.view);
} RegisterCommand(CMD_NewLine, "enter | shift-enter", "");
void CMD_CreateCaretOnNextFind() {
BSet active = GetBSet(ActiveWindowID);
String16 string = GetString(active.buffer, active.view->carets[0].range);
Caret caret = FindNext(active.buffer, string, active.view->carets[0]);
Insert(&active.view->carets, caret, 0);
MergeCarets(active.buffer, &active.view->carets);
} RegisterCommand(CMD_CreateCaretOnNextFind, "ctrl-d", "");
void CMD_ClearCarets() {
BSet active = GetBSet(ActiveWindowID);
active.view->carets.len = 1;
active.view->carets[0] = MakeCaret(GetFront(active.view->carets[0]));
} RegisterCommand(CMD_ClearCarets, "escape", "Clear all carets and reset to 1 caret, also do some windowing stuff that closes things on escape");
+75
View File
@@ -0,0 +1,75 @@
WindowID BuildWindowID;
ViewID BuildViewID;
BufferID BuildBufferID;
void InitBuildWindow() {
Window *window = CreateWind();
BuildWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(ProjectDirectory, "build"));
buffer->special = true;
buffer->no_history = true;
BuildBufferID = buffer->id;
View *view = CreateView(buffer->id);
view->special = true;
BuildViewID = view->id;
window->active_view = view->id;
window->secondary_window_style = true;
window->draw_line_highlight = true;
window->primary = false;
window->visible = false;
window->lose_visibility_on_escape = true;
window->jump_history = false;
}
void LayoutBuildWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(BuildWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = window->font->line_spacing * 10;
window->document_rect = window->total_rect = CutBottom(rect, barsize);
}
BSet ExecBuild(String windows_cmd, String unix_cmd, String working_dir = ProjectDirectory) {
SaveAll();
BSet build = GetBSet(BuildWindowID);
BSet main = GetBSet(PrimaryWindowID);
SelectRange(build.view, Range{});
ResetBuffer(build.buffer);
if (OS_WINDOWS) {
Exec(build.view->id, true, windows_cmd, working_dir);
} else {
Exec(build.view->id, true, unix_cmd, working_dir);
}
main.window->active_goto_list = build.view->id;
main.window->goto_list_pos = 0;
build.window->visible = true;
return build;
}
void CMD_Build1() {
ExecBuild(Build1OnWindows, Build1OnUnix);
} RegisterCommand(CMD_Build1, "f1", "Run Build1OnWindows or OnUnix in working directory, output is printed in a popup console and a special build buffer");
void CMD_Build2() {
ExecBuild(Build2OnWindows, Build2OnUnix);
} RegisterCommand(CMD_Build2, "f2", "Run Build2OnWindows or OnUnix in working directory, output is printed in a popup console and a special build buffer");
void CMD_RunFile() {
Scratch scratch;
BSet primary = GetBSet(PrimaryWindowID);
String windows_command = Format(scratch, "cl %S -Fe:cfile.exe /Zi /FC /nologo /WX /W3 /wd4200 /wd4334 /diagnostics:column && cfile.exe && del cfile.*", primary.buffer->name);
String unix_command = Format(scratch, "bash <<EOF\nclang %S -o cfile.exe -g -Wall -Wno-missing-braces -Wno-writable-strings -Wno-writable-strings -fsanitize=address -fdiagnostics-absolute-paths -lm \n./cfile.exe \nrm cfile.exe\nEOF", primary.buffer->name);
ExecBuild(windows_command, unix_command, GetDirectory(primary.buffer));
} RegisterCommand(CMD_RunFile, "", "Run and build current file, currently only C/C++ supported");
void CMD_ShowBuildWindow() {
BSet main = GetBSet(BuildWindowID);
if (ActiveWindowID != BuildWindowID) {
main.window->visible = true;
NextActiveWindowID = BuildWindowID;
} else {
main.window->visible = false;
}
} RegisterCommand(CMD_ShowBuildWindow, "ctrl-grave", "Toggles visibility of the build window");
+85
View File
@@ -0,0 +1,85 @@
WindowID CommandWindowID;
void CMD_ShowCommands() {
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (GlobalCommands) {
RawAppendf(command_bar.buffer, "\n:%-30S <|| ", it.name);
if (it.docs.len) {
RawAppendf(command_bar.buffer, "%S", it.docs);
}
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowCommands, "ctrl-shift-p", "List available commands and their documentation inside the command window");
void CMD_ShowDebugBufferList() {
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (Buffers) {
bool is_special = it->special || it->temp || it->dont_try_to_save_in_bulk_ops;
#if PLUGIN_DIRECTORY_NAVIGATION
is_special |= it->is_dir;
#endif
if (!is_special) {
continue;
}
RawAppendf(command_bar.buffer, "\n%S", it->name);
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowDebugBufferList, "ctrl-shift-alt-p", "Show full list of buffers, including the special ones that normally just clutter list");
void CMD_ShowBufferList() {
BSet command_bar = GetBSet(CommandWindowID);
command_bar.window->visible = true;
NextActiveWindowID = command_bar.window->id;
ResetBuffer(command_bar.buffer);
For (Buffers) {
bool is_special = it->special || it->temp || it->dont_try_to_save_in_bulk_ops;
#if PLUGIN_DIRECTORY_NAVIGATION
is_special |= it->is_dir;
#endif
if (is_special) {
continue;
}
RawAppendf(command_bar.buffer, "\n%S", it->name);
}
command_bar.view->update_scroll = true;
SelectRange(command_bar.view, GetBufferBeginAsRange(command_bar.buffer));
} RegisterCommand(CMD_ShowBufferList, "ctrl-p", "List open buffers inside the command window that you can fuzzy search over");
void LayoutCommandWindow(Rect2I *rect, int16_t wx, int16_t wy) {
Window *window = GetWindow(CommandWindowID);
Rect2I copy_rect = *rect;
if (!window->visible) {
rect = &copy_rect;
}
Int barsize = Clamp((Int)window->font->line_spacing*10, (Int)0, (Int)wx - 100);
window->document_rect = window->total_rect = CutBottom(rect, barsize);
}
void InitCommandWindow() {
Window *window = CreateWind();
CommandWindowID = window->id;
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(ProjectDirectory, "command_bar"));
buffer->special = true;
buffer->no_history = true;
View *view = CreateView(buffer->id);
view->special = true;
SetFuzzy(view);
window->active_view = view->id;
window->draw_line_numbers = false;
window->draw_scrollbar = false;
window->secondary_window_style = true;
window->draw_line_highlight = true;
window->primary = false;
window->visible = false;
window->sync_visibility_with_focus = true;
window->lose_focus_on_escape = true;
window->jump_history = false;
}
+163
View File
@@ -0,0 +1,163 @@
#if PLUGIN_CONFIG
BufferID GlobalConfigBufferID;
void CMD_OpenConfig() {
Buffer *buffer = GetBuffer(GlobalConfigBufferID);
Open(buffer->name);
} RegisterCommand(CMD_OpenConfig, "", "Open the global config file");
void CMD_OpenConfigOptions() {
BSet main = GetBSet(PrimaryWindowID);
JumpTempBuffer(&main);
NextActiveWindowID = main.window->id;
For (Variables) {
RawAppendf(main.buffer, "\n:Set %-50S ", it.name);
switch(it.type) {
case VariableType_Color: RawAppendf(main.buffer, "%x", it.color->value); break;
case VariableType_String: RawAppendf(main.buffer, "'%S'", *it.string); break;
case VariableType_Int: RawAppendf(main.buffer, "%lld", (long long)*it.i); break;
case VariableType_Float: RawAppendf(main.buffer, "%f", *it.f); break;
default: InvalidCodepath();
}
}
For (GlobalCommands) {
RawAppendf(main.buffer, "\n:Set %-50S '%S'", it.name, it.binding);
}
} RegisterCommand(CMD_OpenConfigOptions, "", "List available variables and associated documentation inside the command window");
void EvalCommandsLineByLine(BSet set) {
WindowID save_last = PrimaryWindowID;
WindowID save_active = ActiveWindowID;
WindowID save_next = NextActiveWindowID;
Caret save_caret = set.view->carets[0];
ActiveWindowID = set.window->id;
PrimaryWindowID = set.window->id;
NextActiveWindowID = set.window->id;
for (Int i = 0; i < set.buffer->line_starts.len; i += 1) {
Range range = GetLineRangeWithoutNL(set.buffer, i);
String16 string = GetString(set.buffer, range);
string = Trim(string);
if (string.len == 0) {
continue;
}
if (StartsWith(string, u"//")) {
continue;
}
Open(string);
}
set.view->carets[0] = save_caret;
PrimaryWindowID = save_last;
ActiveWindowID = save_active;
NextActiveWindowID = save_next;
}
void CMD_EvalCommandsLineByLine() {
BSet set = GetBSet(PrimaryWindowID);
EvalCommandsLineByLine(set);
} RegisterCommand(CMD_EvalCommandsLineByLine, "", "Goes line by line over a buffer and evaluates every line as a command, ignores empty or lines starting with '//'");
BufferID LoadConfig(String config_path) {
ReportConsolef("Loading config %S...", config_path);
Window *window = GetWindow(NullWindowID);
ViewID active_view_before = window->active_view;
View *view = WindowOpenBufferView(window, config_path);
Buffer *buffer = GetBuffer(view->active_buffer);
EvalCommandsLineByLine({window, view, buffer});
if (window->active_view == view->id) {
window->active_view = active_view_before;
}
return buffer->id;
}
#define ExpectP(x, ...) \
if (!(x)) { \
ReportErrorf("Failed to parse '" __FUNCTION__ "' command, " __VA_ARGS__); \
return; \
}
void Set(String string) {
String name = SkipIdent(&string);
ExpectP(name.len != 0, "expected a variable name, instead got '%S'", string);
Variable *var = NULL;
For (Variables) {
if (name == it.name) {
var = &it;
break;
}
}
if (var) {
SkipWhitespace(&string);
if (var->type == VariableType_String) {
char c = At(string, 0);
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
string = Skip(string, 1);
String quote = SkipUntil(&string, {&c, 1});
ExpectP(At(string, 0) == c, ":Set %S <error here>, unclosed quote", name);
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
*var->string = Intern(&GlobalInternTable, quote);
} else if (var->type == VariableType_Int) {
ExpectP(IsDigit(At(string, 0)), "Expected an integer to follow the command name, instead got: %S", string);
Int number = SkipInt(&string);
ReportConsolef(":Set %S %lld", name, number);
*var->i = number;
} else if (var->type == VariableType_Float) {
ExpectP(IsDigit(At(string, 0)), "Expected float to follow the command name, instead got: %S", string);
Float number = SkipFloat(&string);
ReportConsolef(":Set %S %f", name, number);
*var->f = number;
} else if (var->type == VariableType_Color) {
ExpectP(IsHexDigit(At(string, 0)), "Expected hex integer to follow the command name, instead got: %S", string);
String begin = {string.data, 0};
while (IsHexDigit(At(string, 0))) {
string = Skip(string, 1);
begin.len += 1;
}
ReportConsolef(":Set %S %S", name, begin);
var->color->value = (uint32_t)strtoll(begin.data, NULL, 16);
} ElseInvalidCodepath();
if (name == "FontSize" || name == "PathToFont") {
ReloadFont(PathToFont, (U32)FontSize);
}
#if PLUGIN_PROJECT_MANAGEMENT
if (name == "ProjectDirectory") {
SetProjectDirectory(*var->string);
}
#endif
return;
}
Command *cmd = NULL;
For (GlobalCommands) {
if (it.name == name) {
cmd = &it;
break;
}
}
if (cmd) {
SkipWhitespace(&string);
char c = At(string, 0);
ExpectP(c == u'"' || c == u'\'', "Expected string to follow the command name, instead got %S", string);
string = Skip(string, 1);
String quote = SkipUntil(&string, {&c, 1});
ExpectP(At(string, 0) == c, "Failed to parse command, unclose quote");
quote = Intern(&GlobalInternTable, quote);
ReportConsolef(":Set %S %c%S%c", name, c, quote, c);
Trigger *trigger = ParseKeyCached(quote);
if (trigger) {
cmd->binding = quote;
cmd->trigger = trigger;
}
return;
}
ReportErrorf("Failed to :Set, no such variable found: %S", name);
}
#endif
+3
View File
@@ -0,0 +1,3 @@
#if PLUGIN_CONFIG
void Set(String string);
#endif

Some files were not shown because too many files have changed in this diff Show More