forked from mattiasgustavsson/libs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.h
4817 lines (4015 loc) · 210 KB
/
app.h
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
/*
------------------------------------------------------------------------------
Licensing information can be found at the end of the file.
------------------------------------------------------------------------------
app.h - v0.5 - Small cross-platform base framework for graphical apps.
Do this:
#define APP_IMPLEMENTATION
before you include this file in *one* C/C++ file to create the implementation.
*/
#ifndef app_h
#define app_h
#ifndef APP_S16
#define APP_S16 short
#endif
#ifndef APP_U32
#define APP_U32 unsigned int
#endif
#ifndef APP_U64
#define APP_U64 unsigned long long
#endif
typedef struct app_t app_t;
int app_run( int (*app_proc)( app_t*, void* ), void* user_data, void* memctx, void* logctx, void* fatalctx );
typedef enum app_state_t { APP_STATE_EXIT_REQUESTED, APP_STATE_NORMAL, } app_state_t;
app_state_t app_yield( app_t* app );
void app_cancel_exit( app_t* app );
void app_title( app_t* app, char const* title );
char const* app_cmdline( app_t* app );
char const* app_filename( app_t* app );
char const* app_userdata( app_t* app );
char const* app_appdata( app_t* app );
APP_U64 app_time_count( app_t* app );
APP_U64 app_time_freq( app_t* app );
typedef enum app_log_level_t { APP_LOG_LEVEL_INFO, APP_LOG_LEVEL_WARNING, APP_LOG_LEVEL_ERROR, } app_log_level_t;
void app_log( app_t* app, app_log_level_t level, char const* message );
void app_fatal_error( app_t* app, char const* message );
void app_pointer( app_t* app, int width, int height, APP_U32* pixels_abgr, int hotspot_x, int hotspot_y );
void app_pointer_default( app_t* app, int* width, int* height, APP_U32* pixels_abgr, int* hotspot_x, int* hotspot_y );
void app_pointer_pos( app_t* app, int x, int y );
int app_pointer_x( app_t* app );
int app_pointer_y( app_t* app );
void app_pointer_limit( app_t* app, int x, int y, int width, int height );
void app_pointer_limit_off( app_t* app );
typedef enum app_interpolation_t { APP_INTERPOLATION_NONE, APP_INTERPOLATION_LINEAR, } app_interpolation_t;
void app_interpolation( app_t* app, app_interpolation_t interpolation );
typedef enum app_screenmode_t { APP_SCREENMODE_WINDOW, APP_SCREENMODE_FULLSCREEN, } app_screenmode_t;
void app_screenmode( app_t* app, app_screenmode_t screenmode );
void app_window_size( app_t* app, int width, int height );
int app_window_width( app_t* app );
int app_window_height( app_t* app );
void app_window_pos( app_t* app, int x, int y );
int app_window_x( app_t* app );
int app_window_y( app_t* app );
typedef struct app_display_t
{
char id[ 64 ];
int x;
int y;
int width;
int height;
} app_display_t ;
typedef struct app_displays_t { app_display_t* displays; int count; } app_displays_t;
app_displays_t app_displays( app_t* app );
void app_present( app_t* app, APP_U32 const* pixels_xbgr, int width, int height, APP_U32 mod_xbgr, APP_U32 border_xbgr );
void app_sound( app_t* app, int sample_pairs_count,
void (*sound_callback)( APP_S16* sample_pairs, int sample_pairs_count, void* user_data ), void* user_data );
void app_sound_volume( app_t* app, float volume );
typedef enum app_key_t { APP_KEY_INVALID, APP_KEY_LBUTTON, APP_KEY_RBUTTON, APP_KEY_CANCEL, APP_KEY_MBUTTON,
APP_KEY_XBUTTON1, APP_KEY_XBUTTON2, APP_KEY_BACK, APP_KEY_TAB, APP_KEY_CLEAR, APP_KEY_RETURN, APP_KEY_SHIFT,
APP_KEY_CONTROL, APP_KEY_MENU, APP_KEY_PAUSE, APP_KEY_CAPITAL, APP_KEY_KANA, APP_KEY_HANGUL = APP_KEY_KANA,
APP_KEY_JUNJA, APP_KEY_FINAL, APP_KEY_HANJA, APP_KEY_KANJI = APP_KEY_HANJA, APP_KEY_ESCAPE, APP_KEY_CONVERT,
APP_KEY_NONCONVERT, APP_KEY_ACCEPT, APP_KEY_MODECHANGE, APP_KEY_SPACE, APP_KEY_PRIOR, APP_KEY_NEXT, APP_KEY_END,
APP_KEY_HOME, APP_KEY_LEFT, APP_KEY_UP, APP_KEY_RIGHT, APP_KEY_DOWN, APP_KEY_SELECT, APP_KEY_PRINT, APP_KEY_EXEC,
APP_KEY_SNAPSHOT, APP_KEY_INSERT, APP_KEY_DELETE, APP_KEY_HELP, APP_KEY_0, APP_KEY_1, APP_KEY_2, APP_KEY_3,
APP_KEY_4, APP_KEY_5, APP_KEY_6, APP_KEY_7, APP_KEY_8, APP_KEY_9, APP_KEY_A, APP_KEY_B, APP_KEY_C, APP_KEY_D,
APP_KEY_E, APP_KEY_F, APP_KEY_G, APP_KEY_H, APP_KEY_I, APP_KEY_J, APP_KEY_K, APP_KEY_L, APP_KEY_M, APP_KEY_N,
APP_KEY_O, APP_KEY_P, APP_KEY_Q, APP_KEY_R, APP_KEY_S, APP_KEY_T, APP_KEY_U, APP_KEY_V, APP_KEY_W, APP_KEY_X,
APP_KEY_Y, APP_KEY_Z, APP_KEY_LWIN, APP_KEY_RWIN, APP_KEY_APPS, APP_KEY_SLEEP, APP_KEY_NUMPAD0, APP_KEY_NUMPAD1,
APP_KEY_NUMPAD2, APP_KEY_NUMPAD3, APP_KEY_NUMPAD4, APP_KEY_NUMPAD5, APP_KEY_NUMPAD6, APP_KEY_NUMPAD7,
APP_KEY_NUMPAD8, APP_KEY_NUMPAD9, APP_KEY_MULTIPLY, APP_KEY_ADD, APP_KEY_SEPARATOR, APP_KEY_SUBTRACT,
APP_KEY_DECIMAL, APP_KEY_DIVIDE, APP_KEY_F1, APP_KEY_F2, APP_KEY_F3, APP_KEY_F4, APP_KEY_F5, APP_KEY_F6, APP_KEY_F7,
APP_KEY_F8, APP_KEY_F9, APP_KEY_F10, APP_KEY_F11, APP_KEY_F12, APP_KEY_F13, APP_KEY_F14, APP_KEY_F15, APP_KEY_F16,
APP_KEY_F17, APP_KEY_F18, APP_KEY_F19, APP_KEY_F20, APP_KEY_F21, APP_KEY_F22, APP_KEY_F23, APP_KEY_F24,
APP_KEY_NUMLOCK, APP_KEY_SCROLL, APP_KEY_LSHIFT, APP_KEY_RSHIFT, APP_KEY_LCONTROL, APP_KEY_RCONTROL, APP_KEY_LMENU,
APP_KEY_RMENU, APP_KEY_BROWSER_BACK, APP_KEY_BROWSER_FORWARD, APP_KEY_BROWSER_REFRESH, APP_KEY_BROWSER_STOP,
APP_KEY_BROWSER_SEARCH, APP_KEY_BROWSER_FAVORITES, APP_KEY_BROWSER_HOME, APP_KEY_VOLUME_MUTE, APP_KEY_VOLUME_DOWN,
APP_KEY_VOLUME_UP, APP_KEY_MEDIA_NEXT_TRACK, APP_KEY_MEDIA_PREV_TRACK, APP_KEY_MEDIA_STOP, APP_KEY_MEDIA_PLAY_PAUSE,
APP_KEY_LAUNCH_MAIL, APP_KEY_LAUNCH_MEDIA_SELECT, APP_KEY_LAUNCH_APP1, APP_KEY_LAUNCH_APP2, APP_KEY_OEM_1,
APP_KEY_OEM_PLUS, APP_KEY_OEM_COMMA, APP_KEY_OEM_MINUS, APP_KEY_OEM_PERIOD, APP_KEY_OEM_2, APP_KEY_OEM_3,
APP_KEY_OEM_4, APP_KEY_OEM_5, APP_KEY_OEM_6, APP_KEY_OEM_7, APP_KEY_OEM_8, APP_KEY_OEM_102, APP_KEY_PROCESSKEY,
APP_KEY_ATTN, APP_KEY_CRSEL, APP_KEY_EXSEL, APP_KEY_EREOF, APP_KEY_PLAY, APP_KEY_ZOOM, APP_KEY_NONAME, APP_KEY_PA1,
APP_KEY_OEM_CLEAR, APP_KEYCOUNT } app_key_t;
typedef enum app_input_type_t { APP_INPUT_KEY_DOWN, APP_INPUT_KEY_UP, APP_INPUT_DOUBLE_CLICK, APP_INPUT_CHAR,
APP_INPUT_MOUSE_MOVE, APP_INPUT_MOUSE_DELTA, APP_INPUT_SCROLL_WHEEL, APP_INPUT_TABLET } app_input_type_t;
typedef enum app_pressed_t { APP_NOT_PRESSED, APP_PRESSED, } app_pressed_t;
typedef struct app_input_event_t
{
app_input_type_t type;
union data_t
{
app_key_t key;
char char_code;
struct { int x; int y; } mouse_pos;
struct { float x; float y; } mouse_delta;
float wheel_delta;
struct { int x; int y; float pressure; app_pressed_t tip; app_pressed_t lower; app_pressed_t upper; } tablet;
} data;
} app_input_event_t;
typedef struct app_input_t { app_input_event_t* events; int count; } app_input_t;
app_input_t app_input( app_t* app );
void app_coordinates_window_to_bitmap( app_t* app, int width, int height, int* x, int* y );
void app_coordinates_bitmap_to_window( app_t* app, int width, int height, int* x, int* y );
#endif /* app_h */
/**
app.h
=====
Small cross-platform base framework for graphical apps.
Example
-------
Here's a basic sample program which starts a windowed app and plots random pixels.
#define APP_IMPLEMENTATION
#define APP_WINDOWS
#include "app.h"
#include <stdlib.h> // for rand and __argc/__argv
#include <string.h> // for memset
int app_proc( app_t* app, void* user_data ) {
APP_U32 canvas[ 320 * 200 ]; // a place for us to draw stuff
memset( canvas, 0xC0, sizeof( canvas ) ); // clear to grey
app_screenmode( app, APP_SCREENMODE_WINDOW );
// keep running until the user close the window
while( app_yield( app ) != APP_STATE_EXIT_REQUESTED ) {
// plot a random pixel on the canvas
int x = rand() % 320;
int y = rand() % 200;
APP_U32 color = rand() | ( (APP_U32) rand() << 16 );
canvas[ x + y * 320 ] = color;
// display the canvas
app_present( app, canvas, 320, 200, 0xffffff, 0x000000 );
}
return 0;
}
int main( int argc, char** argv ) {
(void) argc, argv;
return app_run( app_proc, NULL, NULL, NULL, NULL );
}
API Documentation
-----------------
app.h is a single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it,
you just include app.h to get the API declarations. To get the definitions, you must include app.h from *one* single
C or C++ file, and #define the symbol `APP_IMPLEMENTATION` before you do.
As app.h is a cross platform library, you must also define which platform you are running on, like this for Windows:
#define APP_IMPLEMENTATION
#define APP_WINDOWS
#include "app.h"
Or like this for other platforms:
#define APP_IMPLEMENTATION
#define APP_SDL
#include "app.h"
### Customization
There are a few different things in app.h which are configurable by #defines. Most of the API use the `int` data type,
for integer values where the exact size is not important. However, for some functions, it specifically makes use of 16,
32 and 64 bit data types. These default to using `short`, `unsigned int` and `unsigned long long` by default, but can be
redefined by #defining APP_S16, APP_U32 and APP_U64 respectively, before including app.h. This is useful if you, for
example, use the types from `<stdint.h>` in the rest of your program, and you want app.h to use compatible types. In
this case, you would include app.h using the following code:
#define APP_S16 int16_t
#define APP_U32 uint32_t
#define APP_U64 uint64_t
#include "app.h"
Note that when customizing the data types, you need to use the same definition in every place where you include app.h,
as they affect the declarations as well as the definitions.
The rest of the customizations only affect the implementation, so will only need to be defined in the file where you
have the #define APP_IMPLEMENTATION.
#### Custom memory allocators
Even though app.h attempts to minimize the memory use and number of allocations, it still needs to make *some* use of
dynamic allocation by calling `malloc`. Programs might want to keep track of allocations done, or use custom defined
pools to allocate memory from. app.h allows for specifying custom memory allocation functions for `malloc` and `free`.
This is done with the following code:
#define APP_IMPLEMENTATION
#define APP_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) )
#define APP_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) )
#include "app.h"
where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter
is an optional parameter of type `void*`. When `app_run` is called, you can pass in a `memctx` parameter, which can be a
pointer to anything you like, and which will be passed through as the `ctx` parameter to every APP_MALLOC/APP_FREE call.
For example, if you are doing memory tracking, you can pass a pointer to your tracking data as `memctx`, and in your
custom allocation/deallocation function, you can cast the `ctx` param back to the right type, and access the tracking
data.
If no custom allocator is defined, app.h will default to `malloc` and `free` from the C runtime library.
#### Custom logging function
There's a bunch of things being logged when app.h runs. It will log an informational entry with the date and time for
when the app is started and stopped, it will log warnings when non-essential initialization fails, and it will log
error messages when things go wrong. By default, logging is done by a simple printf to stdout. As some applications may
need a different behavior, such as writing out a log file, it is possible to override the default logging behavior
through defines like this:
#define APP_IMPLEMENTATION
#define APP_LOG( ctx, level, message ) ( my_log_func( ctx, level, message ) )
#include "app.h"
where `my_log_func` is your own logging function. Just like for the memory allocators, the `ctx` parameter is optional,
and is just a `void*` value which is passed through. But in the case of logging, it will be passed through as the value
off the `logctx` parameter passed into `app_run`. The `level` parameter specifies the severity level of the logging,
and can be used to direct different types of messages to different logging systems, or filter out messages of certain
severity level, e.g. supressing informational messages.
#### Custom fatal error function
As the app.h library works on the lowest level of your program, interfacing directly with the operating system, there
might occur errors which it can not recover from. In these cases, a *fatal error* will be reported. By default, when a
fatal error happens, app.h will print a message to stdout, show a messagebox to the user, and force exit the program.
It is possible to change this behaviour using the following define:
#define APP_IMPLEMENTATION
#define APP_FATAL_ERROR( ctx, message ) ( my_custom_fatal_error_func( ctx, message ) )
#include "app.h"
where `my_custom_fatal_error_func` is your own error reporting function. The `ctx` parameter fills the same purpose as
for the allocator and logging functions, but here it is the `fatalctx` parameter to `app_run` which is passed through.
app_run
-------
int app_run( int (*app_proc)( app_t*, void* ), void* user_data, void* memctx, void* logctx, void* fatalctx )
Creates a new app instance, calls the given app_proc and waits for it to return. Then it destroys the app instance.
* app_proc - function pointer to the user defined starting point of the app. The parameters to that function are:
app_t* a pointer to the app instance. This is an opaque type, and it is passed to all other functions in the API.
void* pointer to the user defined data that was passed as the `user_data` parameter to `app_run`.
* user_data - pointer to user defined data which will be passed through to app_proc. May be NULL.
* memctx - pointer to user defined data which will be passed through to custom APP_MALLOC/APP_FREE calls. May be NULL.
* logctx - pointer to user defined data to be passed through to custom APP_LOG calls. May be NULL.
* fatalctx - pointer to user defined data to be passed through to custom APP_FATAL_ERROR calls. May be NULL.
When app_run is called, it will perform all the initialization needed by app.h, and create an `app_t*` instance. It will
then call the user-specified `app_proc`, and wait for it to return. The `app_t*` instance will be passed to `app_proc`,
and can be used to call other functions in the API. When returning from `app_proc`, a return value is specified, and
`app_run` will perform termination and cleanup, and destroy the `app_t*` instance, and then return the same value it got
from the `app_proc`. After `app_run` returns, the `app_t*` value is no longer valid for use in any API calls.
app_yield
---------
app_state_t app_yield( app_t* app )
Allows for app.h and the operating system to perform internal house keeping and updates. It should be called on each
iteration of your main loop.
The return value can be either `APP_STATE_NORMAL` or `APP_STATE_EXIT_REQUESTED`. `APP_STATE_EXIT_REQUESTED` means that
the user have requested the app to terminate, e.g. by pressing the *close* button on the window, and the user defined
`app_proc` needs to handle this, by either returning (to signal that the app should terminate) or by calling
`app_cancel_exit` to ignore the request. A typical pattern is to display a message to the user to confirm that the app
should exit. In the case of `APP_STATE_NORMAL`, there is no need to do anything.
app_cancel_exit
---------------
void app_cancel_exit( app_t* app )
Used to reset the `APP_STATE_EXIT_REQUESTED` state. See `app_yield` for details.
app_title
---------
void app_title( app_t* app, char const* title )
Sets the name of the application, which is displayed in the task switcher and in the title bar of the window.
app_cmdline
-----------
char const* app_cmdline( app_t* app )
Returns the command line string used to launch the executable. This can be parsed to get command line arguments.
app_filename
------------
char const* app_filename( app_t* app )
Returns the full filename and path of the executable. The first part of `app_cmdline` usually contains the name of the
executable, but not necessarily the full path, depending on how it was launched. `app_filename`, however, always returns
the full path.
app_userdata
------------
char const* app_userdata( app_t* app )
Returns the full path to a directory where a users personal files can be stored. Depending on the access rights of the
user, it may or may not be possible to write data to the same location as the executable, and instead it must be stored
in a specific area designated by the operating system. `app_userdata` returns the path to the root if that directory.
A typical use for this is to store the users savegame files, by creating a subfolder corresponding to your app, and save
the data there.
app_appdata
-----------
char const* app_appdata( app_t* app )
Returns the full path to a directory where application specific files can be stored. Similar to the location returned by
`app_userdata`, but suitable for application data shared between users. Typical use for this is to store the result of
cached calculations or temporary files.
app_time_count
--------------
APP_U64 app_time_count( app_t* app )
Returns the current value of the high precision clock. The epoch is undefined, and the resolution can vary between
systems. Use `app_time_freq` to convert to seconds. Typical use is to make two calls to `app_time_count` and calculate
the difference, to measure the time elapsed between the two calls.
app_time_freq
-------------
APP_U64 app_time_freq( app_t* app )
Returns the number of clock ticks per second of the high precision clock. An example use case could be:
APP_U64 current_count = app_time_count( app );
APP_U64 delta_count = current_count - previous_count;
double delta_time = ( (double) delta_count ) / ( (double) app_time_freq( app ) );
previous_count = current_count;
to measure the time between two iterations through your main loop.
app_log
-------
void app_log( app_t* app, app_log_level_t level, char const* message )
app.h will do logging on certain events, e.q when the app starts and ends or when something goes wrong. As the logging
can be customized (see section on customization), it might be desirable for the program to do its own logging the same
way as app.h does it. By calling `app_log`, logging will be done the same way as it is done inside app.h, whether custom
logging or default logging is being used.
app_fatal_error
---------------
void app_fatal_error( app_t* app, char const* message )
Same as with app_log, but for reporting fatal errors, `app_fatal_error` will report an error the same way as is done
internally in app.h, whether custom or default fatal error reporting is being used.
app_pointer
-----------
void app_pointer( app_t* app, int width, int height, APP_U32* pixels_abgr, int hotspot_x, int hotspot_y )
Sets the appearence current mouse pointer. `app_pointer` is called with the following parameters:
* width, height - the horizontal and vertical dimensions of the mouse pointer bitmap.
* pixels_abgr - width x height number of pixels making up the pointer bitmap, each pixel being a 32-bit unsigned integer
where the highest 8 bits are the alpha channel, and the following 8-bit groups are blue, green and red channels.
* hotspot_x, hotspot_y - offset into the bitmap of the pointer origin, the center point it will be drawn at.
app_pointer_default
-------------------
void app_pointer_default( app_t* app, int* width, int* height, APP_U32* pixels_abgr, int* hotspot_x, int* hotspot_y )
Retrieves the width, height, pixel data and hotspot for the default mouse pointer. Useful for restoring the default
pointer after using `app_pointer`, or for doing software rendered pointers. Called with the following parameters:
* width, height - pointers to integer values that are to receive the width and height of the pointer. May be NULL.
* pixels_abgr - width x height number of pixels to receive the pointer bitmap. May be NULL
* hotspot_x, hotspot_y - pointers to integer values that are to receive the hotspot coordinates. May be NULL.
A typical pattern for calling `app_pointer_default` is to first call it with `pixels_abgr` as NULL, to query the bitmaps
dimensions, and then call it again after preparing a large enough memory area.
app_pointer_pos
---------------
void app_pointer_pos( app_t* app, int x, int y )
Set the position of the mouse pointer, in window coordinates. The function `app_coordinates_bitmap_to_window` can be
used to convert between the coordinate system of the currently displayed bitmap and that of the window.
app_pointer_limit
-----------------
void app_pointer_limit( app_t* app, int x, int y, int width, int height )
Locks the mouse pointer movements to stay within the specified area, in window coordinates. The function
`app_coordinates_bitmap_to_window` can be used to convert between the coordinate system of the currently displayed
bitmap and that of the window.
app_pointer_limit_off
---------------------
void app_pointer_limit_off( app_t* app )
Turns of the mouse pointer movement restriction, allowing the pointer to be moved freely again.
app_interpolation
-----------------
void app_interpolation( app_t* app, app_interpolation_t interpolation )
app.h supports two different modes of displaying a bitmap. When using `APP_INTERPOLATION_LINEAR`, the bitmap will be
drawn with bilinear interpolations, stretching it to fill the window (maintaining aspect ratio), giving it a smooth, if
somwhat blurry, look. With `APP_INTERPOLATION_NONE`, scaling will only be done on whole pixel ratios, using no
interpolation, which is particularly suitable to maintain the clean, precise look of pixel art.
`APP_INTERPOLATION_LINEAR` is the default setting.
app_screenmode
--------------
void app_screenmode( app_t* app, app_screenmode_t screenmode )
Switch between windowed mode and fullscreen mode. `APP_SCREENMODE_WINDOW` is used to select windowed mode, and
`APP_SCREENMODE_FULLSCREEN` is used to switch to fullscreen mode. `APP_SCREENMODE_FULLSCREEN` is the default. Note that
the app.h fullscreenmode is of the "borderless windowed" type, meaning that fullscreen mode just means that the window
is set to cover the entire screen, and its borders are hidden. It does not imply any exclusive locking of GPU resources.
When switching from windowed to fullscreen mode on a multi-display system, the app will go fullscreen on the display
that the window is currently on.
app_window_size
---------------
void app_window_size( app_t* app, int width, int height )
Sets the size of the window. If currently in `APP_SCREENMODE_FULLSCREEN` screen mode, the setting will not take effect
until switching to `APP_SCREENMODE_WINDOW`. `width` and `height` specifies the size of the windows client area, not
counting borders, title bar or decorations.
app_window_width/app_window_height
----------------------------------
int app_window_width( app_t* app )
int app_window_height( app_t* app )
Returns the current dimensions of the window (which might have been resized by the user). Regardless of whether the app
is currently in fullscreen or windowed mode, `app_window_width` and `app_window_height` returns the dimension the window
*would* have in windowed mode. Width and height specifies the size of the windows client area, not counting borders,
title bar or decorations.
app_window_pos
--------------
void app_window_pos( app_t* app, int x, int y )
Sets the position of the top left corner of the window. If currently in `APP_SCREENMODE_FULLSCREEN` screen mode, the
setting will not take effect until switching to `APP_SCREENMODE_WINDOW`.
app_window_x/app_window_y
-------------------------
int app_window_x( app_t* app )
int app_window_y( app_t* app )
Returns the current position of the windows top left corner. Regardless of whether the app is currently in fullscreen or
windowed mode, `app_window_x` and `app_window_y` returns the position the window *would* have in windowed mode.
app_displays
------------
app_displays_t app_displays( app_t* app )
Returns a list of all displays connected to the system. For each display, the following fields are reported:
* id - a platform specific string used to identify the display. Useful for saving which display was in use.
* x, y - position of the top left corner of the display, relative to the primary dispay which is always at 0,0.
* width, height - size of the display, in pixels.
app_present
-----------
void app_present( app_t* app, APP_U32 const* pixels_xbgr, int width, int height, APP_U32 mod_xbgr, APP_U32 border_xbgr )
app.h provides a very minimal API for drawing - the only thing you can really do, is provide it with a bitmap for it to
display on the screen. It is then up to the rest of your program to implement code for drawing shapes or sprites onto
that bitmap. When all your drawing is done, you call `app_present` passing it the bitmap, and it will be displayed on
the screen. `app_present` takes the following parameters:
* pixels_xbgr - width x height number of pixels making up the bitmap to be presented, each pixel being a 32-bit unsigned
integer where the highest 8 bits are not used, and the following 8-bit groups are blue, green and red channels. This
parameter may be NULL, in which case no bitmap is drawn, to allow for custom rendering. See below for details.
* width, height - the horizontal and vertical dimensions of the bitmap
* mod_xbgr - an rgb color value which will be automatically multiplied with each pixel, component by component, before
it is displayed. Can be used to for example fade the bitmap to/from black. Set to 0xffffff for no effect.
* border_xbgr - an rgb color value to be used as *border color*. The borders are the areas outside of the bitmap, which
are visible when the window aspect ratio does not match that of the bitmap, so you get bars above or below it.
Since app.h uses opengl, you can also opt to not pass a bitmap to `app_present`, by passing NULL as the `pixels_xbgr`
parameter (in which case the rest of the parameters are ignored). When doing this, it is up to your program to perform
drawing using opengl calls. In this case `app_present` will work as a call to SwapBuffers only. Note that glSetViewPort
will be automatically called whenever the window is resized.
app_sound_buffer_size
---------------------
void app_sound_buffer_size( app_t* app, int sample_pairs_count )
The api for playing sound samples is just as minimal as that for drawing. app.h provides a single, looping sound stream,
and it is up to your program to handle sound formats, voices and mixing. By calling `app_sound_buffer_size`, a sound
stream of the specified size is initialized, and playback is started. If a `sample_pairs_count` of 0 is given, sound
playback will be stopped.
The sound buffer is in 44100hz, signed 16-bit stereo format, and the `sample_pairs_count` specified how many left/right
pairs of 16-bit samples the buffer will contain. As an example, to specify a 1 second stream buffer, you would give the
value 44100 for the `sample_pairs_count` parameter, which would internally create a sound buffer of 176,400 bytes, from
44100 samples x 2 channels x 2 bytes per sample. However, since the bits per sample and number of channels are fixed,
the exact byte size of the sound buffer is not important in the app.h API.
app_sound_position
------------------
int app_sound_position( app_t* app )
Returns the current playback position of the sound stream, given in the number of sample pairs from the start of the
buffer. Typical use of a streaming sound buffer is to fill the buffer with data, wait for the playback position to get
passed the mid point of the buffer, and then write the next bit of data over the part that has already been played, and
so on.
app_sound_write
---------------
void app_sound_write( app_t* app, int sample_pairs_offset, int sample_pairs_count, APP_S16 const* sample_pairs )
Writes sample data to the sound buffer. It takes the following parameters:
* sample_pairs_offset - the offset into the buffer of where to start writing, in number of sample pairs from the start.
* sample_pairs_count - the number of sample pairs to write. Must be less than the buffer size.
* sample_pairs - an array of sound samples, as signed 16-bit integers. Must be at least `sample_pairs_count` in length.
The `sample_pairs` parameter can be NULL, in which case the corresponding part of the buffer is cleared.
app_sound_volume
----------------
void app_sound_volume( app_t* app, float volume )
Sets the output volume level of the sound stream, as a normalized linear value in the range 0.0f to 1.0f, inclusive.
app_input
---------
app_input_t app_input( app_t* app )
Returns a list of input events which occured since the last call to `app_input`. Each input event can be of one of a
list of types, and the `type` field of the `app_input_event_t` struct specifies which type the event is. The `data`
struct is a union of fields, where only one of them is valid, depending on the value of `type`:
* APP_INPUT_KEY_DOWN, APP_INPUT_KEY_UP, APP_INPUT_DOUBLE_CLICK - use the `key` field of the `data` union, which contains
one of the keyboard key identifiers from the `app_key_t` enumeration. `APP_INPUT_KEY_DOWN` means a key was pressed,
or that it was held long enough for the key repeat to kick in. `APP_INPUT_KEY_UP` means a key was released, and is
not sent on key repeats. For both these events, a `key` may also mean a mouse button, as those are listed in the
`app_key_t` enum. `APP_INPUT_DOUBLE_CLICK` means a mouse button have been double clicked, and is not sent for
keyboard keys.
* APP_INPUT_CHAR - use the `char_code` field of the `data` union, which contains the ASCII value of the key that was
pressed. This is used to read text input, and will handle things like upper/lower case, and characters which
requires multiple keys to be pressed in sequence to generate one input. This means that generally, when a key is
pressed, you will get both an `APP_INPUT_KEY_DOWN` event and an `APP_INPUT_CHAR` event - just use the one you are
interested in, and ignore the other.
* APP_INPUT_MOUSE_MOVE - use the `mouse_pos` field of the `data` union, which contains the x and y position of the
mouse pointer, in window coordinates. The function `app_coordinates_window_to_bitmap` can be used to convert between
the coordinate system of the window and that of the currently displayed bitmap. The `APP_INPUT_MOUSE_MOVE` event is
sent whenever the user moves the mouse, as long as the window has focus and the pointer is inside its client area.
* APP_INPUT_MOUSE_DELTA - use the `mouse_delta` field of the `data` union, which contains the horizontal and vertical
offset which the mouse has been moved by. Ideally, these values should be in normalized -1.0f to 1.0f range, but as
there is no standardisation on the hardware and os level for this, it is not possible to do, so instead the value
have been scaled to give roughly normalized -1.0f to 1.0f values on a typical setup. For serious use, sensitivity
settings and/or user calibration is recommended. The `APP_INPUT_MOUSE_DELTA` event is sent whenever the user moves
the mouse, regardless of whether the window has focus or whether the pointer is inside the window or not. The
`APP_INPUT_MOUSE_DELTA` event is a better option for reading relative mouse movements than using the
`APP_INPUT_MOUSE_MOVE` event together with `app_pointer_pos` to re-center the pointer on every update.
* APP_INPUT_SCROLL_WHEEL - use the `wheel_delta` field of the `data` union, which contains the number of clicks by which
the scroll wheel on the mouse was turned, where positive values indicate that the wheel have been rotated away from
the user, and negative values means it has turned towards the user. The `APP_INPUT_SCROLL_WHEEL` is sent every time
the user turns the scroll wheel, as long as the window has focus.
* APP_INPUT_TABLET - use the `tablet` field of the `data` union, which contains details about the pen used with a
graphical tablet, if connected and installed. The `x` and `y` fields are the horizontal and vertical positions of
the pen on the tablet, scaled to the coordinate system of the window. The function `app_coordinates_window_to_bitmap`
can be used to convert between the coordinate system of the window and that of the currently displayed bitmap. The
`pressure` field is the current pressure of the pen against the tablet, in normalized 0.0f to 1.0f range, inclusive,
where 0.0f means no pressure and 1.0f means full pressure. The `tip` field is set to `APP_PRESSED` if the tip of the
pen is touching the tablet at all, and to `APP_NOT_PRESSED` otherwise. The `upper` and `lower` fields indicate the
current state of the buttons on the side of the pen. The "eraser" part of the pen is not currently supported.
app_coordinates_window_to_bitmap
--------------------------------
void app_coordinates_window_to_bitmap( app_t* app, int width, int height, int* x, int* y )
Functions in the `app.h` API expects and returns coordinates in the windows coordinate system, where 0, 0 is the top
left corner of the windows client area (the area inside of the window borders, excluding title bar and decorations), and
width, height is the dimension, in pixels, of the client area. It is often desirable to translate a position given in
window coordinates into a position on the bitmap that is being displayed - taking into account whether the window is in
fullscreen or windowed mode, and how the bitmap is stretched or padded depending on which interpolation mode is being
used: `APP_INTERPOLATION_NONE` or `APP_INTERPOLATION_LINEAR`. `app_coordinates_window_to_bitmap` performs this
translation, and is called with the following parameters:
* width, height - dimensions of the bitmap being presented, the same as the ones passed to `app_present`.
* x, y - pointers to integer values containing the coordinate, in the coordinate system of the window, to be translated.
When the function returns, their values will have been updated with the corresponding position in the coordinate
system of the bitmap.
app_coordinates_bitmap_to_window
--------------------------------
void app_coordinates_bitmap_to_window( app_t* app, int width, int height, int* x, int* y )
This performs the opposite translation to `app_coordinates_window_to_bitmap` - it converts a position given in the
coordinate system of the bitmap into the coordinate system of the window. See `app_coordinates_window_to_bitmap` for
details.
*/
/*
----------------------
IMPLEMENTATION
----------------------
*/
#ifdef APP_IMPLEMENTATION
#undef APP_IMPLEMENTATION
#include <stdlib.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OPENGL CODE - Shared between platform implementations
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef APP_NULL
#if defined( APP_WINDOWS )
#define _CRT_NONSTDC_NO_DEPRECATE
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stddef.h>
#define APP_GLCALLTYPE __stdcall
typedef unsigned int APP_GLuint;
typedef int APP_GLsizei;
typedef unsigned int APP_GLenum;
typedef int APP_GLint;
typedef float APP_GLfloat;
typedef char APP_GLchar;
typedef unsigned char APP_GLboolean;
typedef size_t APP_GLsizeiptr;
typedef unsigned int APP_GLbitfield;
#define APP_GL_FLOAT 0x1406
#define APP_GL_FALSE 0
#define APP_GL_FRAGMENT_SHADER 0x8b30
#define APP_GL_VERTEX_SHADER 0x8b31
#define APP_GL_COMPILE_STATUS 0x8b81
#define APP_GL_LINK_STATUS 0x8b82
#define APP_GL_INFO_LOG_LENGTH 0x8b84
#define APP_GL_ARRAY_BUFFER 0x8892
#define APP_GL_TEXTURE_2D 0x0de1
#define APP_GL_TEXTURE0 0x84c0
#define APP_GL_CLAMP 0x2900
#define APP_GL_TEXTURE_WRAP_S 0x2802
#define APP_GL_TEXTURE_WRAP_T 0x2803
#define APP_GL_TEXTURE_MIN_FILTER 0x2801
#define APP_GL_TEXTURE_MAG_FILTER 0x2800
#define APP_GL_NEAREST 0x2600
#define APP_GL_LINEAR 0x2601
#define APP_GL_STATIC_DRAW 0x88e4
#define APP_GL_RGBA 0x1908
#define APP_GL_UNSIGNED_BYTE 0x1401
#define APP_GL_COLOR_BUFFER_BIT 0x00004000
#define APP_GL_TRIANGLE_FAN 0x0006
#elif defined( APP_SDL ) || defined( APP_WASM )
#if defined( APP_WASM )
#include <wajic_gl.h>
#define WA_CORO_IMPLEMENT_NANOSLEEP
#include <wajic_coro.h>
#else
#include <GL/glew.h>
#include "SDL_opengl.h"
#endif
#define APP_GLCALLTYPE GLAPIENTRY
typedef GLuint APP_GLuint;
typedef GLsizei APP_GLsizei;
typedef GLenum APP_GLenum;
typedef GLint APP_GLint;
typedef GLfloat APP_GLfloat;
typedef GLchar APP_GLchar;
typedef GLboolean APP_GLboolean;
typedef GLsizeiptr APP_GLsizeiptr;
typedef GLbitfield APP_GLbitfield;
#define APP_GL_FLOAT GL_FLOAT
#define APP_GL_FALSE GL_FALSE
#define APP_GL_FRAGMENT_SHADER GL_FRAGMENT_SHADER
#define APP_GL_VERTEX_SHADER GL_VERTEX_SHADER
#define APP_GL_COMPILE_STATUS GL_COMPILE_STATUS
#define APP_GL_LINK_STATUS GL_LINK_STATUS
#define APP_GL_INFO_LOG_LENGTH GL_INFO_LOG_LENGTH
#define APP_GL_ARRAY_BUFFER GL_ARRAY_BUFFER
#define APP_GL_TEXTURE_2D GL_TEXTURE_2D
#define APP_GL_TEXTURE0 GL_TEXTURE0
#if defined( APP_WASM )
#define APP_GL_CLAMP GL_CLAMP_TO_EDGE
#else
#define APP_GL_CLAMP GL_CLAMP
#endif
#define APP_GL_TEXTURE_WRAP_S GL_TEXTURE_WRAP_S
#define APP_GL_TEXTURE_WRAP_T GL_TEXTURE_WRAP_T
#define APP_GL_TEXTURE_MIN_FILTER GL_TEXTURE_MIN_FILTER
#define APP_GL_TEXTURE_MAG_FILTER GL_TEXTURE_MAG_FILTER
#define APP_GL_NEAREST GL_NEAREST
#define APP_GL_LINEAR GL_LINEAR
#define APP_GL_STATIC_DRAW GL_STATIC_DRAW
#define APP_GL_RGBA GL_RGBA
#define APP_GL_UNSIGNED_BYTE GL_UNSIGNED_BYTE
#define APP_GL_COLOR_BUFFER_BIT GL_COLOR_BUFFER_BIT
#define APP_GL_TRIANGLE_FAN GL_TRIANGLE_FAN
#else
#error Undefined platform. Define APP_WINDOWS, APP_SDL, APP_WASM or APP_NULL.
#define APP_GLCALLTYPE
typedef int APP_GLuint;
typedef int APP_GLsizei;
typedef int APP_GLenum;
typedef int APP_GLint;
typedef int APP_GLfloat;
typedef int APP_GLchar;
typedef int APP_GLboolean;
typedef int APP_GLsizeiptr;
typedef int APP_GLbitfield;
#endif
#ifdef APP_REPORT_SHADER_ERRORS
#include <string.h>
#endif
struct app_internal_opengl_t
{
APP_GLuint (APP_GLCALLTYPE* CreateShader) (APP_GLenum type);
void (APP_GLCALLTYPE* ShaderSource) (APP_GLuint shader, APP_GLsizei count, APP_GLchar const* const* string, APP_GLint const* length);
void (APP_GLCALLTYPE* CompileShader) (APP_GLuint shader);
void (APP_GLCALLTYPE* GetShaderiv) (APP_GLuint shader, APP_GLenum pname, APP_GLint *params);
APP_GLuint (APP_GLCALLTYPE* CreateProgram) (void);
void (APP_GLCALLTYPE* AttachShader) (APP_GLuint program, APP_GLuint shader);
void (APP_GLCALLTYPE* BindAttribLocation) (APP_GLuint program, APP_GLuint index, APP_GLchar const* name);
void (APP_GLCALLTYPE* LinkProgram) (APP_GLuint program);
void (APP_GLCALLTYPE* GetProgramiv) (APP_GLuint program, APP_GLenum pname, APP_GLint *params);
void (APP_GLCALLTYPE* GenBuffers) (APP_GLsizei n, APP_GLuint *buffers);
void (APP_GLCALLTYPE* BindBuffer) (APP_GLenum target, APP_GLuint buffer);
void (APP_GLCALLTYPE* EnableVertexAttribArray) (APP_GLuint index);
void (APP_GLCALLTYPE* VertexAttribPointer) (APP_GLuint index, APP_GLint size, APP_GLenum type, APP_GLboolean normalized, APP_GLsizei stride, void const* pointer);
void (APP_GLCALLTYPE* GenTextures) (APP_GLsizei n, APP_GLuint* textures);
void (APP_GLCALLTYPE* Enable) (APP_GLenum cap);
void (APP_GLCALLTYPE* ActiveTexture) (APP_GLenum texture);
void (APP_GLCALLTYPE* BindTexture) (APP_GLenum target, APP_GLuint texture);
void (APP_GLCALLTYPE* TexParameteri) (APP_GLenum target, APP_GLenum pname, APP_GLint param);
void (APP_GLCALLTYPE* DeleteBuffers) (APP_GLsizei n, APP_GLuint const* buffers);
void (APP_GLCALLTYPE* DeleteTextures) (APP_GLsizei n, APP_GLuint const* textures);
void (APP_GLCALLTYPE* BufferData) (APP_GLenum target, APP_GLsizeiptr size, void const *data, APP_GLenum usage);
void (APP_GLCALLTYPE* UseProgram) (APP_GLuint program);
void (APP_GLCALLTYPE* Uniform1i) (APP_GLint location, APP_GLint v0);
void (APP_GLCALLTYPE* Uniform3f) (APP_GLint location, APP_GLfloat v0, APP_GLfloat v1, APP_GLfloat v2);
APP_GLint (APP_GLCALLTYPE* GetUniformLocation) (APP_GLuint program, APP_GLchar const* name);
void (APP_GLCALLTYPE* TexImage2D) (APP_GLenum target, APP_GLint level, APP_GLint internalformat, APP_GLsizei width, APP_GLsizei height, APP_GLint border, APP_GLenum format, APP_GLenum type, void const* pixels);
void (APP_GLCALLTYPE* ClearColor) (APP_GLfloat red, APP_GLfloat green, APP_GLfloat blue, APP_GLfloat alpha);
void (APP_GLCALLTYPE* Clear) (APP_GLbitfield mask);
void (APP_GLCALLTYPE* DrawArrays) (APP_GLenum mode, APP_GLint first, APP_GLsizei count);
void (APP_GLCALLTYPE* Viewport) (APP_GLint x, APP_GLint y, APP_GLsizei width, APP_GLsizei height);
void (APP_GLCALLTYPE* DeleteShader) (APP_GLuint shader);
void (APP_GLCALLTYPE* DeleteProgram) (APP_GLuint program);
#ifdef APP_REPORT_SHADER_ERRORS
void (APP_GLCALLTYPE* GetShaderInfoLog) (APP_GLuint shader, APP_GLsizei bufSize, APP_GLsizei *length, APP_GLchar *infoLog);
#endif
app_interpolation_t interpolation;
int window_width;
int window_height;
APP_GLuint vertexbuffer;
APP_GLuint texture;
APP_GLuint shader;
};
static int app_internal_opengl_init( app_t* app, struct app_internal_opengl_t* gl, app_interpolation_t interpolation,
int window_width, int window_height )
{
(void) app;
gl->interpolation = interpolation;
gl->window_width = window_width;
gl->window_height = window_height;
char const* vs_source =
#ifdef APP_WASM
"precision highp float;\n"
#else
"#version 120\n"
#endif
"attribute vec4 pos;"
"varying vec2 uv;"
""
"void main( void )"
" {"
" gl_Position = vec4( pos.xy, 0.0, 1.0 );"
" uv = pos.zw;"
" }"
;
char const* fs_source =
#ifdef APP_WASM
"precision highp float;\n"
#else
"#version 120\n"
#endif
"varying vec2 uv;"
""
"uniform sampler2D texture;"
"uniform vec3 modulate;"
""
"void main(void)"
" {"
" gl_FragColor = texture2D( texture, uv ) * vec4( modulate, 1.0 );"
" }"
;
#ifdef APP_REPORT_SHADER_ERRORS
char error_message[ 1024 ];
#endif
APP_GLuint vs = gl->CreateShader( APP_GL_VERTEX_SHADER );
gl->ShaderSource( vs, 1, (char const**) &vs_source, NULL );
gl->CompileShader( vs );
APP_GLint vs_compiled;
gl->GetShaderiv( vs, APP_GL_COMPILE_STATUS, &vs_compiled );
if( !vs_compiled )
{
#ifdef APP_REPORT_SHADER_ERRORS
char const* prefix = "Vertex Shader Error: ";
memcpy( error_message, prefix, strlen( prefix ) + 1 );
int len = 0, written = 0;
gl->GetShaderiv( vs, APP_GL_INFO_LOG_LENGTH, &len );
gl->GetShaderInfoLog( vs, (APP_GLsizei)( sizeof( error_message ) - strlen( prefix ) ), &written,
error_message + strlen( prefix ) );
app_fatal_error( app, error_message );
#endif
return 0;
}
APP_GLuint fs = gl->CreateShader( APP_GL_FRAGMENT_SHADER );
gl->ShaderSource( fs, 1, (char const**) &fs_source, NULL );
gl->CompileShader( fs );
APP_GLint fs_compiled;
gl->GetShaderiv( fs, APP_GL_COMPILE_STATUS, &fs_compiled );
if( !fs_compiled )
{
#ifdef APP_REPORT_SHADER_ERRORS
char const* prefix = "Fragment Shader Error: ";
memcpy( error_message, prefix, strlen( prefix ) + 1 );
int len = 0, written = 0;
gl->GetShaderiv( vs, APP_GL_INFO_LOG_LENGTH, &len );
gl->GetShaderInfoLog( fs, (APP_GLsizei)( sizeof( error_message ) - strlen( prefix ) ), &written,
error_message + strlen( prefix ) );
app_fatal_error( app, error_message );
#endif
return 0;
}
APP_GLuint prg = gl->CreateProgram();
gl->AttachShader( prg, fs );
gl->AttachShader( prg, vs );
gl->BindAttribLocation( prg, 0, "pos" );
gl->LinkProgram( prg );
APP_GLint linked;
gl->GetProgramiv( prg, APP_GL_LINK_STATUS, &linked );
if( !linked )
{
#ifdef APP_REPORT_SHADER_ERRORS
char const* prefix = "Shader Link Error: ";
memcpy( error_message, prefix, strlen( prefix ) + 1 );
int len = 0, written = 0;
gl->GetShaderiv( vs, APP_GL_INFO_LOG_LENGTH, &len );
gl->GetShaderInfoLog( prg, (APP_GLsizei)( sizeof( error_message ) - strlen( prefix ) ), &written,
error_message + strlen( prefix ) );
app_fatal_error( app, error_message );
#endif
return 0;
}
gl->shader = prg;
gl->DeleteShader( fs );
gl->DeleteShader( vs );
gl->GenBuffers( 1, &gl->vertexbuffer );
gl->BindBuffer( APP_GL_ARRAY_BUFFER, gl->vertexbuffer );
gl->EnableVertexAttribArray( 0 );
gl->VertexAttribPointer( 0, 4, APP_GL_FLOAT, APP_GL_FALSE, 4 * sizeof( APP_GLfloat ), 0 );
gl->GenTextures( 1, &gl->texture );
#ifndef APP_WASM
// This enable call is not necessary when using fragment shaders, avoid logged warnings in WebGL
gl->Enable( APP_GL_TEXTURE_2D );