-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathfinal_platform_layer.docs
More file actions
4484 lines (3473 loc) · 172 KB
/
final_platform_layer.docs
File metadata and controls
4484 lines (3473 loc) · 172 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
// ****************************************************************************
//
// Documentation
//
// ****************************************************************************
/*!
@mainpage
@tableofcontents
@section section_overview Overview
Final Platform Layer is a Single-Header-File cross-platform <b>C99</b>/<b>C++</b> development library, designed to abstract the underlying platform to a simple and easy-to-use API - providing low-level access to the operating system and hardware devices.<br>
<br>
The main focus is rapid game/media/simulation development, so the default settings will create a window, set up an OpenGL rendering context, and initialize audio playback on any platform.<br>
<br>
FPL supports the platforms <b>Windows</b>/<b>Linux</b>/<b>Unix</b> for the architectures <b>x86</b>/<b>x64</b>/<b>arm</b>.<br>
<br>
The only dependencies are built-in operating system libraries and a <b>C99</b> or <b>C++/11</b> compliant compiler.<br>
<br>
It is released under the @subpage page_license "MIT License". This license allows you to use FPL freely in any software, for private or commercial usages.<br>
@section section_using_this_documentation How to use this documentation?
Use the following links to learn more about FPL:
- @subpage page_introduction
- @subpage page_gettingstarted
- @subpage page_categories
- @subpage page_examples
- @subpage page_faq
- @subpage page_contribute
- @subpage page_changelog
- @subpage page_license
I hope you find all the information you need. If not please drop an issue on the <a href="https://github.com/f1nalspace/final_game_tech/issues">GitHub</a> project page and it will be addressed as soon as possible!
Thanks for using, have a great day!
*/
/*!
@page page_introduction Introduction
@tableofcontents
@section section_intro Introduction to FPL
@subsection subsection_intro_whatisfpl What is FPL?
Final Platform Layer is a Single-Header-File cross-platform <b>C99</b>/<b>C++</b> development library designed to abstract the underlying platform to a very simple and easy-to-use API - providing low level access to:<br>
- Single Window creation and handling
- Graphics Software or Hardware Rendering initialization.
- Asynchronous Playback of Audio Samples
- Accessing Input Devices (Keyboard, Mouse, Gamepad)
- IO handling (Files, Directories, Paths)
- Multithreading (Threads, Mutexes, Signals, Conditions)
- String conversions UTF8 <-> WideString
- Allocating Memory
- Retrieve Hardware & OS Informations
The main focus is game/media/simulation development, so the default settings will create a window, set up an OpenGL rendering context, and initialize audio playback on any platform.<br>
<br>
Final Platform Layer is released under the @subpage page_license "MIT License". This license allows you to use FPL freely in any software.<br>
@subsection subsection_intro_whatissingleheaderfilelibrary What is a single-header-file library and why is FPL based on that?
A single header file library (as the name implies) is a development library designed to be one file only.<br>
Such a file contains the header (API) and the body (Implementation) in one file but separated and controlled by compiler conditions.<br>
Due to the nature of a single-header-file library, all the sources come with it - so it is most likely licensed by a public domain license.<br>
Also, such libraries mostly do not require any dependencies at all, to making them more friendly to the user.<br>
This makes it easy to use the library however you want (with source, Static-linked, As a DLL, Private use only).<br>
<br>
So, why then is FPL based on that?<br>
<br>
Because normal libraries typically have a lot of disadvantages:
- Force you to link to it dynamically or statically
- Force you to use build-systems just to compile it
- Requires specific CRT versions which make linking a madness
- Require or come with a ton of dependencies
- Are closed source or use an incompatible license
- Takes ages to compile because of its hundreds of translation units
@subsection subsection_intro_supported_platforms Which platforms are supported by FPL?
- Windows (x86/x64)
- Linux (x86/x64/arm)
- Unix/BSD (x86/x64, partially)
For more details see the page: @subpage page_support_status
@subsection subsection_intro_supported_compilers Which compilers are supported by FPL?
FPL should compile on any <b>C99</b> or <b>C++/11</b> compliant compiler, such as <b>MSVC</b>, <b>GCC</b>, <b>Clang</b>, etc.
@subsection section_intro_features What can FPL do?
Read below a detailed feature overview of FPL:
- Core
- Compiler detection
- Architecture detection
- OS detection
- Window
- Create and handle a Single Window
- Fullscreen toggling
- Event handling
- Clipboard string reading and writing
- Input (Event-based or by Polling)
- Text input (Event-based only)
- Keyboard
- Mouse
- Game Controllers
- Video:
- Graphics initialization
- Backends:
- OpenGL 1.x (Legacy)
- OpenGL 3.x or higher (Modern)
- Software Backbuffer
- Audio
- Raw audio asyncronous playback
- Device iteration and selection
- Backends:
- DirectSound
- ALSA
- Memory
- Allocation and Deallocation
- Custom Alignment functions
- Fast Clear/Set and Copy
- Atomics
- Support for 8,16,32,64 bit signed and unsigned integer types
- Support for void pointer type
- Support for size type
- Compare and Exchange (CAS)
- Add / Exchange
- Load / Store
- Memory Barriers
- Shared library
- Loading of Shared Libraries (DLL on Windows, .so on Linux)
- Function Pointer Lookup
- IO
- Path functions
- Query User Home Directory
- Query Executable Path
- Extract Filename, Extension and Path
- Combine Paths
- Change File Extension
- Files/Directories
- Reading and Writing of Binary Files (32-bit and 64-bit)
- Iterate over Files/Directories
- Rename/Copy/Delete/Move operations
- Hardware info retrievement
- Query Processor Infos (Core count, Name)
- Query Current Memory State (Physical size, Virtual Size, Page Size, etc.)
- Query System Architecture
- OS info retrievement
- Query logged in Username
- Query OS infos (Name, Version)
- Timings
- Get number of seconds (Low and High precision) used for profiling and delta calculations
- Get number of milliseconds (Low and High precision) user for simple measurement
- String conversion functions
- UTF-8 <-> Widestring
- Copy
- Comparing
- Matching
- Formatting
- Locales
- Get keyboard/user/system locale
- Console
- Standard/Error out
- Formatted out
- Char input
- Debug
- DebugBreak for most compilers/platforms
- DebugOut for limited compilers/platforms
- Threading
- Threads
- Mutexes
- Signals
- Condition-Variables
- Semaphores
@subsection section_intro_getstarted Getting started with FPL
- You download the latest <a href="https://github.com/f1nalspace/final_game_tech/blob/master/final_platform_layer.h">"final_platform_layer.h"</a> file.
- Drop it into your C/C++ project and use it in any place you want.
- Define **FPL_IMPLEMENTATION** in at least one translation-unit before including this header file!
- Ready to go.
For more details see the pages: @subpage page_gettingstarted / @subpage page_categories / @subpage page_examples.
*/
/*!
@page page_gettingstarted Getting started
@tableofcontents
@section section_usage_setup Download & Setup
@subsection subsection_usage_setup_download Download
- You download the latest <a href="https://github.com/f1nalspace/final_game_tech/blob/master/final_platform_layer.h">"final_platform_layer.h"</a> file.
- Drop it into your C/C++ project and use it in any place you want.
@subsection subsection_usage_setup_setup Setup?
- No setup required
@section section_usage_requirements Requirements
FPL uses built-in operating system libraries and requires a <b>C99</b> or <b>C++/11</b> compliant compiler.<br>
Depending on the compiler and platform - linking to one system library may be needed:
@subsection usage_requirements_win32 Win32
- Link against "kernel32.lib"
@subsection usage_requirements_unix Unix/Linux
- Link against "libld.so"
- Compiler parameter "-pthread" (<a href="https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#Preprocessor-Options">GCC Preprocessor Options</a>)
@subsection usage_requirements_crt C-Runtime optional
By default, FPL uses the CRT (C-Runtime-Library) for functions such as vsnprintf(), but its usage is optional.<br>
To learn how to use FPL without the CRT more details, see the page @subpage page_nocrt
@section section_usage_howtouse How to use FPL?
In your main C/C++ translation-unit include the header file and call @ref fplPlatformInit() and @ref fplPlatformRelease() respectively:
@code{.c}
#define FPL_IMPLEMENTATION
#include "final_platform_layer.h"
int main(int argc, char **argv) {
// Initialize the platform with default settings
if (fplPlatformInit(fplInitFlags_All, fpl_null)) {
// your code goes here
// Release the platform
fplPlatformRelease();
return 0;
} else {
return -1;
}
}
@endcode
You can then include this file in any other C/C++ source or header file as you would with any other header file.
Provide the typical main entry point with at least the initialization and release of the platform:
@section section_usage_multiple_translation_units How to use FPL in multiple translation units?
To use FPL in multiple translation units, it is recommended to create a separated "final_platform_layer.c" file in the same directory FPL is located and define the implementation there only:<br>
<b>final_platform_layer.c</b>:
@code{.c}
#define FPL_IMPLEMENTATION
#define FPL_NO_ENTRYPOINT // Disable the entry point inclusion
#include "final_platform_layer.h"
@endcode
This way FPL implementation is compiled once and can be used everywhere.<br>
<br>
In your main translation-unit, you just include the entry point only using the preprocessor define **FPL_ENTRYPOINT**.
<b>main_translation_unit.c</b>:
@code{.c}
#define FPL_ENTRYPOINT // Integrate entrypoint only
#include "final_platform_layer.h"
@endcode
@section section_usage_static_library How to use FPL in a static library?
To use FPL as a/in static library you do the same steps required for using FPL in multiple translation units.
See @ref section_usage_multiple_translation_units for more details.
@section section_usage_codecomments How do I get the code-documentation to show up in the IDE?
When FPL is compiled directly in your main translation-unit, some IDE's read the comments from the implementation bodies instead of from the header definitions.<br>
This is wrong, but we can't help it. Those editors just are not designed for single-header-file libraries :-(
But do not fear, you can get the comments to show up in your IDE properly, just compile the implementation into a separated translation-unit only.<br>
This way the IDE will parse the comments from the API declaration only. See @ref section_usage_multiple_translation_units for more details.
@section section_usage_options Options
See @subpage page_compiler_options for all compile-time options.
*/
/*!
@page page_categories Categories
@tableofcontents
@section section_category_general General
@subpage page_category_initialization <br>
@subpage page_category_errorhandling <br>
@subpage page_category_logging <br>
@section section_category_window Window
@subpage page_category_window_basics <br>
@subpage page_category_window_events <br>
@subpage page_category_window_style <br>
@section section_category_input Input
@subpage page_category_input_events <br>
@subpage page_category_input_polling <br>
@subpage page_category_input_config <br>
@section section_category_memory Memory
@subpage page_category_memory_handling <br>
@section section_category_platform Platform
@subpage page_category_platform <br>
@subpage page_category_hardware <br>
@section section_category_dll Dynamic Library Loading
@subpage page_category_dll <br>
@section section_category_io File IO
@subpage page_category_io_binaryfiles <br>
@subpage page_category_io_paths <br>
@section section_category_threading Multithreading
@subpage page_category_threading_threads <br>
@subpage page_category_threading_mutexes <br>
@subpage page_category_threading_signals <br>
@subpage page_category_threading_conditions <br>
@subpage page_category_threading_semaphores <br>
@subpage page_category_threading_atomics <br>
@subpage page_category_threading_sync <br>
@section section_category_video Video
@subpage page_category_video_general <br>
@subpage page_category_video_legacy_opengl <br>
@subpage page_category_video_modern_opengl <br>
@subpage page_category_video_vulkan <br>
@subpage page_category_video_software <br>
@section section_category_audio Audio
@subpage page_category_audio_general <br>
@subpage page_category_audio_writesamples <br>
@subpage page_category_audio_multichannel <br>
@subpage page_category_audio_manual <br>
*/
/*!
@page page_category_initialization Initialization & Release
@tableofcontents
@section section_category_initialization_include Include the Library
In one of your C/C++ translation units include this:
@code{.c}
#define FPL_IMPLEMENTATION
#include "final_platform_layer.h"
@endcode
You can then include this file in any other C/C++ source or header file as you would with any other header file.
@section section_category_initialization_entrypoint Entry Point
Simply provide the typical main entry point:<br>
@code{.c}
int main(int argc, char **argv) {
// code goes here
}
@endcode
@section section_category_initialization_simple Initialization with default settings
Call @ref fplPlatformInit() (inside the main @ref section_category_initialization_entrypoint) and provide the desired @ref fplInitFlags and @ref fpl_null as arguments, to initialize FPL with default settings.
@code{.c}
int main(int argc, char **argv) {
// With defaults (Window, Video, Audio)
fplPlatformInit(fplInitFlags_All, fpl_null);
// Only audio
fplPlatformInit(fplInitFlags_Audio, fpl_null);
// Only window and audio
fplPlatformInit(fplInitFlags_Window | fplInitFlags_Audio, fpl_null);
return 0;
}
@endcode
It is recommended to always pass a pointer to a @ref fplSettings structure, but you can leave it as @ref fpl_null as well.<br>
Call @ref fplSetDefaultSettings() with a pointer to your local settings container to initialize the settings container with default values.
@section section_category_initialization_with_settings Initialization with custom settings
Call @ref fplPlatformInit() (inside the main @ref section_category_initialization_entrypoint) and provide the desired @ref fplInitFlags and a pointer to @ref fplSettings argument to initialize FPL with custom settings.
@code{.c}
// Overwrite settings
fplSettings settings;
fplSetDefaultSettings(&settings);
// or
fplSettings settings = fplMakeDefaultSettings();
// change the settings here
fplPlatformInit(fplInitFlags_All, &settings);
@endcode
@section section_category_initialization_release Releasing the Platform
Call @ref fplPlatformRelease() when you are done. This will release all internal resources.<br>
@code{.c}
fplPlatformRelease();
@endcode
@section section_category_initialization_result Result/Error checking
There is no guarantee that @ref fplPlatformInit() will always work with the fplSettings you specified, maybe the audio device does not support a sample rate of 1337 kHz or your video card does not support OpenGL version 3.7 - who knows.<br>
<br>
Therefore, you should always check the result using @ref fplGetPlatformResult() !<br>
This returns a @ref fplPlatformResultType enum which is @ref fplPlatformResultType_Success when initialization succeeded.<br>
<br>
Also, you should release the platform when the initialization was successful only!<br>
If something goes wrong the remaining resources are already cleaned up by FPL automatically.<br>
<br>
Also, you should use @ref fplGetLastError() to print out the actual error when the initialization fails!<br>
<b>Very bad:</b> (But will work)
@code{.c}
fplPlatformInit(fplInitFlags_All, fpl_null);
// your code here
fplPlatformRelease();
@endcode
<b>Bad:</b> (But will work)
@code{.c}
if (fplPlatformInit(fplInitFlags_All, fpl_null)) {
// your code here
}
fplPlatformRelease();
@endcode
<b>Good:</b>
@code{.c}
if (fplPlatformInit(fplInitFlags_All, fpl_null)) {
// your code here
fplPlatformRelease();
}
@endcode
<b>Better:</b>
@code{.c}
if (fplPlatformInit(fplInitFlags_All, fpl_null)) {
// your code here
fplPlatformRelease();
} else {
const char *errStr = fplGetLastError();
fplConsoleFormatError("FPL-ERROR: %s\n", errStr);
}
@endcode
<b>Much better:</b>
@code{.c}
if (fplPlatformInit(fplInitFlags_All, fpl_null)) {
// your code here
fplPlatformRelease();
} else {
fplPlatformResultType initResult = fplGetPlatformResult();
const char *initResultStr = fplPlatformGetResultName(initResult);
const char *errStr = fplGetLastError();
fplConsoleFormatError("FPL-ERROR[%s]: %s\n", initResultStr, errStr);
}
@endcode
See the @subpage page_category_errorhandling page for more details about error handling.
@section section_category_initialization_tips Tips
After releasing FPL you can call @ref fplPlatformInit() again if needed - for example: Finding the proper audio device, Testing for OpenGL compatibility, etc. may require you to call @ref fplPlatformInit() and @ref fplPlatformRelease() multiple times.<br>
For more details see @subpage page_gettingstarted <br>
<br>
Optionally you can use @ref fplMakeDefaultSettings to create a default filled @ref fplSettings structure, which can be directly used for @ref fplPlatformInit()<br>
<br>
If needed you can get the currently used @ref fplSettings configuration by calling @ref fplGetCurrentSettings()
*/
/*!
@page page_category_errorhandling Error handling
@tableofcontents
@section section_category_errorhandling_getplatformresult Check platform result
Use @ref fplGetPlatformResult() to query the current platform result.<br>
This is useful to check if @ref fplPlatformInit() was already called or not.
Also, this is useful to see which system failed in @ref fplPlatformInit() .
Example:
@code{.c}
fplPlatformResultType resultType = fplGetPlatformResult();
switch (resultType) {
case fplPlatformResultType_NotInitialized:
printf("Platform is not initialized yet!");
break;
case fplPlatformResultType_FailedAudio:
printf("The audio system failed to initialize: %s", fplGetLastError());
break;
}
@endcode
@note You may combine @ref fplGetPlatformResult() with @ref fplGetLastError, to get a more understanding of what exactly went wrong.
@section section_category_errorhandling_getlatest Get latest error
In case something goes wrong you can always call @ref fplGetLastError() - at any time, regardless if it is initialized or not.<br>
This either returns an empty string indicating everything is fine or a formatted string with a valid error message.<br>
Example:
@code{.c}
const char *errStr = fplGetLastError();
// Do something with the error string
@endcode
@section section_category_errorhandling_count Was there an error?
If you just want to check if there was an error, you can call @ref fplGetErrorCount() to use the number of errors as a condition.<br>
Example:
@code{.c}
if (fplGetErrorCount()) {
// Print out the error message
}
@endcode
@section section_category_errorhandling_getbyindex Get error by index
Use @ref fplGetErrorByIndex() to get a error string for the given index in range @ref fplGetErrorCount() .
Example:
@code{.c}
size_t errorCount = fplGetErrorCount();
if (errorCount > 0) {
const char *lastError = fplGetErrorByIndex(errorCount - 1);
// Do something with the last error
}
@endcode
@section section_category_errorhandling_clear Clearing the errors
Errors will never be cleared by FPL! You have to do this yourself using @ref fplErrorsClear() .<br>
Example:
@code{.c}
fplClearErrors();
@endcode
*/
/*!
@page page_category_logging Debug & Logging
@tableofcontents
@section section_category_logging_logging Logging
FPL has an internal logging system built-in.<br>
By default this logging system is disabled, but you can enable it by defining the preprocessor definition **FPL_LOGGING** before including the FPL header file.<br>
<br>
You can change the maximum log-level using @ref fplSetMaxLogLevel() . By default, this is set to @ref fplLogLevel_Critical which means that only system-wide critical errors will be reported.<br>
When the logging system is enabled, you can get or change the configuration using @ref fplGetLogSettings() / @ref fplSetLogSettings() respectively.<br>
This configuration has two modes, a mode in which you can define one writer for every log level and one mode in which you have a writer for each log-level separately. By default, it uses the first mode, which is one writer for all log-levels.<br>
To change this behavior, you can set the preprocessor definition **FPL_LOG_MULTIPLE_WRITERS**. With this, you can change the logging in every detail.<br>
A log writer can be configured to log to multiple logging-targets.<br>
<br>
FPL supports up-to 4 log-targets:
- Console standard output
- Console error output
- Debug console output
- Custom callback
See @ref fplLogWriterFlags and @ref fplLogSettings for more details.
@subsection subsection_category_logging_logging_example_console_only Example: Log everything to the standard console only
@code{.c}
fplLogSettings logSettings = fplZeroInit;
logSettings.maxLevel = fplLogLevel_All;
logSettings.writers[0].flags = fplLogWriterFlags_StandardConsole;
fplSetLogSettings(&logSettings);
@endcode
@subsection subsection_category_logging_logging_example_errors_only Example: Log all errors to the error console only
Log all errors, warnings, and criticals to the default error console.
@code{.c}
fplLogSettings logSettings = fplZeroInit;
logSettings.maxLevel = fplLogLevel_Error;
logSettings.writers[0].flags = fplLogWriterFlags_ErrorConsole;
fplSetLogSettings(&logSettings);
@endcode
@subsection subsection_category_logging_logging_example_custom Example: Log all errors to a custom logging function
Log all errors, warnings, and criticals to a custom callback defined as @ref fpl_log_func_callback .
@code{.c}
static void MyLogFunction(const fplLogLevel level, const char *message) {
// ...
}
fplLogSettings logSettings = fplZeroInit;
logSettings.maxLevel = fplLogLevel_Error;
logSettings.writers[0].flags = fplLogWriterFlags_Custom;
logSettings.writers[0].custom.callback = MyLogFunction;
fplSetLogSettings(&logSettings);
@endcode
@section section_category_logging_debug Debug
@subsection subsection_category_logging_debug_break Forced Breakpoint
You can force to stop on a specific line of code always by calling the function @ref fplDebugBreak() .<br>
It works exactly like a breakpoint, but it will always break until you remove the call to it.
Example:
@code{.c}
// ... code
fplDebugBreak(); // Debugger will always stop here
// ... code
@endcode
@subsection subsection_category_logging_debug_out Output to the Debug-Console
On IDE's such as visual studio you can use @ref fplDebugOut() or @ref fplDebugFormatOut() to print out stuff in the console directly in your IDE.<br>
Example:
@code{.c}
// Basic output
fplDebugOut("Debug-Values:\n");
// or
// Formatted output
fplDebugFormatOut("Value of X: %f\n", xValue);
@endcode
@section section_category_assertions Assertions
FPL contains runtime and compile-time assertion macros, which you can use to ensure application state consistency.
@subsection subsection_category_assertions_runtime Runtime assertion
You can use the macro function @ref fplAssert() to trigger an runtime assertion in a debug-build.<br>
When the condition in your assertion is false, your application will crash immediately.
Example:
@code{.c}
// When i is less than 5 this code will trigger a assertion that will crash your application immediately.
fplAssert(i >= 5);
// Will trigger a assertion when the "str" pointer is null.
fplAssert(str != fpl_null);
@endcode
@warning When you are building in release-mode runtime-time assertions are compiled out entirely - unless you have specific **FPL_FORCE_ASSERTIONS**!
@warning Do not call any important functions inside an assertion statement, because it will get compiled out eventually.
@subsection subsection_category_assertions_static Compile-time / static assertion
You can use the macro function @ref fplStaticAssert() to trigger a compile-time assertion in a debug-build.<br>
Example:
@code{.c}
typedef struct myStruct {
int a;
float b;
} myStruct;
// Will throw a compile error when "myStruct" is not of total size of 8-bytes
fplStaticAssert(sizeof(myStruct) == 8);
@endcode
@warning When you are building in release-mode compile-time assertions are compiled out entirely - unless you have specific **FPL_FORCE_ASSERTIONS**!
@warning Do not call any important functions inside an assertion statement, because it will get compiled out eventually.
@subsection subsection_category_assertions_enabledisable Enable/Disable assertions
In Debug-Mode assertions are enabled, unless you have specified **FPL_NO_ASSERTIONS**.<br>
In Release-Mode assertions are disabled, unless you have specified **FPL_FORCE_ASSERTIONS**.<br>
<br>
You can use **FPL_DEBUG** or **FPL_RELEASE** to force either a "Release" or "Debug" mode.<br>
See @subpage page_compiler_options for more details.<br>
@note I highly recommend to never define this in your code, but rather outside in your build-configuration.
*/
/*!
@page page_category_window_basics Window basics
@tableofcontents
@section section_window_basics_init Initialization
To create a window, you add the @ref fplInitFlags_Window flag to the @ref fplInitFlags argument in the @ref fplPlatformInit() call.<br>
It makes no sense to create a window alone, so we combine it at least with something else, like for example a video context or audio playback.<br>
@code{.c}
fplPlatformInit(fplInitFlags_Window | fplInitFlags_Video, fpl_null);
@endcode
@section section_window_basics_mainloop Main loop
After you initialize FPL with a window, you have to create some sort of a loop to keep the window open until you close them.<br>
This is required because the operating systems use an event-based system to communicate with the window and your application.<br>
If no communication happens with your window and your app, the window will no longer be responsive - so make sure to communicate properly.<br>
<br>
To solve this, you have to use @ref fplWindowUpdate() and @ref fplPollEvent() respectively.
<br>
First, you need to call @ref fplWindowUpdate() for every 'tick' for your application. This will clear the internal event queue and update input devices properly.<br>
After that, you have to poll all events from the operating systems event queue using @ref fplPollEvent() .<br>
@code{.c}
while (fplWindowUpdate()) {
fplEvent ev;
while (fplPollEvent(&ev)) {
// ... Handle event here
}
}
@endcode
See @subpage page_category_window_events for more details.<br>
@attention All window-based calls are required to be executed from the main-thread only!
@section section_window_basics_shutdown Shutdown the window
Simply call @ref fplWindowShutdown to shutdown the window, while it is still running.<br>
<br>
You can also query the running state of the window by calling @ref fplIsWindowRunning() .<br>
@note The window is not immediately shut-down, one tick of window/input events may still be executed after that.<br>To forcefully terminate the window, use @ref fplPlatformRelease() instead.
*/
/*!
@page page_category_window_events Window events
@tableofcontents
@section section_category_window_events_polling Polling the window events
Call @ref fplPollEvent() in a while-loop inside your actual main-loop with a pointer to a @ref fplEvent argument to poll the next event from the OS event queue.<br>
Each event is translated into the @ref fplEvent argument which you can handle or not. If there are no events left, the function returns false.
@code{.c}
fplEvent currentEvent;
while (fplPollEvent(¤tEvent)) {
// ... Handling the event
}
@endcode
@section section_category_window_events_handling Handling the Events
Each event has a @ref fplEvent.type field which you can check on to read the actual data (Keyboard, Mouse, Window, etc.).
@code{.c}
fplEvent currentEvent;
while (fplPollEvent(¤tEvent)) {
switch (currentEvent.type) {
case fplEventType_Window:
{
// A window event, like resize, lost/got focus, etc.
switch (currentEvent.window.type) {
// ...
}
} break;
case fplEventType_Keyboard:
{
// A keyboard event, like key down/up, pressed, etc.
switch (currentEvent.keyboard.type) {
// ...
}
} break;
case fplEventType_Mouse:
{
// A mouse event, like mouse button down/up, mouse move, etc.
switch (currentEvent.mouse.type) {
// ...
}
} break;
case fplEventType_Gamepad:
{
// A gamepad event, like connected/disconnected, state-updated etc.
switch (currentEvent.gamepad.type) {
// ...
}
} break;
}
}
@endcode
All available event types are stored in the @ref fplEventType enumeration.
@section section_category_window_events_handle_event_type Handle the event data
All relevant event data are stored in fields that match the lowercase @ref fplEventType name.<br>
Each event structure has another type field to check for the actual type (Key-Down, Mouse-Move, Window-Resize, etc.).<br>
@subsection subsection_category_window_events_handle_event_buttonstate Button states
All mouse/keyboard or gamepad button states are descriped as a @ref fplButtonState.<br>
<br>
To detect a non-repeatable button press, you simply compare against @ref fplButtonState_Press.<br>
To detect a repeatable button press, you simply compare against @ref fplButtonState_Repeat.<br>
To detect a non button press, you simply compare against @ref fplButtonState_Release.<br>
<br>
If you just want to know if a key is pressed or hold-down, just do a greater equals comparison of @ref fplButtonState_Press and you are golden.
@subsection subsection_category_window_events_handle_event_type_mouse Mouse events
Mouse event data are stored in the @ref fplMouseEvent structure.<br>
A mouse event contains either a single button click/release or a mouse wheel change or a position change.<br>
@code{.c}
switch (currentEvent.mouse.type) {
case fplMouseEventType_Button:
{
fplMouseButtonType button = currentEvent.mouse.button;
fplButtonState state = currentEvent.mouse.buttonState;
bool buttonDown = state >= fplButtonState_Press;
switch (button) {
case fplMouseButtonType_Left:
{
// Left mouse button down/released
} break;
case fplMouseButtonType_Middle:
{
// Middle mouse button down/released
} break;
case fplMouseButtonType_Right:
{
// Right mouse button down/released
} break;
}
} break;
case fplMouseEventType_Wheel:
{
float wheelDelta = currentEvent.mouse.wheelDelta;
if (wheelDelta < 0.0f) {
// Mouse-wheel down
} else if (wheelDelta > 0.0f) {
// Mouse-wheel up
}
} break;
case fplMouseEventType_Move:
{
int mouseX = currentEvent.mouse.mouseX;
int mouseY = currentEvent.mouse.mouseY;
// ... do something with the mouse position
} break;
}
@endcode
@note Any mouse button event contains the position of the click as well.
@subsection subsection_category_window_events_handle_event_type_keyboard Keyboard events
Keyboard event data are stored in the @ref fplKeyboardEvent structure.<br>
<br>
You can either check for the original @ref fplKeyboardEvent.keyCode or use the fplKeyboardEvent.mappedKey field - which is much easier and less error-prone.<br>
@code{.c}
switch (currentEvent.keyboard.type) {
case fplKeyboardEventType_KeyButton:
{
fplButtonState state = currentEvent.keyboard.buttonState;
// ... Handle the key code
uint64_t keyCode = currentEvent.keyboard.keyCode;
if (state >= fplButtonState_Pressed) {
if (keyCode == 65 || keyCode == 97) {
// Letter A is held down
}
}
// or
// ... handle the mapped key
fplKey mappedKey = currentEvent.keyboard.mappedKey;
if (state == fplButtonState_Released) {
if (mappedKey == fplKey_F1) {
// F1 key pressed
}
}
} break;
case fplKeyboardEventType_CharInput:
{
if(currentEvent.keyboard.keyCode > 0 && event.keyboard.keyCode < 0x10000) {
// Handle character input
}
} break;
}
@endcode
@subsection subsection_category_window_events_handle_event_type_gamepad Gamepad events
Gamepad event data are stored in the @ref fplGamepadEvent structure.<br>
@code{.c}
switch (currentEvent.gamepad.type) {
case fplGamepadEventType_Connected:
{
// New gamepad device connected
} break;
case fplGamepadEventType_Disconnected:
{
// Lost connection to a gamepad device
} break;
case fplGamepadEventType_StateChanged:
{
// State of one controller updated (Buttons, Movement, etc.)
if (absf(currentEvent.gamepad.leftStickX) > 0) {
// ... Handle horizontal movement on left stick
}
if (currentEvent.gamepad.actionX.isDown) {
// ... X-Button is held down
}
} break;
}
@endcode
@subsection subsection_category_window_events_handle_event_type_window Window events
Window event data are stored in the @ref fplWindowEvent structure.<br>
@code{.c}
switch (currentEvent.window.type) {
case fplWindowEventType_Resized:
{
uint32_t newWidth = currentEvent.window.width;
uint32_t newHeight = currentEvent.window.height;
// ... Window was resized, handle it properly
} break;
case fplWindowEventType_GetFocus:
case fplWindowEventType_LostFocus:
{
// ... Do something when window lost/got focus
} break;
case fplWindowEventType_Exposed:
{
// ... Do something when window was exposed
} break;
case fplWindowEventType_DropSingleFile:
{
const char *filePath = ev.window.dropFiles.single.filePath;
// ... Do something when window got a single file dropped into it
} break;
case fplWindowEventType_Minimized:
case fplWindowEventType_Maximized:
case fplWindowEventType_Restored:
{
// ... Do something when window state was changed
} break;
}
@endcode
@section section_category_window_events_process Ignoring the events
When you don't care about any events you can simply call @ref fplPollEvents() to process the events and be done with them.<br>
@code{.c}
while (fplWindowUpdate()) {
fplPollEvents();
// ... Your code
}
@endcode
@section section_category_window_events_inotes Important Notes
@note FPL does not cache the events from the previous update. If you don't handle or cache the event - the data is lost!
*/
/*!
@page page_category_window_style Window style & layout
@tableofcontents
@section section_category_window_style_style Reading/Setting the style
@subsection subsection_category_window_style_style_decorated Decoration (Border, Titlebar)
By default, a window is decorated. This means that it has a border, a title bar, and can be moved by the user.<br>
If you enable window decorations, your window will have a border and a title bar always.<br>
<br>
Use @ref fplIsWindowDecorated() to determine if the window has decoration enabled or not.<br>
Use @ref fplSetWindowDecorated() to enable/disable the window decoration.<br>
<b>Example:</b>
@code{.c}
// Enable window decoration