VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gxcanvas.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gxcanvas.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gxdef.h"
23 #include "gxcanvas.h"
24 #include "gxdisplay.h"
25 #include "gxwindow.h"
26 #include "gxcolourmap.h"
27 #include "glog.h"
28 #include "gtest.h"
29 #include "gassert.h"
30 #include "gstr.h"
31 #include "grcolour16.h"
32 #include "grglyph.h"
33 #include <stdexcept>
34 #include <utility>
35 
36 GX::Canvas::Canvas( GX::Window & window , int dx , int dy , int colours , bool server_side ) :
37  m_window(window) ,
38  m_dx(dx>0?dx:window.dx()) ,
39  m_dy(dy>0?dy:window.dy()) ,
40  m_colours(colours) ,
41  m_client_side(!server_side) ,
42  m_aspect_top(7) ,
43  m_aspect_bottom(10) ,
44  m_pixmap(m_window.windowDisplay(),m_window,m_dx,m_dy) ,
45  m_image(m_window.windowDisplay(),m_window,m_dx,m_dy) ,
46  m_context(m_window.windowDisplay(),m_window) ,
47  m_stereo_mode(normal)
48 {
49  if( G::Test::enabled("gxcanvas-server-side") ) m_client_side = false ;
50  if( G::Test::enabled("gxcanvas-client-side") ) m_client_side = true ;
51  if( G::Test::enabled("gxcanvas-palette") ) colours = m_colours = 16 ;
52  G_ASSERT( colours == 0 || colours == 16 || colours == 256 ) ; // rgb,bios,greyscale
53  if( m_colours != 0 )
54  {
55  m_colour_map.reset( new GX::ColourMap( m_window.windowDisplay() , m_colours == 256 ) ) ;
56  m_window.install( *m_colour_map.get() ) ;
57  }
58 }
59 
61 {
62 }
63 
64 int GX::Canvas::dx() const
65 {
66  return m_dx ;
67 }
68 
69 int GX::Canvas::dy() const
70 {
71  return m_dy ;
72 }
73 
75 {
76  return m_colours ;
77 }
78 
79 std::pair<unsigned int,unsigned int> GX::Canvas::aspect() const
80 {
81  return std::make_pair( m_aspect_top , m_aspect_bottom ) ;
82 }
83 
84 Gr::Colour GX::Canvas::colour( unsigned int n ) const
85 {
86  G_ASSERT( m_colours != 0 && static_cast<int>(n) < m_colours ) ;
87  return Gr::Colour( n , 0U , 0U ) ;
88 }
89 
91 {
92  return m_colours == 0 ? Gr::Colour() : colour(0U) ;
93 }
94 
96 {
97  return m_colours == 0 ? Gr::Colour(255,255,255) : (m_colours==16?colour(1U):colour(255U)) ;
98 }
99 
100 namespace
101 {
102  struct out
103  {
104  out( GX::Canvas & canvas , int x , int y , Gr::Colour c , Gr::Colour b ) : m_canvas(canvas) , m_x(x) , m_y(y) , m_c(c) , m_b(b) {}
105  void operator()( int x , int y , bool b )
106  {
107  m_canvas.point( x + m_x , m_canvas.dy() - ( y + m_y ) , b ? m_c : m_b ) ;
108  }
109  GX::Canvas & m_canvas ;
110  int m_x ;
111  int m_y ;
112  Gr::Colour m_c ;
113  Gr::Colour m_b ;
114  } ;
115 }
116 
117 void GX::Canvas::text( const std::string & s , int x , int y , Gr::Colour c )
118 {
119  out o( *this , x , y , c , black() ) ;
120  Gr::Glyph::output( s , o ) ;
121 }
122 
123 unsigned long GX::Canvas::pixel( const Gr::Colour & c_in ) const
124 {
125  return pixel( c_in , m_stereo_mode ) ;
126 }
127 
128 unsigned long GX::Canvas::pixel( const Gr::Colour & c_in , Canvas::Stereo stereo_mode ) const
129 {
130  Gr::Colour c = c_in ;
131  if( stereo_mode == Canvas::left )
132  {
133  static Gr::Colour red_0( 200 , 0 , 0 ) ;
134  static Gr::Colour red_16( 12 , 0 , 0 ) ;
135  static Gr::Colour red_256( 210 , 0 , 0 ) ;
136  c = m_colours == 0 ? red_0 : ( m_colours == 16 ? red_16 : red_256 ) ;
137  }
138  else if( stereo_mode == Canvas::right )
139  {
140  static Gr::Colour green_0( 0 , 200 , 0 ) ;
141  static Gr::Colour green_16( 10 , 0 , 0 ) ;
142  static Gr::Colour green_256( 120 , 0 , 0 ) ;
143  c = m_colours == 0 ? green_0 : ( m_colours == 16 ? green_16 : green_256 ) ;
144  }
145 
146  G_ASSERT( (m_colour_map.get()==nullptr) == (m_colours==0) ) ;
147  if( m_colours != 0 && ( c.g() || c.b() ) )
148  G_WARNING_ONCE( "GX::Canvas::pixel: invalid colour: green and blue components ignored" ) ;
149 
150  return m_colour_map.get() ? m_colour_map->get(c.r()) : c.cc() ;
151 }
152 
154 {
155  return
156  m_stereo_mode != Canvas::left && m_stereo_mode != Canvas::right &&
157  m_colour_map.get() == nullptr &&
158  m_client_side && m_image.fastable() ;
159 }
160 
161 void GX::Canvas::point( int x , int y , Gr::Colour c )
162 {
163  if( m_client_side )
164  {
165  bool pixel_or = m_stereo_mode == Canvas::left || m_stereo_mode == Canvas::right ;
166  m_image.drawPoint( x , m_dy-1-y , pixel(c) , pixel_or ) ;
167  }
168  else
169  {
170  m_context.setForeground( pixel(c) ) ;
171  m_pixmap.drawPoint( m_context , x , m_dy-1-y ) ;
172  }
173 }
174 
175 void GX::Canvas::line( int x0 , int y0 , int x1 , int y1 , Gr::Colour c )
176 {
177  if( m_client_side )
178  {
179  bool pixel_or = m_stereo_mode == Canvas::left || m_stereo_mode == Canvas::right ;
180  m_image.drawLine( x0 , m_dy-1-y0 , x1 , m_dy-1-y1 , pixel(c) , pixel_or ) ;
181  }
182  else
183  {
184  m_context.setForeground( pixel(c) ) ;
185  m_pixmap.drawLine( m_context , x0 , m_dy-1-y0 , x1 , m_dy-1-y1 ) ; // GX::Drawable::drawLine()
186  }
187 }
188 
189 void GX::Canvas::lineAcross( int y , int x_first , int x_last , const Gr::Colour & c )
190 {
191  if( m_client_side )
192  m_image.drawLineAcross( x_first , x_last , m_dy-1-y , pixel(c) ) ;
193  else
194  line( x_first , y , x_last , y , c ) ;
195 }
196 
197 void GX::Canvas::lineDown( int x , int y_first , int y_last , const Gr::Colour & c )
198 {
199  if( m_client_side )
200  m_image.drawLineDown( x , m_dy-1-y_first , m_dy-1-y_last , pixel(c) ) ;
201  else
202  line( x , y_first , x , y_last , c ) ;
203 }
204 
205 Gr::Colour GX::Canvas::readPoint( int x , int y ) const
206 {
207  unsigned long pixel = 0UL ;
208  if( m_client_side )
209  {
210  pixel = m_image.readPoint( x , m_dy-1-y ) ;
211  }
212  else
213  {
214  G_WARNING( "Canvas::readPoint: slow implementation" ) ;
215  unique_ptr<GX::Image> image_ptr ;
216  m_pixmap.readImage( image_ptr ) ;
217  pixel = image_ptr.get()->readPoint( x , m_dy-1-y ) ;
218  }
219 
220  G_ASSERT( (m_colour_map.get()==nullptr) == (m_colours==0) ) ;
221  if( m_colour_map.get() != nullptr )
222  {
223  G_ASSERT( m_colour_map->size() == static_cast<unsigned int>(m_colours) ) ;
224  pixel %= m_colour_map->size() ;
225  return Gr::Colour( m_colour_map->find(pixel) , 0U , 0U ) ;
226  }
227  else
228  {
229  Gr::Colour::cc_t cc = pixel ;
230  return Gr::Colour::from( cc ) ;
231  }
232 }
233 
234 void GX::Canvas::clear( bool to_white )
235 {
236  if( m_client_side )
237  {
238  m_image.clear( to_white ) ;
239  }
240  else
241  {
242  unsigned long pixel = to_white ? white().cc() : black().cc() ;
243  m_context.setForeground( pixel ) ;
244  m_pixmap.drawRectangle( m_context , 0 , 0 , m_dx , m_dy ) ;
245  }
246 }
247 
249 {
250  if( m_client_side )
251  m_image.blit( m_window , 0 , 0 , m_dx , m_dy , 0 , 0 ) ; // XPutImage()
252  else
253  m_pixmap.blit( m_window , 0 , 0 , m_dx , m_dy , 0 , 0 ) ; // XCopyArea()
254 }
255 
256 void GX::Canvas::stereo( Canvas::Stereo mode )
257 {
258  m_stereo_mode = mode ;
259 }
260 
261 /// \file gxcanvas.cpp
Gr::Colour colour(unsigned int n) const
Returns a colour from the palette.
Definition: gxcanvas.cpp:84
A window class that is-a GX::Drawable and a GX::EventHandler.
Definition: gxwindow.h:47
value_t r() const
Returns the red value.
Definition: grcolour.h:88
void install(GX::ColourMap &)
Installs a colourmap.
Definition: gxwindow.cpp:181
void point(int x, int y, Gr::Colour c)
Draws a single pixel.
Definition: gxcanvas.cpp:161
void lineDown(int x, int y_first, int y_last, const Gr::Colour &c)
Draws a vertical line.
Definition: gxcanvas.cpp:197
Canvas(GX::Window &, int dx=0, int dy=0, int colours=0, bool server_side=false)
Constructor.
Definition: gxcanvas.cpp:36
void clear(bool white=false)
Clears the canvas to black (or white).
Definition: gxcanvas.cpp:234
void blit()
Blits the canvas contents to the window.
Definition: gxcanvas.cpp:248
void lineAcross(int y, int x_first, int x_last, const Gr::Colour &c)
Draws a horizontal line.
Definition: gxcanvas.cpp:189
A simple rgb colour structure.
Definition: grcolour.h:36
std::pair< unsigned int, unsigned int > aspect() const
Returns the canvas aspect ratio as a fraction (normally about 0.7).
Definition: gxcanvas.cpp:79
A colourmap class that provides pixel values for a set of mapped colours.
Definition: gxcolourmap.h:41
static Colour from(cc_t cc)
Creates a colour from a combined-component value.
Definition: grcolour.h:115
~Canvas()
Destructor.
Definition: gxcanvas.cpp:60
int colours() const
Returns the number of colours, as passed in to the ctor.
Definition: gxcanvas.cpp:74
bool fastable() const
Returns true if fastpoint() can be used rather than point().
Definition: gxcanvas.cpp:153
GX::Display & windowDisplay()
Returns a reference to the display as passed in to the ctor.
Definition: gxwindow.cpp:122
value_t g() const
Returns the green value.
Definition: grcolour.h:94
Gr::Colour white() const
Returns white.
Definition: gxcanvas.cpp:95
int dx() const
Returns the canvas width in pixels.
Definition: gxcanvas.cpp:64
static bool enabled()
Returns true if test features are enabled.
Definition: gtest.cpp:49
Gr::Colour readPoint(int x, int y) const
Reads a pixel.
Definition: gxcanvas.cpp:205
void line(int x0, int y0, int x1, int y1, Gr::Colour c)
Draws a line.
Definition: gxcanvas.cpp:175
void text(const std::string &s, int x, int y, Gr::Colour c)
Draws a single-line text string at the given position.
Definition: gxcanvas.cpp:117
A drawing surface that is embedded in a window.
Definition: gxcanvas.h:61
static void output(const std::string &s, Tout &out_functor)
Calls an (x,y,bool) functor for all the glyph points corresponding to the given line of text...
Definition: grglyph.h:67
value_t b() const
Returns the blue value.
Definition: grcolour.h:100
cc_t cc() const
Returns a combined-component value that incorporates the r(), g() and b() values. ...
Definition: grcolour.h:106
unsigned long readPoint(int x, int y) const
Reads a pixel value at a point.
Definition: gximage.cpp:95
int dy() const
Returns the canvas height in pixels.
Definition: gxcanvas.cpp:69
Gr::Colour black() const
Returns black.
Definition: gxcanvas.cpp:90
void stereo(Stereo mode=normal)
Sets the left/right stereo mode for subsequent line() and point() drawing operations.
Definition: gxcanvas.cpp:256