-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNotes.nts
More file actions
1438 lines (880 loc) · 127 KB
/
Notes.nts
File metadata and controls
1438 lines (880 loc) · 127 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[05/23/25]
Tonight marks the very beginning of the "Nostalgia Engine" project (also referred to unofficially as the "Rose Tinted Engine"). The goal for this engine will be to capture the style, feeling, and "vibe" of PC and console games from the early PS2 era while including more modern sensibilities and quality of life features (e.g: better controls, higher resolutions, framerate != game logic speed, etc). The file structure for this project was initially inspired by the file structure for Valve's "Source Engine" (or at least the SDK and the 2020 leaks). I don't know if I'll stick to this way of organizing my files, but I thought it'd be fitting since the Source engine is from the time period that I'm trying to capture.
[05/26/25]
I'm gonna try and start on this engine. I want to begin with the renderer; specifically, I want to implement a debug rendering function that gets called after the normal one which will use custom render commands specifically for debug drawing (i.e: simple lines, points, tris, etc).
All right all right all right! I've gotten a decent amount of work done tonight; I created the _Manager and Manager classes, changed up the project structure a bit, updated the Makefile, and added a much-needed gitignore file. Currently, the RenderManager class is what's being worked on and isn't fully finished yet. I think for tonight, however, I'm gonna call it here and wrap up.
All in all, it was a good fuckin' sesh :3
[05/27/25]
Okay, today I want to finish the render manager and then move onto perhaps designing how a game would interface with the engine. All the engine needs to know is where to draw a mesh and some specific properties of that mesh (like scale, material, etc). The game could invoke certain functions or classes to generate render commands based on certain information, with no possibility of undefined behaviour. But for now, I work on the render manager.
Note: the fov of 90 degrees is hardcoded into the engine. I want to change that.
Finished the first pass of the RenderManager class! Things related to the world manager are missing, of course, but I've implemented pretty much everything else. The whole CameraProperty thing as well as the GetForward function are kind of strange and I'm not 100% on whether or not I want to keep them as they are or use a different system. It does make sense to do those calculations in the render manager, but I want to keep an eye on it so I know how the game should get the proper data to that function.
Yeah, I think it's time to move on to the world manager (although, I want to rename it to "TheatreManager", because I'm quirky).
I implemented as much of the "WorldManager" class as I could; I changed it back to "WorldManager", since it makes more sense to rename "Levels" to "Theatres" and keep "World".
I've implemented a bit of the input system and input manager classes. The idea for them will be to have the input system running constantly, using the glfw key callback function to store and/or send inputs as well as polling the mouse, etc etc. The input manager will then check the input system for new inputs during its Update function, and will then go on to process them as commands (ideally).
I also added a shitty little "press enter to exit" type function & thread so the program can be exited while there is no input handling (or even a window).
[05/28/25]
Today, I wanna work a bit on the input manager. At least see if I can get some ideas down in Milanote.
# Notes from Milanote: "The input manager will interface with some sort of "input system", which is always running and always processing inputs. I'm thinking that I could implement some object that stores a giant list of all valid inputs and whether or not they're currently down. Maybe a custom type/struct".
While working on app systems, I've realized that I should abstract all API calls (and library calls related to API like GLFW) to a "window manager" class that is interfaced with via simple functions. This way I can account for any number of APIs and libraries, as well as add/remove support for them, without having to worry about how it will affect the rest of the engine.
I spent a whole bunch of time working on `WindowManager` and the `API` class templates... just to realize that I don't need allat and I can move WindowManager's code into RenderManager. I'll keep the API class, but it won't be a template anymore.
Okay, I've implemented `API` and integrated it with `RenderManager` and it works like a charm! `API` handles all the api-specific calls, while `RenderManager` just interfaces with `API` via simple functions. This means that (hopefully) `RenderManager` will not be affected by any additions/removals/changes to any api-specific code.
[05/27/25]
Goal for today: try and get a window running.
Just realized, it makes no sense to have an input system (at least in the way I'm doing it). Instead, I just need a class that interfaces with the specific key & mouse callback functions and InputManager will be responsible for interacting with that class + polling inputs otherwise. Oh, and the class to interface with the callback functions can just be the API class.
[05/30/25]
Okay, I'm at the point where I really should start diverging from Source; it's (obviously) overscoped for my project, so I want to take a step back and try to get a working window and main app loop working today.
[06/02/25]
Today, I'm going to try and get the program to a state where I have a working window that I can close with the 'esc' key.
Finally!! The main issue was that the render manager had an early return in the Update function for if there was no level loaded (which there never would be, since levels don't exist yet). Now, the engine crashes on exit; it might be due to my shitty prototype functions, but it's more likely that it's not so I'm gonna try and fix it before comitting.
It works! Before comitting, I have one last thing I want to do, which is consolidate the backends into one class since the windowing library depends on the graphics API and the main function for the backend is graphics related (with window inputs being an outlier). Then, I can commit lmfao.
Actually, I *do* like the separation (since the windowing library doesn't have to be one specific library), but I think I'll keep most of the functions in the manager, and the more anal/dedicated functions in their respective graphics/windowing backend class.
Alright, time to commit!
Okay, now what? I think I want to try and dig into Source's rendering pipeline, but it's a fucking mess and I don't know if I really wanna spend all that time giving myself a headache. I'll look at Godot's a little bit but if it's too much, I'll just default to a render command based pipeline.
I might also want to work on the whole "console commmands" pipeline, too, but that might be a bit too high level rn.
# Okay, here's the structure for the render manager: one (or a few) main functions for rendering that will ALWAYS return and will NEVER crash the engine, and various smaller functions for more specific tasks (generating buffers, interfacing with shaders, etc). Those functions will interface with the backend manager which will interface with the backend classes which will do the direct API calls.
Okay, I finished a basic framework for the render commands system, as well as the "camera property" system for the main "camera". I'm fucking tired, lmfao, but it works and I'm committing and pushing this shit.
Last minute addition: added a character callback function to GLFW_Backend so it can use PRINTDEBUG to output which keys I've pressed.
[06/04/25]
After spending most of my time on the GraphX project structure & makefile overhaul (ughhhhhhhh), I did a smaller one for Nostalgia (smaller bc it didn't need nearly as large of a change as GraphX did). I might work a bit on Nostalgia, but I'm pretty mentally tired so idk.
Okay, I want to move input-related code out of `WindowingBackend`, so I'm going to make functions for assigning the various callback functions.
I actually eneded up going in a totally different direction and I think it paid off! I made a custom "KeyboardHandler" class that interfaces with each windowing backend directly (via the backend). Basically, each windowing backend will interface with the KeyboardHandler in their respective key callback function, driving the KeyboardHandler's own pseudo-callback. Then, the KeyboardHandler interfaces directly with the InputManager's pseudo-callback function, which drives the actual input code. Basically, I've made a system for translating various windowing libraries' key handling to my own in a way that should be super modular and API/library agnostic.
[06/05/25]
All right, I fiddled with the Makefile this morning (and a little more just now) and I think it's in a really nice state. On to actual coding! I'm thinking that what I could do next could be to flesh out the render manager more and try to get a shader and a default cube going!
I think the BackendManager will be interfaced with for the most abstracted calls, since it can interface with the graphics API & the windowing library at the same time. Granted, it also has functions for accessing the backends to the API & library respectively, but I feel like the more contained I keep these direct calls, the better. Two degrees of separation feels better to me.
Hmm, while working in the backend manager code, I realized I want to quickly change the whole BackendID system; basically, I need for one graphics API to be able to work with different windowing libraries, but only if those libraries are for that graphics API. This way I can account for things like how GLFW can be used with OpenGL and Vulkan but not DirectX, while SDL can be used with all 3 (iirc). A simple struct should do.
UGH I'M SO STUPID LMFAO. Keep it simple, stupid: give the responsibility of keeping track of compatible backends to the fucking windowing backend class. I didn't need to do all the coding I just did.
Aight, I implemented a way for the windowing backends to check their compatibility with any of the graphics backends. All the functional code is contained in the 'WindowingBackend' base class, so the only code that needs to be written for any new derived windowing backends is a simple one-line definition of the 'compatible_graphics_ids' set in the 'Init' function (see 'src/engine/backends/windowing/glfw.cpp' for an example).
[06/06/25]
Fixed up the makefile a bit and started working on some rendering-related code. I fixed that issue with address sanitizer; the makefile works fine on my laptop, but had some issues on my PC that I addressed and fixed.
I created a 'Vertex' struct, a 'Mesh' struct, and gave 'RenderContext' a Mesh variable & function preemptively.
# NOTE: Interfaces can be classes/structs that other classes/structs implement (via multiple inheritance).
Hmm, how am I gonna store and reference Mesh objects? Maybe either the render manager or another class can store all relevant resources! Probably the render manager.
Okay, the world manager will be what stores all relevant world resources and delegates world rendering.
[06/09/25]
Spent an hour getting the changes I made off my Linux install from my Windows install from a VNC server from my laptop... fucking sucked, but I got it! I'm gonna continue on with the shader stuff today; finish up the Makefile (at least to a functional degree and spruce it up later), and start working on rendering a simple cube.
I've gotten shader compilation working, and it's a really well-oiled machine now! There's even a safety shader so that if all shaders fail to compile, that one (which has a high likelihood of succeeding) can be a fallback to stop the program from crashing. Speaking of crashes, I had a one related to not making a window before attempting to compile shaders, another one due to forgetting a '!' when checking that the safety shader compiled correctly, and while they weren't crashes I did have some errors due to the Makefile adding an extra '"' to the end of the shader files. Those are all fixed now, though, and it works like a dream!
I've overhauled the key id system to include codepoints; it works, but now it's tremendously slower. I'm probably going to undo all that work and just use the GLFW character callback function and pipe it straight to the input manager instead of the key handler.
Honestly, the character callback isn't too useful aside from typing to the screen.
[06/10/25]
# I had an idea: finish up a rough draft of Levitate, and include it in Nostalgia (as a library) to act as the default UI text editor!
Levitate is going to take a fucking SECOND and a half to finish.
# I have an idea: "TheToyMaker" will be the name for the editor window/app and the engine will have it's own!
[06/11/25]
I started off by changing the Makefile to spit out two executables: one for the engine and one for the editor. Then, I realized that the engine doesn't need a window, or application-related code and that it really needs to be a library. The rest of my time was spent in the Makefile, doing just that, and I'm happy to say it's a success! The engine now compiles to a static library and the application properly uses it when linking. While this works, I still need to decide what to do about the project structure. I'm thinking of moving all the application-related code to a separate repository/branch that's just for the editor/game(s), and changing the Makefile to build a library instead of a binary. Then, when making the editor/game(s), I just need to go build the game engine library in its own repo and add the resulting files to my other project.
Finally!!! This repository now contains only the engine-related code and the Makefile only creates a library (static and dynamic). I still need to make sure that compiling a .dll works, but the static library does and I'm fairly certain the dynamic linux library does as well. I've already tested linking this library to an app executable and it works! Hell yeah!
[06/13/25]
# Note for later today: that video on Doom 3's source code discussed the event queue and I want to emulate it for many reasons but especially for the logs.
[06/17/25]
I had to fiddle with the Makefile a bit to get the editor build system to work nicely, but now I want to start working on maybe implementing some rendering?
[06/18/25]
I'm really tired today but so far I fiddled with the build system a tad and gave Meshes a '_mesh_name' variable so the WorldManager can identify them before wrapping and adding them to the map.
I also ended up re-making 'uintvec3' from GraphX, as well as a header file "cube mesh" resource. I updated 'Mesh' to support using uintvec3 for initializing face indices and gave it some constructors as well.
[06/30/25]
On a flight to San Francisco; thinking I might get some coding in.
Working on a "Thing Spawner" for the editor debug menu and I'm running into some issues related to me trying to get vector of Thing pointers after creating a new Thing.
[07/20/25]
I wanna dick around before going to bed; it's 0046 rn lmfao. Lmfao, all I did was add 'imgui.ini' to the gitignore and move 'backends/' to 'rendering/backends', since that makes the most sense to me.
[07/21/25]
Okay, I want to work on the renderer now. Lemme just commit these old changes I forgot to commit on my laptop. Hmm, maybe not; I might not want to start work on Actors and Things before making the rendering engine, lmfao.
I ended up spending all my time reworking the Makefile, but I'm very happy with it. It's so much cleaner, better represents my skills, and is much more aesthetically pleasing. It can only make the static version of the library but that's for two reasons: the first being that I don't like the idea of the entire engine not being compiled into whatever game/editor binary I create, and the second being that as much as I still dislike Microsoft, I've had a bit of a change of heart and want to make native Windows compilation easier. That means, on top of all the other stuff, configuring the Makefile to be able to build a '.so' version *and* a '.dll' version. The static library should be fine because that gets compiled into the binary anyways (I hope it's fine, at least).
[07/31/25]
I think I want to overhaul the command line system to more closely follow my command line arguments library I made, as well as be more restricted to strings. I'm thinking that getting rid of variables is a good idea; something like "+forward" can just flag a function/class to move forwards while "-forward" flags them to stop, instead of setting a variable.
[08/01/25]
I forgot about the demo system!! That's what the commands were made for! I'm gonna take a look at both of these systems and review them. I should also start integrating ImGui into my debugging process a lot more, instead of changing values manually and re-compiling.
Okay, I thought that `std::print` was being weird because it wasn't correctly replacing `%s`, but I finally realized that the problem was me not reading the fucking documentation; `std::print` uses '{#}' instead of '%s'. I'm gonna try and add dependency file generation to the Makefile while I'm here, though, because that should make it so that if I change a header file, the correct source files get re-compiled.
Oh god, I'm gonna have to redo the entire Makefile... thank god for `makemake`; that should make my life a little bit easier.
Okay, for some reason, `makemake` is spitting garbage data out when I run it in this directory, but ONLY when I run it in this directory.
[08/03/25]
Fucking... spent all day in the Makefile; specifically, finally made the resources embed perfectly the way I want them to. Okay, more like 95% the way I want them to, but that's pretty good!
TODO: Change Makefile printouts to match the ones in Levitate (specifically the 'resources' Makefile).
[08/04/25]
Aight, time to do just that.
[08/05/25] (These notes were salvaged from Sublime Text)
I'm working on the events system before therapy & work. I've decided to remove the command line bc it was accidentally recreating the event system. The idea is that keys and commands are separate, and the key handler will have a map pairing the string names of keys with the string names of their bound command. Bindings can be set, removed, and cleared by key handler functions. I think I want to be able to bind multiple commands to the same key; the drawback to this would be that clearing all bindings for a key is the only way to replace a binding instead of add to it.
Okay, so here's the structure: KeyHandler - Abstracts the window library's key callback function. - Passes key data to the input manager. - That's literally it. - Must be as static as possible. InputManager - Decides what to do with inputs based on certain conditions. - i.e: populates the event queue if it's time to do so - This should be done on demand. - Every tick, processes the current event queue (or initiates another object to process it) - This flushes the current event queue - Acts as a delegator
[08/06/25] (These notes were salvaged from Sublime Text)
Okay, I'm gonna try and re-work the input handling framework around this: (https://app.milanote.com/1UJKjG1xRu4f1s/input-system).
[08/07/25]
i'm so broken... i just lost three days of work... because i wanted to make the `make clean` target slightly better...
i just lost so much
i had done so much
i'm... i'm genuinely devastated
and like, i know i can always rebuild, and thankfully it was only three days and not something crazy, but...
fuck, man... i had *just* figured out the input system!!
maybe this is a blessing in disguise: i can figure out a better way to do things.
i also have learned my second lesson regarding Linux and deleting things.
fuck...
i need a couple minutes to calm down and re-motivate myself.
Thanks to Sublime Merge, I found some of the deleted commit messages:
:::GitCommit
build: Updated Makefile to match my new "standard" and cleaned up a lot of nasty shit
build: Complete overhaul of the "resources" Makefile. I'd say it's 95% perfect and that's good enough for me
build/chores: cleanup & re-ordering the targets that `all` calls, just in case
fix/chore(resources): Forgot to use the new variable names for embedded resources
refactor: prettied up the 'sed' function
build(resources): Implemented better printouts and `clean` targets from `Levitate`
docs(notes)
refactor: Deleted 'command_line' files, moved 'command' files to 'src/events/', moved the `Key` struct into its own 'key.hpp' file, renamed 'input_id_conversion_maps.cpp' to 'key_id_lookup_tables.cpp'
:::
These should help me keep track of what I did.
[08/08/25]
Okay, I'm gonna try and redo all my fucking work, lmfao. Honestly, I'm motivated to try and redo everything in a cleaner and better way.
Aight, after re-evaluating things, I've decided on a framework... kinda:
- Input starts with the windowing library
- Its key callback function will be controlled by the windowing backend
- Key input is sent to the key handler
- The key handler formats the inputs and sends them to the input manager
- This could be done with only functions instead of using a class
- The input manager does the most work of all the classes/functions
- It checks whether or not to send inputs to the event queue or the UI manager
- Then it actually sends inputs to the correct place
- If it's to the event queue, the input manager first checks whether or not the input is valid and has a binding before sending it to the queue
- It also processes events from the event queue once every frame
- Finally, it will be responsible for managing key binds
And here are some of the data types:
- Event
- Container for a keybind and a timestamp
- KeyBind
- Container for a key id and a command name (e.g: '+forward')
- ConsoleCommand/Command
- Contains an unsigned short ID, and function pointer
- A separate, public map will pair up string names to command objects
I'm gonna ignore demos for the time being; those will be integrated afterwards, as they can just be a file full of string representations of events. If I wanna be *really* cheeky, demo files could be hex data (with an option for generating an additional "human readable" demo file with strings).
Finally got the compile_commands.json file built; time to actually get to work.
Actually, I'm gonna quickly merge 'indev' into 'trunk' and change my workflow. When I wanna work on new changes, I'll start a new branch. I can commit broken or unfinished code there all I want, because when I'm all done and it all works, I'll merge/rebase it into/onto 'trunk', which will bring it to a working state, and I can decide what to do about commits of broken/unfinished code before I merge/rebase.
Okay, time to do this shit... again. First, I'm gonna check the key handler and windowing backend and see if I really need the key handler. Yeah, actually, the key handler functions can just be input manager functions.
Aight, I cleaned up the key handling process up to the input manager. Basically, I gave 'InputManager' the 'Press', 'Release', and 'Repeat' functions; I had the windowing backend send keys to 'InputManager' instead of 'KeyHandler'; I changed keys from a struct to just unsigned integers; and I replaced my old error handling shit with the new 'SafeReturn' and 'SafeStatus' methods.
Oh, I also removed 'KeyHandler'.
I finished up by creating the command line (although, not sure if I really need to make it a queue or if it's okay to just have it execute commands directly, which can be done with a single function), optimizing the event queue (e.g: using lists instead of vectors due to all the pushing and popping), and connected everything together. There's a weird bug where the first input isn't processed (at least, I don't think it is), and I'm temporarily hardcoding the InputManager to enable the EventQueue in its Init function, but other than that, it should be working fine!
[08/10/25]
At my parents' house, I tested the code and made some small changes and a few fixes. Mainly, I fixed a lot of off-by-one/direction errors; this ended up fixing that weird bug where the first input wasn't being processed. Basically, the variable that stores the last processed queue index was being incremented incorrectly; I was adding one less than the size of the safe queue to it every time I processed events, which made the check for if it was a valid index return false on the first input. My resoning for this, at the time, was simply trying to keep the index at the last processed index (i.e: one less than the size of the queue), but the way that I use it to test queue validity only works if it ends on the index for the next event (i.e: the size of the queue). This also makes sure that the last event processed for a frame doesn't get processed again at the start of the next frame.
I also changed the print color variables; they're more verbose and less modular, but a lot simpler/easier to use.
[08/15/25]
I'm gonna first check that everything I worked on last is working and I am ready to move on from it; then, I want to start working on a UI system. I'll probably heavily integrate DearImGui, so I may want to streamline the ImGui integration within my backend system.
Ooh, before the UI stuff, I want to make sure my printouts are the ones from my "ctrl" repo and tidy up anything else that's in 'common/' or is otherwise a "helper".
[08/17/25]
I created 'SettingsManager', and implemented three default engine settings (tick rate, tick interval, and app name).
I'm torn between keeping settings simple but static, or complex but dynamic. If I keep it simple and static, I can just have some structs with some static variables and those can be the settings. If I keep it complex and dynamic, I have to use the maps, names, functions, etc, but I can add/remove settings without needing to go into the library code and recompile it.
Probably a mix of both, tbh.
Yeah, I'm doing both.
[08/18/25]
TODO: Window interactions are WILDLY different bewtween X11 and Wayland (as to be expected), and my current setup only works well on X11. I need to either create two ways of interfacing with the window for each display protocol, or I need to create an agnostic way of interfacing with both at the same time. Frankly, the two separate ways will probably be easier as it's very small stuff (so far), like how X11 can have a separate width/height for fullscreen and windowed mode and they don't interact with eachother, but Wayland seems to use the same values and overwrites them if fullscreen is manually called (e.g: pressing `Meta+S` on my keyboard).
But today, I will continue working on the rendering engine. I want to fix it up a bit, iron out the wrinkles, and then try to get an idea of how to design the pipeline so I can make a debugger that actually interacts with the rendering engine. I'm going to forgo a decent amount of the Source engine code for my own.
Here are some notes from (https://app.milanote.com/1UbfQh1ist7t1Y/nostalgia-engine):
'The game/application is responsible for providing data to the engine (e.g: mesh data, position, rotation, etc), and the engine is responsible for filtering that data into what can eventually become rendered output. The game simply provides input and data to the engine that the engine then runs with.'
This is all very complex, so I'm gonna start from the bottom and work up; basically, start at the end of the pipeline where I don't need to worry too much about future abstractions and can just think about raw data, then let that shape the abstractions. I think, at least.
Note I wrote on Discord:
'Diagram and notes containing a rough sketch of the rendering pipeline for "Nostalgia". Staring at Valve's source code will make you go fucking insane. I need to remind myself that Source is EXTREMELY too complicated for what I'm trying to do and I should STOP trying to model my engine after it so closely. Their system is beautiful (even when the leaked code is dated from 2006-2013), but it's quite like me saying "I'm gonna learn how to make a car" and then spending hours trying to reverse engineer the exact rubber they used in the timing belt in the camshaft in the engine.
So, this pipeline doesn't resemble Source's pipeline very much at all, it's extremely basic, still pretty much a prototype, but I understand it better and it fits the scope of my project a lot better than trying to re-create Valve's entire fucking rendering system. Frankly, it's way better than trying to re-create the general idea of Valve's rendering system. That shit is so fucking complex and intertwined and, frankly, beautiful.'
[08/19/25]
Okay, I wanna do a lot today. Let's get cracking on rendering.
I need to make Theatres before I can make the rendering code. To do this, I have to decide on a syntax. While I like the plain-text syntax, I think that making the final Theatre file be a compiled C++ object will be better.
# Holy shit, I can just generate text files using these techniques:
- Plain text: (https://stackoverflow.com/a/37532722)
- Hex data: (https://www.geeksforgeeks.org/cpp/readwrite-class-objects-fromto-file-c)
- Hex data (again): (https://cplusplus.com/forum/beginner/32200)
Hmm, but it also seems like a bad idea (https://cplusplus.com/forum/beginner/32200/#msg174485). Maybe I can get away with it if I read/write only numbers and strings.
[08/20/25]
Okay, I've shelved most of my sweeping changes yesterday in order to re-focus. I think that in copying Valve's "manager" system, I've overcomplicated some things. Specifically, I didn't understand how they did level loading. Now, I think I have a better idea and while I want to continue in that general direction, I also want to slim it down a fair bit. Basically, the actual file for the level and its data isn't directly loaded but, I assume, is put into some storage object. Then, the main manager is signalled to change levels, which unloads the current level, loads the one in storage, and proceeds to run the same functions for each manager. I don't know this 100% for sure, but it seems like what's happening. I want to go in a similar direction but, again, slim it down.
Okay, I need to stop looking at Source and just... do this all myself. Source is so big and interconnected that any one function or idea is actually in service of millions of others. I just need to do what I did with GraphX and face this head-on with my own ideas. Hopefully my ideas are less bug-prone and easier to build from.
I've improved the code in various places, and started to implement resource/theatre handling. I'm going to store the resources in static variables and interface with them via a 'ResourceManager'. The same thing goes for Theatres. When parsing a new Theatre, the parser will set the current Theatre in 'TheatreManager' if it's successful. Then, 'TheatreManager' will use that object to construct the various 'Things', load the right resources, and after all that, 'BackendManager' will call the functions in 'GraphicsBackend' for buffering the necessary data.
I'm feeling good!
[08/21/25]
Made a realization: Theatres are just the "blueprints" for building a level. The TheatreManager is the thing that actually will store the objects, update the Things, etc. This means I can safely replace the "current Theatre" before shutting down the current Theatre, because the 'Theatre' object isn't actually storing anything.
[08/22/25]
Okay, I want to continue to work on the engine. I want to simplify Theatres and Resources and bring over some code from GraphX.
Oh dear god I misinterpreted std::list vs std::vector. I need to fix this immediately.
[08/23/25]
Okay, I'm gonna try and get Theatres loading. I think I'm gonna start working on interpreting Theatre files into Theatre objects.
Although, I could also try to get a cube rendering... hmm, might do that.
Actually... do I even *need* a Theatre object? Theatres are just gonna be text files that are parsed and interpreted, so storing their data in an object that just gets its data translated is a waste.
Okay, so here's the new syntax:
- Things and Resources are separated into their own contexts
- There are two types of Resources: "real" Resources and "tag" Resources
- "tag" Resources are just containers for a file-path or memory data
- e.g: the path to an image file (Image), embedded .obj file data (Model)
- "real" Resources are actual 'Resource' blueprints and can use "tag" Resources
- i.e: a 'Texture' can use an 'Image' or a file-path/memory data
- Resources can be single-line or multi-line
- "tag" Resources are always single-line
- Single-line "real" Resources take a single 'main' value, but everything else is left to their default values
- e.g: a single-line 'Mesh' would take a 'Model'/file-path/memory data and nothing else
- Multi-line "real" Resources look similar to Things and are where more variables are set
- Things are always multi-line
[08/26/25]
Idea!! What if I don't parse Theatre files one word at a time and instead parse them one *definition* at a time? Like, I add each word to a vector until I hit a certain delimiter ('\n', '}', etc). Then, I check a few booleans/enums, craft the variable object, and add it to the data object!
[08/29/25]
I finished the parser. Idea for interpreter: generate IDs for each Resource and Thing, and use a map to pair their names with their IDs. This map will only be used while interpreting, for getting the ID of any Theatre Reference variables.
[08/31/25]
I had an idea for settings: What if each Thing/Resource had a map that paired string keys with pointers to variables (or something along those lines), and the TheatreParser could lookup those variables when interpreting the TheatreData; then, in an 'Init' function, or something similar, the Thing/Resource would use the map to update their respective variables.
[09/01/25]
After watching most of a YouTube video on 'Pratt Parsing', I kinda wanna try and implement a version of that for the parser. I'll probably hold off on doing that until after the interpreter is finished, as the parser does its job and I don't *need* to re-write it just yet.
I think I might remove 'ResourceManager' and instead make it a unique static class that isn't a Manager (basically a namespace for functions). The reason for this is that I want 'TheatreManager' to control all the Resources *and* Things, as they will all belong to the current working Theatre.
[09/02/25]
Started working on Resource creation, and I had an idea. I want to bring back 'Theatre' as an object that manages its own Things and Resources, and have 'TheatreManager' manage one or more Theatres. Theatres in Theatres can just be done in whatever editor I make, by just "unwrapping" the inner-Theatre(s) and merging them all into one, but I like the ability for the engine to have multiple separate Theatres running at one time.
[09/03/25]
The program freezes up when exiting, specifically when trying to join the 'Tick' thread. I'm assuming it has something to do with the ResourceHandler. Oh, also, at one point I got an error from something being deleted when it wasn't made with 'new' (although I think I might've fixed it).
God fucking damnit... it was a single line
:::C++
// Broken:
float current_tick_length = 0.0f;
double current_time = Time::Current();
current_tick_length += (current_time - last_time) / Settings::Engine::TickInterval;
last_time = current_time; // THIS FUCKING LINE
// Fixed:
float current_tick_length = 0.0f;
double current_time = Time::Current();
last_time = current_time; // GOD FUCKING DAMNIT
current_tick_length += (current_time - last_time) / Settings::Engine::TickInterval;
:::
Fucking... kill me.
Okay, when loading and exiting a Theatre, there's a stutter; I need to test if this scales and, if it does, FIX IT.
I've concluded that the one second lag time is not due to the parser; I stress tested and even when adding 100 extra Resources to the file, it only added, like, a microsecond or two. This one second stutter is definitely from somewhere else (I'm guessing the interpeting functions might have something to do with it; maybe the recursion?).
Fixed the problem (and many others)... in `WAIT_FOR`, I erroneously used `||` instead of `&&`, so it would *always* wait for the timer...
God damnit.
I didn't even need to check the code; I just realized that the "stutter" seemed to be the same exact length every single time... almost like it was intentional. Hmmmmm...
Fucking hell, macros can be evil.
Oh, yeah, I'll definitely need to change this whole process if and when I introduce heavy multithreading... so that's gonna be fun.
Finally got everything committed!
[09/05/25]
I've gotten compilation of the static libraries (freetype + friends) *and* cross-compilation of the static libraries figured out (I hope). Here are some notes:
:::Notes
cross compiling windows brotli static library
Use the CMake application to load a toolchain file for mingw-w64, configure, and generate makefiles
Then, inside the output directory, run:
cmake --build . --config Release --target install
compiling linux brotli static library
mkdir out && cd out
cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed -DBUILD_SHARED_LIBS=OFF ..
cmake --build . --config Release --target install
cross compiling windows bzip2 static library
Use the CMake application to load a toolchain file for mingw-w64, configure, and generate makefiles
Then, inside the output directory, run:
cmake --build .
compiling the linux bzip2 static library is almost exactly the same as cross-compiling it
compiling the linux & windows static libraries for zlib & libpng are just as simple and easy as bzip2
:::
And here's what to put in the mingw-w64 CMake toolchain file:
:::CMake
# toolchain-mingw64.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
# specify the cross compiler
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
# where is the target environment
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
:::
Hell yeah! Time to test this shit!
Aight, it *should* work; wine shit, again. Time to push this shit.
[09/08/25]
Okay, I'm gonna try to merge 'ResourceHandler' into 'TheatreManager' and try to implement 'Thing' interpreting into the current functions.
!!!IMPORTANT!!!
Render commands will have mesh/texture IDs, and the backend will do something unique with them. In OpenGL's case, it'll store vertex/index offset values in a struct that's mapped to its mesh's ID (same thing for textures, except it's the texture's OpenGL ID that gets mapped to the texture's ID).
[09/09/25]
I'm completely changing engine resources. They are now "ResourceData" and are embedded data that is referenced instead of an external file by certain Resources.
TODO: Merge 'Font' and 'Texture' into a common 'BinaryFile Resource' type and make 'Font' and 'Texture' inherit from that with the only changes being unique 'Missing' static members.
I've made Things and Resources derive from the same base class; I now have a much easier time processing them.
[09/10/25]
I have an idea for ids. The default 'ID::None', which is '0', cannot be assigned via the random generator. This was an accidental brilliant maneuver because I can use that to my advantage with things like mesh buffering; for example, I can make sure that the 'Error' mesh's data is always buffered with an id of '0'.
[09/11/25]
I can get of the Theatre file "contexts".
[09/16/25]
I kind of got sidetracked and ended up doing a lot of work to many different things all at once. I need to get back to self-contained work, smaller pieces, one at a time. Once I get the work I just did to be stable, I will go back to that.
I think the problem with images not loading/crashing is that 'FileData' isn't correctly loading data from a file path. I'm gonna make 'Resource::Data' return the data from its 'FileData' variable (along with a new 'Resource::String') so it can return safe data when 'FileData::data' is invalid.
Nah, I think I'll just do a quick check in 'opengl.cpp' and use the missing texture if that check fails. Maybe later I'll have Resource do that.
The fucking... the 'GetData' function needs to take a `shared_ptr` reference, not just a `shared_ptr`.
[09/17/25]
I found the problem with the weird 'free()' fault, here: (https://stackoverflow.com/a/65482334). It's about `unique_ptr` but it applies to `shared_ptr` as well.
I don't want to store copies of embedded resource data, so I'm creating a small storage struct in 'resource_data.cpp' that stores the `unsigned char` pointer, size of the array, and file type. 'Resource' now holds a 'FileData' object instead of a pointer and 'ResourceData::GetData' mutates that variable by reference, using the storage structs.
I made a mistake by making 'Resource::m_FileData' private instead of protected. I thought that would avoid the weird issue caused by running 'Resource::SetupVariables' from a derived class but it actually *caused* that issue (whereas, making it protected solved the issue).
Okay, now it's time to try and solve these rendering and file issues.
I don't know what the fuck is wrong with the rendering.
[09/18/25]
I really need to figure out what's wrong with rendering. The mesh data doesn't seem to be wrong, at least according to Nsight; is it the offset? The shaders? The matrices? The model?
I THINK I FOUND THE PROBLEM!! I THINK IT'S THE NORMALS!!
Nope...
Nope...
I'm so fucking stupid...
I forgot to enable the depth buffer for OpenGL, so everything *was* rendering inside out and everything was 100% correct, fine, and okay.
Kill me.
Okay, I've made lots of improvements to the debug windows, changed up some stuff with transform data, and I think I'm just about ready to start working on the next big thing!!
[09/19/25]
What now?
I'm thinking of figuring out how I want to connect input handling to Things. First, some housekeeping.
Ohhhh, here's a note from (https://math.stackexchange.com/a/2975462): basically, I think that when I convert a quat into euler angles and want to convert euler angles back into a quat, I need to do it step by step? Maybe that'll alleviate the problem I've been running into. It could also just be gimble lock causing an issue?
I think I want to make a way to draw directly to the screen for debugging purposes. Like a "DrawLine" function.
Welp, I didn't do that, but I did finally fix the Quaternion & Euler Angle problem. I also did lots of house-keeping and started slimming down the RenderCommand system.
Oh, yeah, lemme add *why* the Quats and angles were fighting: basically, when GLM converts between the two, it does so in a way that will cause problems when the yaw is greater than 90 degrees in either direction. To fix this, I keep both a Quat and a vector of angles and when I set one, it sets the other.
[09/21/25]
Todo: Removing 'LightRenderCommand' and instead passing a 'light_t' pointer to the light rendering function. Also need a way of counting the current point/spot/directional light without doing the loop in the OpenGL_Backend function.
I implemented light Things and full Blinn Phong shading.
[09/22/25]
I've been committing code and started fiddling with having lights setup their debug MeshInstance on their own, and it's thrown a few wrinkles at me that I'll want to further take care of after I finish committing this code.
Uhoh, it looks like the name and id aren't being correctly assigned or, more likely, passing `this` causes issues when trying to call `mesh->GetID()` in the buffer function.
Oh, wait... they aren't being assigned at all? Oh, wait, are all the base versions of 'SetupVariables' being called?
Nope, 'Resource' didn't call 'Thing::SetupVariables'; simple mistake. All fixed.
Okay, I've just come to the conclusion that 'Resource' should be dedicated to "basic resources", i.e: meshes, textures, etc. They should be used to supply both data for buffering and an ID for referencing to the graphics backend. Once the backend is finished, that data is no longer needed, as is the 'Resource' object itself, so it shouldn't be added to the Theatre (unless I keep it small enough that the benefit of being able to see its data outweighs the downside of keeping the object in memory). "Complex Resources" should *not* derive from 'Resource' and should use only IDs to reference Resource data. I should re-design the 'EngineRef' variable to be applicable to IDs as well as resource data; basically, if an EngineRef is being applied to a 'FileData' variable, load it as usual, but if it's being applied to an ID variable, get the pre-defined ID for that Resource.
Todo: Make basic Resources not be added to the Theatre, since we only need their ID and for them to be buffered. Once they're buffered, they can be dropped.
After finishing my cleanup, I majorly overhauled the Theatre Interface window of the debugger. You can now interface with many more variables, even ones that are unique to specific sub classes!
[09/23/25]
Today was a chores/cleanup day; I fixed the issue with the SpotLight (I wasn't calculating the cutoff radius, lmao), and went through all the #pragma warnings. Most of them were comments I could delete or small issues I could easily fix; a few I turned back into comments, and I added some new #pragma warnings. I want to keep them in source files, not headers; this way they won't be *as* annoying as they were, but still annoying enough to get my attention. I also updated the debugger a bit and fiddled with the window sizing variables/functions. I wanna overhaul the backend manager, create 'ComplexResource', and then move on to setting up player movement input handling.
I want to put the rendering and windowing backend definitions in their own headers in 'backends/graphics' and 'backends/windowing'. I also want to make the model to mesh construction the backend's job.
Okay, I need to change how the Theatre file format works. Basically, Resources will just be wrappers for FileData (maybe even replaced by FileData itself); in a Theatre file, they will be defined via one-liners. In the engine, these one-liners are translated to 'ResourceData::AddData' and that whole implementation will be changed to assign IDs to all the defined Resources and the engine Resources (Missing Texture, Error Mesh, etc). Then, Devices will just hold IDs to those Resources, which aren't in the Theatre per-se but are buffered by the Backend, which uses their IDs as keys to their data (in maps). How this will all play out is that the Backend will buffer the data (including loading model data and creating mesh data), and Resource-derived classes will simply pass FileData and an ID to the Backend. Then, any Actors/Devices that reference that data will do so via the Resource's ID, which is no longer used to point to a Resource but is used to identify buffered data to the Backend. This means that I should be able to supply an "engine reference" to, for instance, a Material's 'DiffuseTexture' variable, and since all the (including engine-level ones) are all buffered first, the parser should be able to get the ID of any Resource, including "engine references".
[09/24/25]
Aight, let's get started. I need to re-work Theatre files and Theatre parsing while doing the Resource re-work. First, I'm gonna commit and push any unrelated work.
After about six hours of working non-stop, I've successfully implemented Devices, made Resources as small as possible, implemented embedded Resources (currently only engine resources but it should be trivial to add the ability to add to them), and updated the parser. On the surface, not much seems to have changed, but internally the code is much more stable and far easier to iterate on.
[09/25/25]
Here's what's up next: skybox, fonts/text, physics. Although, I might want to implement player movement inputs first, for sanity's sake.
[09/26/25]
InputEvent is a wrapper for an InputBinding (wrapper for an ID and InputType) and an InputStatus. InputAction will be changed to just be a way to identify certain pre-defined actions for certain bindings (so, probably a map of bindings to sets of strings or something).
[09/29/25]
Okay, I'm back. I'm going to outline the new input system before I fuck around with it. Probably using Milanote or something.
Aight, I'm going to loosely base my input events and actions off of Godot's InputEvent and input actions.
[09/30/25]
I finished up the input system! Managed to get mouse motion working; it *should* be queue-able and usable in demo files, but I'm implementing demos next time. There's a very rudimentary player control system in place, for demonstration/debugging purposes, but I'm worried that choosing to handle inputs every tick instead of every frame might be making the camera controls feel less smooth. The movement is stuttery but that's to be expected until I implement interpolation. All inputs have an ID used by the new 'binding_t' type, which is a small wrapper for an ID, status, and boolean which represents whether or not that binding was just changed. 'InputEvent' objects are only pushed to the queue if the binding is pressed/active or has just been changed on that tick. The InputManager along with the WindowingBackend iterate over every binding and determine which ones get InputEvents and which ones don't. Then, the InputManager iterates over every InputEvent and passes them to TheatreManager, an InputEvent callback function (if supplied), and other places in the future. Currently, the inputs for toggling the menu and window fullscreen are now handled by the application!
Curious to see if I can get demos working in under an hour... probably not, lmao, but why the hell not try?
Well, I got the demo files to generate with the proper data; now all I need to do is write the parser.
It wasn't an hour, but in just under two I fully implemented demo files. Holy shit!
Playing back demos is not fully working yet.
[10/01/25]
Okay, the main issue is that demo playback needs to either be deferred until the next Tick or interrupt the current Tick's input processing. I'm going to put this logic into InputManager.
[10/02/25]
I've figured out the issue with demos: the event queue is used to process all input events for *only the current tick/frame* but the demo queue is full of events over multiple ticks/frames. I just need to spread out the demo playback code over multiple ticks instead of a singular tick.
Holy shit I fucking finished the demo system and it works near perfectly!!! The only thing left to do is implement state loading for the Theatre, player, and Things. Right now, when you play a demo it just plays back the inputs regardless of what Theatre is loaded or what the player's state is.
Started working on that + a hash system for TheatreData. I've noticed that there's a lot of lag when playing back a demo file, so I'll want to work on optimizing playback.
Oh, and demos also fuck up some bindings/actions (probably happens when creating the input event if I had to guess).
[10/03/25]
Okay, time to finish up the demos system. I need to make demos store the Theatre and player state and, when played back, load that Theatre and setup that state. I also need to fix the performance issues.
[10/06/25]
Whew, I had gotten really sucked into the whole ID system and I made a huge re-write of IDs, Unique IDs, and Binding IDs.
All right, finished up the ID re-write and also fiddled with the Theatre data printout a bit.
I finished up by updating the demo system. It now takes Theatre data and isn't lagging like it was before, but it doesn't actually load/reset the Theatre yet.
Not gonna write it yet, but I need to store the TheatreData either in the demo file or (preferably) in an external Theatre file (or, store the file path to an existing one if one exists).
[10/07/25]
All right, here's the plan: demos will have a TheatreData member and a FileData member. If the TheatreData member is full and the FileData member is empty, then the demo will save the TheatreData to a Theatre file (I'll need to build a reverse parser and/or rebuild the current parser). The top of the demo file will contain both the absolute and relative file path to the Theatre file; if the demo doesn't create the file, it's because the FileData member was full, instead.
First, I'm gonna clean up the TheatreParser and its relationship with the TheatreManager.
Okay, so I've cleaned up the parser, data types, and added some functions to FileSystem for writing to a file and making a directory path (i.e: appending '/' to a string if it needs it). Now, I need to replace the TheatreData in Demo with FileData. I also want to take these functions and variables out of Demo and put them into some "DemoController" class.
Also, refer here: (https://www.reddit.com/r/cpp_questions/comments/oeq7sa/comment/n6yfdtt/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button)
[10/08/25]
On my home PC, I fixed some syntax errors and improved `ThingData` a little bit. There's still an issue with external meshes and textures not being processed, and Devices not being used. I think it's probably related to either the `ThingFactory`, `TheatreParser`, or something with the ID system.
Found the problem, lmfao; I'm fairly certain it's that the TheatreParser isn't assigning IDs to Theatre reference variables. Honestly, that should be done by the TheatreManager, so no better time than now to change that. I'll fix this issue first to confirm that's what's wrong.
Yup, once again I did a
:::C++
if(thing != thing || thing != thing)
:::
instead of
:::C++
if(thing != thing && thing != thing)
:::
lmfao.
Huh, now only the Actors with cube meshes are showing and no Error meshes are showing. The other ones are just... gone?
God damnit... it's the fucking parser; it's not parsing sandwiches and that fucks up the entire thing. It's because of me trying to get rid of the duplicate code.
Yup, it works now. Aight, I still wanna try and condense that code before I move on to the ID assignment shit and then finally finishing the demo controller system and testing it.
Fixed. Finally. On to the ID assignment.
[10/09/25]
I committed my code from last night, implemented the DemoController, refactored the printouts/debug system, and made some other various changes. All this at my house before work. Pretty happy, all things considered. Oh, and yes, demos load Theatres and play correctly (so far).
Okay, there's a few small issues; firstly, playing back a demo causes a crash at the very end (most likely due to an access violation in the demo vector) and secondly, playing back a demo will *always* load a Theatre and reset the player. There might also be input dropping/off-by-one errors but those aren't as important to fix. The biggest issue is the Theatre loading and player setting because it kind of bleeds into save states. I'm not gonna bother with building a save/load system yet; instead, I'll either use `ThingData`, `TheatreData`, or a new custom struct to save the player's information.
Here's an idea: maybe save the current Theatre state as a `TheatreData` object, diff it with the original Theatre's `TheatreData`, and then save the difference to the demo file?
Oh, also, re-sizing the window in Wayland doesn't correctly re-size the viewport.
Shit, I need to undo the separation of `ThingVar::eReference`. The only real reason for doing that was for the printout, but I can just use `value < UniqueIDs::front`.
After researching Doom vs Quake/Source demos, I've concluded that I want to change demo files. They're currently like DOOM demos, just a bunch of recorded inputs, but I want them to be more like Quake/Source demos which are actual snapshots of the game state (I think on each tick). I'm naming the current demo system "gen1 demos".
[10/10/25]
Before I get started, a note about Gen 1 demos: I should change `sDemo` from a vector of EventQueues to a vector of strings. That way I can slot in exactly when the Theatre is loaded and add other things when necessary. I might also wanna make it a manager. Anyways, on to planning the next feature and planning more than I have been.
Time to implement Jolt! I'm gonna have the physics manager be the final abstraction to get Jolt bodies via IDs, collider Devices will be the only Things that directly access those bodies, and everything else is through the collider (position, orientation, friction, etc).
[10/15/25]
Holy shit, so after the weekend, I tried to implement Jolt and I was mostly successful, but I thought I had a problem where the contact validator wasn't validating contacts. Nope, turns out I'm dumb and while the Collider's scale was applying to the Actor and its MeshInstance, it *wasn't* being applied to the size of the collider body's shape. Which wasted an entire day. I'm now comitting all of my changes.
I want to change the Theatre debug menu; I want only Actors to be selectable, and their meshes/materials/colliders/etc to be accessible from their menu.
Improved the Theatre debug menu a lot. Here's my notes from my Discord channel:
:::Discord
You can actually create Theatres with physics. Any Actor can now have a Collider assigned to them. Colliders derive Transform3D so they get Origin, Quaternion/Rotation, and Scale variables as well as Shape and Motion variables. Shape and Motion are "engine references" and are delimited by square brackets ([/]). Valid shapes are: [Box], [Sphere], [Cylinder], and [Capsule]. Valid "motion" are: [Dynamic], [Kinematic], and [Static]. The shapes are pretty self explanatory; their sizes are determined by the Collider's Scale property, but will be more fine-tuneable in the future. The "motions" are like the Collider's "body type". Dynamic makes it a "rigid body collider", Kinematic makes it a "kinematic body collider", and Static makes it a "static body collider". Basically, if you want it to respond to gravity and other objects, make it dynamic; if you want it to be movable, make it kinematic; and if you want it to be stationary, make it static. If an Actor is assigned a Collider, it'll use the Collider's transform values; even if you assigned some already. This just means that the Collider's position, scale, and rotation will override the Actor's. This is still a very basic system; once I implement a more dynamic parent/children system, these kinds of things won't be so hard-coded. Also, the debugger got a pretty big overhaul. In the Theatre debugger, you can only select Actors; this is because Resource and Device things are almost always children of an Actor or Device. The menu instead displays their information in a series of little sub-menus. This helps keep things cleaner and makes more sense, seeing as you can't change any variables in a Resource after the Theatre is loaded, and most Devices are just containers for one or more Resources. Collider and own section (if the Actor has one) with its changeable options. Material will get a similar section next to Collider in the future
:::
The only things left are camera controls and player physics. Quoting my Discord messages:
:::Discord
Nostalgia now officially has all of GraphX's features (and then some) (these features are, of course, implemented much better). The only thing missing is player camera controls and player physics; the camera controls should hopefully be easy to implement with my input event system. The physics should also be easy; in fact, you can interact with physics bodies if you give the player a collider, although gravity is missing (and the collider might not work entirely properly with the current controls implementation). I just want to try and make player physics not a hardcoded implementation (e.g: i want you to be able to customize, control, or even not use it).
:::
Currently there's a crash when trying to destroy bodies before exiting a Theatre.
[10/17/25]
Yesterday was crazy; made plans to move in the next few days so I didn't work on Nostalgia much. I may work on it today or work on some other projects to boost my portfolio.
Huh, just found out I've been using a pseudo-ECS (entity-component system) without knowing what ECS is. Kinda cool, I guess.
What? The using deallocated memory crash looks like it's because `Collider::Shape` and `Collider::Motion` return something that gets deallocated before `std::print` has a chance to process it? Meaning, the `penum_t` reference gets fucked up somehow?
Interesting note about my brain: when I've been programming and I don't give myself any time to decomp before talking to peopl (especially via text), I tend to word my statements kinda backwards and I think I might know one of the reasons why: boolean logic. I get so used to things like `!(statement is true)` instead of `(statement is false)` and I think it bleeds into my speaking logic. Kinda cool!
Okay, the crash is a 'heap use after free' crash and it may be related to this: (https://stackoverflow.com/a/56701074); I'm thinking it might be due to the shared pointer being passed via const reference? Let's see.
Oh shit, is it because of how I get `penum_t` variables with `GetThing`? Is it a pointer that gets freed when the data variable goes out of scope? Oh my god I think it is!
Okay, so it has something to do with when `ThingData::GetPrettyEnum` was assigning the `penum_t&` variable to a new `penum_t` object (e.g: `output = penum_t{name, id};`). When I instead set it to a penum_t variable in the `sPrettyEnumLookup` map, the crash goes away! I kind of want to look into this real quickly.
Oh my god... is it because it's constructing the object, setting the reference to that object, and then the object dies out of scope? I think it is!
Also, refer here for when to use `const &` versus normal function arguments (https://stackoverflow.com/a/2627535).
TODO: MAJOR TODO: I don't like the global key binds thing. The queue should be the master, not the bindings. I fucked up.
[10/20/25]
Finished up my Input rework.
I'm also going to move the backends into `src/backends`.
[10/21/25]
I'm gonna move the backends while I also try to fix the viewport issue. Also, I need to commit my changes today.
I want to also create some documentation and releases for GitHub.
[10/22/25]
Well, I didn't do that second thing but I did majorly overhaul/clean up lots of older code and just now overhauled `Settings::Window` and the windowing backend so they now interface with eachother much more nicely (and `Settings::Window` is now used to directly update the window state).
I really worked on making the settings nice and foolproof and finally fixed that fucking viewport issue. Honestly, the engine is really starting to shape up nicely! I might even work on the editor...
[10/23/25]
I want to make the tester app the editor; it's just way more advanced and pretty much an editor at this point.
[10/24/25]
I've been working on the editor; got it to render the viewport in a small space which is cool. Now I want to actually add some live-editing things like live updating/changing of a shader and things like that. Specifically, to make the default .shader for a scene distinct (with a horizon, too) so that I can differentiate it from the rest of the background.
OOH, what if I developed a way to live create a DearImGui gui?! Like, using drag n drop or something!
That's for later, for now I'm going to try and learn how to use framebuffers to render the scene into an ImGui window more effectively.
Okay, I first decided to implement dynamic viewport interfacing via my backend system. Now you can create, edit, set, and remove as many viewports as you please (with the main window viewport always being available to use/fallback to).
Okay, now time to try my hand at framebuffers.
[10/27/25]
Stressful moving. Anyways, I got a test program for the framebuffer image working and I'm going to now try and learn from it + implement it into my code.
[10/28/25]
I'm going to overhaul the graphics backend and implement on-demand draw functions, specialized draw functions, and only setting the viewport in those functions. I will also overhaul RenderCommands and how they work in the system. First, though, commits and pushes.
[11/03/25]
Fully moved in to Piper's place; had a fun, relaxing weekend with Dexter and my other friends. Now, back to this project. Maybe. I might take a break for a few days just to work on other things and let some of the ideas for Nostalgia stew in my head.
[11/11/25]
I want to take more ideas from Godot. See the documentation, specifically: (https://docs.godotengine.org/en/stable/engine_details/architecture/internal_rendering_architecture.html#renderingdevice-abstraction)
Okay, I think I might just follow that abstraction image very closely when modelling my own abstraction. First thing's first, let me get the project to a working build, then I'll make a new branch and get to work on the new abstraction(s).
This marks the start of the rendering backend overhaul.
[11/13/25]
Okay, okay, I'm going to be using Hazel as another guide for structuring my code.
# As a note: `src/backends/` for me is going to be like `Hazel/src/Platform/` in Hazel.
The abstract/interface classes will be in their own separate directories (e.g: renderer/, window/, etc.) and the platform-specific implementations will be in the backends directory.
Okay, so, the 'backend' class will be for initializing backends (like GLFW), and each backend will have implementations of various classes (like Window, Renderer, Framebuffer, etc).
I think 'Window' should live in 'src/backends/' for now, since I'm only gonna have the one class (for now) and there's really no other place to put it.
This 'Window' class will be Nostalgia's version of Hazel's 'Window' and Godot's 'DisplayServer'. Godot uses a lot of enums for properties of things, but I want to use structs instead.
[11/14/25]
I'm gonna switch my focus to the entire engine and take a "top-down" approach. Basically, instead of starting with a platform-specific implementation of an interface and working my way up, I'll start at the very top and work down. For instance: what about starting with a simple "DrawWorld" function and going down from there?
Okay, starting first with the window class: I'm gonna stick to GLFW for the forseeable future, so that will be the only implementation; I'll probably split it between Linux and Windows, as well as between X11 and Wayland if necessary.
Okay, so I'm ripping a lot of Hazel's code, but only for the renderer. After that's done, I'll move on (finally) to other things and hopefully not have to think too hard about the renderer.
[11/17/25]
Okay, let's finish this shit.
I think I need to learn Uniform buffers, too.
The new WindowManager is just a passthrough to the main window for now, but in the future I'd like to have multiple windows that are interfaced with via the WindowManager. The WindowManager should be updated separately and ALWAYS after every other manager is updated.
[11/18/25]
No Half Life 3 today, but the hopium is still strong. Anyways, back to the engine.
I worked on the Window and Application classes a bit more, but turned my attention to fixing the build system and all the various errors. There is now a working build of the engine and editor which will make continued work on these new systems much easier.
Okay, what's next? I think the input system, most likely.
Welp, that was shockingly easy to re-implement. I'm almost impressed by my own work. Okay, now time to shamelessly copy Hazel's codebase again. This time the ImGui-related stuff.
[11/19/25]
Updated the Notes syntax. Now gonna finish up the UI stuff. I'm gonna try to enforce using the implementor macro by making a virtual function that always fails via `static_assert`, which the macro would override with an empty function.
[11/20/25]
I might just give up on the whole dynamic aspect of the implementors & solutions.
NEVER MIND IT FUCKING WORKS NOW!!
[11/21/25]
Yeah, I don't know how it works but it does, lol. Anyways, time to commit and continue.
[11/24/25]
Okay, I want to try and get the GUI rendering; if I can't do that before finishing the renderer, I'll do that first.
[11/25/25]
I'm almost done stealing from Hazel. I'll want to change all the code I've stolen to be more of my own, just because I want it to be more original and I have some design ideas, but seeing as how Hazel's 3D renderer is so rudimentary, it's actually a really great starting point and I shouldn't have to re-write a lot of code.
Okay, so I got pretty far with copying some of Hazel's mechanics before I realized something about the way I handle input events.
>>> THEY DON'T NEED TO BE LOCKED OFF AND LIMITED TO A FRAME-BY-FRAME BASIS <<<
Because... **YOU CAN ONLY QUERY INPUTS DURING A SINGLE FRAME!** Meaning, you could just replay the input events with a new system similar to Godot/Unity and it would *still* work the way it's supposed to.
So, I tried overhauling the input system and gave up. Time not wasted as long as I try to learn from my mistakes.
# My Mistakes: not stopping to remind myself why I built something a certain way before trying to completely fucking change every single aspect of it.
[11/26/25]
I want to improve the input system; specifically, I'd like to work on `InputBinding` and `InputEvent`, and try to streamline them a bit.
Hmmm, okay, I'm thinking rq and there's something I want to try. Basically, create a new class (or use InputManager) that "handles" input events by storing their information in an way that's more easily accessible in a group (as opposed to something like a vector of events). I think I want to make that.
Some of the features this new 'InputPresenter' should have/be able to do:
- query inputs by id, name, or action
- query mouse movement
- query input states (i.e: down, up, pressed, released, etc)
I think that input events should be both physical IDs (i.e: keys, buttons, etc) *and* the current idea of "actions" (identifiable labels); input actions should be changed to be like Godot's input actions, where they are names that represent one or more input states (i.e: :Shift+G, :Space, :Ctrl+Alt+D, etc). Godot only lets you combine modifier keys and one normal key, but maybe I could allow you to combine any keys you want (so an action would only fire if :Ctrl+A+H+9 are pressed).
I think I'm gonna model Godot's input system more; every frame, all inputs are updated and any changes are stored as an `InputEvent` inside of a queue. Then, each event in that queue is sent to all `Input` functions, one by one, until there are no more events. Events can be single inputs, input combos, named inputs/combos, or mouse movement. I think that named events without ties to inputs (i.e: window closing, monitor changed, etc) should be handled separately.
I'm gonna remove `InputBinding` and move `BindingID` from 'id.hpp' to some file inside 'src/input/'.
[12/01/25]
I've got an idea! I'm gonna rename `InputManager` to `EventManager` and have it manage all events, including inputs.
Input events will be polled by the window and placed into a queue by the event manager; with each input event, the manager will also go through a list of input actions and filter out any actions with keys that weren't pressed. One idea for how to do this is to have `InputAction` keep track of whether or not all of its `KeyID`s are active with some "check" and "reset" functions.
[12/02/25]
Fiddling with my vector template while trying to get this thing to compile so I can get my bearings.
Spent pretty much all of my time working on the vector class, but I'm super fucking proud of it. It's decently robust, takes any numerical type, is decently compatible with `glm::vec`, and has a really cool implementation of named member variables depending on a given "enum" (empty structs in a namespace).
[12/03/25]
Hopefully able to get this shit to not crash after launching and then I can continue my overhaul.
FUCKING FINALLY!!!! GRAAAAAAAAAHHHH!!! Changed member variables to functions and everything is fixed (for now).
Time to finish inputs, hopefully.
Ugh..... I've been looking at input events all wrong. They're not mandatory, they're just a nice way to handle inputs on demand instead of checking every frame. The ability to call a global 'is_key_down' type of function should be implemented (alongside the many other ones in that same vein). I'm getting kinda burnt out so I might call it quits, idk; I'm gonna eat for a lil bit and chill out.
[12/04/25]
Happy birthday to me! Okie, time to completely redo the input/event system(s).
All right, so here's some notes from Milanote:
:::Milanote
Inputs & Events
Inputs
processed on-demand via functions like Input::IsKeyDown or Input::IsActionJustPressed
InputEvents
processed directly via inheriting the Input(InputEvent) function from another class
AppEvents
processed by the current Application implementation only
Input Process
1. the IWindow implementation is responsible for catching inputs as they happen (e.g: WindowGLFW defines a "key callback function" to pass to the GLFW window)
2. when inputs happen, the InputManager updates the state of the binding that was changed
3. the updated binding is passed to the EventManager as an InputEventBinding if it is either active or was just deactivated
4. at any point, the Input:: functions may be called to query the current state of an input binding, action, etc
5. if the IWindow implementation detects mouse movement (or joystick movement) instead, that information is directly passed to the InputManager to update its relative stored values, and the EventManager to queue an InputEventMouseMotion
:::
I touched-up `InputAction` a lot; it now uses bitmasks instead of booleans for its states, which makes it so simple as a class that it's all contained in the header!
[12/08/25]
Okay, so the current problem is that inheriting from `OnAppEvent` and the like doesn't add that class to the "instances" vector. Why? Also, the WiFi is down, so I get to try and solve this all on my own.
Fixed! It was me using `m_sInstances` instead of `IGetEvents::m_sInstances` for some reason (at least, that's what fixed it).
And that marks the redesign of the event/input system. Now time to finish the rendering system...
Ugh, that's so much work and I'm kinda burnt out on this project rn. I think I might take a small break.
[12/09/25]
All right, let's finish the renderer.
I'm gonna take a few ideas from Hazel, but make my own stuff from them. Basically, I like the idea of creating objects for storing mesh data (e.g: `VertexArray`, `VertexBuffer`, `IndexBuffer`), and I like having separate functions for rendering that take those objects. I can separate rendering the world, 2D objects, etc by simply using the right `VertexArray`, `VertexBuffer`, etc. when calling specific draw functions.
Ugh,,,, almost there. Got it compiling, but running into some errors. Tempted to just go back to my old system... but whatever. I'll give it another day.
[12/10/25]
Hmm, I think I want to combine this system with my old system and make some changes. I want `RenderManager` to control *all* the renderer-related code, and accessing the renderer (e.g: `TheatreManager` buffering & rendering Theatre meshes) will either be done by queueing some render command in the render manager, or just interfacing with the render manager directly.
Okay, I've redesigned everything slightly so now the theatre manager creates a static `VertexArray` specially made for packed mesh data, and implemented a function in the renderer for specifically rendering packed mesh data.
Now it's crashing due to what looks like string errors when creating the shaders, so I'll have to fix that.
Aight, now it's just graphics problems; mainly buffer issues. I might want to throw out the hazel code and just write some more simple classes but idk. That's for later.
[12/11/25]
I think it might be time to work towards just getting the engine in a state where I can make *something*. Let's just get the damn thing out the door.
OMG WAIT!! Rendering is working, it's just... the data is bugged again. Always this problem whenever I redesign the rendering backend. However, this means that it's just the data being passed around wrong, which is a better problem than "it crashed for no reason (pointers)".
Getting closer! I've decided to forgo combining every mesh into one VAO and just make separate VAO/VBO/IBOs for all meshes (for now, at least).
Okay, NSight is telling me that the 'Data in index buffer is insufficient for the specified index count and offset', so I'm pretty sure that the problem is that my index offset/count is wrong.
[12/12/25]
Forgot to write down that yesterday I got the models rendering and the textures sometimes working. I'm gonna try to nail down the textures and I might revive the render command system.
I think I need to re-think how resources work.
Yeah, I need to totally redesign resources.
The crash is due to a double free from IUIImplementor's `OnInput` destructor being called twice.
[12/15/25]
Actually, I think it's due to a race condition where the vector iterators get invalidated by one `OnInput` object erasing itself while another is iterating. My solution will be to use an index for loop, instead of a range-based for loop (which isn't great but isn't terrible, either).
Oh my fucking god... it was because the static application instance variable is a shared pointer to an already existing object and it was trying to free that pointer improperly (because the pointer wasn't malloc-ed). At least, I think that's it.
Yup, that was it.
Well, not entirely; there's still a crash if either `IApplication` or `NostalgiaGoggles` inherits from any of the event handler components, but I think that's to do with the application class destroying too quickly or the way I create the application object in the main file. Either way, using a separate class for handling events works perfectly fine so I'll do that and maybe fix this weird bug in the future.
[12/16/25]
There was a strange problem with clangd/clang where it would eat up all my RAM and CPU when compiling/indexing the project. I eventually found the source of the problem: in 'events/bindings.hpp', the `FOR_EACH` macro had a couple arguments too many for either this laptop or clang in general. Either way, I decided to just bite the bullet and just add all the key IDs to the `frozen::map` manually; honestly, it's not that big of a deal, especially since they're all constexpr anyways.
I also changed how forward declarations are done; now, each header file will put its forward declarations at the top of the file using these preprocessor directives:
:::C++
#ifdef FWD_DCL
// Forward Declarations...
#elif !defined THIS_HEADER_FILE_H
#define THIS_HEADER_FILE_H
//...
#endif // THIS_HEADER_FILE_H
:::
Which, in turn, let you include *only* the header's forward declarations by doing something like this:
:::C++
#define FWD_DCL
# include "this_header_file.hpp"
#undef FWD_DCL
:::
I also wrote a Sublime Text snippet for the '#define/#undef FWD_DCL' portion.
This makes forward declarations easier to use, make, and maintain.
I also revamped how verbosity works in `__print_verbose`, so instead of levels they're bit flags for all three types of message prefix.
[12/17/25]
Got straight to work on uprooting `penum_t`. I created the `EnumPrettifier` namespace and have some ideas for Theatre files. What if I wrapped all the classes up into one big class that also had functions for registering new variables and shit?
Holy shit, I just spent all night absolutely gutting `penum_t` along with overhauling a bunch of random shit, and guess what? It worked on nearly the first fucking try! A few things are off, specifically the colliders don't seem to be doing anything. That's probably due to me changing around the containers I used to store their data.
Aw, the problem is that the enums aren't getting set properly, which is one of the things I overhauled. However, it's not totally joever; just a small fix... famous last words.
FUCK YES!! IT ALL WORKS!!! EVEN THE TEXTURES!!!
Okay, only problems left for now are:
1. lights have no debug mesh/show up using the error mesh
2. the "spawner" thingy also uses the wrong mesh
Those are probably due to the ID system changing and me not accomodating those IDs. Simple as. I think, at least.
[12/18/25]
I want to stop fiddling with minor tweaks/changes and start making major improvements and adding new features! Sooooo, let's get the new renderer up to speed and then start moving forward.
I don't know if this is the reason for the thing spawner problem, but why are all Theatre variables one class? I think it's time to templatize them.
Ugh, I removed `PEnum` and then just rediscovered why I actually needed it: collisions with registered enum values in the variable registry. Time to re-create `PEnum`, again.
Got an error when trying to fill a static unordered map from the constructor of a global variable. See this link for info: (https://en.cppreference.com/w/cpp/language/siof)
Oh wait... what if I moved the reference IDs from the variable registry into `UID` and replace its unique ids map with those? That makes more sense, especially since I can add/remove IDs in the `Thing` constructor.
AAAAAND WE'RE BACK!!!!!
AND I GOT THE DEBUG LIGHT MESHES WOORKING!!
Now all that's left is to re-implement Viewports and it'll be right back to where it was before, but better this time!
[12/20/25]
The heap-use-after-free error is because the vectors for the `OnInput`, `OnAppEvent`, and `OnEngineEvent` classes are static and when the `__run_exit_handlers` function gets called, it deletes all the pointers... which is after they've already been freed by the destructors.
Hmm, I think that if I have a static, global container and I exit the app, `__run_exit_handlers` seems to delete all the memory in these containers before or while they're being accessed.
No, wait, it looks like the app is just closing too quickly; it needs to wait for all the jobs to be finished.
[12/22/25]
Fixing/tidying up the ANSI code... code and then I'm going to overhaul the Theatre parser with some ideas I wrote down in my notes.
Okay, finished with the ANSI stuff, here's my notes on the Theatre parser:
:::Notes
Make a 'ThingVar' wrapper class template that stores the actual variable data, the delimiter as two characters, and functions/function templates for converting between a string and the data. You could change the delimiter and the pointers live.
:::
I'm also gonna be making the parser loop more like the demo file parser loop. I also might make a theatre parser class that allows for live updates to the file format like adding/removing parts of the syntax (e.g: variable types/delimiters) or changing how they're parsed by using function pointers in the main parsing loop.
I think I'll start with the parser first and just change the main loop from a single switch statement that does everything to a system more like the demo file parser.
Uhoh, hold on, there's a segfault when quitting while a Theatre is loaded; probably just a nullptr exception from some destructor getting called too early/late is my guess.
Technically, I was right; it's `glfwTerminate()` getting called and shutting down OpenGL (or something to that effect), which makes all the 'gl-' function pointers nullptr, and since the map of VAOs is a static global variable it gets destroyed *after* opengl is shut down and the VAO pointer in the iterator (or something like that) tries to call its destructor which tries to call `glDeleteVertexArrays` which causes a nullptr exception.
Okay, I solved the problem by making the unordered maps not global static variables. This is probably the best solution, because anything that relates to the rendering API should not be able to be constructed or destructed outside of the API's initialization and termination windows.
Now, on to the stuff I wanted to do, lmfao.
[12/23/25]
I made the giant, terrible commit. Now, I want to take a break from the frame buffer stuff to quickly try and find out if there's a way for me to query the state of OpenGL (to avoid those function pointer crashes).
[12/24/25]
I'm sick, again. Anyways, I've finished up the `FrameBuffer` implementation and also improved `TextureBuffer` creation a bit. You can now specify things like the sampler filter types (e.g: linear, nearest, linear + mipmap linear, etc) and even the data format of the image. I've also learned how to inject custom render callbacks into ImGui, which allows me to enable SRGB colors in OpenGL while the framebuffer image is being rendered via ImGui.
Okay, I think I want to make it so that you pass a camera or something to the renderer api and basically, each layer in `RenderLayers` will be assigned to a frame buffer and the renderer will then render things depending on those layers. So, for instance, the editor camera might have the editor viewport frame buffer enabled in its `RenderLayers`, but not the default frame buffer (0), which means that the renderer will not render to the main frame buffer but only to the one that the editor viewport uses.
[12/26/25]
Don't feel as bad today but still definitely sick. Started working on the Thing spawning and Theatre debug panels; I've implemented more thorough interactions but I'll definitely want to implement a "children" container of sorts for `Thing`. I also made some more general refactors, specifically gutting the whole "event handler" functionality from the event components and just implementing event/input handling manually. This keeps control tighter and avoids those crashes. Besides, I only really need to call these functions on a couple managers in order to propogate the calls down to everything else (e.g: `TheatreManager`, `UIManager`, etc). I also implemented mutexes in some of the classes (specifically, `InputManager` and `EventQueue`) and learned that if I want to lock the same mutex in multiple functions, I'll want to use a `recursive_mutex` since that still (if I'm correct) stops other threads from accessing the mutex but doesn't stop the same thread (which was happening while using normal mutexes).
[12/28/25]
Finally almost fully better. I'll be working on my PC tonight, so first things first: gotta compile the project and see if it runs.
NOTE: I can just combine the enum prettifier into the theatre variables registry.
All right, I've finished with a giant refactor; basically, created a new `fwd` directory where all forward declarations will go, and tidied up a lot of the header files; I also deleted some unused files & split some header code into source files.
I think that I want to finally commit to making a v1.0 of Nostalgia (or at least flesh out the GitHub some more).
[12/29/25]
Meds weren't refilled today, so a Bang energy and lots of coping is hopefully gonna keep me kicking. I don't feel that bad, honestly; forcing myself to go on a drive in the morning, do my laundry, and not brain rot was very successfull. I actually get shit done with a fire lit under my ass. Anyways, time for some minor improvements or something like that before going to work. Already fixed the issue with the light meshes. Maybe implementing the editor camera?
Here's an idea: render the scene for every camera in the scene and match them to the correct framebuffers using their render layers. Then, I could do something like have the editor camera and the player camera views both be visible at the same time on separate image layers. This would work well, I think.
[12/30/25]
Did a lot of stuff that I'll document in a second, but I wanted to quickly write that with ImGui, if you have a child window and a lot of widgets/logic that could result in an early return, you shouldn't use `if(BeginChild)`, as that could cause issues per this quote from (https://github.com/ocornut/imgui/issues/1783#issuecomment-385241309):
:::Quote