summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/multimedia/opieplayer2/lib.cpp8
-rw-r--r--noncore/multimedia/opieplayer2/xinevideowidget.cpp378
-rw-r--r--noncore/multimedia/opieplayer2/xinevideowidget.h39
3 files changed, 207 insertions, 218 deletions
diff --git a/noncore/multimedia/opieplayer2/lib.cpp b/noncore/multimedia/opieplayer2/lib.cpp
index 748ae1f..d8a0694 100644
--- a/noncore/multimedia/opieplayer2/lib.cpp
+++ b/noncore/multimedia/opieplayer2/lib.cpp
@@ -92,9 +92,9 @@ Lib::Lib(XineVideoWidget* widget) {
92 if (m_wid != 0 ) { 92 if (m_wid != 0 ) {
93 printf("!0\n" ); 93 printf("!0\n" );
94 resize ( m_wid-> size ( )); 94 resize ( m_wid-> size ( ));
95 ::null_set_mode( m_videoOutput, qt_screen->depth(), qt_screen->pixelType() ); 95 ::null_set_mode( m_videoOutput, qt_screen->depth(), qt_screen->pixelType() );
96 m_wid-> setImage ( new QImage ( Resource::loadImage("") ) ); 96 m_wid-> setLogo ( new QImage ( Resource::loadImage("")));
97 m_wid->repaint(); 97 m_wid->repaint();
98 } 98 }
99 null_display_handler( m_videoOutput, 99 null_display_handler( m_videoOutput,
100 xine_display_frame, 100 xine_display_frame,
@@ -225,10 +225,8 @@ void Lib::drawFrame( uint8_t* frame, int width, int height, int bytes ) {
225 if (!m_video ) { 225 if (!m_video ) {
226 qWarning("not showing video now"); 226 qWarning("not showing video now");
227 return; 227 return;
228 } 228 }
229// qWarning("called draw frame %d %d", width, height); 229// qWarning( "called draw frame %d %d", width, height );
230
231 m_wid->setImage( frame, width, height, bytes );
232// m_wid->repaint(false);
233 230
231 m_wid-> setVideoFrame ( frame, width, height, bytes );
234} 232}
diff --git a/noncore/multimedia/opieplayer2/xinevideowidget.cpp b/noncore/multimedia/opieplayer2/xinevideowidget.cpp
index d06d62a..9b26d41 100644
--- a/noncore/multimedia/opieplayer2/xinevideowidget.cpp
+++ b/noncore/multimedia/opieplayer2/xinevideowidget.cpp
@@ -1,10 +1,9 @@
1 1
2/* 2/*
3                This file is part of the Opie Project 3                This file is part of the Opie Project
4 4
5              Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> 5 Copyright (c) 2002 Robert Griebl <sandman@handhelds.org>
6 Copyright (c) 2002 LJP <>
7 Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> 6 Copyright (c) 2002 Holger Freyther <zecke@handhelds.org>
8 =. 7 =.
9 .=l. 8 .=l.
10           .>+-= 9           .>+-=
@@ -28,9 +27,9 @@
28    --        :-=` this library; see the file COPYING.LIB. 27    --        :-=` this library; see the file COPYING.LIB.
29 If not, write to the Free Software Foundation, 28 If not, write to the Free Software Foundation,
30 Inc., 59 Temple Place - Suite 330, 29 Inc., 59 Temple Place - Suite 330,
31 Boston, MA 02111-1307, USA. 30 Boston, MA 02111-1307, USA.
32 31
33*/ 32*/
34 33
35#include <qimage.h> 34#include <qimage.h>
36#include <qpainter.h> 35#include <qpainter.h>
@@ -44,230 +43,221 @@
44#include <qpe/resource.h> 43#include <qpe/resource.h>
45 44
46#include "xinevideowidget.h" 45#include "xinevideowidget.h"
47 46
47// 0 deg rot: copy a line from src to dst (use libc memcpy)
48
49// 180 deg rot: copy a line from src to dst reversed
48 50
49static inline void memcpy_rev ( void *dst, void *src, size_t len ) 51static inline void memcpy_rev ( void *dst, void *src, size_t len )
50{ 52{
51 ((char *) src ) += len; 53 ((char *) src) += len;
52 54
53 len >>= 1; 55 len >>= 1;
54 while ( len-- ) 56 while ( len-- )
55 *((short int *) dst )++ = *--((short int *) src ); 57 *((short int *) dst) ++ = *--((short int *) src);
56} 58}
57 59
58static inline void memcpy_step ( void *dst, void *src, size_t len, size_t step ) 60// 90 deg rot: copy a column from src to dst
61
62static inline void memcpy_step ( void *dst, void *src, size_t len, size_t linestep )
59{ 63{
60 len >>= 1; 64 len >>= 1;
61 while ( len-- ) { 65 while ( len-- ) {
62 *((short int *) dst )++ = *((short int *) src ); 66 *((short int *) dst) ++ = *((short int *) src);
63 ((char *) src ) += step; 67 ((char * ) src) += linestep;
64 } 68 }
65} 69}
66 70
67static inline void memcpy_step_rev ( void *dst, void *src, size_t len, size_t step ) 71// 270 deg rot: copy a column from src to dst reversed
72
73static inline void memcpy_step_rev ( void *dst, void *src, size_t len, size_t linestep )
68{ 74{
69 len >>= 1; 75 len >>= 1;
70 76
71 ((char *) src ) += ( len * step ); 77 ((char *) src) += ( len * linestep );
72 78
73 while ( len-- ) { 79 while ( len-- ) {
74 ((char *) src ) -= step; 80 ((char *) src) -= linestep;
75 *((short int *) dst )++ = *((short int *) src ); 81 *((short int *) dst) ++ = *((short int *) src);
76 } 82 }
77} 83}
78 84
79 85
80XineVideoWidget::XineVideoWidget ( QWidget* parent, const char* name ) 86XineVideoWidget::XineVideoWidget ( QWidget* parent, const char* name )
81 : QWidget ( parent, name, WRepaintNoErase | WResizeNoErase ) 87 : QWidget ( parent, name, WRepaintNoErase | WResizeNoErase )
82{ 88{
83 setBackgroundMode ( NoBackground ); 89 setBackgroundMode ( NoBackground );
84 90
85 m_image = 0; 91 m_logo = 0;
86 m_buff = 0; 92 m_buff = 0;
87 m_bytes_per_line_fb = qt_screen-> linestep ( ); 93 m_bytes_per_line_fb = qt_screen-> linestep ( );
88 m_bytes_per_pixel = ( qt_screen->depth() + 7 ) / 8; 94 m_bytes_per_pixel = ( qt_screen-> depth ( ) + 7 ) / 8;
89 m_rotation = 0; 95 m_rotation = 0;
90} 96}
91 97
92 98
93XineVideoWidget::~XineVideoWidget ( ) 99XineVideoWidget::~XineVideoWidget ( )
94{ 100{
95 delete m_image; 101 delete m_logo;
96} 102}
97 103
98void XineVideoWidget::clear ( ) 104void XineVideoWidget::clear ( )
99{ 105{
100 m_buff = 0; 106 m_buff = 0;
101 repaint ( false ); 107 repaint ( false );
102} 108}
103 109
104void XineVideoWidget::paintEvent ( QPaintEvent * ) 110void XineVideoWidget::paintEvent ( QPaintEvent * )
105{ 111{
106 //qWarning( "painting <<<" ); 112 if ( m_buff == 0 ) {
107 if ( m_buff == 0 ) { 113 QPainter p ( this );
108 QPainter p ( this ); 114 p. fillRect ( rect ( ), black );
109 p. fillRect ( rect ( ), black ); 115 if ( m_logo )
110 if ( m_image ) 116 p. drawImage ( 0, 0, *m_logo );
111 p. drawImage ( 0, 0, *m_image ); 117 }
112 //qWarning ( "logo\n" ); 118 else {
113 } 119 // Qt needs to be notified which areas were really updated .. strange
114 else { 120 QArray <QRect> qt_bug_workaround_clip_rects;
115// qWarning ( "paintevent\n" ); 121
116 122 {
117 QArray <QRect> qt_bug_workaround_clip_rects; 123 QDirectPainter dp ( this );
118 124
119 { 125 int rot = dp. transformOrientation ( ) + m_rotation; // device rotation + custom rotation
120 QDirectPainter dp ( this ); 126
121 127 uchar *fb = dp. frameBuffer ( );
122 int rot = dp. transformOrientation ( ) + m_rotation; 128 uchar *frame = m_buff;
123 129
124 uchar *fb = dp. frameBuffer ( ); 130 // where is the video frame in fb coordinates
125 uchar *frame = m_buff; // rot == 0 ? m_buff : m_buff + ( m_thisframe. height ( ) - 1 ) * m_bytes_per_line_frame; 131 QRect framerect = qt_screen-> mapToDevice ( QRect ( mapToGlobal ( m_thisframe. topLeft ( )), m_thisframe. size ( )), QSize ( qt_screen-> width ( ), qt_screen-> height ( )));
126 132
127 QRect framerect = qt_screen-> mapToDevice ( QRect ( mapToGlobal ( m_thisframe. topLeft ( )), m_thisframe. size ( )), QSize ( qt_screen-> width ( ), qt_screen-> height ( ))); 133 qt_bug_workaround_clip_rects. resize ( dp. numRects ( ));
128 134
129 qt_bug_workaround_clip_rects. resize ( dp. numRects ( )); 135 for ( int i = dp. numRects ( ) - 1; i >= 0; i-- ) {
130 136 const QRect &clip = dp. rect ( i );
131 for ( int i = dp. numRects ( ) - 1; i >= 0; i-- ) { 137
132 const QRect &clip = dp. rect ( i ); 138 qt_bug_workaround_clip_rects [ i ] = qt_screen-> mapFromDevice ( clip, QSize ( qt_screen-> width ( ), qt_screen-> height ( )));
133 139
134 qt_bug_workaround_clip_rects [i] = qt_screen-> mapFromDevice ( clip, QSize ( qt_screen-> width ( ), qt_screen-> height ( ))); 140 uchar *dst = fb + ( clip. x ( ) * m_bytes_per_pixel ) + ( clip. y ( ) * m_bytes_per_line_fb ); // clip x/y in the fb
135 141 uchar *src = frame;
136 uchar *dst = fb + ( clip. x ( ) * m_bytes_per_pixel ) + ( clip. y ( ) * m_bytes_per_line_fb ); 142
137 uchar *src = frame; 143 // Adjust the start the source data based on the rotation (xine frame)
138 144 switch ( rot ) {
139 switch ( rot ) { 145 case 0: src += ((( clip. x ( ) - framerect. x ( )) * m_bytes_per_pixel ) + (( clip. y ( ) - framerect. y ( )) * m_bytes_per_line_frame )); break;
140 case 0: src += ( (( clip. x ( ) - framerect. x ( )) * m_bytes_per_pixel ) + (( clip. y ( ) - framerect. y ( )) * m_bytes_per_line_frame ) ); break; 146 case 1: src += ((( clip. y ( ) - framerect. y ( )) * m_bytes_per_pixel ) + (( clip. x ( ) - framerect. x ( )) * m_bytes_per_line_frame ) + (( framerect. height ( ) - 1 ) * m_bytes_per_pixel )); break;
141 case 1: src += ( (( clip. y ( ) - framerect. y ( )) * m_bytes_per_pixel ) + (( clip. x ( ) - framerect. x ( )) * m_bytes_per_line_frame ) + (( framerect. height ( ) - 1 ) * m_bytes_per_pixel ) ); break; 147 case 2: src += ((( clip. x ( ) - framerect. x ( )) * m_bytes_per_pixel ) + (( clip. y ( ) - framerect. y ( )) * m_bytes_per_line_frame ) + (( framerect. height ( ) - 1 ) * m_bytes_per_line_frame )); break;
142 case 2: src += ( (( clip. x ( ) - framerect. x ( )) * m_bytes_per_pixel ) + (( clip. y ( ) - framerect. y ( )) * m_bytes_per_line_frame ) + (( framerect. height ( ) - 1 ) * m_bytes_per_line_frame ) ); break; 148 case 3: src += ((( clip. y ( ) - framerect. y ( )) * m_bytes_per_pixel ) + (( clip. x ( ) - framerect. x ( )) * m_bytes_per_line_frame )); break;
143 case 3: src += ( (( clip. y ( ) - framerect. y ( )) * m_bytes_per_pixel ) + (( clip. x ( ) - framerect. x ( )) * m_bytes_per_line_frame ) ); break; 149 default: break;
144 default: break; 150 }
145 } 151
146 152 // all of the following widths/heights are fb relative (0deg rotation)
147 uint leftfill = 0; 153
148 uint framefill = 0; 154 uint leftfill = 0; // black border on the "left" side of the video frame
149 uint rightfill = 0; 155 uint framefill = 0; // "width" of the video frame
150 uint clipwidth = clip. width ( ) * m_bytes_per_pixel; 156 uint rightfill = 0; // black border on the "right" side of the video frame
151 157 uint clipwidth = clip. width ( ) * m_bytes_per_pixel; // "width" of the current clip rect
152 if ( clip. left ( ) < framerect. left ( )) 158
153 leftfill = (( framerect. left ( ) - clip. left ( )) * m_bytes_per_pixel ) <? clipwidth; 159 if ( clip. left ( ) < framerect. left ( ))
154 if ( clip. right ( ) > framerect. right ( )) 160 leftfill = (( framerect. left ( ) - clip. left ( )) * m_bytes_per_pixel ) < ? clipwidth;
155 rightfill = (( clip. right ( ) - framerect. right ( )) * m_bytes_per_pixel ) <? clipwidth; 161 if ( clip. right ( ) > framerect. right ( ))
156 162 rightfill = (( clip. right ( ) - framerect. right ( )) * m_bytes_per_pixel ) < ? clipwidth;
157 framefill = clipwidth - ( leftfill + rightfill ); 163
158 164 framefill = clipwidth - ( leftfill + rightfill );
159 for ( int y = clip. top ( ); y <= clip. bottom ( ); y++ ) { 165
160 if (( y < framerect. top ( )) || ( y > framerect. bottom ( ))) { 166 for ( int y = clip. top ( ); y <= clip. bottom ( ); y++ ) {
161 memset ( dst, 0, clipwidth ); 167 if (( y < framerect. top ( )) || ( y > framerect. bottom ( ))) {
162 } 168 // "above" or "below" the video -> black
163 else { 169 memset ( dst, 0, clipwidth );
164 if ( leftfill ) 170 }
165 memset ( dst, 0, leftfill ); 171 else {
166 172 if ( leftfill )
167 if ( framefill ) { 173 memset ( dst, 0, leftfill ); // "left" border -> black
168 switch ( rot ) { 174
169 case 0: memcpy ( dst + leftfill, src, framefill ); break; 175 if ( framefill ) { // blit in the video frame
170 case 1: memcpy_step ( dst + leftfill, src, framefill, m_bytes_per_line_frame ); break; 176 // see above for an explanation of the different memcpys
171 case 2: memcpy_rev ( dst + leftfill, src, framefill ); break; 177
172 case 3: memcpy_step_rev ( dst + leftfill, src, framefill, m_bytes_per_line_frame ); break; 178 switch ( rot ) {
173 default: break; 179 case 0: memcpy ( dst + leftfill, src, framefill ); break;
174 } 180 case 1: memcpy_step ( dst + leftfill, src, framefill, m_bytes_per_line_frame ); break;
175 } 181 case 2: memcpy_rev ( dst + leftfill, src, framefill ); break;
176 if ( rightfill ) 182 case 3: memcpy_step_rev ( dst + leftfill, src, framefill, m_bytes_per_line_frame ); break;
177 memset ( dst + leftfill + framefill, 0, rightfill ); 183 default: break;
178 } 184 }
179 185 if ( rightfill )
180 dst += m_bytes_per_line_fb; 186 memset ( dst + leftfill + framefill, 0, rightfill ); // "right" border -> black
181 187 }
182 switch ( rot ) { 188
183 case 0: src += m_bytes_per_line_frame; break; 189 dst += m_bytes_per_line_fb; // advance one line in the framebuffer
184 case 1: src -= m_bytes_per_pixel; break; 190
185 case 2: src -= m_bytes_per_line_frame; break; 191 // advance one "line" in the xine frame data
186 case 3: src += m_bytes_per_pixel; break; 192 switch ( rot ) {
187 default: break; 193 case 0: src += m_bytes_per_line_frame;break;
188 } 194 case 1: src -= m_bytes_per_pixel; break;
189 } 195 case 2: src -= m_bytes_per_line_frame; break;
190 } 196 case 3: src += m_bytes_per_pixel; break;
191 } 197 default: break;
192 //qWarning ( " ||| painting |||" ); 198 }
193 { 199 }
194 // QVFB hack by MArtin Jones 200 }
195 QPainter p ( this ); 201
196 202 {
197 for ( int i = qt_bug_workaround_clip_rects. size ( ) - 1; i >= 0; i-- ) { 203 // QVFB hack by Martin Jones
198 p. fillRect ( QRect ( mapFromGlobal ( qt_bug_workaround_clip_rects [i]. topLeft ( )), qt_bug_workaround_clip_rects [i]. size ( )), QBrush ( NoBrush ) ); 204 // We need to "touch" all affected clip rects with a normal QPainter in addition to the QDirectPainter
199 } 205
200 } 206 QPainter p ( this );
201 } 207
202 //qWarning( "painting >>>" ); 208 for ( int i = qt_bug_workaround_clip_rects. size ( ) - 1; i >= 0; i-- ) {
203} 209 p. fillRect ( QRect ( mapFromGlobal ( qt_bug_workaround_clip_rects [ i ]. topLeft ( )), qt_bug_workaround_clip_rects [ i ]. size ( )), QBrush ( NoBrush ));
204 210 }
205 211 }
206void XineVideoWidget::setImage ( QImage* image ) 212 }
207{ 213 }
208 delete m_image; 214
209 m_image = image; 215 QImage *XineVideoWidget::logo ( ) const {
210} 216 return m_logo;
211 217 }
212void XineVideoWidget::setImage ( uchar* img, int w, int h, int bpl )
213{
214 bool rot90 = (( -m_rotation ) & 1 );
215
216 if ( rot90 ) {
217 int d = w;
218 w = h;
219 h = d;
220 }
221
222 m_lastframe = m_thisframe;
223 m_thisframe. setRect (( width ( ) - w ) / 2, ( height ( ) - h ) / 2, w , h );
224
225// qDebug ( "Frame: %d,%d - %dx%d", ( width ( ) - w ) / 2, ( height ( ) - h ) / 2, w , h );
226
227 m_buff = img;
228 m_bytes_per_line_frame = bpl;
229
230 repaint ((( m_thisframe & m_lastframe ) != m_lastframe ) ? m_lastframe : m_thisframe, false );
231}
232
233void XineVideoWidget::resizeEvent ( QResizeEvent * )
234{
235 QSize s = size ( );
236 bool fs = ( s == qApp-> desktop ( )-> size ( ));
237
238 m_rotation = fs ? -qt_screen-> transformOrientation ( ) : 0;
239
240 if ( fs && qt_screen-> isTransformed ( )) {
241 s = qt_screen-> mapToDevice ( s );
242 }
243
244// qDebug ( "\n\nResize: %dx%d, Rot: %d", s.width(),s.height(),m_rotation );
245
246 emit videoResized ( s );
247}
248
249
250void XineVideoWidget::mousePressEvent ( QMouseEvent * /*me*/ )
251{
252 QWidget *p = parentWidget ( );
253 218
254 if ( p ) { 219 void XineVideoWidget::setLogo ( QImage * image ) {
255 // QMouseEvent pme ( QEvent::MouseButtonPress, mapToParent ( me-> pos ( )), me-> globalPos ( ), me-> button ( ), me-> state ( )); 220 delete m_logo;
221 m_logo = image;
222 }
256 223
257 // QApplication::sendEvent ( p, &pme ); 224 void XineVideoWidget::setVideoFrame ( uchar * img, int w, int h, int bpl ) {
258 // emit clicked(); 225 bool rot90 = (( -m_rotation ) & 1 );
259 }
260}
261
262void XineVideoWidget::mouseReleaseEvent ( QMouseEvent * /*me*/ )
263{
264 QWidget *p = parentWidget ( );
265 226
266 if ( p ) { 227 if ( rot90 ) { // if the rotation is 90 or 270 we have to swap width / height
267 // QMouseEvent pme ( QEvent::MouseButtonRelease, mapToParent ( me-> pos ( )), me-> globalPos ( ), me-> button ( ), me-> state ( )); 228 int d = w;
229 w = h;
230 h = d;
231 }
268 232
269 // QApplication::sendEvent ( p, &pme ); 233 m_lastframe = m_thisframe;
270 emit clicked(); 234 m_thisframe. setRect (( width ( ) - w ) / 2, ( height ( ) - h ) / 2, w , h );
271 } 235
272} 236 m_buff = img;
237 m_bytes_per_line_frame = bpl;
238
239 // only repaint the area that *really* needs to be repainted
240
241 repaint ((
242 }
243
244 void XineVideoWidget::resizeEvent ( QResizeEvent * ) {
245 QSize s = size ( );
246 bool fs = ( s == qApp-> desktop ( ) -> size ( ));
247
248 // if we are in fullscreen mode, do not rotate the video
249 // (!! the paint routine uses m_rotation + qt_screen-> transformOrientation() !!)
250
251 m_rotation = fs ? -qt_screen-> transformOrientation ( ) : 0;
252
253 if ( fs && qt_screen-> isTransformed ( ))
254 s = qt_screen-> mapToDevice ( s );
255
256 emit videoResized ( s );
257 }
258
259
260 void XineVideoWidget::mouseReleaseEvent ( QMouseEvent * ) {
261 emit clicked ( );
262 }
273 263
diff --git a/noncore/multimedia/opieplayer2/xinevideowidget.h b/noncore/multimedia/opieplayer2/xinevideowidget.h
index c5101da..33f1470 100644
--- a/noncore/multimedia/opieplayer2/xinevideowidget.h
+++ b/noncore/multimedia/opieplayer2/xinevideowidget.h
@@ -1,9 +1,8 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3 3
4              Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> 4 Copyright (c) 2002 Robert Griebl <sandman@handhelds.org>
5 Copyright (c) 2002 LJP <>
6 Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> 5 Copyright (c) 2002 Holger Freyther <zecke@handhelds.org>
7 =. 6 =.
8 .=l. 7 .=l.
9           .>+-= 8           .>+-=
@@ -37,37 +36,39 @@
37 36
38#include "lib.h" 37#include "lib.h"
39 38
40class QImage; 39class QImage;
40
41
41class XineVideoWidget : public QWidget { 42class XineVideoWidget : public QWidget {
42 Q_OBJECT 43 Q_OBJECT
44
43public: 45public:
44 XineVideoWidget( QWidget* parent, const char* name ); 46 XineVideoWidget ( QWidget* parent, const char* name );
45 ~XineVideoWidget(); 47 ~XineVideoWidget ( );
46 QImage *image() { return m_image; }; 48 QImage *logo ( ) const;
47 void setImage( QImage* image ); 49 void setLogo ( QImage *image );
48 void setImage( uchar* image, int width, int height, int linestep); 50 void setVideoFrame ( uchar *image, int width, int height, int linestep );
49 void clear() ; 51 void clear ( );
50 52
51protected: 53protected:
52 void paintEvent( QPaintEvent* p ); 54 void paintEvent( QPaintEvent *p );
53 void resizeEvent ( QResizeEvent *r ); 55 void resizeEvent ( QResizeEvent *r );
54 56
55 void mousePressEvent ( QMouseEvent *e );
56 void mouseReleaseEvent ( QMouseEvent *e ); 57 void mouseReleaseEvent ( QMouseEvent *e );
57 58
58signals: 59signals:
59 void clicked(); 60 void clicked ( );
60 void videoResized ( const QSize &s ); 61 void videoResized ( const QSize &s );
61 62
62private: 63private:
63 QRect m_lastframe; 64 QRect m_lastframe;
64 QRect m_thisframe; 65 QRect m_thisframe;
65 66
66 uchar* m_buff; 67 uchar *m_buff;
67 int m_bytes_per_line_fb; 68 int m_bytes_per_line_fb;
68 int m_bytes_per_line_frame; 69 int m_bytes_per_line_frame;
69 int m_bytes_per_pixel; 70 int m_bytes_per_pixel;
70 QImage* m_image; 71 QImage *m_logo;
71 int m_rotation; 72 int m_rotation;
72}; 73};
73 74