Bare Metal Programming Tool Kit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
graphics.h
1 // ==========================================================================
2 //
3 // file: bmptk/graphics/bmptk-graphics.h
4 //
5 // ==========================================================================
6 
7 #ifndef BMPTK_GRAPHICS_H
8 #define BMPTK_GRAPHICS_H
9 
10 #include <iostream>
11 #include <limits>
12 
13 namespace bmptk {
14 
16 namespace graphics {
17 
18 // ==========================================================================
19 //
20 // class vector
21 //
23 //
50 //
51 
52 class vector {
53 private:
54 
56  static int sign( short int x ){
57  return ( x > 0 ) - (x < 0); }
58 
60  static bool is_within( short int x, short int m ){
61  return (( x >= 0 ) && ( x < m )) || (( x <= 0 ) && ( x > m )); }
62 
64  short int x;
65 
67  short int y;
68 
69 public:
70 
72  vector(): x( 0 ), y( 0 ) {}
73 
75  vector( short int x, short int y ): x( x ), y( y ) {}
76 
78  short int x_get() const { return x; }
79 
81  short int y_get() const { return y; }
82 
84  vector operator + ( const vector p ) const {
85  return vector( x + p.x, y + p.y ); }
86 
89  return vector( x += p.x, y += p.y ); }
90 
92  vector operator + ( void ) const {
93  return vector( x, y ); }
94 
96  vector operator - ( const vector p ) const {
97  return vector( x - p.x, y - p.y ); }
98 
101  return vector( x -= p.x, y -= p.y ); }
102 
104  vector operator - ( void ) const {
105  return vector( - x, - y ); }
106 
108  vector operator / ( int n ) const {
109  return vector( x / n, y / n ); }
110 
112  vector & operator /= ( int n ){
113  x /= n;
114  y /= n;
115  return *this;
116  }
117 
119  vector operator * ( int n ) const {
120  return vector( x * n, y * n ); }
121 
123  vector & operator *= ( int n ){
124  x *= n;
125  y *= n;
126  return *this;
127  }
128 
130  vector operator * ( const vector rhs ) const {
131  return vector( x * rhs.x, y * rhs.y ); }
132 
134  bool operator == ( const vector p ) const {
135  return ( x == p.x ) && ( y == p.y ); }
136 
138  bool operator != ( const vector p ) const {
139  return ! ( *this == p ); }
140 
142  //
147  vector direction( void ) const {
148  return vector( sign( x ), sign( y )); }
149 
151  //
156  vector abs( void ) const {
157  // std::abs is not present in DevKitPro??
158  return vector(
159  ( x >= 0 ) ? x : -x,
160  ( y >= 0 ) ? y : -y );
161  }
162 
164  //
166  vector x_projection( void ) const {
167  return vector( x, 0 ); }
168 
170  //
172  vector y_projection( void ) const {
173  return vector( 0, y ); }
174 
176  //
178  vector mirrored( void ) const {
179  return vector( y, x ); }
180 
182  //
187  bool is_within( const vector p ) const {
188  return is_within( x, p.x ) && is_within( y, p.y ); }
189 
191  static vector origin(){ return vector( 0, 0 ); }
192 
194  static vector zero(){ return vector( 0, 0 ); }
195 
197  static vector one(){ return vector( 1, 1 ); }
198 };
199 
201 //
209 vector max(
210  vector a,
211  vector b,
212  vector c = vector::origin(),
213  vector d = vector::origin()
214 );
215 
217 vector operator * ( int n, const vector v );
218 
220 //
223 std::ostream & operator<< ( std::ostream &s, const vector p );
224 
225 
226 // ==========================================================================
227 //
228 // class color
229 //
231 //
256 //
257 
258 class color {
259 private:
260 
261  static int clip( int x ){
262  return ( x < 0 ) ? 0 : ( x > 0xFF ? 0xFF : x ); }
263 
264  bool transp;
265  unsigned char r;
266  unsigned char g;
267  unsigned char b;
268 
269 public:
270 
272  //
278  color( int r, int g, int b, bool t = 0 ):
279  transp( t ), r( clip( r )), g( clip( g )), b( clip( b ))
280  {
281  if( t ){ r = g = b = 0; }
282  }
283 
285  //
287  color( unsigned int rgb = 0 ):
288  transp( 0 ),
289  r( clip( ( rgb & 0xFF0000 ) >> 16 )),
290  g( clip( ( rgb & 0x00FF00 ) >> 8 )),
291  b( clip( ( rgb & 0x0000FF ) >> 0 )){}
292 
294  unsigned int rgb15_get( void ) const {
295  return (
296  ((unsigned int)( r & 0xF8 ) >> 3 )
297  | ((unsigned int)( g & 0xF8 ) << 2 )
298  | ((unsigned int)( b & 0xF8 ) << 7 )
299  );
300  }
301 
303  //
305  bool is_transparent() const { return transp; }
306 
308  //
311  unsigned char red_get() const { return r; }
312 
314  //
317  unsigned char green_get() const { return g; }
318 
320  //
323  unsigned char blue_get() const { return b; }
324 
326  color operator + ( const color c ) const {
327  return color(
328  r + (int)c.r,
329  g + (int)c.g,
330  b + (int)c.b,
331  transp && c.transp ); }
332 
334  const color & operator += ( const color c ){
335  r = clip( r + (int)c.r );
336  g = clip( g + (int)c.g );
337  b = clip( b + (int)c.b );
338  transp = transp && c.transp;
339  return *this;
340  }
341 
343  color operator + ( void ) const {
344  return color( r, g, b, transp ); }
345 
347  color operator - ( const color c ) const {
348  return color(
349  r - (int)c.r,
350  g - (int)c.g,
351  b - (int)c.b,
352  transp && c.transp ); }
353 
355  color & operator -= ( const color c ){
356  r = clip( r - (int)c.r );
357  g = clip( g - (int)c.g );
358  b = clip( b - (int)c.b );
359  transp = transp && c.transp;
360  return *this;
361  }
362 
364  color operator - ( void ) const {
365  return color(
366  0xFF - (int)r,
367  0xFF - (int)g,
368  0xFF - (int)b,
369  transp ); }
370 
372  color operator / ( unsigned int n ) const {
373  return color( r / n, g / n, b / n, transp ); }
374 
376  color & operator /= ( unsigned int n ){
377  r = clip( r / n );
378  g = clip( g / n );
379  b = clip( b / n );
380  return *this;
381  }
382 
384  color operator * ( unsigned int n ) const {
385  return color( r * n, g * n, b * n, transp ); }
386 
388  color & operator *= ( unsigned int n ){
389  r = clip( r * n );
390  g = clip( g * n );
391  b = clip( b * n );
392  return *this;
393  }
394 
396  bool operator == ( const color c ) const {
397  return transp ? c.transp :
398  ( ! c.transp ) && ( r == c.r ) && ( g == c.g ) && ( b == c.b ); }
399 
401  bool operator != ( const color c ) const {
402  return ! ( *this == c ); }
403 
405  color mixed_with( const color c ) const {
406  return color(
407  ( r + c.r ) / 2,
408  ( g + c.g ) / 2,
409  ( b + c.b ) / 2,
410  transp && c.transp ); }
411 
413  //
419 
420  // these 'constants' are delibreately NOT Doxygen-documented
421  static color black() { return color( 0, 0, 0 ); }
422  static color white() { return color( 0xFF, 0xFF, 0xFF ); }
423  static color red() { return color( 0xFF, 0, 0 ); }
424  static color green() { return color( 0, 0xFF, 0 ); }
425  static color blue() { return color( 0, 0, 0xFF ); }
426  static color gray() { return color( 0x80, 0x80, 0x80 ); }
427  static color yellow() { return color( 0xFF, 0xFF, 0 ); }
428  static color cyan() { return color( 0, 0xFF, 0xFF ); }
429  static color magenta() { return color( 0xFF, 0, 0xFF ); }
430  static color transparent() { return color( 0, 0, 0, 1 ); }
431  static color violet() { return color( 0xEE82EE ); }
432  static color sienna() { return color( 0xA0522D ); }
433  static color purple() { return color( 0x800080 ); }
434  static color pink() { return color( 0xFFC8CB ); }
435  static color silver() { return color( 0xC0C0C0 ); }
436  static color brown() { return color( 0xA52A2A ); }
437  static color salmon() { return color( 0xFA8072 ); }
438 
439 };
440 
442 //
446 std::ostream & operator << ( std::ostream &s, const color c );
447 
448 
449 // ==========================================================================
450 //
451 // class event
452 //
453 
455 //
460 //
461 enum event_type {
462 
464  //
469 
471  //
476 
478  //
484 
486  //
496 
498  //
505 
507  //
513 };
514 
518 //
519 const char * event_type_name( const event_type e );
520 
524 //
525 std::ostream & operator<<( std::ostream &s, const event_type &e );
526 
528 //
549 //
550 class event {
551 
555  const vector location;
556 
558  const event_type e;
559 
560 public:
561 
563  event( const vector p, const event_type e ):
564  location( p ), e( e ) {}
565 
567  vector location_get() const { return location; }
568 
570  event_type event_type_get() const { return e; }
571 
572 };
573 
575 //
580 std::ostream & operator<<( std::ostream &s, const event &e );
581 
582 
583 // forward declaration needed because drawable
584 // must know its frame
585 class frame;
586 
587 
588 // ==========================================================================
589 //
590 // class drawable
591 //
593 //
596 //1 frame where it can draw itself, and
604 //
605 class drawable {
606 private:
607 
609  drawable( const drawable &rhs );
610 
612  drawable & operator=( const drawable &rhs );
613 
614 protected:
615 
618 
621 
624 
627 
629  unsigned int width;
630 
632  //
636  void drawable_draw_pixel(
637  const vector address,
638  const color c
639  ) const;
640 
642  //
647  frame &fr,
648  const vector position = vector::origin(),
649  const color fg = color::black(),
650  const color bg = color::transparent(),
651  unsigned int width = 1
652  ): fr( fr ), position( position ), fg( fg ), bg( bg ), width( width ) {}
653 
654 public:
655 
657  frame &frame_get() const { return fr; }
658 
660  const vector position_get() const { return position; }
661 
663  color fg_get() const { return fg; }
664 
666  color bg_get() const { return bg; }
667 
669  unsigned int width_get() const { return width; }
670 
672  void position_set( const vector pos ){ position = pos; }
673 
675  void fg_set( const color c ){ fg = c; }
676 
678  void bg_set( const color c ){ bg = c; }
679 
681  void width_set( unsigned int w ){ width = w; }
682 
684  virtual void draw() const = 0;
685 
686 };
687 
688 
689 // ==========================================================================
690 //
691 // class frame
692 //
694 //
702 //
703 
704 class frame {
705 private:
706 
708  frame( const frame &rhs );
709 
711  frame & operator=( const frame &rhs );
712 
713 
714 protected:
715 
717  const vector size;
718 
721 
723  //
726  virtual void checked_write( const vector p, const color c ) = 0;
727 
728 public:
729 
731  frame( const vector size ): size( size ), bg( color::white()) {}
732 
734  vector size_get() const { return size; }
735 
737  virtual vector translate_outfrom( const vector p ) const {
738  return p; }
739 
741  virtual vector translate_into( const vector p ) const {
742  return p; }
743 
745  bool is_valid( vector p ){
746  return p.is_within( size ); }
747 
749  //
752  color bg_get(){ return bg; }
753 
755  //
758  void write( const vector p, const color c ){
759  if( is_valid( p ) ){ checked_write( p, c ); }}
760 
762  //
765  virtual void clear( const color c = color::white() );
766 
768  //
772  virtual void flush(){}
773 };
774 
775 
776 // ==========================================================================
777 //
778 // class frame_dummy
779 //
781 //
782 
783 class frame_dummy : public frame {
784 public:
785 
787  //
794 
795 protected:
796 
798  //
801  void checked_write( const vector p, const color c ){}
802 };
803 
804 
805 // ==========================================================================
806 //
807 // class frame_buffer
808 //
810 //
826 
827 class frame_buffer : public frame {
828 private:
830  frame &f;
831 
833  color *pixels;
834 
836  //
839  color & pixel( vector p ){
840  return pixels[ p.x_get() + f.size_get().x_get() * p.y_get() ];
841  }
842 
843  color pixel( vector p ) const {
844  return pixels[ p.x_get() + f.size_get().x_get() * p.y_get() ];
845  }
846 
848  frame_buffer( const frame_buffer &rhs );
849 
851  void operator=( const frame_buffer &rhs );
852 
853 public:
854 
856  //
861  frame( fr.size_get()),
862  f( fr )
863  {
864  pixels = new color[ f.size_get().x_get() * f.size_get().y_get() ];
865  for( int x = 0; x < f.size_get().x_get(); x++ ){
866  for( int y = 0; y < f.size_get().y_get(); y++ ){
867  pixel( vector( x, y )) = color::transparent();
868  }
869  }
870  }
871 
873  virtual ~frame_buffer(){
874  delete[] pixels;
875  }
876 
878  void checked_write( const vector p, const color c ){
879  pixel( p ) = c;
880  }
881 
883  //
886  void flush(){
887  for( int x = 0; x < f.size_get().x_get(); x++ ){
888  for( int y = 0; y < f.size_get().y_get(); y++ ){
889  vector p( x, y );
890  if( ! pixel( p ).is_transparent() ){
891  f.write( p, pixel( p ));
892  pixel( p ) = color::transparent();
893  }
894  }
895  }
896  f.flush();
897  }
898 
900  void clear( const color c = color::white() ){
901  bg = c;
902  frame::clear( c );
903  }
904 
905 };
906 
907 
908 // ==========================================================================
909 //
910 // class frame_snapshot
911 //
913 //
919 
920 class frame_snapshot : public frame {
921 private:
923  frame &f;
924 
926  color *pixels;
927 
929  //
932  color & pixel( vector p ){
933  return pixels[ p.x_get() + f.size_get().x_get() * p.y_get() ];
934  }
935 
936  color pixel( vector p ) const {
937  return pixels[ p.x_get() + f.size_get().x_get() * p.y_get() ];
938  }
939 
941  frame_snapshot( const frame_snapshot &rhs );
942 
944  void operator=( const frame_snapshot &rhs );
945 
946 public:
947 
949  //
954  frame( fr.size_get()),
955  f( fr )
956  {
957  pixels = new color[ f.size_get().x_get() * f.size_get().y_get() ];
958  for( int x = 0; x < f.size_get().x_get(); x++ ){
959  for( int y = 0; y < f.size_get().y_get(); y++ ){
960  pixel( vector( x, y )) = color::transparent();
961  }
962  }
963  }
964 
966  virtual ~frame_snapshot(){
967  delete[] pixels;
968  }
969 
971  void checked_write( const vector p, const color c ){
972  if( ! c.is_transparent() ){
973  pixel( p ) = c;
974  }
975  f.write( p, c );
976  }
977 
979  void flush(){
980  f.flush();
981  }
982 
984  void clear( const color c = color::white() ){
985  bg = c;
986  frame::clear( c );
987  }
988 
990  //
995  void write_to_bmp_file( const char *file_name );
996 
997 };
998 
999 
1000 // ==========================================================================
1001 //
1002 // class frame_tee
1003 //
1005 //
1008 
1009 class frame_tee : public frame {
1010 private:
1011  frame &f1, &f2, &f3, &f4;
1012 
1013  static frame & frame_dummy_ref(){
1014  static frame_dummy dummy;
1015  return dummy;
1016  }
1017 
1018 public:
1019 
1022  frame &f1,
1023  frame &f2,
1024  frame &f3 = frame_dummy_ref(),
1025  frame &f4 = frame_dummy_ref()
1026  ):
1027  frame( max(
1028  f1.size_get(),
1029  f2.size_get(),
1030  f3.size_get(),
1031  f4.size_get() )),
1032  f1( f1 ),
1033  f2( f2 ),
1034  f3( f3 ),
1035  f4( f4 ){}
1036 
1038  void checked_write( const vector p, const color c ){
1039  f1.write( p, c );
1040  f2.write( p, c );
1041  f3.write( p, c );
1042  f4.write( p, c );
1043  }
1044 
1046  void flush(){
1047  f1.flush();
1048  f2.flush();
1049  f3.flush();
1050  f4.flush();
1051  }
1052 
1054  void clear( const color c = color::white() ){
1055  bg = c;
1056  f1.clear( c );
1057  f2.clear( c );
1058  f3.clear( c );
1059  f4.clear( c );
1060  }
1061 };
1062 
1063 
1064 // ==========================================================================
1065 //
1066 // class frame_filter
1067 //
1069 //
1076 
1077 class frame_filter : public frame {
1078 private:
1079  frame &f;
1080  color (&filter)(color);
1081  void (&writer)(frame &f, vector p, color c, color bg );
1082 
1083  static color default_filter( color c ){ return c; }
1084  static void default_writer( frame &f, vector p, color c, color bg ){
1085  f.write( p, c ); }
1086 
1087 public:
1088 
1090  frame_filter( frame &f, color (&filter)(color) ):
1091  frame( f.size_get()),
1092  f( f ),
1093  filter( filter ),
1094  writer( frame_filter::default_writer ){}
1095 
1098  frame &f,
1099  void (&writer)(frame &f, vector p, color c, color bg )
1100  ):
1101  frame( f.size_get()),
1102  f( f ),
1103  filter( frame_filter::default_filter ),
1104  writer( writer ){}
1105 
1107  void checked_write( const vector p, const color c ){
1108  writer( f, p, filter( c ), bg );
1109  }
1110 
1112  void flush(){
1113  f.flush();
1114  }
1115 
1117  void clear( const color c = color::white() ){
1118  bg = filter( c );
1119  f.clear( bg );
1120  }
1121 };
1122 
1123 
1124 // ==========================================================================
1125 //
1126 // class subframe
1127 //
1129 //
1138 #ifdef notyet
1139 
1140 
1141 
1142 
1143 
1144 
1145 
1146 
1147 
1148 
1149 
1150 
1151 
1152 
1153 
1154 #endif
1155 //
1156 
1157 class subframe : public frame {
1158 public:
1159 
1162 
1165 
1168 
1169 #ifdef notyet
1170 
1171  const unsigned int scale;
1172 #endif
1173 
1175  const bool swapped;
1176 
1178  vector translate_outfrom( const vector p ) const {
1179  vector x(
1181  ? top_left.x_get() + p.x_get()
1182  : top_left.x_get() - p.x_get(),
1184  ? top_left.y_get() + p.y_get()
1185  : top_left.y_get() - p.y_get()
1186  );
1187  if( swapped ){
1188  x = x.mirrored();
1189  }
1190  return x;
1191  }
1192 
1194  vector translate_into( const vector p ) const {
1195  vector x(
1197  ? p.x_get() - top_left.x_get()
1198  : ( - p.x_get()) - top_left.x_get(),
1200  ? + p.y_get()- top_left.y_get()
1201  : ( - p.y_get()) - top_left.y_get()
1202  );
1203  if( swapped ){
1204  x = x.mirrored();
1205  }
1206  return x;
1207  }
1208 
1211  frame &f,
1212  vector top_left,
1213  vector direction,
1214 #ifdef notyet
1215  unsigned int scale = 1,
1216 #endif
1217  bool swapped = false
1218  ):
1219  frame( direction.abs() ),
1220  master( f ),
1221  top_left( top_left ),
1222  bottom_right( top_left + direction - direction.direction() ),
1223 #ifdef notyet
1224  scale( scale ),
1225 #endif
1226  swapped( swapped ){}
1227 
1228 protected:
1229 
1231  //
1235  void checked_write( const vector p, const color c ){
1236  if( is_valid( p )){
1237  vector q = swapped ? p.mirrored() : p;
1238 #ifdef notyet
1239  for( unsigned int x = 0; x < scale; x++ ){
1240  for( unsigned int y = 0; y < scale; y++ ){
1241  master.write( translate( q * scale + vector( x, y )), c );
1242  }}}}
1243 #else
1244  master.write( translate_outfrom( q ), c );
1245  }
1246  }
1247 #endif
1248 
1249 };
1250 
1251 
1252 // ==========================================================================
1253 //
1254 // class line
1255 //
1257 //
1265 //
1266 
1267 class line : public drawable {
1268 public:
1269 
1271  //
1277 
1280  frame &frame,
1281  const vector position,
1282  const vector size,
1283  const color fg = color::black(),
1284  int width = 1
1285  ):
1286  drawable(
1287  frame,
1288  position,
1289  fg,
1290  color::transparent(),
1291  width
1292  ), size( size ){}
1293 
1294 
1296  void draw() const;
1297 };
1298 
1299 
1300 // ==========================================================================
1301 //
1302 // class rectangle
1303 
1307 enum relief {
1308 
1311 
1314 
1317 };
1318 
1322 relief flip( const relief r );
1323 
1327 std::ostream & operator<<( std::ostream &s, const relief &r );
1328 
1329 //
1331 //
1342 //
1343 
1344 class rectangle : public drawable {
1345 private:
1347  rectangle( const rectangle & );
1348 
1350  void operator=( const rectangle & rhs );
1351 
1352 public:
1353 
1355  //
1359 
1361  //
1365 
1367  //
1370 
1372  //
1377 
1380  frame &frame,
1381  const vector position,
1382  const vector size,
1383  const color fg = color::black(),
1384  const color bg = color::transparent(),
1385  int width = 1,
1386  relief rel = relief_flat
1387  ):
1388  drawable( frame, position, fg, bg, width ),
1389  bright( fg ),
1390  dark( fg / 4 ),
1391  border( rel ),
1392  size( size ){}
1393 
1395  void draw() const;
1396 };
1397 
1398 
1399 // ==========================================================================
1400 //
1401 // class circle
1402 //
1404 //
1410 //
1411 
1412 class circle : public drawable {
1413 private:
1414 
1415  void circle_draw(
1416  const color c,
1417  bool fill
1418  ) const;
1419 
1420  void circle_draw_pixel(
1421  const vector v,
1422  const color c
1423  ) const;
1424 
1425 public:
1426 
1432  unsigned int radius;
1433 
1436  frame &frame,
1437  const vector position,
1438  unsigned int radius,
1439  const color fg = color::black(),
1440  const color bg = color::transparent(),
1441  unsigned int width = 1
1442  ):
1443  drawable( frame, position, fg, bg, width ), radius( radius ){}
1444 
1446  void draw() const;
1447 };
1448 
1449 
1450 // ==========================================================================
1451 //
1452 // class image
1453 //
1455 //
1457 //
1458 class image {
1459 private:
1460 
1462  image( const image &rhs );
1463 
1465  image & operator=( const image &rhs );
1466 
1467 public:
1468 
1470  image(){}
1471 
1473  virtual void draw(
1474  frame &frame,
1475  const vector position = vector::origin() ) const = 0;
1476 };
1477 
1478 
1479 // ==========================================================================
1480 //
1481 // class image_pixels
1482 //
1484 //
1494 //
1495 class image_pixels : public image {
1496 protected:
1497 
1500 
1502  //
1507  virtual color checked_read( const vector p ) const = 0;
1508 
1509 public:
1510 
1512  image_pixels( vector size ): size( size ){}
1513 
1515  vector size_get() const { return size; }
1516 
1518  bool is_valid( const vector p ) const {
1519  return p.is_within( size ); }
1520 
1526  virtual void draw(
1527  frame &frame,
1528  const vector position = vector::origin() ) const;
1529 
1531  //
1535  color read( const vector p ) const {
1536  if( is_valid( p )){
1537  return checked_read( p );
1538  } else {
1539  return color::transparent();
1540  }
1541  }
1542 };
1543 
1544 
1545 // ==========================================================================
1546 //
1547 // class inline_rgb_photo
1548 //
1550 //
1558 //
1559 
1561 private:
1562 
1564  const unsigned char *data;
1565 
1567  color checked_read( const vector p ) const;
1568 
1569 public:
1570 
1572  inline_rgb_photo( vector size, const unsigned char *data ):
1573  image_pixels( size ), data( data ){}
1574 
1575 };
1576 
1577 // ==========================================================================
1578 //
1579 // class inline_bw_photo
1580 //
1582 //
1598 //
1599 
1601 private:
1602 
1604  const unsigned char *data;
1605 
1606  color fg, bg;
1607 
1608 public:
1609 
1611  bool bool_read( const vector p ) const;
1612 
1615 
1617  const vector size,
1618 
1620  //
1624  const unsigned char *data
1625  ):
1626  image_pixels( size ),
1627  data( data )
1628  {
1629  fg = color::black();
1630  bg = color::white();
1631  }
1632 
1633 private:
1634 
1636  color checked_read( const vector p ) const {
1637  return bool_read( p ) ? fg : bg; }
1638 };
1639 
1640 
1641 // ==========================================================================
1642 //
1643 // class font
1644 //
1646 //
1655 //
1656 
1657 class font {
1658 public:
1659 
1661  bool const fixed;
1662 
1664  bool const proportional;
1665 
1668 
1670  font( bool fixed, const vector char_size ):
1671  fixed( fixed ), proportional( ! fixed ), font_char_size( char_size ){}
1672 
1674  //
1677  virtual bool has( char c ) const = 0;
1678 
1680  virtual bool read( char c, const vector p ) const = 0;
1681 
1683  //
1686  virtual vector char_size( char c ) const = 0;
1687 
1688 };
1689 
1690 
1691 // ==========================================================================
1692 //
1693 // class char_photo
1694 //
1696 //
1710 //
1711 
1712 class char_photo : public image_pixels {
1713 public:
1714 
1716  const font &f;
1717 
1719  const char c;
1720 
1722  const color fg;
1723 
1725  const color bg;
1726 
1729  const font &f,
1730  char c,
1731  const color fg = color::black(),
1732  const color bg = color::transparent()
1733  ):
1734  image_pixels( f.char_size( c )),
1735  f( f ),
1736  c( c ),
1737  fg( fg ),
1738  bg( bg )
1739  {}
1740 
1742  color checked_read( const vector p ) const {
1743  return f.read( c, p ) ? fg : bg; }
1744 
1745 };
1746 
1747 
1748 // ==========================================================================
1749 //
1750 // class inline_font
1751 //
1753 //
1765 //
1766 
1767  // font type
1768  // picture is a picture of the characters in the font,
1769  // stored as one long line
1770  // when list is NULL the characters 0x20 .. 0x7F are supported,
1771  // otherwise it is a (0-terminated) list of characters
1772  // for a fixed-width font x_size is the width of a char,
1773  // and start is NULL
1774  // for a proportional font x_size is 0, and
1775  // start points to an array with the x-offsets of each
1776  // character. The first offset is of course 0, but
1777  // still stored, and there are 0x61 offsets (not 0x60!)
1778 
1779 class inline_font : public font, public inline_bw_photo {
1780 public:
1781 
1783  const int *start;
1784 
1787 
1789  bool fixed,
1790 
1792  const vector char_size,
1793 
1795  const int *start,
1796 
1798  const vector size,
1799 
1801  const unsigned char *data
1802  ):
1803  font( fixed, char_size ),
1804  inline_bw_photo( size, data ),
1805  start( start )
1806  {}
1807 
1809  bool has( char c ) const {
1810  if( ( c < ' ' ) || ( c >= 127 ) ) return false;
1811  return start[ (int) c - 32 ] >= 0;
1812  }
1813 
1815  vector char_size( char c ) const;
1816 
1818  bool read( char c, const vector p ) const;
1819 };
1820 
1821 
1822 // ==========================================================================
1823 //
1824 // class format
1825 
1830 
1833 
1836 
1839 
1842 };
1843 
1847 std::ostream & operator<<( std::ostream &s, const font_alignment &a );
1848 
1850 const inline_font & font_default();
1851 
1852 //
1854 //
1869 //
1870 
1871 class format {
1872 public:
1874  const font &f;
1875 
1878 
1881 
1883  bool wrap;
1884 
1886  unsigned int scale;
1887 
1890 
1893 
1896 
1899 
1902 
1913  const font &f = font_default(),
1914  font_alignment h = align_near,
1915  font_alignment v = align_near,
1916  bool wrap = 0,
1917  unsigned int scale = 1,
1918  vector spacing = vector::origin(),
1919  vector top_left_margin = vector( 2,2 ),
1920  vector bottom_right_margin = vector( 2,2 ),
1921  color fg = color::black(),
1922  color bg = color::transparent()
1923  ):
1924  f( f ),
1925  h( h ),
1926  v( v ),
1927  wrap( wrap ),
1928  scale( scale ),
1929  spacing( spacing ),
1930  top_left_margin( top_left_margin ),
1931  bottom_right_margin( bottom_right_margin ),
1932  fg( fg ),
1933  bg( bg )
1934  {}
1935 
1937  format( const format &fmt, const font &fr ):
1938  f( fr ),
1939  h( fmt.h ),
1940  v( fmt.v ),
1941  wrap( fmt.wrap ),
1942  scale( fmt.scale ),
1943  spacing( fmt.spacing ),
1944  top_left_margin( fmt.top_left_margin ),
1945  bottom_right_margin( fmt.bottom_right_margin ),
1946  fg( fmt.fg ),
1947  bg( fmt.bg )
1948  {}
1949 };
1950 
1952 std::ostream & operator<<( std::ostream &s, const format &f );
1953 
1954 
1955 // ==========================================================================
1956 //
1957 // class text
1958 //
1960 //
1966 //
1967 class text : public image {
1968 public:
1969 
1971  const char *s;
1972 
1975 
1979  //
1984  const char *s,
1985 
1987  //
1990  const format f = format()
1991  ): s( s ), f( f ){}
1992 
1994  //
1998  void draw( frame &f, const vector position = vector::origin() ) const;
1999 };
2000 
2001 
2003 class frame_console_stringbuf : public std::streambuf {
2004 private:
2005  frame &fr;
2006  vector cursor;
2007  format fm;
2008 
2009  void print( char c );
2010  std::streamsize xsputn ( const char * s, std::streamsize n );
2011 
2012 public:
2013 
2014  frame_console_stringbuf( frame &fr, format fm ):
2015  fr( fr ),
2016  cursor(0,0),
2017  fm( fm )
2018  {}
2019 
2020 };
2022 
2023 // ==========================================================================
2024 //
2025 // class frame_console
2026 //
2028 //
2031 //
2032 
2033 class frame_console : public std::ostream {
2034 private:
2035  frame_console_stringbuf buf;
2036 public:
2038  //
2052  //
2053  frame_console( frame &f, format fo = format() ):
2054  // std::ios(0),
2055  std::ostream(&buf),
2056  buf( f, fo )
2057  {}
2058 };
2059 
2060 
2061 // ==========================================================================
2062 //
2063 // A sheet is a graphical object, ultimately to be shown in a frame,
2064 // that can show ASCII text
2065 //
2066 
2067 #ifdef nono
2068 class sheet_base : public drawable {
2069 protected:
2070  const char * buffer;
2071  unsigned int size;
2072  sheet_base( ){}
2073  void add( char c );
2074  void clear(){}
2075  void draw(){}
2076 }
2077 
2078 template< unsigned int charsize > class sheet : public sheet_base {
2079  char buffer[ charsize + 1 ];
2080 public:
2081  sheet( ): sheet_base( , ){}
2082 }
2083 
2084 
2085 
2086 // ==========================================================================
2087 //
2088 // A widget is a graphical object, ultimately to be shown in a frame,
2089 // that can handle events in some way, and can draw itself.
2090 //
2091 
2092 class widget {
2093 protected:
2094  widget * children, * next_child;
2095 public:
2096  const widget *toplevel, *parent;
2097  frame *inner;
2098  bool changed;
2099 
2100  widget( widget * toplevel, widget * parent, frame *f ):
2101  children( 0 ), next_child( 0 ),
2102  toplevel( toplevel ), parent( parent ),
2103  inner( f ), changed( 1 )
2104  {}
2105 
2106  widget( widget * parent, frame *f ):
2107  children( 0 ), next_child( 0 ),
2108  toplevel( parent->toplevel ), parent( parent ),
2109  inner( f ), changed( 1 )
2110  {
2111  parent->add( this ); }
2112 
2113  void add( widget * w ){
2114  w->next_child = children;
2115  children = w; }
2116 
2117  void redraw( bool forced = 0 ){
2118  if( forced ){
2119  changed = 1;
2120  }
2121  if( changed ){
2122  draw();
2123  }
2124  for( widget *w = children; w != 0; w = w->next_child ){
2125  w->redraw( changed );
2126  }
2127  changed = 0;
2128  }
2129 
2130  virtual void handle( const event &e ){
2131  for( widget *w = children; w != 0; w = w->next_child ){
2132  event ew( w->inner->translate(
2133  e.location_get() ),
2134  e.event_type_get() );
2135  if( ew.location_get().is_within( w->inner->size_get() )){
2136  w->handle( ew );
2137  }
2138  }
2139  };
2140 
2141  virtual void draw( void ){};
2142 };
2143 
2144 
2145 // ==========================================================================
2146 //
2147 // A wframe is a widget that has a border around its inner frame.
2148 // This frame has a fixed width, but the colors and the relief can be
2149 // changed.
2150 //
2151 
2152 class wframe : public widget {
2153 private:
2154  subframe subf;
2155 public:
2156  const vector size;
2157  vector origin;
2158  relief border;
2159  color bg;
2160 
2161  wframe(
2162  widget &parent,
2163  const vector size,
2164  const vector &origin = vector( 0, 0 ),
2165  const color &bg = color::red(),
2166  const relief border = relief_raised
2167  ):
2168  widget( &parent, &subf ),
2169  subf( *parent.inner, origin, origin + size ),
2170  size( size ),
2171  origin( origin ),
2172  border( border ),
2173  bg( bg )
2174  {}
2175 
2176  void handle( const event &e ){
2177  //trace << e;
2178  if( e.event_type_get() == event_down ){
2179  bg = color( bg.red_get(), bg.green_get(), bg.blue_get() ^ 0xFFFF );
2180  border = flip( border );
2181  //trace << border;
2182  changed = 1;
2183  }
2184  };
2185 
2186  void draw( void ){
2187  subf.clear( bg );
2188  }
2189 };
2190 
2191 
2192 // ==========================================================================
2193 //
2194 // A wpaint is a widget that paints wherever a touch event occurs.
2195 //
2196 
2197 class wpaint : public widget {
2198 private:
2199  subframe subf;
2200 public:
2201  const vector size;
2202  vector origin;
2203  relief border;
2204  color bg, fg;
2205 
2206  wpaint(
2207  widget &parent,
2208  const vector size,
2209  const vector origin = vector( 0, 0 ),
2210  const color &bg = color::red(),
2211  const color &fg = color::blue()
2212  ):
2213  widget( &parent, &subf ),
2214  subf( *parent.inner, origin, origin + size ),
2215  size( size ),
2216  origin( origin ),
2217  bg( bg ), fg( fg )
2218  {}
2219 
2220  void handle( const event &e ){
2221  if( e.event_type_get() == event_touch ){
2222  inner->write( e.location_get(), fg );
2223  }
2224  };
2225 
2226  void draw( void ){
2227  subf.clear( bg );
2228  }
2229 };
2230 
2231 
2232 // ==========================================================================
2233 //
2234 // A wtoplevel is a widget that has an associated graphics frame
2235 // and a way to get the events that occur within that frame.
2236 //
2237 // It has a run method that keeps getting and handling events
2238 // (untill it gets an event_exit).
2239 //
2240 
2241 class wtoplevel : public widget {
2242 public:
2243  color bg;
2244 
2245  wtoplevel( frame &f, const color &bg ):
2246  widget( this, this, &f ), bg( bg ) {}
2247 
2248  virtual event event_get( void ) = 0;
2249 
2250  void draw( void ){
2251  inner->clear( bg ); }
2252 
2253  void run( void );
2254 };
2255 #endif
2256 
2257 } // namespace graphics
2258 } // namespace bmptk
2259 
2260 #endif // #ifdef BMPTK_GRAPHICS_H