-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathCTurtle.hpp
5932 lines (5332 loc) · 281 KB
/
CTurtle.hpp
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
// MIT License
//
// Copyright (c) 2021 Jesse W. Walker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/**
:::::::: ::::::::::: ::: ::: ::::::::: ::::::::::: ::: ::::::::::
:+: :+: :+: :+: :+: :+: :+: :+: :+: :+:
+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
+#+ +#+ +#+ +:+ +#++:++#: +#+ +#+ +#++:++#
+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+#
######## ### ######## ### ### ### ########## ##########
=================================v1.0.5====================================>
GitHub: https://github.com/walkerje/C-Turtle
Documentation: https://bitshiftmountain.com/projects/cturtle/docs
Semantic Versioning (see https://semver.org/)
Changelog (see https://keepachangelog.com/)
Patch v1.0.5
-----------------02/06/25-------------------
--- Changed
~ Updated dead links to documentation to new host.
~ Removed rendered docs.
Patch v1.0.4
-----------------10/30/21-------------------
--- Changed
~ Fixed a rounding-related position bug making it seem like negative translations were off-by-one while positive ones are not.
~ Only round X and Y coordinate positions if, and only if, it will be used for rendering and explicit integer logic purposes.
Patch v1.0.3
-----------------6/17/21-------------------
--- Added
~ Querying a color that doesn't exist by name now throws a runtime error detailing the issue.
~ Deconstruction behavior is now well-defined for turtle screens and turtles within the same scope.
~ no more segfaults when destroying turtles and their screens out-of-order; one or the other can be destructed first.
~ bye() and exitonclick() are no longer necessary to close an InterativeTurtleScreen
~ Added xcor() and ycor() functions to the Turtle class (returns x coordinate and y coordinate of the related turtle)
--- Changed
~ Rolled-back use of "make_unique" (a C++17 function) in favor of C++11-stable code
~ Remedied many, many clang/(-tidy) warnings throughout.
Patch v1.0.2
-----------------2/25/21-------------------
--- Added
~ Implementation for turtle's goTo function that got erroneously removed.
--- Changed
~ Change isValid for BitmapFont class to consider the size of the glyph vector.
Patch v1.0.1
-----------------2/15/21-------------------
--- Added
~ Added new constructor to Transform class to construct with an position and a rotation.
--- Changed
~ Preprocessor check for M_PI under MSVC was malformed; replaced ifndef with ifdef
~ Implemented polygon line filling for drawLine function, reducing complexity to O(1) from O(n).
~ Removed 100-pixel line width maximum from drawLine function.
Release v1.0.0
-----------------2/13/21-------------------
--- Added
~ Simplistic Bitmap Font Support
~ Default Bitmap Font, Proggy Clean (see https://proggyfonts.net)
~ Support for more dynamic font rendering, specifically allowing control over orientation, scale, and alignment.
~ "face" function to Turtles to orient the turtle towards another Point.
~ "addfont" and "font" function to the TurtleScreen class to register and retrieve user-provided Bitmap Fonts.
~ Appended version number to default title constructors in the TurtleScreen class.
~ Version numbering defines CTURTLE_VERSION_(MAJOR|MINOR|PATCH)
--- Changed
~ Moved turtle function implementations to the inside of the Turtle Class
~ Moved default shape map definition to AbstractTurtleScreen rather than individual screens.
~ Refactored the internal turtle function "pushGeom" to "pushGeometry"
~ Organized include statements, and the top of the file in general.
~ Updated Documentation
~ Changed ivec2 implementation to use a union between an anonymous structure and an 2-wide array of integers
--- Removed
~ N/A
Release v0.2.X
------------------4/23/20------------------
~ See GitHub commit histories 744dd6d through e7e17de
Release v0.1.X
------------------4/23/20------------------
~ See GitHub commit histories a93dc4d through 744dd6d
Release v0.0.X
-------------------9/7/19------------------
~ See GitHub commit histories 12888e7 through a93dc4d
**/
#pragma once
#define CTURTLE_VERSION_MAJOR "1"
#define CTURTLE_VERSION_MINOR "0"
#define CTURTLE_VERSION_PATCH "4"
#define CTURTLE_VERSION "v" CTURTLE_VERSION_MAJOR "." CTURTLE_VERSION_MINOR "." CTURTLE_VERSION_PATCH
#ifdef CTURTLE_HEADLESS
/*Include GIF utility when compiling headless mode.*/
/* public domain, Simple, Minimalistic GIF writer - http://jonolick.com
*
* Quick Notes:
* Supports only 4 component input, alpha is currently ignored. (RGBX)
*
* Latest revisions:
* 1.00 (2015-11-03) initial release
*
* Basic usage:
* char *frame = new char[128*128*4]; // 4 component. RGBX format, where X is unused
* jo_gif_t gif = jo_gif_start("foo.gif", 128, 128, 0, 32);
* jo_gif_frame(&gif, frame, 4, false); // frame 1
* jo_gif_frame(&gif, frame, 4, false); // frame 2
* jo_gif_frame(&gif, frame, 4, false); // frame 3, ...
* jo_gif_end(&gif);
* */
#ifndef JO_INCLUDE_GIF_H
#define JO_INCLUDE_GIF_H
#include <stdio.h>
//Header edited to inline all GIF functionality to avoid re-definitions across compilation units
//otherwise, left the same.
typedef struct {
FILE *fp;
unsigned char palette[0x300];
short width, height, repeat;
int numColors, palSize;
int frame;
} jo_gif_t;
// width/height | the same for every frame
// repeat | 0 = loop forever, 1 = loop once, etc...
// palSize | must be power of 2 - 1. so, 255 not 256.
inline jo_gif_t jo_gif_start(const char *filename, short width, short height, short repeat, int palSize);
// gif | the state (returned from jo_gif_start)
// rgba | the pixels
// delayCsec | amount of time in between frames (in centiseconds)
// localPalette | true if you want a unique palette generated for this frame (does not effect future frames)
inline void jo_gif_frame(jo_gif_t *gif, unsigned char *rgba, short delayCsec, bool localPalette);
// gif | the state (returned from jo_gif_start)
inline void jo_gif_end(jo_gif_t *gif);
#if defined(_MSC_VER) && _MSC_VER >= 0x1400
#define _CRT_SECURE_NO_WARNINGS // suppress warnings about fopen()
#endif
#include <stdlib.h>
#include <memory.h>
#include <math.h>
// Based on NeuQuant algorithm
inline void jo_gif_quantize(unsigned char *rgba, int rgbaSize, int sample, unsigned char *map, int numColors) {
// defs for freq and bias
const int intbiasshift = 16; /* bias for fractions */
const int intbias = (((int) 1) << intbiasshift);
const int gammashift = 10; /* gamma = 1024 */
const int betashift = 10;
const int beta = (intbias >> betashift); /* beta = 1/1024 */
const int betagamma = (intbias << (gammashift - betashift));
// defs for decreasing radius factor
const int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
const int radiusbias = (((int) 1) << radiusbiasshift);
const int radiusdec = 30; /* factor of 1/30 each cycle */
// defs for decreasing alpha factor
const int alphabiasshift = 10; /* alpha starts at 1.0 */
const int initalpha = (((int) 1) << alphabiasshift);
// radbias and alpharadbias used for radpower calculation
const int radbiasshift = 8;
const int radbias = (((int) 1) << radbiasshift);
const int alpharadbshift = (alphabiasshift + radbiasshift);
const int alpharadbias = (((int) 1) << alpharadbshift);
sample = sample < 1 ? 1 : sample > 30 ? 30 : sample;
int network[256][3];
int bias[256] = {}, freq[256];
for(int i = 0; i < numColors; ++i) {
// Put nurons evenly through the luminance spectrum.
network[i][0] = network[i][1] = network[i][2] = (i << 12) / numColors;
freq[i] = intbias / numColors;
}
// Learn
{
const int primes[5] = {499, 491, 487, 503};
int step = 4;
for(int i = 0; i < 4; ++i) {
if(rgbaSize > primes[i] * 4 && (rgbaSize % primes[i])) { // TODO/Error? primes[i]*4?
step = primes[i] * 4;
}
}
sample = step == 4 ? 1 : sample;
int alphadec = 30 + ((sample - 1) / 3);
int samplepixels = rgbaSize / (4 * sample);
int delta = samplepixels / 100;
int alpha = initalpha;
delta = delta == 0 ? 1 : delta;
int radius = (numColors >> 3) * radiusbias;
int rad = radius >> radiusbiasshift;
rad = rad <= 1 ? 0 : rad;
int radSq = rad*rad;
int radpower[32];
for (int i = 0; i < rad; i++) {
radpower[i] = alpha * (((radSq - i * i) * radbias) / radSq);
}
// Randomly walk through the pixels and relax neurons to the "optimal" target.
for(int i = 0, pix = 0; i < samplepixels;) {
int r = rgba[pix + 0] << 4;
int g = rgba[pix + 1] << 4;
int b = rgba[pix + 2] << 4;
int j = -1;
{
// finds closest neuron (min dist) and updates freq
// finds best neuron (min dist-bias) and returns position
// for frequently chosen neurons, freq[k] is high and bias[k] is negative
// bias[k] = gamma*((1/numColors)-freq[k])
int bestd = 0x7FFFFFFF, bestbiasd = 0x7FFFFFFF, bestpos = -1;
for (int k = 0; k < numColors; k++) {
int *n = network[k];
int dist = abs(n[0] - r) + abs(n[1] - g) + abs(n[2] - b);
if (dist < bestd) {
bestd = dist;
bestpos = k;
}
int biasdist = dist - ((bias[k]) >> (intbiasshift - 4));
if (biasdist < bestbiasd) {
bestbiasd = biasdist;
j = k;
}
int betafreq = freq[k] >> betashift;
freq[k] -= betafreq;
bias[k] += betafreq << gammashift;
}
freq[bestpos] += beta;
bias[bestpos] -= betagamma;
}
// Move neuron j towards biased (b,g,r) by factor alpha
network[j][0] -= (network[j][0] - r) * alpha / initalpha;
network[j][1] -= (network[j][1] - g) * alpha / initalpha;
network[j][2] -= (network[j][2] - b) * alpha / initalpha;
if (rad != 0) {
// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
int lo = j - rad;
lo = lo < -1 ? -1 : lo;
int hi = j + rad;
hi = hi > numColors ? numColors : hi;
for(int jj = j+1, m=1; jj < hi; ++jj) {
int a = radpower[m++];
network[jj][0] -= (network[jj][0] - r) * a / alpharadbias;
network[jj][1] -= (network[jj][1] - g) * a / alpharadbias;
network[jj][2] -= (network[jj][2] - b) * a / alpharadbias;
}
for(int k = j-1, m=1; k > lo; --k) {
int a = radpower[m++];
network[k][0] -= (network[k][0] - r) * a / alpharadbias;
network[k][1] -= (network[k][1] - g) * a / alpharadbias;
network[k][2] -= (network[k][2] - b) * a / alpharadbias;
}
}
pix += step;
pix = pix >= rgbaSize ? pix - rgbaSize : pix;
// every 1% of the image, move less over the following iterations.
if(++i % delta == 0) {
alpha -= alpha / alphadec;
radius -= radius / radiusdec;
rad = radius >> radiusbiasshift;
rad = rad <= 1 ? 0 : rad;
radSq = rad*rad;
for (j = 0; j < rad; j++) {
radpower[j] = alpha * ((radSq - j * j) * radbias / radSq);
}
}
}
}
// Unbias network to give byte values 0..255
for (int i = 0; i < numColors; i++) {
map[i*3+0] = network[i][0] >>= 4;
map[i*3+1] = network[i][1] >>= 4;
map[i*3+2] = network[i][2] >>= 4;
}
}
typedef struct {
FILE *fp;
int numBits;
unsigned char buf[256];
unsigned char idx;
unsigned tmp;
int outBits;
int curBits;
} jo_gif_lzw_t;
inline void jo_gif_lzw_write(jo_gif_lzw_t *s, int code) {
s->outBits |= code << s->curBits;
s->curBits += s->numBits;
while(s->curBits >= 8) {
s->buf[s->idx++] = s->outBits & 255;
s->outBits >>= 8;
s->curBits -= 8;
if (s->idx >= 255) {
putc(s->idx, s->fp);
fwrite(s->buf, s->idx, 1, s->fp);
s->idx = 0;
}
}
}
inline void jo_gif_lzw_encode(unsigned char *in, int len, FILE *fp) {
jo_gif_lzw_t state = {fp, 9};
int maxcode = 511;
// Note: 30k stack space for dictionary =|
const int hashSize = 5003;
short codetab[hashSize];
int hashTbl[hashSize];
memset(hashTbl, 0xFF, sizeof(hashTbl));
jo_gif_lzw_write(&state, 0x100);
int free_ent = 0x102;
int ent = *in++;
CONTINUE:
while (--len) {
int c = *in++;
int fcode = (c << 12) + ent;
int key = (c << 4) ^ ent; // xor hashing
while(hashTbl[key] >= 0) {
if(hashTbl[key] == fcode) {
ent = codetab[key];
goto CONTINUE;
}
++key;
key = key >= hashSize ? key - hashSize : key;
}
jo_gif_lzw_write(&state, ent);
ent = c;
if(free_ent < 4096) {
if(free_ent > maxcode) {
++state.numBits;
if(state.numBits == 12) {
maxcode = 4096;
} else {
maxcode = (1<<state.numBits)-1;
}
}
codetab[key] = free_ent++;
hashTbl[key] = fcode;
} else {
memset(hashTbl, 0xFF, sizeof(hashTbl));
free_ent = 0x102;
jo_gif_lzw_write(&state, 0x100);
state.numBits = 9;
maxcode = 511;
}
}
jo_gif_lzw_write(&state, ent);
jo_gif_lzw_write(&state, 0x101);
jo_gif_lzw_write(&state, 0);
if(state.idx) {
putc(state.idx, fp);
fwrite(state.buf, state.idx, 1, fp);
}
}
inline int jo_gif_clamp(int a, int b, int c) { return a < b ? b : a > c ? c : a; }
jo_gif_t jo_gif_start(const char *filename, short width, short height, short repeat, int numColors) {
numColors = numColors > 255 ? 255 : numColors < 2 ? 2 : numColors;
jo_gif_t gif = {};
gif.width = width;
gif.height = height;
gif.repeat = repeat;
gif.numColors = numColors;
gif.palSize = log2(numColors);
gif.fp = fopen(filename, "wb");
if(!gif.fp) {
printf("Error: Could not WriteGif to %s\n", filename);
return gif;
}
fwrite("GIF89a", 6, 1, gif.fp);
// Logical Screen Descriptor
fwrite(&gif.width, 2, 1, gif.fp);
fwrite(&gif.height, 2, 1, gif.fp);
putc(0xF0 | gif.palSize, gif.fp);
fwrite("\x00\x00", 2, 1, gif.fp); // bg color index (unused), aspect ratio
return gif;
}
inline void jo_gif_frame(jo_gif_t *gif, unsigned char * rgba, short delayCsec, bool localPalette) {
if(!gif->fp) {
return;
}
short width = gif->width;
short height = gif->height;
int size = width * height;
unsigned char localPalTbl[0x300];
unsigned char *palette = gif->frame == 0 || !localPalette ? gif->palette : localPalTbl;
if(gif->frame == 0 || localPalette) {
jo_gif_quantize(rgba, size*4, 1, palette, gif->numColors);
}
unsigned char *indexedPixels = (unsigned char *)malloc(size);
{
unsigned char *ditheredPixels = (unsigned char*)malloc(size*4);
memcpy(ditheredPixels, rgba, size*4);
for(int k = 0; k < size*4; k+=4) {
int rgb[3] = { ditheredPixels[k+0], ditheredPixels[k+1], ditheredPixels[k+2] };
int bestd = 0x7FFFFFFF, best = -1;
// TODO: exhaustive search. do something better.
for(int i = 0; i < gif->numColors; ++i) {
int bb = palette[i*3+0]-rgb[0];
int gg = palette[i*3+1]-rgb[1];
int rr = palette[i*3+2]-rgb[2];
int d = bb*bb + gg*gg + rr*rr;
if(d < bestd) {
bestd = d;
best = i;
}
}
indexedPixels[k/4] = best;
int diff[3] = { ditheredPixels[k+0] - palette[indexedPixels[k/4]*3+0], ditheredPixels[k+1] - palette[indexedPixels[k/4]*3+1], ditheredPixels[k+2] - palette[indexedPixels[k/4]*3+2] };
// Floyd-Steinberg Error Diffusion
// TODO: Use something better -- http://caca.zoy.org/study/part3.html
if(k+4 < size*4) {
ditheredPixels[k+4+0] = (unsigned char)jo_gif_clamp(ditheredPixels[k+4+0]+(diff[0]*7/16), 0, 255);
ditheredPixels[k+4+1] = (unsigned char)jo_gif_clamp(ditheredPixels[k+4+1]+(diff[1]*7/16), 0, 255);
ditheredPixels[k+4+2] = (unsigned char)jo_gif_clamp(ditheredPixels[k+4+2]+(diff[2]*7/16), 0, 255);
}
if(k+width*4+4 < size*4) {
for(int i = 0; i < 3; ++i) {
ditheredPixels[k-4+width*4+i] = (unsigned char)jo_gif_clamp(ditheredPixels[k-4+width*4+i]+(diff[i]*3/16), 0, 255);
ditheredPixels[k+width*4+i] = (unsigned char)jo_gif_clamp(ditheredPixels[k+width*4+i]+(diff[i]*5/16), 0, 255);
ditheredPixels[k+width*4+4+i] = (unsigned char)jo_gif_clamp(ditheredPixels[k+width*4+4+i]+(diff[i]*1/16), 0, 255);
}
}
}
free(ditheredPixels);
}
if(gif->frame == 0) {
// Global Color Table
fwrite(palette, 3*(1<<(gif->palSize+1)), 1, gif->fp);
if(gif->repeat >= 0) {
// Netscape Extension
fwrite("\x21\xff\x0bNETSCAPE2.0\x03\x01", 16, 1, gif->fp);
fwrite(&gif->repeat, 2, 1, gif->fp); // loop count (extra iterations, 0=repeat forever)
putc(0, gif->fp); // block terminator
}
}
// Graphic Control Extension
fwrite("\x21\xf9\x04\x00", 4, 1, gif->fp);
fwrite(&delayCsec, 2, 1, gif->fp); // delayCsec x 1/100 sec
fwrite("\x00\x00", 2, 1, gif->fp); // transparent color index (first byte), currently unused
// Image Descriptor
fwrite("\x2c\x00\x00\x00\x00", 5, 1, gif->fp); // header, x,y
fwrite(&width, 2, 1, gif->fp);
fwrite(&height, 2, 1, gif->fp);
if (gif->frame == 0 || !localPalette) {
putc(0, gif->fp);
} else {
putc(0x80|gif->palSize, gif->fp );
fwrite(palette, 3*(1<<(gif->palSize+1)), 1, gif->fp);
}
putc(8, gif->fp); // block terminator
jo_gif_lzw_encode(indexedPixels, size, gif->fp);
putc(0, gif->fp); // block terminator
++gif->frame;
free(indexedPixels);
}
inline void jo_gif_end(jo_gif_t *gif) {
if(!gif->fp) {
return;
}
putc(0x3b, gif->fp); // gif trailer
fclose(gif->fp);
}
#endif /*JO_INCLUDE_GIF_H*/
#endif /*CTURTLE_HEADLESS*/
//Automatic linking when operating under MSVC
//If linking errors occur when compiling on Non-MSVC,
//Make sure you link X11 and PThread when using Unix-Like environments, when NOT using headless mode.
#ifndef CTURTLE_MSVC_NO_AUTOLINK
#ifdef _MSC_VER
/*Automatically link to the necessary windows libraries while under MSVC.*/
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "gdi32.lib")
#endif
#endif
//MSVC 2017 doesn't seem to like defining M_PI. We define it ourselves
//when compiling under VisualC++.
#ifdef _MSC_VER
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
#endif
//When using headless, simply pre-define CTURTLE_CONFIG_HEADLESS.
//This disables the InteractiveTurtleScreen.
//GIF utility is included at the top of the file when under headless mode.
#ifdef CTURTLE_HEADLESS
//Optional define to disable HTML Base64 Image output
//#define CTURTLE_HEADLESS_NO_HTML
//Disable CImg Display
#define cimg_display 0
//Define default width and height.
#ifndef CTURTLE_HEADLESS_WIDTH
#define CTURTLE_HEADLESS_WIDTH 400
#endif
#ifndef CTURTLE_HEADLESS_HEIGHT
#define CTURTLE_HEADLESS_HEIGHT 300
#endif
#ifndef CTURTLE_HEADLESS_SAVEDIR
#define CTURTLE_HEADLESS_SAVEDIR "./cturtle.gif"
#endif
#endif
#ifdef _MSC_VER
//Disable MSVC warnings for CImg. Irrelevant to project.
#include <CodeAnalysis/Warnings.h>
#pragma warning(push, 0)
#pragma warning (disable : ALL_CODE_ANALYSIS_WARNINGS)
#include "CImg.h"
#pragma warning(pop)
#else
#include "CImg.h"
#endif
#include <memory> //For smart pointers.
#include <list> //For the ever-useful list data structure.
#include <unordered_map>//For named color and keys.
#include <chrono> //For time management for movement animations and callbacks.
#include <random> //For random color creation.
#include <functional> //For event function callbacks.
#include <tuple> //Used for CompoundShapes
#include <cstring> //For memcpy
#include <vector> //For Polygon point storage
#include <cmath> //For rounding, etc
#include <algorithm> //For std::count
#include <array> //For Transform storage.
#include <string> //Strings...
#include <cstdint> //For well-defined integer types.
#include <thread> //For the event thread
#include <mutex> //Mutex object for event thread synchronization.
#include <stdexcept> //For standard exceptions.
#include <fstream> //For GIF base-64 encoding to write the file out.
#include <iostream> //For GIF reading.
#include <sstream> //used for base64 encoding.
//See https://github.com/mvorbrodt/blog/blob/master/src/base64.hpp for original source.
//The below has been modified to use unsigned characters to avoid signed->unsigned->signed fiddling.
namespace base64{
static constexpr unsigned char kEncodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static constexpr unsigned char kPadCharacter = '=';
/**
* Encodes a given unsigned character buffer to Base64.
* Can be a file, for example.
* @param input data buffer
* @return Base64 encoded string.
*/
inline std::string encode(const std::vector<unsigned char>& input)
{
std::stringstream encoded;
std::uint32_t temp{};
auto it = input.begin();
for(std::size_t i = 0; i < input.size() / 3; ++i)
{
temp = (*it++) << 16;
temp += (*it++) << 8;
temp += (*it++);
encoded << kEncodeLookup[(temp & 0x00FC0000) >> 18];
encoded << kEncodeLookup[(temp & 0x0003F000) >> 12];
encoded << kEncodeLookup[(temp & 0x00000FC0) >> 6 ];
encoded << kEncodeLookup[(temp & 0x0000003F) ];
}
switch(input.size() % 3)
{
case 1:
temp = (*it++) << 16;
encoded << kEncodeLookup[(temp & 0x00FC0000) >> 18];
encoded << kEncodeLookup[(temp & 0x0003F000) >> 12];
encoded << kPadCharacter << kPadCharacter;
break;
case 2:
temp = (*it++) << 16;
temp += (*it++) << 8;
encoded << kEncodeLookup[(temp & 0x00FC0000) >> 18];
encoded << kEncodeLookup[(temp & 0x0003F000) >> 12];
encoded << kEncodeLookup[(temp & 0x00000FC0) >> 6 ];
encoded << kPadCharacter;
break;
}
return encoded.str();
}
}
namespace cturtle {
/**The CImg library namespace alias used by the CTurtle library.*/
namespace cimg = cimg_library;
/**The common Image type used by CTurtle.*/
typedef cimg::CImg<uint8_t> Image;
namespace detail {
// SECTION: COLORS
// In an effort to make this package easily distributable,
// Colors are defined as packed integers in the header file.
//===========================
typedef uint32_t color_int_t; //Alpha value is extra, serves as padding
typedef uint64_t time_t;
/**
* Pack three bytes into an integer to represent a color at compile time.
* @param r
* @param g
* @param b
* @return
*/
inline constexpr color_int_t resolveColorInt(uint8_t r, uint8_t g, uint8_t b) noexcept{
return ((r & 0xFF) << 16) + ((g & 0xFF) << 8) + (b & 0xFF);
}
/**
* Unpacks R, G, and B bytes to the specified pointer (assumes sequential components).
* @param pack
* @param colorPtr
*/
inline void resolveColorComp(color_int_t pack, uint8_t& r, uint8_t& g, uint8_t& b) {
r = (pack & 0x00FF0000) >> 16; //Red
g = (pack & 0x0000FF00) >> 8; //Green
b = (pack & 0x000000FF); // >> 0; //Blue
}
/**
* Returns the total number of milliseconds elapsed since the UNIX epoch.
* @return
*/
inline time_t epochTime() {
return std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
}
/**\brief Sleeps the calling thread the specified amount of milliseconds.
*\param ms The total number of milliseconds to sleep.*/
inline void sleep(long ms) {
if (ms <= 0)
return;
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
namespace col {
const detail::color_int_t alice_blue = detail::resolveColorInt(240, 248, 255);
const detail::color_int_t AliceBlue = detail::resolveColorInt(240, 248, 255);
const detail::color_int_t antique_white = detail::resolveColorInt(250, 235, 215);
const detail::color_int_t AntiqueWhite = detail::resolveColorInt(250, 235, 215);
const detail::color_int_t AntiqueWhite1 = detail::resolveColorInt(255, 239, 219);
const detail::color_int_t AntiqueWhite2 = detail::resolveColorInt(238, 223, 204);
const detail::color_int_t AntiqueWhite3 = detail::resolveColorInt(205, 192, 176);
const detail::color_int_t AntiqueWhite4 = detail::resolveColorInt(139, 131, 120);
const detail::color_int_t aquamarine = detail::resolveColorInt(127, 255, 212);
const detail::color_int_t aquamarine1 = detail::resolveColorInt(127, 255, 212);
const detail::color_int_t aquamarine2 = detail::resolveColorInt(118, 238, 198);
const detail::color_int_t aquamarine3 = detail::resolveColorInt(102, 205, 170);
const detail::color_int_t aquamarine4 = detail::resolveColorInt(69, 139, 116);
const detail::color_int_t azure = detail::resolveColorInt(240, 255, 255);
const detail::color_int_t azure1 = detail::resolveColorInt(240, 255, 255);
const detail::color_int_t azure2 = detail::resolveColorInt(224, 238, 238);
const detail::color_int_t azure3 = detail::resolveColorInt(193, 205, 205);
const detail::color_int_t azure4 = detail::resolveColorInt(131, 139, 139);
const detail::color_int_t beige = detail::resolveColorInt(245, 245, 220);
const detail::color_int_t bisque = detail::resolveColorInt(255, 228, 196);
const detail::color_int_t bisque1 = detail::resolveColorInt(255, 228, 196);
const detail::color_int_t bisque2 = detail::resolveColorInt(238, 213, 183);
const detail::color_int_t bisque3 = detail::resolveColorInt(205, 183, 158);
const detail::color_int_t bisque4 = detail::resolveColorInt(139, 125, 107);
const detail::color_int_t black = detail::resolveColorInt(0, 0, 0);
const detail::color_int_t blanched_almond = detail::resolveColorInt(255, 235, 205);
const detail::color_int_t BlanchedAlmond = detail::resolveColorInt(255, 235, 205);
const detail::color_int_t blue = detail::resolveColorInt(0, 0, 255);
const detail::color_int_t blue_violet = detail::resolveColorInt(138, 43, 226);
const detail::color_int_t blue1 = detail::resolveColorInt(0, 0, 255);
const detail::color_int_t blue2 = detail::resolveColorInt(0, 0, 238);
const detail::color_int_t blue3 = detail::resolveColorInt(0, 0, 205);
const detail::color_int_t blue4 = detail::resolveColorInt(0, 0, 139);
const detail::color_int_t BlueViolet = detail::resolveColorInt(138, 43, 226);
const detail::color_int_t brown = detail::resolveColorInt(165, 42, 42);
const detail::color_int_t brown1 = detail::resolveColorInt(255, 64, 64);
const detail::color_int_t brown2 = detail::resolveColorInt(238, 59, 59);
const detail::color_int_t brown3 = detail::resolveColorInt(205, 51, 51);
const detail::color_int_t brown4 = detail::resolveColorInt(139, 35, 35);
const detail::color_int_t burlywood = detail::resolveColorInt(222, 184, 135);
const detail::color_int_t burlywood1 = detail::resolveColorInt(255, 211, 155);
const detail::color_int_t burlywood2 = detail::resolveColorInt(238, 197, 145);
const detail::color_int_t burlywood3 = detail::resolveColorInt(205, 170, 125);
const detail::color_int_t burlywood4 = detail::resolveColorInt(139, 115, 85);
const detail::color_int_t cadet_blue = detail::resolveColorInt(95, 158, 160);
const detail::color_int_t CadetBlue = detail::resolveColorInt(95, 158, 160);
const detail::color_int_t CadetBlue1 = detail::resolveColorInt(152, 245, 255);
const detail::color_int_t CadetBlue2 = detail::resolveColorInt(142, 229, 238);
const detail::color_int_t CadetBlue3 = detail::resolveColorInt(122, 197, 205);
const detail::color_int_t CadetBlue4 = detail::resolveColorInt(83, 134, 139);
const detail::color_int_t chartreuse = detail::resolveColorInt(127, 255, 0);
const detail::color_int_t chartreuse1 = detail::resolveColorInt(127, 255, 0);
const detail::color_int_t chartreuse2 = detail::resolveColorInt(118, 238, 0);
const detail::color_int_t chartreuse3 = detail::resolveColorInt(102, 205, 0);
const detail::color_int_t chartreuse4 = detail::resolveColorInt(69, 139, 0);
const detail::color_int_t chocolate = detail::resolveColorInt(210, 105, 30);
const detail::color_int_t chocolate1 = detail::resolveColorInt(255, 127, 36);
const detail::color_int_t chocolate2 = detail::resolveColorInt(238, 118, 33);
const detail::color_int_t chocolate3 = detail::resolveColorInt(205, 102, 29);
const detail::color_int_t chocolate4 = detail::resolveColorInt(139, 69, 19);
const detail::color_int_t coral = detail::resolveColorInt(255, 127, 80);
const detail::color_int_t coral1 = detail::resolveColorInt(255, 114, 86);
const detail::color_int_t coral2 = detail::resolveColorInt(238, 106, 80);
const detail::color_int_t coral3 = detail::resolveColorInt(205, 91, 69);
const detail::color_int_t coral4 = detail::resolveColorInt(139, 62, 47);
const detail::color_int_t cornflower_blue = detail::resolveColorInt(100, 149, 237);
const detail::color_int_t CornflowerBlue = detail::resolveColorInt(100, 149, 237);
const detail::color_int_t cornsilk = detail::resolveColorInt(255, 248, 220);
const detail::color_int_t cornsilk1 = detail::resolveColorInt(255, 248, 220);
const detail::color_int_t cornsilk2 = detail::resolveColorInt(238, 232, 205);
const detail::color_int_t cornsilk3 = detail::resolveColorInt(205, 200, 177);
const detail::color_int_t cornsilk4 = detail::resolveColorInt(139, 136, 120);
const detail::color_int_t cyan = detail::resolveColorInt(0, 255, 255);
const detail::color_int_t cyan1 = detail::resolveColorInt(0, 255, 255);
const detail::color_int_t cyan2 = detail::resolveColorInt(0, 238, 238);
const detail::color_int_t cyan3 = detail::resolveColorInt(0, 205, 205);
const detail::color_int_t cyan4 = detail::resolveColorInt(0, 139, 139);
const detail::color_int_t dark_blue = detail::resolveColorInt(0, 0, 139);
const detail::color_int_t dark_cyan = detail::resolveColorInt(0, 139, 139);
const detail::color_int_t dark_goldenrod = detail::resolveColorInt(184, 134, 11);
const detail::color_int_t dark_gray = detail::resolveColorInt(169, 169, 169);
const detail::color_int_t dark_green = detail::resolveColorInt(0, 100, 0);
const detail::color_int_t dark_grey = detail::resolveColorInt(169, 169, 169);
const detail::color_int_t dark_khaki = detail::resolveColorInt(189, 183, 107);
const detail::color_int_t dark_magenta = detail::resolveColorInt(139, 0, 139);
const detail::color_int_t dark_olive_green = detail::resolveColorInt(85, 107, 47);
const detail::color_int_t dark_orange = detail::resolveColorInt(255, 140, 0);
const detail::color_int_t dark_orchid = detail::resolveColorInt(153, 50, 204);
const detail::color_int_t dark_red = detail::resolveColorInt(139, 0, 0);
const detail::color_int_t dark_salmon = detail::resolveColorInt(233, 150, 122);
const detail::color_int_t dark_sea_green = detail::resolveColorInt(143, 188, 143);
const detail::color_int_t dark_slate_blue = detail::resolveColorInt(72, 61, 139);
const detail::color_int_t dark_slate_gray = detail::resolveColorInt(47, 79, 79);
const detail::color_int_t dark_slate_grey = detail::resolveColorInt(47, 79, 79);
const detail::color_int_t dark_turquoise = detail::resolveColorInt(0, 206, 209);
const detail::color_int_t dark_violet = detail::resolveColorInt(148, 0, 211);
const detail::color_int_t DarkBlue = detail::resolveColorInt(0, 0, 139);
const detail::color_int_t DarkCyan = detail::resolveColorInt(0, 139, 139);
const detail::color_int_t DarkGoldenrod = detail::resolveColorInt(184, 134, 11);
const detail::color_int_t DarkGoldenrod1 = detail::resolveColorInt(255, 185, 15);
const detail::color_int_t DarkGoldenrod2 = detail::resolveColorInt(238, 173, 14);
const detail::color_int_t DarkGoldenrod3 = detail::resolveColorInt(205, 149, 12);
const detail::color_int_t DarkGoldenrod4 = detail::resolveColorInt(139, 101, 8);
const detail::color_int_t DarkGray = detail::resolveColorInt(169, 169, 169);
const detail::color_int_t DarkGreen = detail::resolveColorInt(0, 100, 0);
const detail::color_int_t DarkGrey = detail::resolveColorInt(169, 169, 169);
const detail::color_int_t DarkKhaki = detail::resolveColorInt(189, 183, 107);
const detail::color_int_t DarkMagenta = detail::resolveColorInt(139, 0, 139);
const detail::color_int_t DarkOliveGreen = detail::resolveColorInt(85, 107, 47);
const detail::color_int_t DarkOliveGreen1 = detail::resolveColorInt(202, 255, 112);
const detail::color_int_t DarkOliveGreen2 = detail::resolveColorInt(188, 238, 104);
const detail::color_int_t DarkOliveGreen3 = detail::resolveColorInt(162, 205, 90);
const detail::color_int_t DarkOliveGreen4 = detail::resolveColorInt(110, 139, 61);
const detail::color_int_t DarkOrange = detail::resolveColorInt(255, 140, 0);
const detail::color_int_t DarkOrange1 = detail::resolveColorInt(255, 127, 0);
const detail::color_int_t DarkOrange2 = detail::resolveColorInt(238, 118, 0);
const detail::color_int_t DarkOrange3 = detail::resolveColorInt(205, 102, 0);
const detail::color_int_t DarkOrange4 = detail::resolveColorInt(139, 69, 0);
const detail::color_int_t DarkOrchid = detail::resolveColorInt(153, 50, 204);
const detail::color_int_t DarkOrchid1 = detail::resolveColorInt(191, 62, 255);
const detail::color_int_t DarkOrchid2 = detail::resolveColorInt(178, 58, 238);
const detail::color_int_t DarkOrchid3 = detail::resolveColorInt(154, 50, 205);
const detail::color_int_t DarkOrchid4 = detail::resolveColorInt(104, 34, 139);
const detail::color_int_t DarkRed = detail::resolveColorInt(139, 0, 0);
const detail::color_int_t DarkSalmon = detail::resolveColorInt(233, 150, 122);
const detail::color_int_t DarkSeaGreen = detail::resolveColorInt(143, 188, 143);
const detail::color_int_t DarkSeaGreen1 = detail::resolveColorInt(193, 255, 193);
const detail::color_int_t DarkSeaGreen2 = detail::resolveColorInt(180, 238, 180);
const detail::color_int_t DarkSeaGreen3 = detail::resolveColorInt(155, 205, 155);
const detail::color_int_t DarkSeaGreen4 = detail::resolveColorInt(105, 139, 105);
const detail::color_int_t DarkSlateBlue = detail::resolveColorInt(72, 61, 139);
const detail::color_int_t DarkSlateGray = detail::resolveColorInt(47, 79, 79);
const detail::color_int_t DarkSlateGray1 = detail::resolveColorInt(151, 255, 255);
const detail::color_int_t DarkSlateGray2 = detail::resolveColorInt(141, 238, 238);
const detail::color_int_t DarkSlateGray3 = detail::resolveColorInt(121, 205, 205);
const detail::color_int_t DarkSlateGray4 = detail::resolveColorInt(82, 139, 139);
const detail::color_int_t DarkSlateGrey = detail::resolveColorInt(47, 79, 79);
const detail::color_int_t DarkTurquoise = detail::resolveColorInt(0, 206, 209);
const detail::color_int_t DarkViolet = detail::resolveColorInt(148, 0, 211);
const detail::color_int_t deep_pink = detail::resolveColorInt(255, 20, 147);
const detail::color_int_t deep_sky_blue = detail::resolveColorInt(0, 191, 255);
const detail::color_int_t DeepPink = detail::resolveColorInt(255, 20, 147);
const detail::color_int_t DeepPink1 = detail::resolveColorInt(255, 20, 147);
const detail::color_int_t DeepPink2 = detail::resolveColorInt(238, 18, 137);
const detail::color_int_t DeepPink3 = detail::resolveColorInt(205, 16, 118);
const detail::color_int_t DeepPink4 = detail::resolveColorInt(139, 10, 80);
const detail::color_int_t DeepSkyBlue = detail::resolveColorInt(0, 191, 255);
const detail::color_int_t DeepSkyBlue1 = detail::resolveColorInt(0, 191, 255);
const detail::color_int_t DeepSkyBlue2 = detail::resolveColorInt(0, 178, 238);
const detail::color_int_t DeepSkyBlue3 = detail::resolveColorInt(0, 154, 205);
const detail::color_int_t DeepSkyBlue4 = detail::resolveColorInt(0, 104, 139);
const detail::color_int_t dim_gray = detail::resolveColorInt(105, 105, 105);
const detail::color_int_t dim_grey = detail::resolveColorInt(105, 105, 105);
const detail::color_int_t DimGray = detail::resolveColorInt(105, 105, 105);
const detail::color_int_t DimGrey = detail::resolveColorInt(105, 105, 105);
const detail::color_int_t dodger_blue = detail::resolveColorInt(30, 144, 255);
const detail::color_int_t DodgerBlue = detail::resolveColorInt(30, 144, 255);
const detail::color_int_t DodgerBlue1 = detail::resolveColorInt(30, 144, 255);
const detail::color_int_t DodgerBlue2 = detail::resolveColorInt(28, 134, 238);
const detail::color_int_t DodgerBlue3 = detail::resolveColorInt(24, 116, 205);
const detail::color_int_t DodgerBlue4 = detail::resolveColorInt(16, 78, 139);
const detail::color_int_t firebrick = detail::resolveColorInt(178, 34, 34);
const detail::color_int_t firebrick1 = detail::resolveColorInt(255, 48, 48);
const detail::color_int_t firebrick2 = detail::resolveColorInt(238, 44, 44);
const detail::color_int_t firebrick3 = detail::resolveColorInt(205, 38, 38);
const detail::color_int_t firebrick4 = detail::resolveColorInt(139, 26, 26);
const detail::color_int_t floral_white = detail::resolveColorInt(255, 250, 240);
const detail::color_int_t FloralWhite = detail::resolveColorInt(255, 250, 240);
const detail::color_int_t forest_green = detail::resolveColorInt(34, 139, 34);
const detail::color_int_t ForestGreen = detail::resolveColorInt(34, 139, 34);
const detail::color_int_t gainsboro = detail::resolveColorInt(220, 220, 220);
const detail::color_int_t ghost_white = detail::resolveColorInt(248, 248, 255);
const detail::color_int_t GhostWhite = detail::resolveColorInt(248, 248, 255);
const detail::color_int_t gold = detail::resolveColorInt(255, 215, 0);
const detail::color_int_t gold1 = detail::resolveColorInt(255, 215, 0);
const detail::color_int_t gold2 = detail::resolveColorInt(238, 201, 0);
const detail::color_int_t gold3 = detail::resolveColorInt(205, 173, 0);
const detail::color_int_t gold4 = detail::resolveColorInt(139, 117, 0);
const detail::color_int_t goldenrod = detail::resolveColorInt(218, 165, 32);
const detail::color_int_t goldenrod1 = detail::resolveColorInt(255, 193, 37);
const detail::color_int_t goldenrod2 = detail::resolveColorInt(238, 180, 34);
const detail::color_int_t goldenrod3 = detail::resolveColorInt(205, 155, 29);
const detail::color_int_t goldenrod4 = detail::resolveColorInt(139, 105, 20);
const detail::color_int_t gray = detail::resolveColorInt(190, 190, 190);
const detail::color_int_t gray0 = detail::resolveColorInt(0, 0, 0);
const detail::color_int_t gray1 = detail::resolveColorInt(3, 3, 3);
const detail::color_int_t gray2 = detail::resolveColorInt(5, 5, 5);
const detail::color_int_t gray3 = detail::resolveColorInt(8, 8, 8);
const detail::color_int_t gray4 = detail::resolveColorInt(10, 10, 10);
const detail::color_int_t gray5 = detail::resolveColorInt(13, 13, 13);
const detail::color_int_t gray6 = detail::resolveColorInt(15, 15, 15);
const detail::color_int_t gray7 = detail::resolveColorInt(18, 18, 18);
const detail::color_int_t gray8 = detail::resolveColorInt(20, 20, 20);
const detail::color_int_t gray9 = detail::resolveColorInt(23, 23, 23);
const detail::color_int_t gray10 = detail::resolveColorInt(26, 26, 26);
const detail::color_int_t gray11 = detail::resolveColorInt(28, 28, 28);
const detail::color_int_t gray12 = detail::resolveColorInt(31, 31, 31);
const detail::color_int_t gray13 = detail::resolveColorInt(33, 33, 33);
const detail::color_int_t gray14 = detail::resolveColorInt(36, 36, 36);
const detail::color_int_t gray15 = detail::resolveColorInt(38, 38, 38);
const detail::color_int_t gray16 = detail::resolveColorInt(41, 41, 41);
const detail::color_int_t gray17 = detail::resolveColorInt(43, 43, 43);
const detail::color_int_t gray18 = detail::resolveColorInt(46, 46, 46);
const detail::color_int_t gray19 = detail::resolveColorInt(48, 48, 48);
const detail::color_int_t gray20 = detail::resolveColorInt(51, 51, 51);
const detail::color_int_t gray21 = detail::resolveColorInt(54, 54, 54);
const detail::color_int_t gray22 = detail::resolveColorInt(56, 56, 56);
const detail::color_int_t gray23 = detail::resolveColorInt(59, 59, 59);
const detail::color_int_t gray24 = detail::resolveColorInt(61, 61, 61);
const detail::color_int_t gray25 = detail::resolveColorInt(64, 64, 64);
const detail::color_int_t gray26 = detail::resolveColorInt(66, 66, 66);
const detail::color_int_t gray27 = detail::resolveColorInt(69, 69, 69);
const detail::color_int_t gray28 = detail::resolveColorInt(71, 71, 71);
const detail::color_int_t gray29 = detail::resolveColorInt(74, 74, 74);
const detail::color_int_t gray30 = detail::resolveColorInt(77, 77, 77);
const detail::color_int_t gray31 = detail::resolveColorInt(79, 79, 79);
const detail::color_int_t gray32 = detail::resolveColorInt(82, 82, 82);
const detail::color_int_t gray33 = detail::resolveColorInt(84, 84, 84);
const detail::color_int_t gray34 = detail::resolveColorInt(87, 87, 87);
const detail::color_int_t gray35 = detail::resolveColorInt(89, 89, 89);
const detail::color_int_t gray36 = detail::resolveColorInt(92, 92, 92);
const detail::color_int_t gray37 = detail::resolveColorInt(94, 94, 94);
const detail::color_int_t gray38 = detail::resolveColorInt(97, 97, 97);
const detail::color_int_t gray39 = detail::resolveColorInt(99, 99, 99);
const detail::color_int_t gray40 = detail::resolveColorInt(102, 102, 102);
const detail::color_int_t gray41 = detail::resolveColorInt(105, 105, 105);
const detail::color_int_t gray42 = detail::resolveColorInt(107, 107, 107);
const detail::color_int_t gray43 = detail::resolveColorInt(110, 110, 110);
const detail::color_int_t gray44 = detail::resolveColorInt(112, 112, 112);
const detail::color_int_t gray45 = detail::resolveColorInt(115, 115, 115);
const detail::color_int_t gray46 = detail::resolveColorInt(117, 117, 117);
const detail::color_int_t gray47 = detail::resolveColorInt(120, 120, 120);
const detail::color_int_t gray48 = detail::resolveColorInt(122, 122, 122);
const detail::color_int_t gray49 = detail::resolveColorInt(125, 125, 125);
const detail::color_int_t gray50 = detail::resolveColorInt(127, 127, 127);
const detail::color_int_t gray51 = detail::resolveColorInt(130, 130, 130);
const detail::color_int_t gray52 = detail::resolveColorInt(133, 133, 133);
const detail::color_int_t gray53 = detail::resolveColorInt(135, 135, 135);
const detail::color_int_t gray54 = detail::resolveColorInt(138, 138, 138);
const detail::color_int_t gray55 = detail::resolveColorInt(140, 140, 140);
const detail::color_int_t gray56 = detail::resolveColorInt(143, 143, 143);
const detail::color_int_t gray57 = detail::resolveColorInt(145, 145, 145);
const detail::color_int_t gray58 = detail::resolveColorInt(148, 148, 148);
const detail::color_int_t gray59 = detail::resolveColorInt(150, 150, 150);
const detail::color_int_t gray60 = detail::resolveColorInt(153, 153, 153);
const detail::color_int_t gray61 = detail::resolveColorInt(156, 156, 156);
const detail::color_int_t gray62 = detail::resolveColorInt(158, 158, 158);
const detail::color_int_t gray63 = detail::resolveColorInt(161, 161, 161);
const detail::color_int_t gray64 = detail::resolveColorInt(163, 163, 163);
const detail::color_int_t gray65 = detail::resolveColorInt(166, 166, 166);
const detail::color_int_t gray66 = detail::resolveColorInt(168, 168, 168);
const detail::color_int_t gray67 = detail::resolveColorInt(171, 171, 171);
const detail::color_int_t gray68 = detail::resolveColorInt(173, 173, 173);
const detail::color_int_t gray69 = detail::resolveColorInt(176, 176, 176);
const detail::color_int_t gray70 = detail::resolveColorInt(179, 179, 179);
const detail::color_int_t gray71 = detail::resolveColorInt(181, 181, 181);
const detail::color_int_t gray72 = detail::resolveColorInt(184, 184, 184);
const detail::color_int_t gray73 = detail::resolveColorInt(186, 186, 186);
const detail::color_int_t gray74 = detail::resolveColorInt(189, 189, 189);
const detail::color_int_t gray75 = detail::resolveColorInt(191, 191, 191);
const detail::color_int_t gray76 = detail::resolveColorInt(194, 194, 194);
const detail::color_int_t gray77 = detail::resolveColorInt(196, 196, 196);
const detail::color_int_t gray78 = detail::resolveColorInt(199, 199, 199);
const detail::color_int_t gray79 = detail::resolveColorInt(201, 201, 201);
const detail::color_int_t gray80 = detail::resolveColorInt(204, 204, 204);
const detail::color_int_t gray81 = detail::resolveColorInt(207, 207, 207);
const detail::color_int_t gray82 = detail::resolveColorInt(209, 209, 209);
const detail::color_int_t gray83 = detail::resolveColorInt(212, 212, 212);
const detail::color_int_t gray84 = detail::resolveColorInt(214, 214, 214);
const detail::color_int_t gray85 = detail::resolveColorInt(217, 217, 217);
const detail::color_int_t gray86 = detail::resolveColorInt(219, 219, 219);
const detail::color_int_t gray87 = detail::resolveColorInt(222, 222, 222);
const detail::color_int_t gray88 = detail::resolveColorInt(224, 224, 224);
const detail::color_int_t gray89 = detail::resolveColorInt(227, 227, 227);
const detail::color_int_t gray90 = detail::resolveColorInt(229, 229, 229);
const detail::color_int_t gray91 = detail::resolveColorInt(232, 232, 232);
const detail::color_int_t gray92 = detail::resolveColorInt(235, 235, 235);
const detail::color_int_t gray93 = detail::resolveColorInt(237, 237, 237);
const detail::color_int_t gray94 = detail::resolveColorInt(240, 240, 240);
const detail::color_int_t gray95 = detail::resolveColorInt(242, 242, 242);
const detail::color_int_t gray96 = detail::resolveColorInt(245, 245, 245);
const detail::color_int_t gray97 = detail::resolveColorInt(247, 247, 247);
const detail::color_int_t gray98 = detail::resolveColorInt(250, 250, 250);
const detail::color_int_t gray99 = detail::resolveColorInt(252, 252, 252);
const detail::color_int_t gray100 = detail::resolveColorInt(255, 255, 255);
const detail::color_int_t green = detail::resolveColorInt(0, 255, 0);
const detail::color_int_t green_yellow = detail::resolveColorInt(173, 255, 47);
const detail::color_int_t green1 = detail::resolveColorInt(0, 255, 0);
const detail::color_int_t green2 = detail::resolveColorInt(0, 238, 0);
const detail::color_int_t green3 = detail::resolveColorInt(0, 205, 0);
const detail::color_int_t green4 = detail::resolveColorInt(0, 139, 0);
const detail::color_int_t GreenYellow = detail::resolveColorInt(173, 255, 47);
const detail::color_int_t grey = detail::resolveColorInt(190, 190, 190);
const detail::color_int_t grey0 = detail::resolveColorInt(0, 0, 0);
const detail::color_int_t grey1 = detail::resolveColorInt(3, 3, 3);
const detail::color_int_t grey2 = detail::resolveColorInt(5, 5, 5);
const detail::color_int_t grey3 = detail::resolveColorInt(8, 8, 8);
const detail::color_int_t grey4 = detail::resolveColorInt(10, 10, 10);