-
Notifications
You must be signed in to change notification settings - Fork 9
/
PixelToaster.h
executable file
·1420 lines (1104 loc) · 44.1 KB
/
PixelToaster.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
/*
PixelToaster Framebuffer Library.
Copyright © 2004-2007 Glenn Fiedler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Glenn Fiedler
*/
#ifndef PIXELTOASTER_H
#define PIXELTOASTER_H
// current API version ( API is not allowed to change in point releases )
#define PIXELTOASTER_VERSION 1.5
// disable annoying visual c++ warnings
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4100) // warning C4100: unreferenced formal parameter
# pragma warning(disable : 4201) // warning C4201: nonstandard extension used : nameless struct/union
# pragma warning(disable : 4996) // warning C4201: stupid visual c++ deprecated stuff
#endif
// platforms
#define PIXELTOASTER_NULL 0
#define PIXELTOASTER_APPLE 1
#define PIXELTOASTER_UNIX 2
#define PIXELTOASTER_WINDOWS 3
#if defined(PLATFORM_WINDOWS)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_WINDOWS
#elif defined(PLATFORM_APPLE)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_APPLE
#elif defined(PLATFORM_UNIX)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_UNIX
#elif defined(PLATFORM_NULL)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_NULL
#endif
#ifndef PIXELTOASTER_PLATFORM
# if defined(_WIN32)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_WINDOWS
# elif defined(__APPLE__)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_APPLE
# elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__CYGWIN__)
# define PIXELTOASTER_PLATFORM PIXELTOASTER_UNIX
# else
# define PIXELTOASTER_PLATFORM PIXELTOASTER_NULL
# endif
#endif
// 32 or 64 bits?
#if defined(__LP64__) || defined(__64BIT__) || defined(_LP64) || (__WORDSIZE == 64)
# define PIXELTOASTER_64BIT
#endif
// endianness
#if defined(__LITTLE_ENDIAN__)
# define PIXELTOASTER_LITTLE_ENDIAN
#endif
#if defined(__BIG_ENDIAN__)
# define PIXELTOASTER_BIG_ENDIAN
#endif
#if !defined(PIXELTOASTER_LITTLE_ENDIAN) && !defined(PIXELTOASTER_BIG_ENDIAN)
# if defined(PLATFORM_WINDOWS)
# define PIXELTOASTER_LITTLE_ENDIAN
# elif defined(PLATFORM_APPLE)
# define PIXELTOASTER_BIG_ENDIAN
# else
# define PIXELTOASTER_LITTLE_ENDIAN
# endif
#endif
#if defined(PIXELTOASTER_LITTLE_ENDIAN) && defined(PIXELTOASTER_BIG_ENDIAN)
# error cannot define both big and little endian!
#endif
#if !defined(PIXELTOASTER_LITTLE_ENDIAN) && !defined(PIXELTOASTER_BIG_ENDIAN)
# error endianness not defined
#endif
// dynamic linking
#if defined(_WIN32) && defined(PIXELTOASTER_DYNAMIC)
# ifdef PIXELTOASTER_DLL
# define PIXELTOASTER_API __declspec(dllexport)
# else
# define PIXELTOASTER_API __declspec(dllimport)
# endif
#else
# define PIXELTOASTER_API
#endif
// executable size optimization
#ifdef PIXELTOASTER_TINY
# define PIXELTOASTER_NO_STL
# define PIXELTOASTER_NO_CRT
#endif
#ifndef PIXELTOASTER_NO_STL
# include <vector>
#endif
namespace PixelToaster {
#ifndef PIXELTOASTER_NO_STL
using std::vector;
#endif
using integer32 = unsigned int; ///< unsigned 32 bit integer
using integer16 = unsigned short; ///< unsigned 16 bit integer
using integer8 = unsigned char; ///< unsigned 8 bit integer
/** \brief Represents a pixel in floating point color mode.
Each pixel is made up of three components: red, green and blue.
In floating point color each component is represented by a floating point value.
0.0 is minimum intensity and 1.0 is maximum intensity.
Some examples:
- black (0.0, 0.0, 0.0)
- white (1.0, 1.0, 1.0)
- grey (0.5, 0.5, 0.5)
- red (1.0, 0.0, 0.0)
- purple (1.0, 0.0, 1.0)
- green (0.0, 1.0, 0.0)
Any component less than zero is treated as black, and any value greater than 1.0
is treated as full intensity. You do not need to clamp the component values manually!
You can acheive special effects by exploiting the so called "high dynamic range" available in
floating point color. See http://www.debevec.org for information on this technique.
Also, please note that each floating point pixel contains an alpha value
which you are free to use however you like. For example, it could be used as a z-buffer
for a software renderer, or simply as 4 bytes of storage per pixel for any purpose.
If you dont have any use for the alpha value, its safe to just ignore it.
\note You can refer to this class simply as "Pixel" if you like because floating point color
is the default in Pixel Toaster. See the floating point example source code for details.
**/
class FloatingPointPixel
{
public:
/// The default constructor sets the pixel to black.
FloatingPointPixel()
{
r = 0.0f;
g = 0.0f;
b = 0.0f;
a = 0.0f;
}
/// This convenience constructor lets you specify color and alpha values at creation
FloatingPointPixel(float r, float g, float b, float a = 0.0f)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
float r; ///< red component
float g; ///< green component
float b; ///< blue component
float a; ///< alpha component (unused)
};
/// since floating point color is the default, we setup a typedef to allow users to shortcut it just to "Pixel"
using Pixel = FloatingPointPixel;
/** \brief Represents a pixel in truecolor mode.
Each pixel consists of three 8 bit color values packed into a 32 bit integer.
The color components are stored in the integer in rgb order. The high 8 bits are referred to as 'alpha' but are not used.
Here are some examples:
- black = 0x00000000
- white = 0x00FFFFFF
- grey = 0x007F7F7F
- red = 0x00FF0000
- purple = 0x00FF00FF
- green = 0x0000FF00
Obviously it can get quite tedious manipulating the integer directly, so this union gives you
the option of directly accessing the integer, or manipulating each of the 8 bit component values
directly:
%TrueColorPixel pixel;<br>
pixel.r = 0;<br>
pixel.g = 255;<br>
pixel.b = 0;<br>
And voila, you have a green pixel. Beware though that unlike floating point color,
truecolor does not clamp the components for you. You need to ensure that your values
stay within the [0,255] range or they will wrap around and the pixel color will not
be what you intended.
\note The top 8 bits of the integer are unused and are referred to as 'alpha'.
You can use these bits for 8 bits of per-pixel storage, or ignore them completely,
they have absolutely no effect on the pixel color.
\todo Finish documentation
**/
union TrueColorPixel
{
/// The default constructor sets the pixel to black.
TrueColorPixel()
{
integer = 0;
}
/// This convenience constructor lets you specify color and alpha values at creation
TrueColorPixel(integer8 r, integer8 g, integer8 b, integer8 a = 0)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
/// Construct from an integer
explicit TrueColorPixel(integer32 i)
{
integer = i;
}
integer32 integer; ///< you can work directly with the truecolor integer if you like, but be careful about endianness!
struct
{
#ifdef PIXELTOASTER_LITTLE_ENDIAN
integer8 b; ///< blue component
integer8 g; ///< green component
integer8 r; ///< red component
integer8 a; ///< alpha component
#else
integer8 a; ///< alpha component
integer8 r; ///< red component
integer8 g; ///< green component
integer8 b; ///< blue component
#endif
};
};
/** \brief Lets you chose between floating point and truecolor when you open a display.
Floating point color represents each pixel as four floating point values, while
truecolor packs the color information into a 32bit integer. See FloatingPointPixel and TrueColorPixel for more information.
Please note that this class is just a simple wrapper around an enumeration.
This is done so that you can refer to modes as Mode::TrueColor and Mode::FloatingPoint in your code.
You can assign and compare instances of this class as if they were the enumeration itself.
Here is some example code to demonstrate:
\code
Mode mode = Mode::FloatingPoint;
if ( mode != Mode::TrueColor )
{
mode = Mode::TrueColor;
}
switch ( mode )
{
case Mode::FloatingPoint: print( "floating point mode" ); break;
case Mode::TrueColor: print( "truecolor mode" ); break;
}
Mode a = Mode::FloatingPoint;
Mode b = Mode::TrueColor;
assert( a != b );
assert( ! (a == b) );
Display display( "mode example", 320, 240, Output::Windowed, mode );
if ( display.open() )
{
assert( mode == display.mode() );
}
\endcode
\see Display::open and Display::mode
**/
class Mode
{
public:
/// The internal enumeration wrapped by the Mode class.
/// You should never need to use the enumeration type directly, only the Mode::TrueColor and Mode::FloatingPoint values.
enum Enumeration
{
TrueColor, ///< pixels are represented as packed 32 bit integers. See TrueColorPixel for details.
FloatingPoint ///< pixels are represented by four floating point values for. See FloatingPointPixel for details.
};
/// The mode default constuctor sets the enumeration value to FloatingPoint.
/// Floating point color to considered to be the default throughout the Pixel Toaster API.
Mode()
{
enumeration = FloatingPoint;
}
/// This constructor enables automatic conversion from the enumeration type to a mode object.
/// For example: Mode mode = Mode::FloatingPoint;
/// @param enumeration the enumeration value.
Mode(Enumeration enumeration)
{
this->enumeration = enumeration;
}
/// Cast from mode object to enumeration.
/// Allows you to treat this class as if it was the enumeration itself.
/// This enables the ==, != operators, and the use of mode objects in a switch statement.
operator Enumeration() const
{
return enumeration;
}
private:
Enumeration enumeration;
};
// this is an internal class representing the set of supported pixel formats.
// because conversion occurs automatically when you update the display the details of the underlying display format are hidden.
// if we decide to expose the converter class as a publically supported class, then this class must also become public.
class Format
{
public:
/// The internal enumeration wrapped by the Format class.
/// You should never need to use the enumeration type directly, just use the enumeration values such as Format::RGB565, Format::RGB888 etc.
enum Enumeration
{
Unknown, ///< unknown pixel format.
XRGB8888, ///< 32 bit truecolor. this is the native pixel format in Mode::TrueColor.
XBGR8888, ///< 32 bit truecolor in BGR order.
RGB888, ///< 24 bit truecolor.
BGR888, ///< 24 bit truecolor in BGR order.
RGB565, ///< 16 bit hicolor.
BGR565, ///< 16 bit hicolor in BGR order.
XRGB1555, ///< 15 bit hicolor.
XBGR1555, ///< 15 bit hicolor in BGR order.
XBGRFFFF, ///< 128bit floating point color. this is the native pixel format in Mode::FloatingPoint.
};
/// The default constructor sets the enumeration value to Unknown.
Format()
{
enumeration = Unknown;
}
/// This constructor enables automatic conversion from the enumeration type to a format object.
/// For example: Format format = Format::RGB565;
/// @param enumeration the enumeration value.
Format(Enumeration enumeration)
{
this->enumeration = enumeration;
}
/// Cast from format object to enumeration.
/// Allows you to treat this class as if it was the enumeration itself.
/// This enables the ==, != operators, and the use of format objects in a switch statement.
operator Enumeration() const
{
return enumeration;
}
private:
Enumeration enumeration;
};
/** \brief Lets you chose between fullscreen and windowed when opening a display.
Display output can be either "windowed" or "fullscreen". Windowed output opens a display window on the desktop
and draws your pixels inside this window. Fullscreen output switches to the best display mode mode and fills the
entire screen with your pixels.
An additional "default" output type is used to indicate that you want to open a display and use the 'best'
output mode for the current platform. This is a rather nebulous concept. Currently the default output mode just
maps to windowed mode, but this may change in the future. The bottom line is that if you absolutely require
fullscreen or windowed output, you should specify this, or the display will just do whatever it thinks is best.
Here is some example code to demonstrate output use:
\code
Output output = Output::Fullscreen;
if ( output != Output::Windowed )
{
output = Output::Windowed;
}
switch ( output )
{
case Output::Default: print( "default output" ); break;
case Output::Windowed: print( "windowed output" ); break;
case Output::Fullscreen: print( "fullscreen output" ); break;
}
Output a = Mode::Windowed
Output b = Mode::Fullscreen;
assert( a != b );
assert( ! (a == b) );
Display display( "output example", 320, 240, output );
if ( display.open() )
{
assert( output == display.output() );
}
display.close();
display.open( "default output example", 320, 240, Output::Default );
if ( display.open() )
{
assert( display.output != Output::Default );
switch ( output )
{
case Output::Windowed: print( "default output is windowed" ); break;
case Output::Fullscreen: print( "default output is fullscreen" ); break;
}
}
\endcode
\see Display::open and Display::output.
**/
class Output
{
public:
/// %Output enumeration.
enum Enumeration
{
Default, ///< default output. let the display choose between windowed and fullscreen. windowed output is preferred if available.
Windowed, ///< windowed output. output pixels to a window.
Fullscreen ///< fullscreen output. switch to a fullscreen display mode.
};
/// The default constructor sets the enumeration value to Default.
Output()
{
enumeration = Default;
}
/// This constructor enables automatic conversion from the enumeration type to an output object.
/// @param enumeration the enumeration value.
Output(Enumeration enumeration)
{
this->enumeration = enumeration;
}
/// Cast from output object to enumeration.
/// Allows you to treat this class as if it was the enumeration itself.
/// This enables the ==, != operators, and the use of output objects in a switch statement.
operator Enumeration() const
{
return enumeration;
}
private:
Enumeration enumeration;
};
/** \brief Describes the current mouse position and the state of the left, right and middle mouse buttons.
This class is used by the Listener interface for each of the event callbacks for mouse input.
\see Listener::onMouseButtonDown, Listener::onMouseButtonUp and Listener::onMouseMove.
\note The mouse position is stored as floating point values because the coordinates are relative to the size
of the display, not the size of the window. So if you open a display with dimensions 100x100 then the user
resizes the window to 200x100, then you will get x mouse coordinates 100.5, 101.0, 101.5, 102.0, 102.5 etc...
**/
class Mouse
{
public:
/// Indicates which mouse buttons are currently being pressed.
class Buttons
{
public:
bool left; ///< true if left button is pressed.
bool middle; ///< true if middle button is pressed.
bool right; ///< true if right button is pressed.
};
Buttons buttons; ///< mouse button state. indicates which mouse buttons are currently pressed.
float x; ///< current mouse cursor x position. standard range is from 0 to display width - 1, from left to right. values outside this range occur when the user drags the mouse outside the display window.
float y; ///< current mouse cursor y position. standard range is from 0 to display height - 1, from top to bottom. values outside this range occur when the user drags the mouse outside the display window.
};
/** \brief Identifies a single key on the keyboard.
For all intents and purposes you may treat an instance of this class as if
it was the key code enumeration value itself.
Here is some example code to demonstrate:
\code
Key key = Key::Escape;
if ( key != Key::Enter )
{
key = Key::Space;
}
switch ( key )
{
case Key::Enter: print( "enter key" ); break;
case Key::Space: print( "space key" ); break;
case Key::Escape: print( "escape key" ); break;
}
Key a = Key::A;
Key b = Key::B;
assert( a != b );
assert( ! (a == b) );
\endcode
\see Listener::onKeyDown, Listener::onKeyPressed and Listener::onKeyUp
**/
class Key
{
public:
/// Key code enumeration.
/// You should never need to use this enumeration type directly, just use the enumeration values Key::Enter, Key::Left, Key::Escape etc...
enum Code
{
Enter = '\n', ///< enter key
BackSpace = '\b', ///< backspace key
Tab = '\t', ///< tab key
Cancel = 0x03, ///< cancel key
Clear = 0x0C, ///< clear key
Shift = 0x10, ///< shift key
Control = 0x11, ///< control key
Alt = 0x12, ///< alt key
Pause = 0x13, ///< pause key
CapsLock = 0x14, ///< capslock key
Escape = 0x1B, ///< escape key
Space = 0x20, ///< space key
PageUp = 0x21, ///< page up key
PageDown = 0x22, ///< page down key
End = 0x23, ///< end key
Home = 0x24, ///< home key
Left = 0x25, ///< left key
Up = 0x26, ///< up arrow key
Right = 0x27, ///< right arrow key
Down = 0x28, ///< down arrow key
Comma = 0x2C, ///< comma key ','
Period = 0x2E, ///< period key '.'
Slash = 0x2F, ///< slash key '/'
Zero = 0x30, ///< zero key
One = 0x31, ///< one key
Two = 0x32, ///< two key
Three = 0x33, ///< three key
Four = 0x34, ///< four key
Five = 0x35, ///< five key
Six = 0x36, ///< six key
Seven = 0x37, ///< seven key
Eight = 0x38, ///< eight key
Nine = 0x39, ///< nine key
SemiColon = 0x3B, ///< semicolon key ';'
Equals = 0x3D, ///< equals key '='
A = 0x41, ///< a key
B = 0x42, ///< b key
C = 0x43, ///< c key
D = 0x44, ///< d key
E = 0x45, ///< e key
F = 0x46, ///< f key
G = 0x47, ///< g key
H = 0x48, ///< h key
I = 0x49, ///< i key
J = 0x4A, ///< j key
K = 0x4B, ///< k key
L = 0x4C, ///< l key
M = 0x4D, ///< m key
N = 0x4E, ///< n key
O = 0x4F, ///< o key
P = 0x50, ///< p key
Q = 0x51, ///< q key
R = 0x52, ///< r key
S = 0x53, ///< s key
T = 0x54, ///< t key
U = 0x55, ///< u key
V = 0x56, ///< v key
W = 0x57, ///< w key
X = 0x58, ///< x key
Y = 0x59, ///< y key
Z = 0x5A, ///< z key
OpenBracket = 0x5B, ///< open bracket key '['
BackSlash = 0x5C, ///< back slash key '\'
CloseBracket = 0x5D, ///< close bracket key ']'
NumPad0 = 0x60, ///< numpad 0 key
NumPad1 = 0x61, ///< numpad 1 key
NumPad2 = 0x62, ///< numpad 2 key
NumPad3 = 0x63, ///< numpad 3 key
NumPad4 = 0x64, ///< numpad 4 key
NumPad5 = 0x65, ///< numpad 5 key
NumPad6 = 0x66, ///< numpad 6 key
NumPad7 = 0x67, ///< numpad 7 key
NumPad8 = 0x68, ///< numpad 8 key
NumPad9 = 0x69, ///< numpad 9 key
Multiply = 0x6A, ///< multiply key '*'
Add = 0x6B, ///< add key '+'
Separator = 0x6C, ///< separator key '-'
Subtract = 0x6D, ///< subtract key '-'
Decimal = 0x6E, ///< decimal key '.'
Divide = 0x6F, ///< divide key '/'
F1 = 0x70, ///< F1 key
F2 = 0x71, ///< F2 key
F3 = 0x72, ///< F3 key
F4 = 0x73, ///< F4 key
F5 = 0x74, ///< F5 key
F6 = 0x75, ///< F6 key
F7 = 0x76, ///< F7 key
F8 = 0x77, ///< F8 key
F9 = 0x78, ///< F9 key
F10 = 0x79, ///< F10 key
F11 = 0x7A, ///< F11 key
F12 = 0x7B, ///< F12 key
Delete = 0x7F, ///< delete key
NumLock = 0x90, ///< numlock key
ScrollLock = 0x91, ///< scroll lock key
PrintScreen = 0x9A, ///< print screen key
Insert = 0x9B, ///< insert key
Help = 0x9C, ///< help key
Meta = 0x9D, ///< meta key
BackQuote = 0xC0, ///< backquote key
Quote = 0xDE, ///< quote key
Final = 0x18, ///< final key
Convert = 0x1C, ///< convert key
NonConvert = 0x1D, ///< non convert key
Accept = 0x1E, ///< accept key
ModeChange = 0x1F, ///< mode change key
Kana = 0x15, ///< kana key
Kanji = 0x19, ///< kanji key
Undefined = 0x0 ///< undefined key
};
/// The default constructor sets the key code to Undefined.
Key()
{
code = Undefined;
}
/// Automatically converts from key code enumeration values to key objects.
/// @param code the key code.
Key(Code code)
{
this->code = code;
}
/// Cast from key object to code.
/// Allows you to treat this class as if it was the code itself.
/// This enables the ==, != operators, and the use of key objects in a switch statement.
operator Code() const
{
return code;
}
private:
Code code;
};
// Rectangular range of pixels: [xBegin, xEnd) x [yBegin, yEnd)
//
struct Rectangle
{
int xBegin; ///< first column in range
int xEnd; ///< one past last column in range
int yBegin; ///< first row in range
int yEnd; ///< one past last row in range
Rectangle()
: xBegin(0)
, xEnd(0)
, yBegin(0)
, yEnd(0)
{
}
Rectangle(int xb, int xe, int yb, int ye)
: xBegin(xb)
, xEnd(xe)
, yBegin(yb)
, yEnd(ye)
{
}
};
// internal factory methods
PIXELTOASTER_API class DisplayInterface* createDisplay();
PIXELTOASTER_API class TimerInterface* createTimer();
PIXELTOASTER_API class Converter* requestConverter(Format source, Format destination);
// internal display interface
class DisplayInterface
{
public:
virtual ~DisplayInterface() = default;
virtual bool open(const char title[], int width, int height, Output output = Output::Default, Mode mode = Mode::FloatingPoint) = 0;
virtual void close() = 0;
virtual bool open() const = 0;
virtual bool update(const FloatingPointPixel pixels[], const Rectangle* dirtyBox = nullptr) = 0;
virtual bool update(const TrueColorPixel pixels[], const Rectangle* dirtyBox = nullptr) = 0;
virtual const char* title() const = 0;
virtual void title(const char title[]) = 0;
virtual int width() const = 0;
virtual int height() const = 0;
virtual Mode mode() const = 0;
virtual Output output() const = 0;
virtual void listener(class Listener* listener) = 0;
virtual class Listener* listener() const = 0;
virtual void wrapper(DisplayInterface* wrapper) = 0;
virtual DisplayInterface* wrapper() = 0;
};
/** \brief Provides the mechanism for getting your pixels up on the screen.
Every Pixel Toaster application needs a display. Lets analyze a simple application to understand exactly what is going on:
\code
Display display( "Example", 320, 240 );
vector<Pixel> pixels( 320 * 240 );
while ( display.open() )
{
display.update( pixels );
}
\endcode
In a nutshell, the simple application does the following:
- Create and open a display
- Create an array of pixels to work with
- Loop and update the pixels to the display
All you need to do is implement your rendering code and do it each frame before you update the display.
Each time display update is called the array of pixels are copied to the display, so you can see them!
Now lets actually draw something. Here is the same code again, but this time each update we set a random pixel to the color blue:
\code
const int width = 320;
const int height = 240;
Display display( "Example", width, height );
vector<Pixel> pixels( width, height );
while ( display.open() )
{
const int x = rand() % width;
const int y = rand() % height;
pixels[x+y*width].b = 1.0f;
display.update( pixels );
}
\endcode
**/
class Display : public DisplayInterface
{
public:
/// Creates the display object but does not open the display.
/// You need to call Display::open first before you can copy pixels to the display with Display::update.
Display()
{
internal = createDisplay();
internal->wrapper(this);
}
/// Create and open display in one step.
/// This is equivalent to creating a display using the default constructor then calling Display::open.
/// \see Display::open
Display(const char title[], int width, int height, Output output = Output::Default, Mode mode = Mode::FloatingPoint)
{
internal = createDisplay();
internal->wrapper(this);
open(title, width, height, output, mode);
}
/// Destructor.
/// Closes the display if it is still open.
virtual ~Display() override
{
if (internal)
{
delete internal;
internal = nullptr;
}
}
/// Open display.
/// Opens the display by creating an output window or entering fullscreen mode.
/// @param title the title of the display window or fullscreen application.
/// @param width the width of the display in pixels.
/// @param height the height of the display in pixels.
/// @param output the output type of the display. you can choose between windowed output and fullscreen output, or you can leave it up to the display by passing in default.
/// @param mode the mode of operation for the display. you can choose between true color mode and floating point color mode.
/// @returns true if the display open was successful.
bool open(const char title[], int width, int height, Output output = Output::Default, Mode mode = Mode::FloatingPoint) override
{
if (internal)
return internal->open(title, width, height, output, mode);
else
return false;
}
/// Close display.
/// Closes the display window or leaves fullscreen mode.
/// This method is safe to call even if the display not open.
void close() override
{
if (internal)
internal->close();
}
/// Check if display is open.
bool open() const override
{
if (internal)
return internal->open();
else
return false;
}
/// Update display with floating point pixels.
/// The input pixels must be a linear array of size width x height, where width and height are the
/// dimensions of the display as per the most recent successful call to Display::open.
/// You can calculate the offset for a pixel in the linear array as follows: int offset = width*y + x;
/// This is the correct update method to call when the display was opened in Mode::FloatingPoint,
/// however it is safe to call this method even when operating in Mode::TrueColor if you wish.
///
/// The dirty box acts as a @b hint to the update function that only pixels inside that box have been changed
/// since last update. The update function does not need to respect this hint and may do a full update
/// instead. In particular, it will do this if it can avoid a buffer copy when matching formats are found.
/// That's why you still need to provide a full buffer of pixels, and the ones outside dirtyBox should
/// be the same pixels as the previous call.
///
/// @param pixels the pixels to copy to the screen.
/// @param dirtyBox range of pixels that have been changed since last call.
/// @returns true if the update was successful.
bool update(const class FloatingPointPixel pixels[], const Rectangle* dirtyBox = nullptr) override
{
if (internal)
return internal->update(pixels, dirtyBox);
else
return false;
}
/// Update display with truecolor pixels.
/// The input pixels must be a linear array of size width x height, where width and height are the
/// dimensions of the display as per the most recent successful call to Display::open.
/// You can calculate the offset for a pixel in the linear array as follows: int offset = width*y + x;
/// This is the natural update method to call when the display was opened in Mode::TrueColor,
/// however it is safe to call this method even when operating in Mode::FloatingPoint if you wish.
///
/// The dirty box acts as a @b hint to the update function that only pixels inside that box have been changed
/// since last update. The update function does not need to respect this hint and may do a full update
/// instead. In particular, it will do this if it can avoid a buffer copy when matching formats are found.
/// That's why you still need to provide a full buffer of pixels, and the ones outside dirtyBox should
/// be the same pixels as the previous call.
///
/// @param pixels the pixels to copy to the screen.
/// @param dirtyBox range of pixels that have been changed since last call.
/// @returns true if the update was successful.
bool update(const TrueColorPixel pixels[], const Rectangle* dirtyBox = nullptr) override
{
if (internal)
return internal->update(pixels, dirtyBox);
else
return false;
}
#ifndef PIXELTOASTER_NO_STL
/// Update display with standard vector of floating point pixels.
/// This is just a helper method to make it a bit cleaner to pass a vector of pixels into the update.
/// @param pixels the pixels to copy to the screen.
/// @returns true if the update was successful.
bool update(const vector<FloatingPointPixel>& pixels, const Rectangle* dirtyBox = nullptr)
{
return update(pixels.data(), dirtyBox);
}
/// Update display with standard vector of truecolor pixels.
/// This is just a helper method to make it a bit cleaner to pass a vector of pixels into the update.
/// @param pixels the pixels to copy to the screen.
/// @returns true if the update was successful.
bool update(const vector<TrueColorPixel>& pixels, const Rectangle* dirtyBox = nullptr)
{
return update(pixels.data(), dirtyBox);
}
#endif
/// Get display title
const char* title() const override
{
if (internal)
return internal->title();
else